OGRE关于Demo_CubeMapping 的学习

来源:互联网 发布:站长之家软件 编辑:程序博客网 时间:2024/06/05 02:06

目的: 显示 立方体映射的特色(cube mapping), 还可以设置物体镜面映射出周围的景色
主要有两个类 CubeMapApplication 和 CubeMapListener

* 该例中对象的周围景象反射是通过设置对象的主材质material实现的, 在脚本中设置了env_map cubic_reflect和cubic_texture属性
    该对象的子mesh则是复制原始mesh中的子mesh, 材质也是复制其子mesh的材质
* 该例可以学习如何克隆一个mesh, 并复制其顶点数据, 并克隆其子材质, 该例可以学习 硬件顶点缓存的一些知识
* 该例演示了 如何修改Mesh所带的顶点数据, 给这些顶点位置增加噪值, 并更新顶点的法线数据。 实现很特殊的效果
* 利用天空盒Skybox, 可以直接通过材质中的纹理单元cubic_texture属性来设置六个面。 就可以作出六张照片形成的虚拟空间效果。
* 对象的立体纹理需要开启UVW坐标, 而天空盒的立体纹理不需要开始UVW坐标, 开启该坐标在立体纹理中有用。

1. 类 CubeMapApplication --- 主类, 驱动类
    构造函数: 无
    函数createScene --- 构造场景
        判断显卡是否支持 Cube Mapping.
        环境光 0.5, 0.5, 0.5
        设置天空盒 SKYBOX_MATERIAL "Examples/SceneSkyBox2"
        创建光 MainLight
        光的位置 20,80,50
        创建一个场景节点
        OverlayManager 通过名称“Example/CubeMappingOverlay”得到 一个Overlay
        显示它
    函数createFrameListener
    
       
2. 类 CubeMapListener
    构造函数:
        调用基类的构造函数
        得到场景管理器和对象节点
        通过MaterialManager得到材质 Examples/SceneCubeMap2 material 这个材质使用了combinedUVW格式的立方纹理
        readConfig
            加载 media.cfg
            将该配置文件所有的Mesh和CubeMesh放入字符串容器中 getMultiSetting
        setObject
            设置要用的Mesh索引
            得到mesh名称
            prepareEntity
            更新Overlay元素   
        setMaterialBlending   
            设置材质的混合
        setCubeMap
            设置立体纹理, 更新对象的纹理反射以及天空盒
        setNoiseOn
            在Overlay上提示开始噪值
        updateInfoDisplacement
            在Overlay上提示替换方式
        updateInfoDensity
            在Overlay上提示噪值度
        updateInfoTimeDensity
            在Overlay上提示时间噪值度       

    函数 prepareEntity---参数为纹理名称
        判断是否有对象实体
            有--调用clearEntity
                移除材质容器的所有元素 clonedMaterials
                对象节点移除所有对象的挂接
                场景管理器销毁该环境映射实体 mSceneMgr->destroyEntity(ENTITY_NAME);
                MeshManager 移除 clonedMesh
        MeshManager 根据 mesh名称得到originalMesh——getByName
        如果 originalMesh 为空
            调用 MeshManager 的 load 方法 加载
            如果还为空, 则抛出异常
        函数prepareClonedMesh(复制mesh,顶点共享数据复, 材质名称等等)
        创建一个立体映射实体  objectEntity
        设置其材质, 这里的材质在构造函数中定义好了 MATERIAL_NAME, 为立体材质
        // 下面一段代码的目的是, 根据得到的克隆mesh, 将其子mesh的材质克隆出一个材质, 并让创建的实体使用该克隆材质。
        得到其第一个通道 pass
        循环克隆的子mesh数
            得到克隆的子mesh
            得到对应的子实体
            subMesh调用 isMatInitialised,返回为真的话
                得到子mesh的材质名称 matName
                根据matName 得到该材质 subMat
                如该材质不为空
                    该材质重新加载
                    复制该材质  cloned
                    得到  cloned 的第一个通道 clonedPass
                    如果 meshName 等于 knot.mesh
                        循环该通道的纹理单元数
                            每个纹理单元调用 setScrollAnimation 设置为 1.0, 0
                   
                    循环该通道的纹理单元数
                    将原通道的纹理单元复制到该克隆的纹理单元 getTextureUnitState  createTextureUnitState
                    并调用setColourOperationEx设置为当前的操作
                对应子实体设置为该子材质名称
                将该克隆材质压入容器中
        对象节点绑定该对象实体
        是否开启 noiseOn
            是的话调用 updateNoise()


    函数 prepareClonedMesh
    // 我们根据原始的mesh创建新的mesh, 但更改了 HBU 标识
        创建手工纹理 clonedMesh, 名称为 MESH_NAME
        调用 _setBounds 设置成 原Mesh的Bounds
        调用 _setBoundingSphereRadius
        调用 _prepareVertexData 设置克隆材质的顶点共享数据clonedMesh->sharedVertexData(参数为原材质的共享顶点数据orgVD)
        循环原始mesh的子mesh数
            克隆的mesh也创建一个子mesh newSM
            原始子Mesh 调用isMatInitialised, 如果为真
                newSM的名字同原子mesh
            复制 useSharedVertices
            调用 _prepareVertexData 复制顶点数据
            复制 indexData->indexBuffer, indexData->indexStart, indexData->indexCount           

    函数 _prepareVertexData
        // 设置克隆材质的顶点共享数据(参数为原材质的共享顶点数据orgVD)
        // 将orgVD顶点的位置和法线数据复制到新的硬件缓存中, 其他的顶点数据不变
        // 用顶点缓存的索引号实现绑定, 再将索引号放入顶点声明中
        参数是否为0 ,为0 则直接返回0
        // 当该Demo开始写的时候重组每个元素的顶点缓存,由带有一定扭曲的顶点程序替换, 用软件实现, 可以适应旧的显卡
        调用原始顶点数据的顶点声明的clone方法, 得到新的顶点声明 newDecl
        newDecl 调用 getElements方法得到元素列表
        VertexDeclaration::VertexElementList::const_iterator di;
        遍历元素
            newDecl 调用 modifyElement 修改元素, 和原始数据一样, 效果等于用源顶点数据的类型和类别来初始化newDecl
        orgVD调用reorganiseBuffers重组 newDecl的缓存
        创建新的VertexData对象 newVD
        其vertexCount和vertexStart同orgVD
        得到newVD的声明newVDecl和缓存绑定newVBind
        得到orgVD的顶点声明的元素列表 orgVD->vertexDeclaration->getElements() ;
        遍历orgVD元素列表
            根据每个元素的getSemantic方法得到ves, 为该顶点的类别, 是法线, 还是。。。
            用方法getSource 得到 顶点缓存索引 source
            得到原始顶点数据该顶点的缓存指针 orgBuf  orgVD->vertexBufferBinding->getBuffer( source );
            根据ves设置dynamic, 法线,位置顶点为真, 其余基本为假
            判断dynamic
            是
                根据原始数据的顶点大小和顶点数目创建新的硬件缓存 newBuf
                而后newBuf复制原始的数据
                设置newVBind设置source索引号到newBuf
            否
                设置newVBind设置source索引号到原来的缓存
            newVDecl增加元素, 根据source绑定的硬件缓存索引, 添加进newVDecl
        返回newVD       

    updateNoise
        循环克隆mesh的子mesh数
            分别得到克隆mesh和源mesh的子mesh subMesh, orgSubMesh
            如果 subMesh使用共享顶点, 根据共享顶点数据得到法线的硬件缓存地址
                如果 sharedNormals = 0 即第一次共享时
                    则其等于 _normalsGetCleared
                        得到子Mesh的顶点共享数据的法线元素
                        得到法线的硬件顶点缓存
                        锁定该段缓存, 并将这段数据重置为0
                    _updateVertexDataNoiseAndNormals
                        给mesh的所有顶点加上一个噪值, 并设置法线
            如果不使用共享顶点, 根据子Mesh的顶点数据得到法线的硬件缓存地址
                _normalsGetCleared 清理法线数据
                _updateVertexDataNoiseAndNormals 更新
                _normalsSaveNormalized 单元化并保存硬件缓存中的法线数据
            如果共享法线
                _normalsSaveNormalized 单元化并保存硬件缓存中的法线数据

    函数 _updateVertexDataNoiseAndNormals
        参数: 克隆mesh的顶点共享数据, 原始mesh的顶点共享数据, 子mesh的索引数据(indexData), 锁定的法线硬件缓存
        在克隆mesh的顶点共享数据中找到位置数据的元素dstVEPos--findElementBySemantic(VES_POSITION)
        在顶点共享数据的缓存绑定中找到位置数据个索引得到缓存指针dstHVBPos getBuffer(dstVEPos->getSource())
        同理, 得到原始mesh的orgVEPos 和缓存orgHVBPos
        分别锁定目标和源缓存得到指针 dstDataPos, orgDataPos
        循环-- 次数为 源 顶点数
            将原始数据的顶点位置加上一个随机产生的噪值使得图形发生一种变形
        源 解除锁定
        // 开始计算各处的法线
        根据子mesh的索引数据得到 硬件缓存的索引 indexHB
        根据indexHB, 锁定缓存, 得到指针 vertexIndices
        计算mesh的面数numFaces为 顶点索引数/3 indexData->indexCount / 3
        循环面数 vertexIndices + 3
            vertexIndices[0], vertexIndices[1], vertexIndices[2] 为顶点索引
            在dstDataPos里面根据索引得到三个顶点的位置
            求出法线
            在normals法线缓存中根据索引设置法线向量
        解除indexHB的锁定
        解除目标缓存的锁定
       
    函数 _normalsSaveNormalized
        功能: 单元化硬件缓存中 法线的数据
        参数: 子mesh的顶点数据, 法线的缓存地址 normals
        根据顶点数据的顶点声明找到 法线的元素 normVE
        根据绑定绑定缓存用normVE的索引找到硬件顶点缓存
        循环顶点数 normals + 3
            单元化 normals[0], normals[1], normals[2]
        解除法线缓存的锁定
       
    函数 setMaterialBlending
        设置材质的混合方式
        调用 prepareEntity 重新构造实体
        更新 Overlay信息
       
    函数 setCubeMap
    // 用于改变映射的环境图片
        得到映射的图片名称
        循环立体纹理的每个面
            getFrameTextureName 得到纹理名称
            通过纹理管理器的 getByName 得到纹理指针
            纹理管理移除该纹理
        该纹理单元设置立体纹理 setCubicTextureName
        得到SKYBOX_MATERIAL的材质mat2
        循环该材质的立体纹理
            移除旧的纹理
        设置立体纹理
        场景管理器设置天空盒 SKYBOX_MATERIAL
        prepareEntity 重构实体
       
    函数 frameRenderingQueued
        调用基类的帧更新函数
        设置tm
        如果开始噪值功能, 则调用updateNoise
        旋转对象
       
    函数 processUnbufferedKeyInput
        // 处理键盘输入
        其中 ADJUST_RANGE 宏 和 SWITCH_VALUE 宏很值得学习       
    #define ADJUST_RANGE(_value,_keyPlus,_keyMinus,_minVal,_maxVal,_change,_macro) {/
        if (mKeyboard->isKeyDown(_keyPlus)) /
            { _value+=_change ; if (_value>=_maxVal) _value = _maxVal ; _macro ; } ; /
            if (mKeyboard->isKeyDown(_keyMinus)) /
            { _value-=_change; if (_value<=_minVal) _value = _minVal ; _macro ; } ; /
            }
    #define SWITCH_VALUE(_key,_timeDelay, _macro) { /
        if (mKeyboard->isKeyDown(_key) && timeoutDelay==0) { /
        timeoutDelay = _timeDelay ; _macro ;} }