6

我有一个我一直在写的 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 肯定不会为您提供从多个顶点缓冲区流式传输的能力,然后实际上每个三角形点只有一个索引?

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

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

这是预期的行为吗?

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

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

帮助!

4

1 回答 1

3

我脑海中的第一件事是:

所有支持计算着色器的硬件(几乎等于所有 DirectX 10 及更高版本)也支持ByteAddressBuffer并且其中大部分支持StructuredBuffer。因此,您可以将数组绑定为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)。

希望能帮助到你!

于 2013-04-23T19:16:28.297 回答