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

Posted oilcode

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了D3D11 IASetVertexBuffers 函数与顶点数据的两种组织方式相关的知识,希望对你有一定的参考价值。

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},
  };

 

很多编程教材里面都是使用“交错的顶点数据”这种做法,我也长期使用这种做法。
最近上网查询了一下,很多人都提倡使用“分离的顶点数据”这种做法,优点如下:
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

 

以上是关于D3D11 IASetVertexBuffers 函数与顶点数据的两种组织方式的主要内容,如果未能解决你的问题,请参考以下文章

关于D3D11,你必须了解的几件事情

D3D11:从 6 个图像创建立方体贴图

D3D11:如何将 GDI 文本绘制到 GXDI 表面? (没有 D2D)

在 Windows 10 上使用 D3D11 调试层和 VS2013

d3d11 游戏编程 渲染管线

OBS Studio 窗口采集game-capture注入之OpenGL与D3D11的GPU资源进行互操作