2

我对 DirectX 12 有疑问。我制作了一个小型 3D 渲染器。模型在顶点着色器中转换为 3D 空间,基本世界视图投影矩阵位于常量缓冲区中。

要更改常量缓冲区的数据,我当前使用memcpy(pMappedConstantBuffer + alignedSize * frame, newConstantBufferData, alignedSize)此命令会立即替换常量缓冲区的数据。


所以问题就来了,绘图被记录到一个命令列表中,稍后发送到gpu执行。

例子:

/* Now i want to change the constant buffer to change the next draw call's position to (0, 1, 0) */
memcpy(/*Parameters*/);

/* Now i want to record a draw call to the command list */
DrawInstanced(/*Parameters*/);

/* But now i want to draw other mesh to other position so i have to change the constant buffer. After this memcpy() the draw position will be (0, -1, 0) */
memcpy(/*Parameters*/);

/* Now i want to record new draw call to the list */
DrawInstanced(/*Parameters*/);

在此之后,我将命令列表发送到 gpu 以执行,但询问所有网格将在同一位置,因为所有 memcpys 甚至在命令列表发送到 gpu 之前都已执行。所以基本上最后一个 memcpy 会覆盖以前的。


所以基本上问题是我如何将网格绘制到不同的位置,或者如何在命令列表中替换常量缓冲区的数据,以便常量缓冲区在 gpu 上的每个绘制调用之间发生变化?

谢谢


不再需要帮助,我自己解决了。我为每个网格创建了常量缓冲区。

4

1 回答 1

1

关于执行顺序,您是完全正确的,您的 memcpy 调用将立即更新缓冲区,但是在您将命令列表推送到队列中之前,这些命令不会被处理(并且您不会确切知道何时会发生这种情况)。

在 Direct3D11 中,当您在缓冲区上使用 Map 时,这会为您处理(如果需要,将分配一些空间以避免这种情况)。

因此,在 Direct3D12 中,您有多种选择,我认为您要绘制 N 个对象,并且您希望在 cbuffer 中为每个对象存储一个矩阵。

首先是为每个对象创建一个缓冲区并独立设置数据。如果你只有几个,这很容易维护(并且由于资源分配而导致的额外内存占用是可以的)

另一种选择是创建一个大缓冲区(可以包含 N 个矩阵),并创建 N 个指向每个对象的内存位置的常量缓冲区视图。(请注意,在这种情况下,您还必须遵守 256 字节对齐,请参阅CreateConstantBufferView)。

您还可以使用 StructuredBuffer 并将所有数据复制到其中(在这种情况下您不需要对齐),并使用顶点着色器中的索引来查找正确的矩阵。(可以在着色器中设置一个 uint 值并使用SetGraphicsRoot32BitConstant直接应用它)。

于 2017-03-26T22:38:03.227 回答