How to create a Mesh manually with VB6?

Started by
13 comments, last by Parduz 18 years ago
Hi to all from a newbie. I'm italian, so pls excuse my poor english. I've read everything i've found on the web about D3DXCreateMeshFVF and D3DXCreateMesh.... but i really can't do something good. I'm asking for a source sample about creating a mesh manually with VB6 and DX8.1. I need to see how to create submeshes ('cause i need different textures) and how to make that textures coordinates. If an example is useful to understand what i'm doing, then suppose to build an house of lego bricks. Actually i'm using each different type of lego brick as a single mesh (loading .x files at the startup). The rendering of a "house" built with 1000 briks is really slow. So i'm trying to make an unique mesh of the house, being the brick vertex in "snapped" positions, to leave out the invisible parts of the bricks. Thanks in advance for the help.
Advertisement
A D3DX Mesh has a concept of "attribute buffer", with which you can define subsets per mesh face. Each DWORD (or Long in VB6) in this buffer represents one triangle's subset id. D3DXCreateMesh* functions allocate this buffer for you automatically, so you only have to fill it with the subset indices. To access the attribute buffer data, the mesh interface has methods "LockAttributeBuffer" and "UnlockAttributeBuffer".

When you're finished with filling the attribute buffer, be sure to call the Optimize method with the flag D3DXMESHOPT_ATTRSORT on the mesh, so that the device can render all triangles of any subset with one call instead of one call per triangle.

As for the texture coordinates - they behave exactly the same whether you use the Mesh interface or raw vertex buffers.

As for the bricks - why don't you model the brick pattern as a bump-mapped texture in the first place? It doesn't help to just "snap" individual bricks in order to remove extraneous faces; you'd need a bit more complicated algorithm to remove the triangles between the bricks, such as Boolean union or similar, and this would probably be overkill for what you're trying to do.

Niko Suni

Quote:Original post by Nik02
A D3DX Mesh has a concept of "attribute buffer", with which you can define subsets per mesh face. Each DWORD (or Long in VB6) in this buffer represents one triangle's subset id. D3DXCreateMesh* functions allocate this buffer for you automatically, so you only have to fill it with the subset indices. To access the attribute buffer data, the mesh interface has methods "LockAttributeBuffer" and "UnlockAttributeBuffer".

When you're finished with filling the attribute buffer, be sure to call the Optimize method with the flag D3DXMESHOPT_ATTRSORT on the mesh, so that the device can render all triangles of any subset with one call instead of one call per triangle.

As for the texture coordinates - they behave exactly the same whether you use the Mesh interface or raw vertex buffers.

As for the bricks - why don't you model the brick pattern as a bump-mapped texture in the first place? It doesn't help to just "snap" individual bricks in order to remove extraneous faces; you'd need a bit more complicated algorithm to remove the triangles between the bricks, such as Boolean union or similar, and this would probably be overkill for what you're trying to do.

I'm sorry, Nik, but i'm really a newbie, so this does not help me so much.
Suppose i have an hex shaped brick (where the "button" on the top is another hex, just a bit little than the base).
Also the Button have a texture, while the base have another.
What should i do to create that mesh?
I can sound lazy, but i'm not: i've a nearly finished app, and i can't just figure out this final step....

<edit>
This show my actual rendering, and i need to make the terrain as as unique mesh.
http://heroscapehq.com/modules/coppermine/albums/userpics/11449/normal_maptest.jpg
It already helps a lot if you can get all the tiles to a single mesh. You can do this by using the D3DXConcatenateMeshes function (although it doesn't calculate new subset indices to the concatenated faces). You can define the subsets before the operation, though, so you'll have the necessary info on the mesh later. Think of subsets as "material indices" - every unique material+texture combination in the scene should have an unique index before the concatenation.

The actual polygon count rarely is an issue, rather the number of drawing calls is most often the bottleneck of a graphics engine. Hence, I don't recommend culling "hidden" polygons away unless it is absolutely necessary. Instead, I would cull away those whole tiles that are completely hidden from the player - before the concatenation.

Do ask for more info if needed [smile]

Niko Suni

But D3DXConcatenateMeshes is a DX9 function.
(note: I've not had a chance to fully read the whole thread...)

Quote:Original post by Parduz
But D3DXConcatenateMeshes is a DX9 function.
It shouldn't be too hard to emulate this function yourself. Create a destination mesh of the correct format - if they're the same then great, otherwise check out the union method that the docs mention. Then just lock the destination IB & VB buffers and then each of the source meshes and simply concatenate/append the data to whatever you've already written. The only tricky part will be making sure that the attribute table and ranges remain correct - it shouldn't be hard to do, just one of those things that (in my experience) is easy to trip up on [smile]

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

NOTE: I hope i will be not misunderstood, 'cause my english is not so good. So if the following phrases seems "ungrateful" or something bad, then you know that's not true. [End Note]

There's something that i don't undestand: while i apreciate all your explanation, there's don't move my knowledge a bit. I've read each sigle page i've found about that, i've found some C++ sample to look at, but i'm still in the same position.
The reason i'm asking for code is 'cause i'm stucked with theory. I've tryied a lot of things, obtaining in the better case my app hangs, in the worst a PC reboot. It's evidence to me that i can't do more far than where i am with only "suggestion". Seeing your efforts to lead me in the right way is frustrating, 'cause i'm not able to apreciate these efforts.

So, PLEASE, give me a bit of code to work with, i will study it and being not a "human language" but a programmin language i'm sure that then i will understand you all.

If there's a rule that says "do your code yourself, we're not working for you" then just tell me, i will stop asking until i will able to understand that theory.

Again, thanks for you efforts: i'm so sad that i can't actually understand what you're saying.
This code is in VC++, but the same DirectX functions I used should be available in VB. I think the faces might be the wrong way around though.

bool InitMesh() {	void *vertices = NULL;	void *indices  = NULL;	TESTVERTEX box0[] = {		{-0.5f,  0.5f, -0.5f, 0xFFFF0000},	// Top Left Front		{ 0.5f,  0.5f, -0.5f, 0xFFFF0000},	// Top Right Front		{-0.5f, -0.5f, -0.5f, 0xFFFF0000},	// Bottom Left Front		{ 0.5f, -0.5f, -0.5f, 0xFFFF0000},	// Bottom Right Front		{-0.5f,  0.5f,  0.5f, 0xFFFF0000},	// Top Left Back		{ 0.5f,  0.5f,  0.5f, 0xFFFF0000},	// Top Right Back		{-0.5f, -0.5f,  0.5f, 0xFFFF0000},	// Bottom Left Back		{ 0.5f, -0.5f,  0.5f, 0xFFFF0000},	// Bottom Right Back	};	TESTVERTEX box1[] = {		{-0.5f,  0.5f, -0.5f, 0xFF00FF00},	// Top Left Front		{ 0.5f,  0.5f, -0.5f, 0xFF00FF00},	// Top Right Front		{-0.5f, -0.5f, -0.5f, 0xFF00FF00},	// Bottom Left Front		{ 0.5f, -0.5f, -0.5f, 0xFF00FF00},	// Bottom Right Front		{-0.5f,  0.5f,  0.5f, 0xFF00FF00},	// Top Left Back		{ 0.5f,  0.5f,  0.5f, 0xFF00FF00},	// Top Right Back		{-0.5f, -0.5f,  0.5f, 0xFF00FF00},	// Bottom Left Back		{ 0.5f, -0.5f,  0.5f, 0xFF00FF00},	// Bottom Right Back	};	short	topLeftFront			= 0,	// Top Left Front			topRightFront			= 1,	// Top Right Front			bottomLeftFront			= 2,	// Bottom Left Front			bottomRightFront		= 3,	// Bottom Right Front			topLeftBack				= 4,	// Top Left Back			topRightBack			= 5,	// Top Right Back			bottomLeftBack			= 6,	// Bottom Left Back			bottomRightBack			= 7;	// Bottom Right Back	WORD faces[] = {		// Left faces         topLeftFront,     topLeftBack,      bottomLeftBack,   // 0         bottomLeftBack,   bottomLeftFront,  topLeftFront,     // 1         // Front faces         topLeftFront,     bottomLeftFront,  bottomRightFront, // 2         bottomRightFront, topRightFront,    topLeftFront,     // 3         // Right faces         topRightBack,     topRightFront,    bottomRightFront, // 4          bottomRightFront, bottomRightBack,  topRightBack,     // 5         // Back faces         bottomLeftBack,   topLeftBack,      topRightBack,     // 6         topRightBack,     bottomRightBack,  bottomLeftBack,   // 7         // Top faces         topRightFront,    topRightBack,     topLeftBack,      // 8         topLeftBack,      topLeftFront,     topRightFront,    // 9         // Bottom faces         bottomLeftFront,  bottomLeftBack,   bottomRightBack,  // 10         bottomRightBack,  bottomRightFront, bottomLeftFront   // 11	};	if(FAILED(		D3DXCreateMeshFVF(			12,					// Number of faces (Polygons)			8,					// Number of vertices.			0,					// Adjacency (To do with neighbouring faces, but not needed here)			D3DFVF_TESTVERTEX,	// = D3DFVF_XYZ | D3DFVF_DIFFUSE			g_pD3DDevice,		// The device			&g_pD3DXMesh0		// The mesh		)	)) return false;	if(FAILED(		D3DXCreateMeshFVF(			12,					// Number of faces (Polygons)			8,					// Number of vertices.			0,					// Adjacency (To do with neighbouring faces, but not needed here)			D3DFVF_TESTVERTEX,	// = D3DFVF_XYZ | D3DFVF_DIFFUSE			g_pD3DDevice,		// The device			&g_pD3DXMesh1		// The mesh		)	)) return false;	if(FAILED(g_pD3DXMesh0->LockVertexBuffer(0,(void**)&vertices))) return false;	memcpy(vertices, box0, sizeof(box0));	g_pD3DXMesh0->UnlockVertexBuffer();	if(FAILED(g_pD3DXMesh1->LockVertexBuffer(0,(void**)&vertices))) return false;	memcpy(vertices, box1, sizeof(box1));	g_pD3DXMesh1->UnlockVertexBuffer();	if(FAILED(g_pD3DXMesh0->LockIndexBuffer(0,(void**)&indices))) return false;	memcpy(indices, faces, sizeof(faces));	g_pD3DXMesh0->UnlockIndexBuffer();	if(FAILED(g_pD3DXMesh1->LockIndexBuffer(0,(void**)&indices))) return false;	memcpy(indices, faces, sizeof(faces));	g_pD3DXMesh1->UnlockIndexBuffer();	LPD3DXFRAME frame = new D3DXFRAME[2];	ZeroMemory(frame, sizeof(D3DXFRAME[2]));	frame[0].pMeshContainer = new D3DXMESHCONTAINER;	frame[1].pMeshContainer = new D3DXMESHCONTAINER;	ZeroMemory(frame[0].pMeshContainer, sizeof(D3DXMESHCONTAINER));	ZeroMemory(frame[1].pMeshContainer, sizeof(D3DXMESHCONTAINER));	frame[0].pMeshContainer->MeshData.pMesh = g_pD3DXMesh0;	frame[1].pMeshContainer->MeshData.pMesh = g_pD3DXMesh1;	frame[0].pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;	frame[1].pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;	frame[0].pMeshContainer->Name = "RedCube__";	frame[1].pMeshContainer->Name = "GreenCube";	frame[0].Name = frame[0].pMeshContainer->Name;	frame[1].Name = frame[1].pMeshContainer->Name;	D3DXMATRIX transMatrix;	D3DXMatrixIdentity(&transMatrix);	frame[0].TransformationMatrix = transMatrix;	transMatrix._11 =  0.5;	transMatrix._22 =  0.5;	transMatrix._33 =  0.5;	transMatrix._41 += 0.25f;	frame[1].TransformationMatrix = transMatrix;	frame[0].pFrameFirstChild = &frame[1];	// Can also use D3DXF_FILEFORMAT_TEXT or D3DXF_FILEFORMAT_COMPRESSED or D3DXF_FILEFORMAT_BINARY	D3DXSaveMeshToX("glasscube.x", g_pD3DXMesh0, NULL, NULL, NULL, 0, D3DXF_FILEFORMAT_BINARY);	D3DXSaveMeshHierarchyToFile("frames.x", D3DXF_FILEFORMAT_TEXT, frame, NULL, NULL);	return true;}


EDIT: Vaves, LOL. I meant to type faces.

[Edited by - CodeReaver on April 6, 2006 10:10:42 AM]
I drew a small diagram illustrating the concatenation of multiple meshes into one:



The operation really just copies the meshes into the bigger buffer in order, that's all. To access the buffers, call the LockVertexBuffer, LockIndexBuffer and LockAttributeBuffer of the mesh interface. When you have the pointers, you can use DXCopyMemory to transfer the data around.

Do call the optimize method after this operation, so that the subsets (that the attribute buffer defines) get organized in more efficient manner.

It's my principle not to give source code easily - instead, I would like you to truly understand the operation. Once you do, writing the code is quite trivial.

Niko Suni

Nik02, this is by far the most understandable help to understand mesh (being me a non english speaking).
I've almost done anything...but i'm stucked in the attribute buffer.

The VB version of the LockAttributeBuffer function returns a long, which in C is a pointer, but i can't use in any way in VB.
What i've to do to modify the attribute buffer?

This topic is closed to new replies.

Advertisement