# Retrieving vertex data from D3DXMESH

## Recommended Posts

HI I am loading my d3dxmesh from a xfile using the usual D3DXLoadMeshFromX function. I now want to read my vertex and index data from this d3dxmesh. From what I know the way to do this is first to lock the vertex buffer... UCHAR *vertices ; mesh->LockVertexBuffer(0, (void**)&vertices) ; //Then copy the vertex data over using memcpy memcpy( vertices, SOURCE, SIZE ); //And then unlock the buffer My question is what is the source over here?? Where do I get the vertices in the first place from? Any help will be appreciated. Thanks

##### Share on other sites
Quote:
 Original post by DratsHI I am loading my d3dxmesh from a xfile using the usual D3DXLoadMeshFromX function. I now want to read my vertex and index data from this d3dxmesh. From what I know the way to do this is first to lock the vertex buffer...UCHAR *vertices ;mesh->LockVertexBuffer(0, (void**)&vertices) ; //Then copy the vertex data over using memcpy memcpy( vertices, SOURCE, SIZE ); //And then unlock the buffer My question is what is the source over here?? Where do I get the vertices in the first place from? Any help will be appreciated. Thanks
If you want to copy out of your ID3DXMesh vertex buffer, then the source is the vertices pointer, and your flags should be D3DLOCK_READONLY. And your memcpy() first two arguments should be the other way around, and SOURCE should be a buffer you've allocated for the vertices to go in to.

##### Share on other sites
In addition to the above, note that if you just want to access the vertices before you Unlock(), you can just access vertices like a normal array.

// assume your vertex structure is called VertexVertex *vertices ;mesh->LockVertexBuffer(0, (void**)&vertices) ; Vertex ThirdVertex=vertices[3]; // for example//And then unlock the buffer

Unless you want to create a seperate copy of the vertices to manipulate after you have Unlock()-ed, there is no need to copy at all.

##### Share on other sites
Quote:
 Original post by Evil SteveIf you want to copy out of your ID3DXMesh vertex buffer, then the source is the vertices pointer, and your flags should be D3DLOCK_READONLY. And your memcpy() first two arguments should be the other way around, and SOURCE should be a buffer you've allocated for the vertices to go in to.

Sorry but I am a little confused. How can the vertices pointer be the source?

Does that mean that when I do this

mesh->LockVertexBuffer(0,(void**)&vertices)

the vertices pointer gets filled with the vertex data from the mesh automatically?

Thanks

##### Share on other sites
Quote:
 Original post by DratsSorry but I am a little confused. How can the vertices pointer be the source? Does that mean that when I do this mesh->LockVertexBuffer(0,(void**)&vertices) the vertices pointer gets filled with the vertex data from the mesh automatically?
Yes. Locking the vertex buffer gives you a pointer to the memory inside the buffer (It's a little more complicated than that, but never mind). So you can read / write into that pointer however you wish (Although I'd recommend the readonly flag if you're just reading from it for better performance).

##### Share on other sites
[EDIT - This reply was to drats, not EvilSteve [smile]]

Kinda - the vertices pointer points to the data. However, where that data is and how it got there is kind of down to Direct3D and the graphics hardware.

For example, if the vertex data was only in a hardware specific format on the card when you call Lock(), behind the scenes the chances are the entire buffer has been copied into system memory somewhere.

If the buffer is in the managed pool, the system maintains a copy in system memory so the Lock() probably just points the pointer at that.

There are other possibilities but I'm not an expert on graphics memory.

The important thing is that you can't treat vertices[] like normal memory - you don't own it in the normal sense and it is only accessible until you Unlock().

##### Share on other sites
Oh right. It makes sense now. Thanks both of you.

##### Share on other sites

Could you also explain how memcpy works? I am getting an unhandled error exception for the following code:

UCHAR * vertices ;
UCHAR * vertbuf ; // The destination buffer

memcpy(vertbuf , vertices , sizeof(vertices)) ;

m_pMesh->UnlockVertexBuffer() ;

What am I doing wrong?

##### Share on other sites
Quote:
 Original post by DratsCould you also explain how memcpy works? I am getting an unhandled error exception for the following code: UCHAR * vertices ;UCHAR * vertbuf ; // The destination buffer m_pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&vertices) ; memcpy(vertbuf , vertices , sizeof(vertices)) ; m_pMesh->UnlockVertexBuffer() ; What am I doing wrong?

This is not an issue with how memcpy works - this is an issue with the fact that you are copying into memory that has not been allocated.

In the example above, vertbuf is just a pointer - it is not pointing at anything.

First attempt at a solution might be this:

UCHAR * vertices ;UCHAR * vertbuf=new UCHAR[sizeof(Vertex)*NumberOfVertices];m_pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&vertices) ; memcpy(vertbuf , vertices , sizeof(vertices)) ;  m_pMesh->UnlockVertexBuffer() ;// do stuff with vertbufdelete [] vertbuf;

However, there is a major problem - sizeof(vertices) as the third argument to memcpy returns the size of the pointer, not the size of the data - think about it - how can the compiler know the size of the data returned by Lock()?

So you need another way to know the size of the data, which you can get from a method of D3DXMesh - GetNumVertices().

DWORD NumberOfVertices=m_pMesh->GetNumVertices();UCHAR * vertices ;UCHAR * vertbuf=new UCHAR[sizeof(Vertex)*NumberOfVertices];m_pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&vertices) ; memcpy(vertbuf , vertices , sizeof(Vertex)*NumberOfVertices) ;  m_pMesh->UnlockVertexBuffer() ;// do stuff with vertbufdelete [] vertbuf;

Now we should be working.

But modern C++ idioms try to avoid manual allocation/deletions if possible since if you forget to delete[] or if an exception gets thrown anywhere after the new and before the delete, you end up with memory leaks.

Thankfully, the standard library std::vector<> provides an exception-safe and automatic solution:

DWORD NumberOfVertices=m_pMesh->GetNumVertices();UCHAR * vertices ;std::vector<UCHAR> vertbuf(sizeof(Vertex)*NumberOfVertices);m_pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&vertices) ; memcpy(&(vertbuf[0]) , vertices , sizeof(vertices)) ;  m_pMesh->UnlockVertexBuffer() ;// do stuff with vertbuf

Now vertbuf's memory is automatically released whenever vertbuf goes out of scope, be it through scope exit by function return, exception being thrown etc. For more info on the concept, RAII.

Another point - given that you are almost certainly going to want to access the data above as vertices rather than UCHARs, why not use vertices in the first place? If we assume that your vertex structure is called Vertex:

DWORD NumberOfVertices=m_pMesh->GetNumVertices();Vertex * vertices ;std::vector<Vertex> vertbuf(NumberOfVertices);m_pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&vertices) ; memcpy(&(vertbuf[0]) , vertices , sizeof(UCHAR)*NumberOfVertices) ;  m_pMesh->UnlockVertexBuffer() ;Vertex V=vertbuf[23];float X=vertbuf[8].X;

See what I'm driving at? Obviously the last two lines depend on the particular implementation you've chosen for your vertex structure.

Finally, prefer std::copy over memcpy in C++:

// forgive maybe syntax errors - am at work and can't double checkstd::copy(vertices,vertices+sizeof(UCHAR)*NumberOfVertices,&(vertbuf[0]));

Irrelevant in this situation but a good habit to get into since std::copy will respect copy constructors for non-POD structures but should resolve down to a simple memcpy for POD types.

But I still reiterate - are you sure you actually need to do this copy? What are you using this system copy for? Why can't you just access vertices[] directly before you Unlock()?

Generally you only make a copy of a vertex buffer in system memory manually if you need the copy to persist around for access after you have Unlock()-ed the resource but this is unusual. A classic example might be retrieving a mesh to use for collision information, but you would almost always convert this into a collision-specific structure (i.e. no texture coordinates or diffuse colour elements) in which case you might as well do the conversion directly from the Lock()-ed pointer.

Are you just experimenting or is there some reason you need the vertex buffer in system memory after you Unlock() the buffer?

HTH

[Edited by - EasilyConfused on September 17, 2008 1:24:54 AM]

##### Share on other sites
Wow thanks for the super explanation. And you guessed correctly, I do want a copy of the vertex and index data to pass to my collision detection routines. That is also why I was declaring the vertices as unsigned chars. Because I want to be able to manipulate them one at a time. Basically multiply them with the WORLD MATRIX to get coordinates in world space.

Also how do I find out the vertex structure that my vertices are using? Since I will be loading the mesh from an xfile and not allocating the vertex structure myself. Could I not do this:

UCHAR * vertices ;
UCHAR * vertbuf=new UCHAR[sizeof(vertices)*NumberOfVertices];

Thanks once again. Much appreciated.

##### Share on other sites
Quote:
 Original post by DratsWow thanks for the super explanation. And you guessed correctly, I do want a copy of the vertex and index data to pass to my collision detection routines. That is also why I was declaring the vertices as unsigned chars. Because I want to be able to manipulate them one at a time. Basically multiply them with the WORLD MATRIX to get coordinates in world space. Also how do I find out the vertex structure that my vertices are using? Since I will be loading the mesh from an xfile and not allocating the vertex structure myself. Could I not do this: UCHAR * vertices ;UCHAR * vertbuf=new UCHAR[sizeof(vertices)*NumberOfVertices]; Thanks once again. Much appreciated.

Nope.

sizeof(vertices) returns the size of the pointer. Previously you were trying to use it as the size of the data, now you are trying to use it as the size of a vertex (i.e. the stride between one vertex and another in the vertex buffer).

I'm not sure offhand (at work, can't look it up) how you query the size of the vertex format it uses. I know there is a GetFVF() method that will return a DWORD containing the flexible vertex structure.

Perhaps someone else can advise how to get the vertex size.

Note though that you can't just multiply the vertex data as a string of UCHARs by a world matrix - only some parts of the vertex contain coordinates, and they will most likely be floats, so mulitplying those as UCHARs will be meaningless.

Other elements will be things like texture coordinates, diffuse colours etc. You can't treat vertex buffer data as an array of UCHARs for anything much except copying.

##### Share on other sites
Quote:
 Original post by EasilyConfusedI'm not sure offhand (at work, can't look it up) how you query the size of the vertex format it uses. I know there is a GetFVF() method that will return a DWORD containing the flexible vertex structure.Perhaps someone else can advise how to get the vertex size.
ID3DXBaseMesh::GetNumBytesPerVertex.

If you just need the vertex positions, you can usually assume that the position is the first member of the vertex structure. In that case, you copy out the first 12 bytes of the vertex struct, and then skip forwards by vertex_stride. Example:
// Using a const BYTE* because it's const (Since you lock with READONLY, and// because UCHAR could be 2 bytes or more under unicode I think.const BYTE* pVertices;// ALWAYS check return values of functiosn that return pointers!HRESULT hResult = m_pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&pVertices); if(FAILED(hResult)){   // Error, bail   return false;}// Get num verts and vertex sizeDWORD nVerts = m_pMesh->GetNumVertices();DWORD nStride = m_pMesh->GetNumBytesPerVertex();// Declare a dynamic sized array of 3D vectors (Vertex positions), and reserve itstd::vector<D3DXVECTOR3> vertices;vertices.reserve(nVerts);// Process each vertex...for(DWORD i=0; i<nVerts; ++i){   // Get the position (at the start of the vertex struct)   const D3DXVECTOR3* pPosition = (const D3DXVECTOR3*)pVertices;   vertices.push_back(*pPosition);   // Move on to the next vertex   pVertices += nStride;}// Unlock the VBm_pMesh->UnlockVertexBuffer() ;// Do stuff with vertices, it's automatically cleaned up when it goes out of scope,// no need to delete[] it.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
627740
• Total Posts
2978884

• 10
• 10
• 21
• 14
• 14