用于地形编辑器的 XNA VertexBuffer

发布于 2025-01-06 04:13:40 字数 1443 浏览 2 评论 0原文

我正在开发一个个人项目,与许多 XNA 项目一样,从地形位移图开始,该地图用于生成在 Device.DrawIndexedPrimitives() 调用中渲染的顶点集合。

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

我将 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()

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

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

我可以发布更多代码,但我认为这可能是缺乏对如何设置设备缓冲区或如何将数据流式传输到它们的理解。

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

I'm working on a personal project that, like many XNA projects, started with a terrain displacement map which is used to generate a collection of vertices which are rendered in a Device.DrawIndexedPrimitives() call.

I've updated to a custom VertexDeclaration, but I don't have access to that code right now, so I will post the slightly older, but paradigmatically identical (?) code.

I'm defining a VertexBuffer as:

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

where 'vertices' is defined as:

VertexPositionNormalTexture[] vertices

I've also got two index buffers that are swapped on each Update() iteration. In the Draw() call, I set the GraphicsDevice buffers:

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

Ignoring what I hope are irrelevant lines of code, I've got a method that checks within a bounding shape to determine whether a vertex is within a certain radius of the mouse cursor and raises or lowers those vertex positions depending upon which key is pressed. My problem is that the VertexBuffer.SetData() is only called once at initialization of the container class.

Modifying the VertexPositionNormalTexture[] array's vertex positions doesn't get reflected to the screen, though the values of the vertex positions are changed. I believe this to be tied to the VertexBuffer.SetData() call, but you can't simply call SetData() with the vertex array after modifying it.

After re-examining how the IndexBuffer is handled (2 buffers, swapped and passed into SetData() at Update() time), I'm thinking this should be the way to handle VertexBuffer manipulations, but does this work? Is there a more appropriate way? I saw another reference to a similar question on here, but the link to source was on MegaUpload, so...

I'll try my VertexBuffer.Swap() idea out, but I have also seen references to DynamicVertexBuffer and wonder what the gain there is? Performance supposedly suffers, but for a terrain editor, I don't see that as being too huge a trade-off if I can manipulate the vertex data dynamically.

I can post more code, but I think this is probably a lack of understanding of how the device buffers are set or data is streamed to them.

EDIT: The solution proposed below is correct. I will post my code shortly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风苍溪 2025-01-13 04:13:40

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

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

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

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

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

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

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

First: I am assuming you are not adding or subtracting vertices from the terrain. If you aren't, you won't need to alter the indexbuffer at all.

Second: you are correct in recognizing that simply editing your array of vertices will not change what is displayed on screen. A VertexBuffer is entirely separate from the vertices it is created from and does not keep a reference to the original array of them. It is a 'snapshot' of your vertices when you set the data.

I'm not sure about some of what seem to be assumptions you have made. You can, as far as I am aware, call VertexBuffer.SetData() at any time. If you are not changing the number of vertices in your terrain, only their positions, this is good. Simply re-set the data in the buffer every time you change the position of a vertex. [Note: if I am wrong and you can only set the data on a buffer once, then just replace the old instance of the buffer with a new one and set the data on that. I don't think you need to, though, unless you've changed the number of vertices]

Calling SetData is fairly expensive for a large buffer, though. You may consider 'chunking' your terrain into many smaller buffers to avoid the overhead required to set the data upon changing the terrain.

I do not know much about the DynamicVertexBuffer class, but I don't think it's optimal for this situation (even if it sounds like it is). I think it's more used for particle vertices. I could be wrong, though. Definitely research it.

Out of curiosity, why do you need two index buffers? If your vertices are the same, why would you use different indices per frame?

Edit: Your code for creating the VertexBuffer uses BufferUsage.WriteOnly. Good practice is to make the BufferUsage match that of the GraphicsDevice. If you haven't set the BufferUsage of the device, you probably just want to use BufferUsage.None. Try both and check performance differences if you like.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文