转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=3668

最近这几个版本经常出现一些比较大的改进,需要跨多个版本才能实现。所以一直没写改进的文章。现在4.14很快就要发布了,逼自己把渲染部分的重要变化总结一下吧。

Cluster shading成为默认渲染框架

在4.11里,曾经有个实验性质的cluster shading。那时候性能还不如tile based shading,所以也就默认关闭。在4.12中,cluster shading经过了一系列的优化,终于在性能上赶上来了。所以也就能取代tile based shading,成为默认的渲染框架。

对Cluster shading的优化主要集中在cluster如何划分上。经过对不同参数组合的尝试,找到最佳的一组。不过本来的想法是用pixel shader实现shading的部分,而不是compute shader。那样的话就能让不支持compute shader的平台也能统一用一套cluster shading。结果那个shader还是太复杂,用PS搞不定。目前只能暂时保留light indexed shading,在没有CS的时候用。

实用化的D3D12插件

虽然KlayGE的D3D12插件已经存在一段时间了,但性能一直很低,远不及其他几个渲染插件。这样的D3D12插件并无实用价值。在4.12里,我花了将近一个月的时间从CPU和GPU两方面优化D3D12插件,使得它的性能超过OpenGL和OpenGLES插件,和D3D11插件的差距就剩下10%。

在4.14的优化阶段,还解决了D3D12插件的多个问题,包括压缩纹理的内容错误、stream output无法重复输出到同一个buffer、可以单独读取stencil等。使得启用D3D12插件的时候可以通过所有的测试。已经达到了实用的程度。

这部分细节很多,值得单独写一篇文章来讲解。

Shader graph框架

原先KlayGE的shader代码存在着大量的拷贝代码的情况,修改起来很容易出问题。尤其GBuffer的shader是重灾区。增加一个新的材质就经常需要拷贝一次代码。

现在实现了shader graph,可以在effect文件里定义一些节点,shader本身调用这些节点作为框架,而具体节点的实现可以在载入effect的时候动态组合出来。这么一来,一套shader框架配合多套节点,就能组合出相当多的shader。

然而完成了这个功能之后,我发现光有shader graph还是不够,在effect级别也需要有类似的东西。所以在4.13里,这个功能又进一步扩展成可重载的effect technique。一个technique可以覆盖掉前面定义的technique。比如如果定义了一个普通物体的GBuffer technique,又派生出了透明物体的GBuffe technique。之后对于新的材质的technique,如果覆盖了普通物体的GBuffer technique,就可以自动获得透明物体的版本。这样就进一步减少了shader代码。

场景树

之前多次有用户提到KlayGE里的场景是一个只有两层的扁平结构,并没有组织成较深的树。这使得上层没法简单地通过节点的层级关系,从根节点一直把矩阵累积到子节点。我终于有时间在4.14里把这个做完了。现在可以通过访问场景树里的节点信息来构造出一个节点的层级。

有了这样的场景管理,模型格式也因此需要修改。现在的模型格式里也支持一个小的场景树,通过节点之间的关系来索引。几何信息附在节点上,并且可以再多个节点之间复用。也就是说,在模型格式里做了一个局部的entity-component-system(ECS)。如此一来,模型文件有所减小,并且渲染速度可以提高。

下一个版本打算更进一步,在引擎层面做出完整的ECS系统。

资源的metadata

之前KlayGE只能读取meshml的模型格式和dds的纹理格式。其他格式得通过工具手动转换成这些格式,并需要在命令行指定一些转换参数。4.14里新增的资源metadata简化了这个过程。转换参数可以写在metadata里,并在载入的过程中自动实现转换。如此一来,只要assimp支持的模型格式和FreeImage支持的图片格式,都可以通过metadata直接载入引擎。方便多了。

如此一来,MeshML格式就开始进入退休流程。多年前,没有一个模型格式能满足KlayGE的需求:基于物理的材质、LoD、压缩顶点、骨骼动画。而现在glTF 2.0也已经有了这些功能,所以已经可以逐渐地用glTF 2.0来代替MeshML了。在4.14里,很多模型已经换成了3ds和glb,纹理已经换成了jpg和png。资源大小减小很多。不过目前assimp对glTF 2.0仍不支持LoD和SSS的材质,很可能以后需要自己写一个glTF解析器来解决这个问题。

渲染到MSAA纹理

D3D10.1以上的硬件支持渲染到MSAA纹理,并且可以指定shader是在sample的级别上运行的。4.13也支持了这个特性,并让Deferred rendering pipeline可以全面用上MSAA。GBuffer是输出到MSAA纹理,lighting和shading都是per-sample地执行,最后resolve成一个sample。这样就能利用硬件的MSAA来改善渲染质量。性能方面,MSAA 4x大概是无AA一半的速度。

Shader Resource View

本来在4.12就想加入SRV,但一直到了4.14才加进去。这里是模仿D3D11/12的Shader resource view做的一个抽象。可以简化texture和buffer的绑定,并提高运行速度。