在本章节,我们学习实例(Instancing)技术以及视截体裁剪(Frustum Culling)。实例通常在一个场景中绘制多个同样的物体时使用。实例技术能够优化绘制多个同样物体的性能,这也是为什么Direct3D也支持它的理由。视截体裁剪则是通过一些简单的测试,将在可视范围内的物体剔除。
- 学习如何实现实例技术。
- 熟悉包围盒,为什么要使用它,如何创建它以及如何使用它。
- 探索如何实现视截体裁剪
我们在一个场景中绘制多个同样的物体的时候,就会使用实例技术,但是这些物体的位移,旋转,缩放,材质以及纹理可以不同。下面是一些例子:
- 多次渲染不同的树来构成一座森林。
- 多次渲染不同的小行星来构成星系。
- 多次渲染不同的人物来构成人群。
如果我们对于每个实例都复制一遍顶点缓冲和索引缓冲的话,那么对于性能开销是非常大的,即便每一遍顶点缓冲和索引缓冲不大。因此,我们只存储一个简单的副本,然后我们使用不同的世界矩阵,材质等属性来绘制物体多次。
即便这样的方法能够节约内存开销,但是每个物体需要的API开销是没有减少的,对于每个物体,我们还是需要设置它的材质,世界矩阵以及调用绘制指令。Direct3D instancing API允许我们之调用一次渲染指令就可以渲染多个实例。再加上动态的索引(在之前的章节中提到过),Direct3D 12的实例技术就比Direct3D 11的灵活了很多。
为什么我们需要关心API的开销,因为如果过多的话,就会导致CPU成为我们的性能瓶颈而不是GPU。通常这是由于设计者渲染喜欢使用不同的材质和纹理渲染物体,导致管线状态不断地改变,且每个物体都调用一遍绘制指令。因此,为了维护实时渲染的速度,我们就需要限制调用绘制指令的次数。图形引擎则通常会使用分批技术来最小化调用绘制指令的次数,实例技术就是其中一部分。
其实在之前,我们就是一直使用的实例技术,只不过我们的实例一直都是1而已。
commandList->DrawIndexedInstanced(indexCount, 1, startIndexCount, baseVertexLocation);
第二个参数,InstanceCount
,指定我们要渲染的实例个数,如果我们设置10,那么这个物体就会被绘制10次。
只是单独的绘制一个物体10次并没有任何作用,他们会被渲染到同一个位置使用同样的材质和纹理。因此,下一步就是解决如何指定不同的实例使用不同的数据(我们称之为实例数据),这样我们就可以使用不同的变换,材质和纹理来渲染物体。
实例数据来自输入装配阶段,当我们创建一个输入布局(InputLayout)的时候,我们可以指定数据流