时隔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】。
先看看目录
Legal
Changes:Objects, Scene & Nodes
与ogre1.x不同之处
Technical Overview
使用的技术概述
Compositor
这玩意儿不知道咋翻译
Instancing
GPU instance
Threading
多线程
Performance Hints
优化
HLMS:High Level Material System
HLMS
AZDO changes (Aproaching Zero Driver Overhead)
不知道啥玩意儿
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();获取的数据可能是错的。除非自己修改引擎!!如果非要更改可以调用
强制更新数据,速度慢,不建议大量使用。
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 内存的基本抽象系统。
内存管理器使用模式
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
太长了,不写了。
从这些内容可以得知,文档里的内容都时很关键的。应该认真的看完。
不想翻译,懒!