'CommandList::DrawInstanced' select 多个插槽中的顶点缓冲区之一如何?

How does 'CommandList::DrawInstanced' select one of the vertexbuffers in multiple slots?

我学习了如何使用 IASetVertexVuffers 将顶点缓冲区绑定到特定插槽。 但是后来,当我学习 DrawInstanced 时,我学会了 select 个顶点来仅使用起始顶点的索引进行绘制。 我想知道这个 DrawInstanced selects 顶点如何通过计算到哪个插槽的顶点缓冲区的索引。 或者它只是一个从 slot 0 到下一个 slot 的索引? 这个问题可能很难理解,因为我用错了英文。

如果您在调用 Draw* 时将多个顶点缓冲区绑定到多个插槽,则它们会根据当前输入布局并行使用。

如果您正在使用DrawIndexed*,那么一个绑定索引缓冲区用于生成一个索引,用于所有与D3D11_INPUT_PER_VERTEX_DATA绑定的顶点缓冲区。即,它们被视为并行数组:

// This is psuedo-code!

Vertex0 vb0[nVerts];
Vertex1 vb1[nVerts];
Vertex2 vb2[nVerts];

uint32_t ib[nTris * 3];

Bind vb0 to slot 0, vb1 to slot 1, vb2 to slot 2 of Vertex Buffers
Bind ib to Index Buffer

// For DirectX 12, the input layout is part of the Pipeline State Object (PSO)
Bind an input layout that uses vertex data from from 3 slots

DrawIndexed
    foreach j in 0 to (IndexCount-1);
        index = ib[StartIndexLocation + j] + BaseVertexLocation
        assemble vertex from vb0[index], vb1[index], vb2[index]
        draw when you have enough vertices for the primitive

使用 DirectX 文档的挑战之一是通常每个版本都从假设您已经知道以前的版本开始。早在 DirectX 9 中就引入了多流渲染,所以这是最后一次 概念上 解释:Programming One or More Streams (Direct3D 9)

在 DirectX 11 中,有四种 Draw* 方法:

void Draw( 
    UINT VertexCount,
    UINT StartVertexLocation);

void DrawInstanced( 
    UINT VertexCountPerInstance,
    UINT InstanceCount,
    UINT StartVertexLocation,
    UINT StartInstanceLocation);
    
// Uses an Index Buffer
void DrawIndexed( 
    UINT IndexCount,
    UINT StartIndexLocation,
    INT BaseVertexLocation);
   
void DrawIndexedInstanced( 
    UINT IndexCountPerInstance,
    UINT InstanceCount,
    UINT StartIndexLocation,
    INT BaseVertexLocation,
    UINT StartInstanceLocation);

DirectX 12 支持所有相同的功能,但在两种 方法中完成。如果 InstanceCount 为 1,则 未实例化 :

void DrawInstanced(
  UINT VertexCountPerInstance,
  UINT InstanceCount,
  UINT StartVertexLocation,
  UINT StartInstanceLocation
);

// Uses an Index Buffer
void DrawIndexedInstanced(
  UINT IndexCountPerInstance,
  UINT InstanceCount,
  UINT StartIndexLocation,
  INT  BaseVertexLocation,
  UINT StartInstanceLocation
);

有关使用实例化的信息,请参阅 C++ 示例 SimpleInstancingDX11 / DX12

我误认为顶点缓冲区的元素本身代表了实际的顶点。 顶点缓冲区中的顶点元素本身并不意味着实际的顶点,而只是包含最终将要创建的顶点的某些特征的实体。 顶点缓冲区的元素只是引用的信息,通过引用inputlayout中描述的元素的成员,使实际顶点对应于元素的索引。 例如,假设slot 0的顶点缓冲区中有4个成员的顶点结构,slot 1中有2个成员的顶点结构,这6个特征由inputlayout合成形成一个顶点,并将IA作为输入参数传递给顶点着色器(当然,可能只使用六个中的一些)。 另外,这是我的看法,但是在IA阶段,只是把顶点之间的关系整理好传递给后期,vertex buffer的成员是按照inputlayout中的描述从vertex shader传来的,貌似认真使用。