【问题标题】:Using Multiple Vertex Buffers In DX10/DX11在 DX10/DX11 中使用多个顶点缓冲区
【发布时间】:2013-04-16 22:39:11
【问题描述】:

我有一个正在编写的 C++ DirectX 11 渲染器。

我编写了一个 COLLADA 1.4.1 加载器来导入 COLLADA 数据以用于支持骨骼动画。

此时我正在验证加载程序(我之前在另一个使用不同技术编写的渲染器中支持 COLLADA)并且遇到了将 COLLADA 与 DX10/11 匹配的问题。

我有 3 个独立的数据顶点缓冲区:

唯一顶点位置的顶点缓冲区。 唯一法线的顶点缓冲区。 唯一纹理坐标的顶点缓冲区。

这些顶点缓冲区包含不同的数组长度(位置有 2910 个元素,法线有 9000 多个,纹理坐标大约有 3200 个。)

COLLADA 提供了一个三角形列表,它为我提供了给定三角形的每个数组的索引(一开始很冗长而且很奇怪,但一旦你使用它,最终它就会变得简单。)

知道 DX10/11 支持多个顶点缓冲区,我想我会用索引填充 DX10/11 索引缓冲区到每个缓冲区 * 和 *(这是重要部分),这些对于三角形的给定点,索引可能不同。

换句话说,我可以设置三个顶点缓冲区,设置正确的输入布局,然后在索引缓冲区中放入等价物:

l_aIndexBuffer[ NumberOfTriangles * 3 ]

for( i = 0; i < NumberOfTriangles; i++ )
{
    l_aIndexBufferData.add( triangle[i].Point1.PositionIndex )
    l_aIndexBufferData.add( triangle[i].Point1.NormalIndex )
    l_aIndexBufferData.add( triangle[i].Point1.TextureCoordinateIndex )
}

关于在 DirectX 中使用多个顶点缓冲区的文档似乎没有提供任何关于这如何影响索引缓冲区的信息(稍后会详细介绍。)

以这种方式运行代码会产生奇怪的渲染结果,我可以看到我间歇性正确绘制的网格(奇怪的多边形,但大约三分之一的点在正确的位置 - 提示 - 提示)

我认为我在这一点(昨天)搞砸了我的数据或索引,所以我煞费苦心地验证了这一切,所以我认为我在搞砸我的输入或其他东西。我通过使用法线和纹理缓冲区中的值来交替设置像素着色器使用的颜色值来消除这种情况,颜色是正确的,所以我没有遇到填充问题。

最终我得出的结论是 DX10/11 必须期望数据以不同的方式排序,所以我尝试以这种方式存储索引:

indices.add( Point1Position index )
indices.add( Point2Position index )
indices.add( Point3Position index )
indices.add( Point1Normal index )
indices.add( Point2Normal index )
indices.add( Point3Normal index )
indices.add( Point1TexCoord index )
indices.add( Point2TexCoord index )
indices.add( Point3TexCoord index )

奇怪的是,这产生了一个看起来 1/3 正确的渲染网格 - 提示 - 提示。

然后我推测可能 DX10/DX11 想要“按顶点缓冲区”存储的索引,这意味着我将首先添加所有三角形的所有位置索引,然后添加所有三角形的所有法线索引,然后添加所有纹理坐标所有三角形的索引。

这产生了另一个 1/3 正确(看起来)的网格。

这让我想到 - 好吧,DX10/11 肯定不会为您提供从多个顶点缓冲区流式传输的能力,然后实际上每个三角形点只有一个索引?

仅在位置的顶点缓冲区中包含索引会生成正确渲染的网格,但不幸的是使用了错误的法线和纹理坐标。

似乎将法线和纹理坐标索引放入索引缓冲区会导致在正确渲染的网格上绘制错误。

这是预期的行为吗?

Multiple Vertex Buffers - 一个索引缓冲区和索引缓冲区对于三角形的一个点只能有一个索引?

这对我来说真的没有意义。

救命!

【问题讨论】:

  • 天哪,我从来不知道你可以这样分割你的顶点数据!
  • 不久前我遇到了同样的问题,在寻找解决方案时遇到了this answer。它确实帮助我更深入地了解问题。我也可以帮你。

标签: directx game-engine directx-11


【解决方案1】:

我脑海中的第一件事:

支持计算着色器的所有硬件(几乎等于所有 DirectX 10 及更高版本)也支持ByteAddressBuffers,其中大部分支持StructuredBuffers。因此,您可以将您的数组绑定为 SRVs 并随机访问着色器中的任何元素。

类似这样的东西(未经测试,只是伪代码):

// Indices passed as vertex buffer to shader
// Think of them as of "references" to real data
struct VS_INPUT
{
    uint posidx;
    uint noridx;
    uint texidx;
}

// The real vertex data 
// You pass it as structured buffers (similar to textures)
StructuredBuffer<float3> pos : register (t0);
StructuredBuffer<float3> nor : register (t1);
StructuredBuffer<float2> tex : register (t2);


VS_OUTPUT main(VS_INPUT indices)
{
    // in shader you read data for current vertex
    float3 pos = pos[indices.posidx];
    float3 nor = nor[indices.noridx];
    float2 tex = tex[indices.texidx];

    // here you do something
}

我们称之为“计算着色器方法”。您必须使用 DirectX 11 API。

您还可以以相同的方式绑定索引并在着色器中发挥一些作用。在这种情况下,您需要找出当前的索引 ID。或许您可以从 SV_VertexId 中获取。

也许您可以解决这些缓冲区并以其他方式绑定数据(与 DirectX 9 兼容的纹理采样!O_o)。

希望对你有帮助!

【讨论】:

  • 这是一个有趣的解决方法,我必须尝试一下。我将有兴趣查看在每个网格基础上设置它的性能方面。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多