0

我正在从事一个个人项目,与许多 XNA 项目一样,该项目从地形置换贴图开始,该贴图用于生成在Device.DrawIndexedPrimitives()调用中呈现的顶点集合。

我已更新为 custom VertexDeclaration,但我现在无法访问该代码,因此我将发布稍旧但在范式上相同 (?) 的代码。

我将 a 定义VertexBuffer为:

VertexBuffer = new VertexBuffer(device, VertexPositionNormalTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
VertexBuffer.SetData(vertices);

其中“顶点”定义为:

VertexPositionNormalTexture[] vertices

我还有两个在每次 Update() 迭代时交换的索引缓冲区。在Draw()通话中,我设置了GraphicsDevice缓冲区:

Device.SetVertexBuffer(_buffers.VertexBuffer);
Device.Indices = _buffers.IndexBuffer;

忽略我希望不相关的代码行,我有一个方法可以检查边界形状以确定顶点是否在鼠标光标的某个半径内,并根据按下的键升高或降低这些顶点位置。我的问题是VertexBuffer.SetData()在容器类的初始化时只调用一次。

修改VertexPositionNormalTexture[]数组的顶点位置不会反映到屏幕上,尽管顶点位置的值已更改。我相信这与VertexBuffer.SetData()调用有关,但是您不能SetData()在修改顶点数组后简单地调用它。

SetData()在重新检查了 IndexBuffer 的处理方式(2 个缓冲区,有时交换并传入Update())之后,我认为这应该是处理VertexBuffer操作的方式,但这行得通吗?有没有更合适的方法?我在这里看到了对类似问题的另一个参考,但源链接在 MegaUpload 上,所以......

我会尝试我的VertexBuffer.Swap()想法,但我也看到了参考DynamicVertexBuffer并想知道有什么收获?性能据说会受到影响,但是对于地形编辑器,如果我可以动态地操作顶点数据,我认为这不是太大的权衡。

我可以发布更多代码,但我认为这可能是对设备缓冲区的设置方式或数据流式传输方式缺乏了解。

编辑:下面提出的解决方案是正确的。我会尽快发布我的代码。

4

1 回答 1

1

首先:我假设您没有从地形中添加或减去顶点。如果不是,则根本不需要更改 indexbuffer。

第二:您正确地认识到简单地编辑顶点数组不会改变屏幕上显示的内容。VertexBuffer 与创建它的顶点完全分开,并且不保留对它们的原始数组的引用。它是您设置数据时顶点的“快照”。

我不确定您所做的一些假设。据我所知,您可以随时调用 VertexBuffer.SetData()。如果您不改变地形中的顶点数量,只改变它们的位置,这很好。每次更改顶点的位置时,只需重新设置缓冲区中的数据即可。[注意:如果我错了,您只能在缓冲区上设置一次数据,那么只需将缓冲区的旧实例替换为新实例并在其上设置数据。不过,我认为您不需要这样做,除非您更改了顶点数]

但是,对于大缓冲区而言,调用 SetData 相当昂贵。您可以考虑将地形“分块”成许多较小的缓冲区,以避免在更改地形时设置数据所需的开销。

我对 DynamicVertexBuffer 类了解不多,但我认为它不是这种情况的最佳选择(即使听起来是这样)。我认为它更多地用于粒子顶点。不过,我可能是错的。一定要研究一下。

出于好奇,为什么需要两个索引缓冲区?如果您的顶点相同,为什么要每帧使用不同的索引?

编辑:您创建 VertexBuffer 的代码使用 BufferUsage.WriteOnly。好的做法是使 BufferUsage 与 GraphicsDevice 匹配。如果您没有设置设备的 BufferUsage,您可能只想使用 BufferUsage.None。如果您愿意,请尝试两者并检查性能差异。

于 2012-02-16T19:20:56.730 回答