在游戏场景中,经常需要我们绘制大量相同的模型,比如英雄联盟中,战场上的小兵可以达到非常多的数量。
(图为英雄联盟游戏截图)
如果我们用以前的方法绘制,一个模型draw call一次,那么就会造成巨大的性能损耗。因为每次数据从内存传入显存都需要不少时间;而且每次draw call需要CPU和GPU进行周期同步,会导致CPU或GPU在等待;每次传入顶点数据后,都需要走一遍渲染管线,上下文也要进行切换等等。如果我们有一种方法,对于模型相同的游戏对象,只需要传一次模型的顶点数据,每个实例也可以包含不同的位置信息、颜色信息等,那么就可以极大增加渲染效率。DirectX10开始有Instancing技术的硬件支持,帮助我们完成解决这个问题。(这个问题在之前要通过程序员自己batch合并模型顶点来一次draw call来完成,而现在是通过硬件支持,更加方便)
一、指定输入布局
顶点元素描述如下:
typedef struct D3D11_INPUT_ELEMENT_DESC {
LPCSTR SemanticName;
UINT SemanticIndex;
DXGI_FORMAT Format;
UINT InputSlot;
UINT AlignedByteOffset;
D3D11_INPUT_CLASSIFICATION InputSlotClass;
UINT InstanceDataStepRate;
} D3D11_INPUT_ELEMENT_DESC;
有几个新增的字段需要介绍一下,
- InputSlotClass:为了区分顶点数据和实例数据,在输入布局元素中的InputSlotClass字段应当用
D3D11_INPUT_PER_VERTEX_DATA
和D3D11_INPUT_PER_INSTANCE_DATA
进行区分。 - InstanceDataStepRate:指定每个实例数据有多少个实例要绘制。比如说我们有3种不同的实例颜色,但是有6个模型,我们可以设置2,那么前2个、中间2个、后面2个都分别占有不同的三种颜色。如果每个实例都有一个实例数据,那么就设为1。顶点数据只需要设为0。
我们的Demo中,实例数据包含了世界矩阵和每个实例的颜色,下面是一段代码示例:
const D3D11_INPUT_ELEMENT_DESC InputLayoutDesc::InstancedBasic32[