Skip to main content
gamedev.net
🔒 Locked 🎮 Unity

[C++, DX9] Vertex buffer problem again

Started by Ripiz Jun 21, 2010 at 5:42 AM 3 replies 1.6k views
Original Post
Ripiz
Ripiz
//vertex structurestruct D3DVERTEX {    Vector3 p;};//rendering	vector<Vector3> vertices;	LPDIRECT3DVERTEXBUFFER9 pVertices;	myModel.Mesh->GetVertexBuffer( &pVertices );	D3DVERTEX *pVerticesW;	pVertices->Lock( 0, 0, ( void** )&pVerticesW, 0 );	for(unsigned int i=0; i<myModel.Mesh->GetNumVertices(); i++)		vertices.push_back(Vector3(pVerticesW.p.x, pVerticesW.p.y, pVerticesW.p.z));	pVertices->Unlock();	device->SetFVF(D3DFVF_NORMAL);	device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, vertices.size()/3, &vertices[0], sizeof(D3DVERTEX));//myModel.Mesh is ID3DXMesh*


Problem is, that nothing gets drawn at all.

I tried D3DFVF_XYZ and D3DPT_TRIANGLESTRIP but nothing changes. Anyone know what's wrong? Thank you in advance.

[Edited by - Ripiz on June 21, 2010 7:03:41 AM]
Evil Steve
Evil Steve
This line:
device->SetFVF(D3DFVF_NORMAL);
Tells D3D that the vertex stream has normals in it, it doesn't include a vertex position, which is invalid. If you're drawing vertices that just have a position (And no other data), which seems to be what you're doing from looking at your D3DVertex struct, you'll want to use D3DFVF_XYZ.

You're locking the vertex buffer and reading an array of 3D vectors, but the mesh vertex buffer may have other components in each vertex. You want to skip over each vertex, and read the position out (Luckily the position is always the first component of a vertex):
// Find the size (in bytes) of a single vertex. E.g. a vertex with 3D position// and 3D normal will be 3+3 floats = 6*4 bytes = 24 bytes.DWORD dwVertexSize = myModel.Mesh->GetNumBytesPerVertex();// Lock the vertex buffer and get a BYTE pointer (to make skipping vertices easy):BYTE* pVertexData;pVertices->Lock( 0, 0, ( void** )&pVertexData, 0 );// Process each vertex in turnDWORD dwNumVerts = myModel.Mesh->GetNumVertices();for(DWORD i=0; i<dwNumVerts; ++i){   // Skip to the start of this vertex   BYTE* pVertex = pVertexData + i*dwVertexSize;   // Since the position is the first component, we can do a straight cast   Vector3* pPosition = (Vector3*)pVertex;   // Add this vertex to the vector   vertices.push_back(*pPosition);}pVertices->Unlock();


I'm also fairly sure you'll need to Release() the vertex buffer after all of that (I expect that ID3DXMesh::GetVertexBuffer() increments the reference count), otherwise you'll get a memory leak.
Ripiz
Ripiz
Ahh thanks. It works (almost). There's one little problem.

Current code:
	LPDIRECT3DVERTEXBUFFER9 pVertices;	terrains[0].Mesh->GetVertexBuffer( &pVertices );	DWORD dwVertexSize = terrains[0].Mesh->GetNumBytesPerVertex();	BYTE* pVertexData;	pVertices->Lock( 0, 0, ( void** )&pVertexData, 0 );	DWORD dwNumVerts = terrains[0].Mesh->GetNumVertices();	for(DWORD i=0; i<dwNumVerts; ++i){		BYTE* pVertex = pVertexData + i*dwVertexSize;		Vector3* pPosition = (Vector3*)pVertex;		vertices.push_back(*pPosition);		vertices[vertices.size()-1].y += 50;	}	pVertices->Unlock();	device->SetFVF(D3DFVF_XYZ);	device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, vertices.size()/3, &vertices[0], sizeof(Vector3));


On the left what's rendered by DrawPrimitiveUP, on the right is actual model. There's little artificial, any way to fix it? Image:
http://dl.dropbox.com/u/2637453/mdl2.PNG



Edit: After looking at image again I noticed way more artificials :(
Evil Steve
Evil Steve
The problem is that an ID3DXMesh's vertex buffer doesn't contain vertices in triangle list format, it contains indexed vertex data. To use it correctly you'll have to lock the meshes index buffer (In the same way you are for the vertex buffer), and use DrawIndexedPrimitiveUP() instead.

For example, a single square with 4 vertices (0, 1, 2, 3) might be drawn as:
(0, 1, 2) (1, 2, 3)
Which is 4 vertices, but 6 indices. As it is, you're drawing 1 triangle (4 / 3 = 1 because it's integer division), and if the mesh contained more vertices, you're using the wrong ones to render (E.g. if it contains two seperate squares that'd be 8 vertices, which is 2 triangles, but would you'd draw triangles as (0, 1, 2) (3, 4, 5), which would give you one correct triangle and one distorted triangle).

Out of interest - why are you trying to do this? Why not just use ID3DXMesh::DrawSubset?
Ripiz
Ripiz
I am trying to implement Newton Physics Engine (http://newtondynamics.com/). In order to create Collision Mesh I have to build Vertex Cloud. My Collision Meshes were very wrong, chances that everyone use broken Newton and didn't report bug are very low, so problem was on my side. The first code I posted I used to generate Vertex Cloud, it didn't draw anything neither Collision was right, basically it was broken. But thanks to you it is fixed now, Collision Mesh is (almost) right, but I think now it's Newton side. Instead of making exact mesh, it just rounds it, for example, tube or pipe becomes cylinder.

Maybe you know any other free Physics Engine I could use? :) Would be nice to try other options I have, maybe it's better performance wise, or easier to implement.

Thank you again.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.