枪神纪轮廓渲染方法对比与解析
发表于2016-04-14
一、摘要
在枪神纪里先后采用了两种方式进行了对人物进行轮廓渲染,分别是Object Based几何处理方法与Image Based的图像处理方法,本文就这两种方法的实现方式,性能,系统整合等方面进行对比与解析。
二、方法介绍
角色的轮廓渲染有两种方法,Object Based之类的几何操作的,以及使用后处理进行的图像处理的方法。
Object Based的几何方法
1、首先渲染一遍基础的模型,并标记Stencil。
2、第二遍再渲染一遍模型,不过在VS阶段,沿垂直屏幕方向进行Extrude Vertex一段距离。
3、PS阶段进行勾边颜色的渲染,对于标记Stencil的部分,不通过。
三、Image base的图像处理方法
1、首先渲染一遍基础的模型,利用MRT功能输出轮廓颜色到RT1上。
2、在后处理阶段,对此RT1进行边缘检测,描绘出边缘。
四、性能分析
效果层面,两个并没有多大的区别。然而到了效率层面,Object Based的方法的缺点在于,他需要两次渲染一个物体,虽然第二次的PS简单,但是第二遍绘制的过程,仍然需要处理一遍顶点Shader,对于那些需要GPU Skinning的 顶点来说,这是一个很大的负担。反观Image Based的方法,虽然他节省了一次渲染的过程,但是最后那一次后处理,即使在VS阶段做了AABB标出了物体的大概范围,仍然有很多个像素需要进行处理,每个像素的都需要经历5次的贴图采样,这个对于缺少TMU低端显卡来说[1],简直就是噩梦。
总之,就是Object Based会导致两次的Vetex Process,Image Based会导致贴图采样消耗过大,这两者对于低端显卡都是消耗巨大。那么我们如何去选择呢?
Intel HD Graphics的白皮书上有这样一段阐述[2]:
Multi-Texture Rendering is better than multi-pass rendering since MTR reduces state changes, driver overhead, and CPU load. In addition, Intel integrated graphics utilizes main system memory for graphics. The intermediate pixels computed in a multi-pass rendering need to be transported back to main memory and then back to the graphics subsystem when needed again, causing a full round-trip over the bus per render target for each pass.
上面阐述了在Intel HD Graphics 上,使用MRT会更好一些。
五、性能测试
我们仍然缺少其他平台的理论依据,因此这个时候,我们使用了枪神纪独有的性能测试方法。我们借助NSight来生成单帧测试用例,这个单帧的测试用例可以编译成一个本地的D3D程序,通过衡量在不同平台上该D3D程序的帧率,来评定一个渲染算法的优劣。
1、这样做有这样的好处:
(1)、测试过程准确,可重复。
(2)、测试过程迅速,程序免安装,体积小(通常在10M以下)。
2、具体的步骤如下:
(1)、实现命令行,能够在灵活的调整两种轮廓渲染方法。
(2)、使用Nsight分别截取两个轮廓渲染的帧数据。
(3)、调整编译参数,移除Debug CRT,生成测试用例程序
(4)、在目标机器上运行测试用例程序,并通过Fraps截取帧率。
六、测试结果:
显卡 | Image Based | Object Based |
Intel HD Graphics 1000 | 72 | 61 |
Intel HD Graphics 2000 | 76 | 59 |
Nvidia 7600GT | 100 | 95 |
Nvidia 9500GT | 120 | 113 |
AMD 5450 | 101 | 96 |
Nvidia GT 210 | 109 | 100 |
GTX 660 | 670 | 630 |
760G | 41 | 37 |
我们发现在各个平台上,Image Based方法还是稍微快一些。节省了一次GPU Skinning,这个消耗在低端机器上还是较大的。
七、图像处理方法的弊端
1、带宽的瓶颈加重
MRT虽然是DirectX 9.0c的标准之一,但是早些年的显卡却需要RT的Bit Depth一样才能正确输出MRT[3]。这个看似不起眼的设定,却影响着Image Based的方法的效率,在UE3中,使用了Half[4]去代替BYTE[4]来作为Base Color的格式,因此,我们的Base Color的格式需要Half 格式,同时也就约束了我们的RT1的格式也为Half,而这个是很没有必要的。因为MRT本身就是制约在带宽方面,此处无疑大大加重渲染的负担。
解决的方法:
检查D3D里D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS 标记是否有设置,如果此标记是OK的话,那么就可以设置不同Bit Depth的RT,进而大大节省带宽。如果标记为False,那么还是需要使用和RT0一样的BitDepth。
一般来说,对于支持DX10以上的显卡都支持这个特性,因此,在实际测试中,还是能够覆盖大部分的玩家机器的。
2、Shader爆炸
因为需要在Shader里标记输出的Render Target,就不可避免的需要修改Shader,注意,这里是需要修改一整套的Shader。 Unreal3使用的是Forward Shading,并通过一个ubershader将这个材质根据不同的光照生成不同的Shader[4], 同时一个材质不仅要和光源种类耦合,也要和他的顶点,预计算光照算法种类等等因素耦合。这些耦合导致了Shader的个数成倍的上涨,最终导致了Shader数量上的爆炸。
解决方法:
使用特定的标记,标记当前特定的材质才需要生成MRT材质。在实际的测试中,因为枪神纪的角色大量的使用了公用材质模板,最后实际生成的MRT类型的材质非常的少。
八、参考
1、Comparison of Intel graphics processing units
http://en.wikipedia.org/wiki/Comparison_of_Intel_graphics_processing_units
2、Intel Integrated Graphics Developer Guide 2.7.1
http://software.intel.com/sites/default/files/m/d/4/1/d/8/Intel_Integrated_Graphics_Performance_Developer_s_Guide_v2_7_1..pdf
3、Multiple Render Targets (Direct3D 9)
http://msdn.microsoft.com/en-us/library/windows/desktop/bb147221(v=vs.85).aspx
4、Real Time Rendering 3rd, Chapter 7.9 Combining Lights and Materials.