1
\$\begingroup\$

How can I identify the correct vertecis and move them in XNA using VertexBuffer? Let's say I have a simple cuboid in my project and want to move one face of it. How would I loop thru vertices, get their information and reposition those vertices to a new Vector3 location?

This is a must for my project, since bones aren't flexible enough.

EDIT:

Since everyone is saying this would be bad and slow. Is there a way, again to loop thru vertecis, create a BONE and assign correct vertecis to it? Can this be done outside of content pipeline, during run-time (if not, content pipeline is ok)? How can I also then parent these bones to bones of THIS or OTHER model?

Also, if all of this works great and all. How would I then draw this model, I mean which transform or bone would I use for the world matrix? Especially if I had more than just one new bone.

\$\endgroup\$
0

4 Answers 4

2
\$\begingroup\$

So, first of all, let's say you're trying to resize a cuboid (and it will stay a cuboid). The correct solution in this case isn't to modify vertices or even to use bones. What you want to do is use a model matrix that specifies a scale. You can then scale your model on each axis to place the vertices where you want them.


But, let's say that you're sure that you need to modify individual vertices. And let's say that you want to move them independently and arbitrarily - in which case bones is not a good solution. (Bones would be good if you want to move parts of the model around - you don't want to have one bone per vertex!)

First, let's cover the easy bit: How do you identify which vertices belong to a face? You simply save the indices of those vertices when you construct your cuboid. For each face store a list of indices (List<int> or int[]).

Now let's look at how to actually maintain and draw your vertex buffer.

It's worth considering, at this point, that most people (including myself) are answering this question with an eye for performance. But if all you have is a cuboid - you could do just about anything and not suffer performance issues.

There are three "kinds" of vertex buffers in XNA. There's VertexBuffer, DynamicVertexBuffer and the various DrawUserPrimitves methods. I will give a very quick overview of how they work:

VertexBuffer allocates a section of GPU memory that the GPU reads vertices from. The GPU does some crazy pipelining stuff - it's possible for it to be drawing a frame long after you've started to draw the next one. So if you modify a VertexBuffer that is still being used to draw a previous frame, you stall the pipeline while the GPU finishes using the old data. Basically: Do not modify a VertexBuffer that is in use, if you can avoid it.

DynamicVertexBuffer works around this problem at the expense of GPU memory (and maybe some performance). Basically it allows the GPU to store several copies of your vertex buffer. That means that an older frame can use one copy, while your changes get applied to a different copy. There is also a DynamicIndexBuffer.

DrawUserPrimitves allows the GPU to assume that the vertex buffer won't get modified while it's still in use. The downside is that you are creating a new one each frame and must send the data for it to the GPU each frame. There is also an advantage, in some cases with small primitive counts, in that your data can be batched up with the the draw command, rather than copied separately.


Finally you must actually get your data to the GPU. I have a few important pieces of advice here.

First of all, you should never pull data back from the GPU, if you can avoid it. In XNA, that's the GetData method. It can potentially cause the GPU to pipeline flush and you're stalling your own program on the CPU, while it waits for the slow transfer of data from the GPU.

Given the above, you should keep a copy of your vertex data as an array (of your vertex type, eg: VertexPositionColor) in main memory. You can use this directly, modifying vertex positions (no need for a separate array of just the positions). Select elements in the array with the indicies you stored earlier.

Then simply use your array of vertex data with DynamicVertexBuffer.SetData (probably better - especially if you only change a section of the vertex data) before drawing the buffer, or with DrawUserIndexedPrimitives (probably easier).

If you do use SetData, for best performance you should try to minimise how many writes you do. For example, if you modify the face of a cuboid you only change 4 vertices. But those vertices may be spread out in the buffer - it is likely to be faster to set all 8 vertices of the cuboid, than to set 4 of them one at a time.

And, finally, it's worth pointing out that, no matter what option you choose, your data still has to get onto the GPU somehow! Using bones will not solve this problem. Bone transforms aren't exactly small - they get sent each frame (like DrawUserPrimitves) - so it's very possible for vertex data itself to be smaller if the number of bones is similar to the number of vertices. People are suggesting bones because it means you don't have to modify a VertexBuffer - but as you can see from my answer, there are alternatives.

\$\endgroup\$
2
\$\begingroup\$

An actual VertexBuffer should really only be used for vertice information that wont be changing very often. When you assign a vertex array to a vertex buffer you are essentially moving the vertex info onto the gpu and receiving a reference to it that you can use to indicate to the GraphicsDevice that you will be using for the next render operation. If you want to be changing vertices around then you should really retain the original VertexPositionNormal array or whatever flavor of vertex data you are using and use a the DrawUserPrimitives or DrawUserIndexedPrimitives calls. The advantage of keeping the vertices as an array is that you can readily loop through them to identify if a face has been selected without having to call GetData first.

If you really want to modify a VertexBuffer then you will have to call GetData and then modify the the vertice info, and then call SetData with the modified array.

\$\endgroup\$
1
\$\begingroup\$

A vertex buffer is just as it sounds, a big list of vertex data, and you can frequently access this data by simply indexing the buffer. Changing the values stored in the vertex buffer will achieve the results you want of moving the vertex to a new position. You will have to develop a system yourself for skinning verts to bones, or at least identifying the vertex you want based on your search criteria.

\$\endgroup\$
1
\$\begingroup\$

Generally, you wouldn't do this. There are data structures designed for easy modification, such as those based on lists of half-edges. You would modify that data then regenerate the VertexBuffet rather than modifying the buffer directly.

The basic idea is to find all vertices belonging to the face (again, much easier with a data structure designed for it) and then moving them, splitting up any deformed polygons sharing those vertices (assuming it's not all triangles, which don't generally get into a deformed state).

Doing that with an optimized-for-GPU-rendering structure like a VertexBuffer is silly. You'll be copying the VBO back into memory (slow), doing a lot of iterating to find vertices matching some definition of a face, and then generating a new VBO. It's a lot of extra work for no gain besides a slight decrease in system memory by not needing the second data structure.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .