由于索引要由GPU访问,所以它们必须放在一个特定的资源容器中,该容器称为索引缓冲(index buffer)。创建索引缓冲的过程与创建顶点缓冲的过程非常相似,只不过索引缓冲存储的是索引而非顶点。所以,这里不再赘述之前讨论过的内容,我们直接给出一个创建索引缓冲区的示例:
UINT indices [24] = {
0, 1, 2, // Triangle 0
0, 2, 3, // Triangle 1
0, 3, 4, // Triangle 2
0, 4, 5, // Triangle 3
0, 5, 6, // Triangle 4
0, 6, 7, // Triangle 5
0, 7, 8, // Triangle 6
0, 8, 1 // Triangle 7
} ;
// 要创建的索引的描述
D3D11_BUFFER_DESC ibd;
ibd.Usage = D3D11_USAGE_IMMUTABLE;
ibd.ByteWidth = sizeof(UINT) * 24;
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
ibd.StructureByteStride = 0;
// 设定用于初始化索引缓冲的数据
D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = indices;
// 创建索引缓冲
ID3D11Buffer* mIB;
HR(md3dDevice->CreateBuffer(&ibd, &iinitData, &mIB));
与顶点缓冲区相同,所有的Direct3D资源在使用之前都必须先绑定到管线上。我们使用ID3D11DeviceContext::IASetIndexBuffer方法将一个索引缓冲区绑定到输入装配阶段。下面是一个例子:
md3dImmediateContext->IASetIndexBuffer(mIB, DXGI_FORMAT_R32_UINT, 0);
第2个参数表示索引格式。在本例中,我们使用的是32位无符号整数(DWORD);所以,该参数设为DXGI_FORMAT_R32_UINT。如果你希望节约一些内存,不需要这大的取值范围,那么可以改用16位无符号整数。还要注意的是,在IASetIndexBuffer方法中指定的格式必须与D3D11_BUFFER_DESC::ByteWidth数据成员指定的字节长度一致,否则会出现问题。索引缓冲区只支持DXGI_FORMAT_R16_UINT和DXGI_FORMAT_R32_UINT两种格式。第3个参数是一个偏移值,它表示从索引缓冲区的起始位置开始、到输入装配时实际读取数据的位置之间的字节长度。如果希望跳过索引缓冲区前面的一部分数据,那么可以使用该参数。
最后,当使用索引时,我们必须用DrawIndexed方法代替Draw方法:
void ID3D11DeviceContext::DrawIndexed(
UINT IndexCount,
UINT StartIndexLocation,
INT BaseVertexLocation);
1.IndexCount:在当前绘图操作中使用的索引的数量。在一次绘图操作中不一定使用索引缓冲区中的全部索引;也就是说,我们可以绘制索引的一个连续子集。
2.StartIndexLocation:指定从索引缓冲区的哪个位置开始读取索引数据。
3.BaseVertexLocation:在绘图调用中与索引相加的一个整数。
md3dImmediateContext->DrawIndexed(numSphereIndices, 0, 0);
md3dImmediateContex->DrawIndexed(numBoxIndices, firstBoxIndex, firstBoxVertexPos);
md3dImmediateContex->DrawIndexed(numCylIndices, firstCylIndex, firstCylVertexPos);