2013-04-23 52 views
5

我有一个我一直在编写的C++ DirectX 11渲染器。在DX10/DX11中使用多个顶点缓冲区

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

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

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

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

这些顶点缓冲器包含不同阵列长度(位置具有2910层的元件,法线具有比9000以上,和纹理坐标具有大致3200)

COLLADA提供一个三角形列表这使我的索引到每个这些阵列的对于一个给定的三角形(开始时是冗长而奇怪的,但最终一旦你使用它就变得简单了)。

知道DX10/11支持多个顶点缓冲区我想填充DX10/11索引这些指数可以是不同的f或三角形的给定点。

换句话说,我可以设置三个顶点缓冲区,设置正确的输入布局,然后在索引缓冲区我把相当于:

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不会为您提供从多个顶点缓冲区进行流式处理的能力,然后实际上每个三角形点只有一个索引?

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

看起来,将正常和纹理坐标索引放入索引缓冲区会导致错误地绘制正确渲染的网格。

这是预期的行为?

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

这对我来说确实没有意义。

帮助!

+0

哦,我的上帝,我从来不知道你可以用这种方式分割你的顶点数据! – Lucius 2013-04-23 18:29:38

+0

不久之前,我遇到了同样的问题,并在搜索解决方案时遇到了[此答案](http://stackoverflow.com/a/2305383/1798046)。这真的帮助我更深入地了解问题。我也可能帮助你。 – Krienie 2013-07-20 19:48:26

回答

2

附带在我脑海的第一件事:

支持计算着色器(等同于几乎所有的DirectX 10及更高版本)的所有硬件还支持ByteAddressBuffer S和大部分支持StructuredBuffer秒。因此,您可以将数组绑定为SRV s,并可随机访问着色器中的任何元素。

像这样(没有测试,只是伪代码):

// 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)。

希望它有帮助!

+0

这是一个有趣的解决方法,我将不得不尝试一下。我希望看到在每个网格基础上设置它的性能方面。谢谢 – WTH 2013-04-23 19:45:35