OGRE关于 Demo_DeferedShading 例子的分析

时间:2021-03-25 16:51:04

总结:

1. 可以学会克隆一个实体的方法
2. 可以根据雅典娜的材质得知顶点着色器的使用, 在事先构建的切线数据(buildTangentVectors)放置于 着色程序的属性 tangent中, 着色程序就可以直接使用该属性
3. 学会如何创建一个曲面, 用MovablePlane.
4. 实体调用setMeshLodBias设置LOD, 数值越小则越清晰.
5. 实现如何创建一个只能拥有一个实例的类 class className : public Ogre::Singleton<className>;
6. 设置GPU程序一致变量的方法: ptrProgram->getDefaultParameters()->setNamedConstant("tex0", 0);
7. 该程序材质的生成器使用的GPU程序 顶点 DeferredShading/post/vs 即 DeferredShading/post/glsl/vs.glsl 或 DeferredShading/post/LightMaterial_vs
    片段 DeferredShading/post/glsl/LightMaterial_ps.glsl
    材质 DeferredShading/LightMaterialQuad 或 DeferredShading/LightMaterial
8. 修改实体的渲染次序 setRenderQueueGroup(RENDER_QUEUE_2 + 1);
9. 在LightMaterialGeneratorImpl::setUpBaseParameters方法中, 其参数列表的 setNamedAutoConstant方法可以设置 ACT_CUSTOM参数,
    将该参数关联到一个索引. 而后在Ogre中可以调用setCustomParameter来设置该参数.
    至于其他的参数, 则会自动关联到特定的变量, 详情可以参考API.
    可以通过这样的方法在Ogre中改变GPU程序的一些变量.
10. 可以学会如何继承自 SimpleRenderable, 并设置其mRenderOp的顶点数据, 索引数据, 渲染对列祖, BoundingBox, 内部加材质等等信息. 可在AmbientLight类中学会使用方法
11. 以后可以用 GeomUtils 来直接创建球体和立方体Mesh
12. DeferedShadingSystem类用于控制环境光的材质, 创建MLight类对象--光, 设置光的颜色和散射颜色, 衰减就可以了, 如果仅仅是光用这两个类就足够了

主要的类简略介绍

RenderToTextureApplication 类
    createScene
        1. 检测显卡
        2. 建立athene.mesh , knot.mesh 的切线信息, 准备用于法线映射
        3. 设置环境一些参数
        3. 设置雅典娜实体, 其材质使用了着色程序, 事先的切线信息放置于着色程序的tangent属性中.
        4. MeshManager 创建一个 曲面, 形成草色地面景象.
        5. 创建一实体 Knot, 细节层次使用 0.25
        6. 创建实体 OgreHead, 并挂接
        7. 增加四个随机位置的Knot克隆实体
        8. 设置相机位置
        9. 设置新的Overlay
        10. 设置 DeferredShadingSystem 和 MLight
        11. 创建用于光的场景节点
        12. 创建光点飞舞的动画
        13. 设置共享数据的一些内容
        14. createSampleLights() 创建几个飞舞的小光点

几个类的分析

1. RenderToTextureApplication 类
    createScene
        根据根对象得到RenderSystem *rs
        判断是否能够顶点和片段程序, 多重渲染目标的数量是否小于2.
        MeshManager load athene.mesh -> pAthene
        建立纹理的切线向量信息(suggestTangentVectorBuildParams, buildTangentVectors)
        相同的操作作用于 athene.mesh
        环境光 0.2, 0.2, 0.15, 天空盒 DeferredDemo/SkyBox
        创建节点 rootNode
        创建实体 athena(athene.mesh)
        该实体材质 DeferredDemo/DeferredAthena
        rootNode子节点 - aNode
        aNode绑定实体athena, 位置 -100, 40, 100
        新的移动平面对象 "ReflectPlane" - mPlane
            d = 0
            normal = Y
        MeshManager createCurvedPlane "ReflectionPlane" 创建弯曲平面 宽, 高, 曲度 2000, 2000, -1000;  x,y片段 20, 20; normal 真; 1, 10, 10, Vector3::UNIT_Z
        创建实体 "Plane" ReflectionPlane - mPlaneEnt
        rootNode子节点 mPlaneNode
        绑定实体
        移动 -5, -30, 0
        材质 DeferredDemo/Ground
        ~实体 knot.mesh - knotEnt, 材质 "DeferredDemo/RockWall", MeshLodBias 0.25f
        实体 ogrehead.mesh - ogreHead, 子材质设置  DeferredDemo/Ogre/Eyes, Skin, EarRing, Tusks
        创建子节点并绑定实体 ogreHead
        实体 cloneEnt
        循环四次
            2Pi乘当前的比率, 0, 1/4...
            场景管理创建节点 node
            设置节点位置, 方向随机,
            rootNode添加该节点为子节点
            克隆knot实体
            而后添加该克隆实体
        设置相机位置 -50, 100, 500  朝向 0,0,0
        Overlay Example/ShadowsOverlay
        创建新的 DeferredShadingSystem 对象, 参数为当前视口, 场景管理器, 相机
            其中创建了一个环境光 可渲染对象, 设置了合成器, 所以有了环境光效果
        渲染系统 创建主光 createMLight, 散射光 0.75f, 0.7f, 0.8f 镜面光
            创建了一个光的可渲染对象, 可以看到光的实体
        创建光节点 lightNode
        lightNode 添加该光实体
        创建动画 "LightTrack", 16  -  anim, 关联到上面创建的主光
            setInterpolationMode Animation::IM_SPLINE
            createNodeTrack - track
                createNodeKeyFrame 0 - key
                    setTranslate Vector3(300,300,-300)
                    4    300,300,300
                    8    -300,300,300
                    12    -300,300,-300
                    16    300,300,-300
        场景管理器 createAnimationState 关联到上面的动画
        &&&&createSampleLights()
        ****设置SharedData的一些属性

    createSampleLights 方法
        在根节点下创建一个子节点 parentNode
        两个容器 lights 和 nodes, 类型分别为MLight和Node
        
        创建一个MLight *a
            在parentNode下创建一个节点
            该节点绑定a
            设置衰减 1.0f, 0.001f, 0.002f
            位置 0,0,25
            1,0,0 红光
            压入 lights 和 nodes
        同理创建 *b, *c, *d, *e, *f
        利用 GeomUtils::createSphere 创建一个 球体Mesh, 半径大小只有1.0
        循环所有的光
            用球体mesh创建各自的一个实体
            并用材质管理器创建一个材质
            得到第一个通道 pass
            设置其散射光, 环境光, SelfIlluminatio为光的颜色
            设置该材质为实体材质
            该实体的渲染对列组等同于光的渲染对列祖
            挂接该实体
        创建一个动画, 跟踪所有的光节点
                
2. 雅典娜的材质 DeferredDemo/DeferredAthena
    顶点着色程序使用 DeferredShading/material/nm_vs
    片段着色程序使用 DeferredShading/material/nm_notex_ps
        传递参数 param_named specularity float 0.5
    纹理单元使用 texture atheneNormalMap.png
    
    例如 DeferredShading/material/nm_vs, 找到
    vertex_program DeferredShading/material/nm_vs unified
    {
        delegate DeferredShading/material/hlsl/nm_vs
        delegate DeferredShading/material/glsl/nm_vs
    }
    然后找到
    vertex_program DeferredShading/material/glsl/nm_vs glsl
    {
        source DeferredShading/material/glsl/nm_vs.glsl
    }
    进入  DeferredShading/material/glsl/nm_vs.glsl
    找到了顶点程序
    同理, 片段程序位于 DeferredShading/material/glsl/nm_notex_ps.glsl
    
3. SharedData 类
    基类: Ogre::Singleton<SharedData> , 标识该类只能拥有一个实例
    在该类里设置了一堆成员, 可以用于整个程序的任何地方控制这些成员的变化, 以及读取这些成员的值, 等同于全局函数.

4. MLight 类
    基类: Ogre::SimpleRenderable
    构造函数的参数为 MaterialGenerator 对象
        设置几何体, 设置渲染优先数为高, 让其在所有的环境光渲染之后进行渲染
        设置渲染的操作类型是三角形列表, 顶点对象, 索引对象为空, 是否使用索引为真
        缺省的散射颜色(1,1,1), 镜面颜色(0,0,0), 衰减系数(1.0f,0.0f,0.0f)
            *setDiffuseColour(ColourValue(1,1,1));
            *setSpecularColour(ColourValue(0,0,0));
            *setAttenuation(1.0f,0.0f,0.0f); -- 计算衰减半径, 外围半径, 并用该半径 调用 rebuildGeometry
                这三个函数分别调用 setCustomParameter 方法更新GPU的参数, 并设置了标识屏蔽码 mPermutation
    
    函数 getDiffuseColour, getSpecularColour
        通过函数 getCustomParameter 以及 索引值参数 得到结果
    
    函数 rebuildGeometry
        如果外围半径 大于 10000.0f, 调用函数 createRectangle2D
        否则调用函数 createSphere
        并设置标志屏蔽码 mPermutation
        
    函数 createRectangle2D
        首先删除 mRenderOp 的顶点和索引数据, 确保其为空
        创建新的VertexData对象, 并将该对象赋予 mRenderOp 的vertexData成员, mRenderOp 的 indexData 为 0
        利用 GeomUtils::createQuad, 给mRenderOp 的vertexData成员 填充了顶点数据
        渲染操作类型为 OT_TRIANGLE_STRIP
        是否使用索引为假
        设置该实体的BoundingBox, 非常的大. -10000,-10000,-10000,10000,10000,10000
        设置 mRadius 为15000, bIgnoreWorld 为真
    
    函数 createSphere
        首先删除 mRenderOp 的顶点和索引数据, 确保其为空
        创建新的VertexData对象, IndexData对象, 并将该对象赋予 mRenderOp 的vertexData成员, indexData成员, 是否使用索引为真
        用 GeomUtils::createSphere 填充了顶点数据, 其中球的半径等于传递的外围半径大小
        根据参数的半径长设置 BoundingBox
        mRadius 等于 参数半径, bIgnoreWorld 为假
        
    函数 getSquaredViewDepth
        得到相机的位置与该实体的位置之差
        
    函数 getMaterial
        根据屏蔽码得到材质

    
5. MaterialGenerator 类
    飞舞(on-the=fly)材质生成器: 这个类自动生成和存储一个材质和它的着色器的不同排列组合
    可以用于一个会拥有许多轻微变化的材质上, 像是否使用镜面光, 肤色, 正规映射(法线映射)和其他选项.
    写这些东西是很乏味的工作, 当然可以使用材质来实现这些特色, 但是结果可能会产生巨大, 缓慢的着色程序.
    这个类提供了有效的解决方案
    构造函数具有保护属性.
    公有函数:
    getMaterial - 参数为无符号整数, 表排列组合
        根据屏蔽码得到材质, 并克隆材质, 设置材质的片段和顶点着色程序, 然后返回材质
    内部类:
    Impl
        该类用于处理具体的生成或者查找一些组成部分(模板材质, 片段着色程序, 顶点着色程序). 这些函数每个排列只能调用一次. 结果可以存储或者重用.
        公有函数, 下面三个都为纯虚函数:
        generateVertexShader
        generateFragmentShader
        generateTemplateMaterial
    构造函数:
        该构造函数为保护属性, 这样永远不会构造该类的实例. 这意味着必须实现子类, 并分配一些用于材质生成器的重要属性, 最重要的是Impl类的实现
    属性:
        materialBaseName - 通过该类修改的材质名称
        bitNames - 每个比特的名称
        vsMask - 用于影响顶点着色器选择的排列屏蔽符(Mask)
        fsMask - 用于影响片段着色器选择的排列屏蔽符(Mask)
        matMask -  用于影响模板材质选择的排列屏蔽符(Mask)
        mImpl - 生成器
        
    本例创建了材质生成器
    LightMaterialGenerator
    其内部类实现
    LightMaterialGeneratorImpl, LightMaterialGeneratorGLSL, LightMaterialGeneratorHLSL
    
6. LightMaterialGenerator 类
    构造函数: 参数为 表示语言的字符串
        bitNames 存储一些字符串: Quad, Attenuated, Specular
        vsMask: 0x00000001
        fsMask: 0x00000006
        matMask: 0x00000001
    基本的材质名称:
        "DeferredShading/LightMaterial/"
    实现 mImpl
        new LightMaterialGeneratorGLSL("DeferredShading/LightMaterial/glsl/");

7. LightMaterialGeneratorImpl 类
    基类为 MaterialGenerator::Impl
    构造函数: 参数为材质的名称
    保护成员:
        getPPDefines函数 -- 参数为 排列的无符号整数
            根据参数得到影响的信息
        setUpBaseParameters 函数 -- 参数为 GpuProgramParametersSharedPtr
            设置着色程序中需要自动更新的参数
            worldView, invProj, lightDiffuseColor, lightSpecularColor, lightFalloff
    公有接口:
        generateVertexShader 函数 --- 参数为 排列的无符号整数
            根据参数选择着色程序
        generateFragmentShader 函数 --- 参数为 排列的无符号整数
            该函数只是实现, 并无任何意义
        generateTemplateMaterial 函数 --- 参数为 排列的无符号整数
            根据参数选择材质
    
8. LightMaterialGeneratorGLSL 类
    共有接口:
        generateFragmentShader 函数
        重新实现了该函数
            如果第一次调用
                通过资源组管理器得到数据流资源 DeferredShading/post/glsl/LightMaterial_ps.glsl
                将里面的内容保存进字符串 mMasterSource
            得到名称, 为材质名称+参数+_ps
            根据该名称创建片段着色程序, 来源为 mMasterSource
            设定参数preprocessor_defines, 其值为getPPDefines的返回值, 要在得到其他参数之前做这个
            设定一般的参数 setUpBaseParameters
            设定参数 tex0, tex1
            返回该片段程序

9. GeomUtils 类
    函数 createSphere
        1) 给定一个名称, 半径, 环数, 片段数, 创建一个球的纹理
        2) 给定环数, 片段数, 填充一个全新的拷贝, 内容为球体坐标的顶点和索引数据
    函数 createQuad
        填充一个全新的拷贝, 其内容为四个角的数据
        
10. DeferredShadingSystem 类
    基类为 RenderTargetListener
    内部的枚举值: DSM_SHOWLIT, DSM_SHOWCOLOUR, DSM_SHOWNORMALS, DSM_SHOWDSP, DSM_COUNT
    构造函数: 参数为视口, 场景管理器, 相机
        合成器句柄数组 mInstance 元素初始化为 0
        createResources        设置了合成器
        createAmbientLight    创建了一个环境观可渲染对象
        mActive 为真
        mCurrentMode 为 DSM_COUNT (4)
        setMode(DSM_SHOWLIT)    启用合成器
        mLightMaterialsDirty 为真
    
    析构函数
        删除所有的MLight对象
        删除Abient对象
        如当前模式为 DSM_SHOWLIT, 要移除监听器 this
        得到本视口的CompositorChain
        移除所有的合成器
    
    函数 createResources
        得到合成器管理器 compMan
        判断当前渲染系统的名称是否为 OpenGL Rendering Subsystem -- Root::getSingleton().getRenderSystem()->getName()
            根据语言创建 LightMaterialGenerator对象, 看是glsl还是hlsl
        四个合成器对象分别为: DeferredShading/ShowLit, DeferredShading/ShowNormals, DeferredShading/ShowDepthSpecular, DeferredShading/ShowColour
    
    函数 createAmbientLight
        创建一个新的AmbientLight对象 mAmbientLight
        根节点对象则挂接该对象
    
    函数 setMode
        如果参数中的模式等于当前模式, 且该模式对应的合成器已激活, 返回
        如当前模式为 DSM_SHOWLIT, 且允许该模式 CompositorInstance::getEnabled()
            得到该模式对应的"mrt_output"渲染对象 getRenderTarget("mrt_output");
            该渲染对象移除当前对象的监听器 this
        循环所有的合成器
            设置与参数相等的合成器启用, 其他的关闭
        设置 mCurrentMode等同参数模式
        如果参数模式为 DSM_SHOWLIT
            得到其 "mrt_output"渲染目标
            添加监听器 this
            mLightMaterialsDirty 为真
            设置 mDirtyLightList, 这个为MLight对象的链表
    
    函数 preRenderTargetUpdate
        如果为真, 调用函数 mLightMaterialsDirty
            根据当前模式, 得到合成器句柄
            调用 getTextureInstanceName 得到局部纹理的句柄名称
            setUpAmbientLightMaterial()
    
    函数 setUpAmbientLightMaterial
        得到当前合成器纹理句柄名称, mrt0, mrt1
        而后 调用 setupMaterial 将该AmbientLight的纹理设置为上面的两个纹理
    
    函数 setupMaterial
        将该材质的所有通道的纹理单元1和纹理单元2的纹理名称设置为参数指定的名称
        
    函数 createMLight
        创建新的MLight对象
        将该对象插入到 mLights
        如果当前模式为 DSM_SHOWLIT
            将该对象插入到 mDirtyLightList
            
    函数 setupLightMaterials
        所有的 mDirtyLightList的材质设置纹理名称 为合成器的 mrt_output中的 0和1号索引
        
    函数 logCurrentMode
        用于log信息
        
    函数 preRenderTargetUpdate
        如果 mLightMaterialsDirty
            调用 setupLightMaterials, 设置所有光材质的纹理单元
            
11. AmbientLight 类
    基类为 SimpleRenderable
        设置渲染对列祖为 RENDER_QUEUE_2
        设置 mRenderOp 的 vertexData 为新的 VertexData对象, indexData成员为0
        调用 GeomUtils::createQuad 创建一个立方体
        mRenderOp.operationType 为 OT_TRIANGLE_STRIP
        不使用索引
        设置BoundingBox
        设置内部材质 mMatPtr, 而后加载 (DeferredShading/AmbientLight)
            这个材质使用了 着色程序 DeferredShading/post/vs  DeferredShading/post/Ambient_ps, 见 deferred_post_ambient.material

本例用到的重要Ogre类和方法

Ogre
    Mesh 类
        suggestTangentVectorBuildParams 方法
            为buildTangentVectors的调用询问mesh合适的参数. 如果你希望能够使用纹理坐标保存正切的话
            备注:
                在调用buildTangentVectors时建议一个源和目标的纹理坐标系的帮助函数. 如果检测到mesh有3D坐标系, 并且可能准备好正切信息时, 返回true.
        buildTangentVectors 方法
            建立给定 mesh 的一系列切线向量信息, 并将其放入3D纹理坐标缓存
            备注:
                基于2D纹理的方向和法线, 建立给定顶点的局部'X'轴向量代表其切线向量. 主要用于顶点和片段程序.
                使用该函数的先决条件是每个SubMesh使用的顶点数据都包含顶点法线和2D纹理坐标.    
    Math 类
        SymmetricRandom 方法
            返回随机值 -1 到 1 范围
            
    Entity 类
        setMeshLodBias 方法
            设置用于该实体mesh细节的细节层次
            备注: 基于Mesh的设定, 通常自动应用细节层次的缩减. 也可以通过修正LOD偏移来影响该实体的细节层次操作.
                根据你的需求增加或者减少该实体的纹理细节.
                你可能希望使用这个技巧来使得场景中的重要实体比其他的实体更加细腻,清晰.
                三个参数, 第一个参数factor缺省为1.0, 如果使用2.0, 在细节方面将降低两倍. 0.5使用更低的细节版本. 越低越清晰.
                另外两个参数用于设定LOD版本的最高和最低版本号.
                
    SceneManager 类
        createAnimation 方法
            创建用于可动场景节点的动画
            备注: 通过改变节点对象的位置/方向进行跟踪所形成的动画.
            你不需要使用Animation对象来移动对象节点, 可以在你的帧监听器类使用 Node的方法.
            然而, 如果你需要相关的复杂脚本动画, 使用该类将会在帧之间插入动画, 这样整个实现进程变得易于管理
            一个简单的动画可以被多个节点对象所影响(每个AnimationTrack都会作用域该节点). 额外的, 通过将这些动画混合, 可以创建多重动画, 对于骨骼动画非常有用.
            
    Animation 类
        InterpolationMode 方法
            可利用的动画插值类型
            IM_LINEAR    线性插值
            IM_SPLINE    链性插值, 结果更加的平滑
        createNodeTrack 方法
            创建一个自动关联到特定节点的 AnimationTrack
            备注: 该方法创建一个AnimationTrack, 但其关联到特定的节点, 该节点接收所有的关键帧效果.
            
    NodeAnimationTrack 类
        createNodeKeyFrame 方法
            给动画创建一个该时间索引的关键帧, 返回一个 TransformKeyFrame
            
    TransformKeyFrame 类
        setTranslate 方法
            设置该关键帧的转移操作
            备注: 该方法设置关键帧如何转移它的可移动对象
            
    SimpleRenderable 类
        继承自 MovableObject , Renderable
        
    GpuProgramParameters 类
        setNamedAutoConstant 方法
            建立该系统会自动更新的常量
            备注: 顶点和片段程序需要一些参数, 这些参数和当前的渲染状态像关联, 或者时时刻刻都在变化的那些参数.
                这个方法允许你设定一系列预定义的需要更新的参数.
            注意: 参数的名称必须是有高级程序所创建的名称才行.
        setParameter 方法
            一般的参数设置方法
            备注: 通过参数的名称和值的字符串形式来调用这个方法.
            
    GpuProgram类
        getDefaultParameters 方法
            得到用于这个程序的缺省参数的引用
            备注: 可以给程序提供一系列的缺省参数, 用同样的设定多次调用材质的程序可以节约时间. 通过返回缺省参数和给它最常用的选项, 任何这个程序之后创建的新参数对象都会被自动的包含进缺省参数.
                这样程序的使用者仅仅需要修改的一致变量.
                
    MovableObject 类
        setRenderQueueGroup 方法
            设置该实体所属的渲染队列组
            备注: 渲染队列分组让你能够紧紧地控制渲染对象的渲染排序, 如果不调用该函数, 所有的实体对象按照缺省的队列渲染. 或许你想修改以便让该实体始终在其他对象之前.
            
    Renderable 类
        setCustomParameter 方法
            设置该可渲染对象的自定义参数, 用于特定渲染操作的计算, 如GPU程序参数
            备注: 调用该函数 关联一系列的索引到特定可渲染对象的四维值. 这对于使用GPU程序的可渲染对象非常有用, 该实体使用了ACT_CUSTOM参数.
                这个参数可以关联一个索引. 而此自定义参数可以关联到程序参数
                
    AxisAlignedBox 类
        根据x, y, z的长度创建 3D盒
        
    RenderTargetListener 类
        可以接收到通知的监听器, 重要函数如下, 可以根据名称理解其含义
        函数 preRenderTargetUpdate
        函数 postRenderTargetUpdate
        函数 preViewportUpdate
        函数 postViewportUpdate
        函数 viewportAdded
        函数 viewportRemoved
        
    CompositorInstance 类
        调用 addCompositor 函数返回数据的类型. 为视口的合成器对象句柄