D3D11
+ -

D3D11 IASetVertexBuffers 函数与顶点数据的两种组织方式

2024-12-17 8 0
原文转自:https://www.cnblogs.com/oilcode/p/10451785.html

D3D11中的 IASetVertexBuffers 函数用来向GPU传递顶点数据。
一般情况下,我都是传入一个buff,也即在0号slot上绑定了一个buff,其他slot都没有绑定buff。
我传入的这个buff,是一个存储了顶点结构体数据的数组,每个顶点结构体中都有Position成员,Color成员,UV成员等等。
用术语来描述我这种做法,就是“交错的顶点数据”,英文称呼有这些 Interleaved Vertex Data , an array of structs 。

相对应的,另外一种做法就是“非交错的顶点数据”“分离的顶点数据”,英文称呼有这些 Non-Interleaved Vertex Data , De-Interleaved Vertex Data , separate Vertex Data , a struct of arrays 。

这种做法的具体方案是,把顶点的所有的Position成员填充到buff0中,把所有的Color成员填充到buff1中,把所有的UV成员填充到buff2中,等等。

当执行 IASetVertexBuffers 函数时,0号slot绑定buff0,1号slot绑定buff1,2号slot绑定buff2,等等。

需要注意的是,当为顶点数据创建 InputLayout 时,
如果是交错的顶点数据,示例如下:

  D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
  {
    {"POSITION",0, DXGI_FORMAT_R32G32B32_FLOAT, 0,0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
  };

如果是分离的顶点数据,要为每个成员设置正确的slot序号,示例如下:

  D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
  {
    {"POSITION",     0, DXGI_FORMAT_R32G32B32_FLOAT,       0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"COLOR",         0, DXGI_FORMAT_R32G32B32A32_FLOAT,   1, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,              2, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
  };

回过头来再看这个结构体:

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;

很多编程教材里面都是使用“交错的顶点数据”这种做法,我也长期使用这种做法。
最近上网查询了一下,很多人都提倡使用“分离的顶点数据”这种做法,优点如下:
1,一个模型有Position成员,Color成员,UV成员。在某些情况下可能只需要向GPU中传递一类成员或者两类成员,本做法能够节省带宽。
例子1,绘制ShadowMap时,只需要传递Position成员。
例子2,做插值的骨骼动画时,在slot0中传递上一帧的Position和Normal,在slot1中传递当前帧的Position和Normal,在slot2中传递其他的顶点数据成员。
2,一个模型有Position成员,Color成员,UV成员。其中某一类成员的值需要频繁的发生变化,本做法能够降低内存拷贝的大小。例如,Position成员在每帧都要发生变化,那么只需要更改它的buff。
3,模型1和模型2有相同的Color成员,那么模型1和模型2就可以共用一个Color buff。本做法能够节省内存。
4,在GPU渲染时,当GPU需要若干个Position成员时,只需要从Position buff中读取若干个Position成员,需要多少就读多少,没有浪费,本做法能够提升GPU的工作流水线的效率。如果是交错的顶点数据,GPU必须读取若干个顶点结构体,才能拿到若干个Position成员。

参考链接

https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html
https://anteru.net/blog/2016/storing-vertex-data-to-interleave-or-not-to-interleave/
https://gamedev.stackexchange.com/questions/66545/vertex-buffers-interleaved-or-separate
https://stackoverflow.com/questions/19822102/non-interleaved-vertex-buffers-directx11

0 篇笔记 写笔记

作者信息
站长漫谈
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!