当前位置: 首页 > 工具软件 > Ogre-Next > 使用案例 >

ogre-next 学习笔记 - Day 8

莘昊
2023-12-01

ogre-next 学习笔记 - Day 8

时隔N天,都忘得差不多了,先回忆一下。

看看 hlms 几个cache的描述

  • mRenderableCache
    此缓存包含设置给可渲染类的所有属性,并且可以在为可渲染类分配数据块(即在Renderable::setDatablock内部)时提前对其进行计算。包含诸如材质是否具有法线贴图、网格是否具有UV集、材质是否需要切线进行法线贴图等特性。负责填充此缓存的主要函数是Hlms::calculateHashFor

  • mPassCache
    此缓存包含每个pass的信息,例如场景中有多少灯光,这是否是阴影贴图过程等。负责填充此缓存的主要函数是Hlms::preparePassHash

  • mShaderCodeCache
    包含基于从mRenderableCache和mPassCache合并的属性的唯一着色器缓存(来自 Hlms模板->实际有效着色器代码)。然而,两个着色器可能完全相同,因此可能会重复,如果两个属性组合最终生成完全相同的代码,则可能会发生这种情况。 Microcode(GpuProgramManager::setsavemicrocodetocache)可以帮助解决这个问题.

  • mShaderCache
    包含PSO的缓存。这与mShaderCodeCache之间的区别在于,PSO需要额外的信息,例如HlmsMacroblock, HlmsBlendblock。 有关所需的更多信息,请参阅HlmsPso


可以知道的是涉及到可渲染对象属性,pass,shader, PSO(管线状态对象),也就基本等同与整个渲染管线了。

这部分可以想象的是很复杂, 但是,作为入门,目标只要能分清这几个对象是干嘛的,怎么来的就可以了。

从代码入手,找到几个cache对象,

    typedef vector<HlmsCache*>::type HlmsCacheVec;

    typedef vector<PassCache>::type PassCacheVec;
    typedef vector<RenderableCache>::type RenderableCacheVec;
    typedef vector<ShaderCodeCache>::type ShaderCodeCacheVec;
    
    PassCacheVec        mPassCache;
    RenderableCacheVec  mRenderableCache;
    ShaderCodeCacheVec  mShaderCodeCache;
    HlmsCacheVec        mShaderCache;

都是vector,必然就有 push_back,找到这几个地方,并加入断点,调试。
发现,
 GraphicsSystem::loadHlmsDiskCache 里调用了 mRenderableCache / mPassCache.
 LoadHlmsDiskCache 为了加快加载速度。在这里我们就不使用整个属性。
在 loadHlmsDiskCache 由变量 mUseHlmsDiskCache 控制。将这个变量设置为false。
竟然没有发现设置的地方?那就把文件删掉吧。按照之前已知的资源位置查找方法,找到资源位置,删除 hlmsDiskCache1.bin
调试,发现
  Renderable::setDatablock 调用 mRenderableCache.push_back。已知datablock就是 hlms的材质.
  Hlms::compileShaderCode 调用 mShaderCodeCache.push_back,
其他两个没有调用?那就直接搜索吧。
  Hlms::createShaderCacheEntry 调用 mShaderCache.insert( it, retVal );(addshadercode)
  Hlms::preparePassHashBase 调用 mPassCache.push_back( passCache );

到这里,发现继续分析已经很吃力了,涉及到代码细节。这里涉及的几个函数,都没有在之前分析过的流程图中。


既然如此,就该跳出来了,不再深入分析。

花点时间,回顾一下。分析过大体流程,知道了如何使用 hlms。


这个时候,尝试去看一看文档【Ogre 2.1 Porting Manual】。

先看看目录


  1. Legal

  2. Changes:Objects, Scene & Nodes
    与ogre1.x不同之处

  3. Technical Overview
    使用的技术概述

  4. Compositor
    这玩意儿不知道咋翻译

  5. Instancing
    GPU instance

  6. Threading
    多线程

  7. Performance Hints
    优化

  8. HLMS:High Level Material System
    HLMS

  9. AZDO changes (Aproaching Zero Driver Overhead)
    不知道啥玩意儿

  10. The Command Buffer
    gpu command buffer

很有必要把这个文档完全看一遍。

以下是一部分大致内容,完整的各位自己看了。


1
2 修改:对象、场景和节点

  • 名称现在是可选的
    名称不再需要是唯一的,并且是可选的。不能通过名称查找对象,否则会有bug。

  • 如何调试MovableObject(Node)的数据
    每帧需要更新的所有相关数据都以 SoA 形式(数组结构)存储,而不是 AoS(结构数组).
    例如,假如有4个对象的A,B,C,D,数据结构是以
    A B C D = {A.x B.x C.x D.x,A.y B.y C.y D.y, A.z B.z C.z D.z }
    的格式存放,而不是普通的
    A B C D ={A.x, A.y, A.z} {B.x, B.y, B.z} {C.x, C.y, C.z} {D.x, D.y, D.z}
    这是因为它使用了SIMD(Single Instruction, Multiple Data / 单指令多数据).
    通过这种方式,一次性可以计算4个对象的属性,可以提高性能。类似于gpu。
    但是调试起来就麻烦了,因为不是一一对应的,需要通过index来找到它的数据。好烦!
    通过伪指针代替空指针。由于特殊的数据存放格式,在 mParents里看到null可能是bug?

  • 附加和可见性
    在 Ogre 1.x 中,当一个对象附加到最终父节点是 root 的场景节点时,该对象"在场景中"。因此,分离的实体永远不会显示,并且在附加时,调用setVisible(false)将隐藏它。
    在 Ogre 2.x 中,对象始终位于"场景中"。节点仅保存位置信息,可以进行动画处理, 并且可以从其父节点继承转换.当实体不再与节点关联时,它会隐藏自身(隐式调用 setVisible(false)以避免在没有位置的情况下呈现。多个实体可以共享同一位置,因此具有相同的节点。在附加/分离到/分离 SceneNode 时,MovableObject::getVisible 的先前值将丢失。此外,在分离时调用 setVisible( true ) 是非法的,并且会导致崩溃.

  • 连接/分离比隐藏更昂贵
    由于 Ogre 1.x 在遍历 SceneNodes(又名 Scene Graph)时的速度很慢,
    一些用户建议分离其对象或从其父级中删除 SceneNode,
    而不是调用 setVisible(false);尽管官方文件另有说明。
    在 Ogre 2.x 中,我们付出了巨大的努力来尽可能快地保持更新和迭代。
    这可能反过来增加了添加/删除节点和对象的开销。
    因此,使用 setVisible 隐藏对象比销毁对象快几个数量级(除非它们必须隐藏很长时间)

  • 所有可移动对象都需要一个 SceneNode(灯光和摄像机)
    不再有无节点灯光存在。

  • 获取派生变换
    为了性能考虑,位置的 dirty 标志被删除(debug存在,只用来断言),所以设置完位置直接调用 sceneNode->_getDerivedPosition();获取的数据可能是错的。除非自己修改引擎!!如果非要更改可以调用

    • Node:_getDerivedPositionUpdated
    • Node:_getDerivedOrientationUpdated
    • Node:_getDerivedScaleUpdated

    强制更新数据,速度慢,不建议大量使用。
    MovableObject’s world Aabb & radius 是一样的设计。

  • 静态场景/动态场景
    MoableObject和Node在创建时都有一个标示是否是静态的,静态的表示不会更新或者不会经常更新的对象。静态对象的设置属性不会主动更新,需要调用 SceneManager::notifyStaticDirty。更改单个静态对象会导致多个静态对象同时被修改。
    可以通过setStatic在运行时改变状态,除了 InstancedEntity。

  • Ogre 在调试模式下断言 mCachedAabbOutOfDate 或 mCachedTransformOutOfDate
    如果 “mCachedAabbOutOfDate"或"mCachedTransformOutOfDate” 断言,
    它们意味着AABB没有被更新,但被尝试使用,或者派生的转换已经过时并尝试使用它;

  • 从可渲染或可移动对象派生的自定义类
    在 Ogre 1.x 中,高级用户可以直接向 RenderQueue 提交或注入 RenderQueue,而无需 MovableObject。因为存在冗余(两个类都复制了相同的数据),或者 Renderable 使用虚拟函数从 MovableObject 查询数据(高级用户可以重载以直接提交此数据,而不是依赖于 MO)。

    由于 Ogre 2.x; Renderable 必须有一个 MovableObject 链接到它,因为 RenderQueue 的 addRenderable 函数需要两个参数,一个用于 MovableObject,另一个用于 Renderable。
    提供空指针作为 MovableObject 可能会导致崩溃。多个可渲染对象仍然可以共享相同的MovableObject,并且实现也不必同时从两者派生。对于属于场景一部分的对象,Ogre 1.x 使用访客模式来查询 MovableObject 包含的所有可渲染对象。在ogre 2.x中,此模式已被删除。实现从 MO 派生的自己的类的 Ogre 用户必须填充 MovableObject::mRenderables vector;SceneManager将直接访问该通道,以将可渲染对象添加到 RenderQueue。

    此更改背后的原因是性能。访问者模式对于此任务来说成本太高。

  • 如何从新的 v2 Mesh 类中获取顶点信息?

  • 如何设置元素偏移量、顶点缓冲区的源和索引?

  • 我的场景看起来太暗或沉闷!
    检查是否正在使用伽马校正
    切换到PBS管道并期望所有内容仍按原样工作是一个常见的误解。材质参数可能需要认真调整。

  • 激活了伽玛校正,但GUI纹理不见了
    HlmsTextureManager 将加载具有伽玛校正的漫反射纹理以避免此问题。
    但是,如果您通过外部方式加载它们(即使用常规的TextureManager;例如CEGUI),.
    则需要显式加载它们并进行伽马校正。

3 技术概述

  • 概述
    ArrayMemoryManager 是用于处理 SoA 内存的基本抽象系统。

    • SIMD一致性
      使用SSE2单精度,OGRE通常一次处理4个节点/实体。但是,如果只有3个节点;我们需要为其中4个分配内存
  • 内存管理器使用模式
    ArrayMemoryManagers使用插槽的概念。当节点请求转换时,它要求一个槽.在 SSE2 版本中,4 个插槽构成一个块。制作一个块需要多少个槽取决于宏ARRAY_PACKED_REALS的值。

    • 清理
  • 内存预分配

  • 配置内存管理器

  • RenderTarget::update在哪里?为什么我在Viewports中收到错误?
    高级用户可能习惯于渲染目标的低级操作。因此,他们习惯于设置其自定义视口并调用 RenderTarget::update。这太低了。相反,现在鼓励用户设置合成器节点和多个工作区以执行对多个RT的渲染,即使它是针对您自己的自定义内容。新的合成器比旧的合成器(已被删除)灵活得多。有关详细信息,请参阅有关合成器的部分。

    视口不再与摄像机相关联,因为它们现在是无状态的(它们用于缓存当前正在使用的摄像机),并且它们曾经保存的许多设置(如背景颜色,清晰设置等)已移至节点。请参阅CompositorPassClearDef和CompositorPassClear。

    RenderTarget::update已消失,因为渲染场景更新已分为两个阶段:剔除和渲染。如果您仍然坚持使用低级别,请参阅CompositorPassScene::execute上的代码,了解如何准备 RenderTarget 并手动渲染它。但同样,我们坚持认为您应该尝试合成器。

  • 1.x 移植到 2.x

  • 从2.0移植到2.1


太长了,不写了。

从这些内容可以得知,文档里的内容都时很关键的。应该认真的看完。

不想翻译,懒!

 类似资料: