Rendering from a Vertex Buffer

Started by
9 comments, last by brooksyd22 18 years, 7 months ago
I have recently begun to implement a terrain engine into my game but have stumbled on the first hurdle! I have set up a vertex buffer and an index buffer and filled these with the relevant data in what seems to be the right way to me! The problem is that when I go to render them (using the DrawIndexedPrimitive function) then nothing appears on my screen! If I just enter in three vertices into the VB then a triangle will appear but in screen coordinates. Im assuming that I need to loop through the amount of polygons and render through each loop, setting the world matrix each time. I cant seem to get the implementation right however. Is this the right way to approach it or is there something im missing? The code below is what I use to fill the Vertex and Index buffers;

HRESULT CTerrain::CreateTerrain( LPDIRECT3DDEVICE9 m_pd3dDevice )
{
	HRESULT hResult;

///Dimension Variables
	D3DXVECTOR3 minBounds;
	D3DXVECTOR3 maxBounds;

	//Define boundaries
	minBounds.x = 100; minBounds.y = 0; minBounds.z = 100;
	maxBounds.x = 400; maxBounds.y = 1; maxBounds.z = 400;

	//Define Cell dimensions
	int numCellsWide = 1;
	int numCellsHigh = 1;

	//Calculate number of verts on each axis
	int numVertsX = numCellsWide + 1;
	int numVertsZ = numCellsHigh + 1;

	//Calculate total number of verts
	NumVerts = numVertsX * numVertsZ;

	//Calculate total number of polygons
	NumPolygons = (numCellsWide * numCellsHigh) * 2;

	//Calculate step between each vertex
	float stepX = (maxBounds.x - minBounds.x) / numCellsWide;
	float stepZ = (maxBounds.z - minBounds.z) / numCellsHigh;

	// Set the start position
	D3DXVECTOR3 pos(minBounds.x, 0, maxBounds.z);

	//Initialise counter
	int count = 0;

	//Create custom data structure variable to hold info
	TERRAINVERTEX* pVertices = new TERRAINVERTEX[NumVerts];

	// Loop across and down
	for (int z = 0; z < numVertsZ ;z++)
		{
			//Set X position
			pos.x = minBounds.x;

			for (int x = 0; x < numVertsX; x++)
				{
					// Create the verts
					pVertices[count].vInfo = D3DXVECTOR4( pos.x, pos.z, 0.0f, 1.0f );
					pVertices[count].color = 0xffff0f00;

					// Increment x across
					pos.x += stepX;
					count++;
				}

			// Increment Z down
			pos.z -= stepZ;
	}

////Vertex Buffer
	// Create a vextex buffer for the viewport
    if( FAILED( m_pd3dDevice->CreateVertexBuffer( NumVerts * sizeof(TERRAINVERTEX),
                                       D3DUSAGE_DYNAMIC, D3DFVF_TERRAINVERTEX,
                                       D3DPOOL_MANAGED, &m_TerrainVB, NULL ) ) )
        return DXTRACE_ERR( TEXT("m_pd3dDevice->CreateVertexBuffer"), S_OK);

	//Custom vertex format
	TERRAINVERTEX* Verts;

    m_TerrainVB->Lock( 0, 0, (void**)&Verts, 0 );

	//Copy Vertex data across
	memcpy( Verts, pVertices, sizeof(pVertices) );

	//Unlock buffer
    m_TerrainVB->Unlock();

////Index Buffer
	int NumIndices = (numCellsWide * 6) * numCellsHigh;

	// Create an index buffer for the Terrain
    if( FAILED( m_pd3dDevice->CreateIndexBuffer( NumIndices * sizeof(WORD), 
										0, D3DFMT_INDEX16, 
										D3DPOOL_MANAGED, &m_TerrainIB, NULL ) ) )
		return false;

	//Reinitialise Count
	count = 0;
	int vIndex = 0;
	WORD* pIndices;
	WORD* Indices = new WORD[NumIndices];

	for (int z = 0; z < numCellsHigh; z++)
	{
		for (int x = 0;x < numCellsWide; x++)
		{
			// first triangle
			Indices[count++] = (WORD)vIndex;
			Indices[count++] = (WORD)(vIndex + 1);
			Indices[count++] = (WORD)(vIndex + numVertsX);

			// second triangle
			Indices[count++] = (WORD)(vIndex + numVertsX);
			Indices[count++] = (WORD)(vIndex + 1);
			Indices[count++] = (WORD)(vIndex + numVertsX + 1);

			vIndex++;
		}

		vIndex++;
	}

   //Get a pointer to the index buffer indices and lock the index buffer
	m_TerrainIB->Lock(0,  NumIndices * sizeof(WORD), (void**)&pIndices, 0);

	//Copy indices data across
	memcpy( pIndices, Indices,  NumIndices * sizeof(WORD) );

	//Unlock the index buffer
	m_TerrainIB->Unlock();
								
	return S_OK;
}

This code is the rendering code;
[source = lang"cpp"]
BOOL CTerrain::RenderTerrain( LPDIRECT3DDEVICE9 m_pd3dDevice )
{
	D3DXMATRIX matTerrainWorld;

	D3DXMatrixIdentity( &matTerrainWorld );
		
	m_pd3dDevice->SetTransform( D3DTS_WORLD, &matTerrainWorld );

	D3DMATERIAL9 m_matMaterial;

	//Set material default values (R, G, B, A)
	D3DCOLORVALUE rgbaDiffuse  = {1.0f, 1.0f, 1.0f, 0.0f};
	D3DCOLORVALUE rgbaAmbient  = {1.0, 1.0, 1.0, 0.0};
	D3DCOLORVALUE rgbaEmissive = {0.0, 0.0, 0.0, 0.0};

	//Set the RGBA for diffuse light reflected from this material. 
	m_matMaterial.Diffuse = rgbaDiffuse; 

	//Set the RGBA for ambient light reflected from this material. 
	m_matMaterial.Ambient = rgbaAmbient; 

	//Set the RGBA for light emitted from this material. 
	m_matMaterial.Emissive = rgbaEmissive;

	//Select the material to use
	m_pd3dDevice->SetMaterial(&m_matMaterial);

	// Tell DX from which index buffer you want to render. We have our indices
	// stored in m_pIndexBuffer, so we tell dx to take indices from there. 
    m_pd3dDevice->SetIndices(m_TerrainIB);

	//Set vertex format and terrain vertex buffer as stream source
	m_pd3dDevice->SetFVF(D3DFVF_TERRAINVERTEX);
	m_pd3dDevice->SetStreamSource(0, m_TerrainVB, 0, sizeof(TERRAINVERTEX));

	//Draw the terrain
	m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, NumVerts, 0, NumPolygons);

	return TRUE;
}


Advertisement
hi,

you said that the triangle apperas in screen coordinates. do you set up view and projection matrices to some meaningful value? I cannot see this from your code snippets.

kp
------------------------------------------------------------Neo, the Matrix should be 16-byte aligned for better performance!
I do set up the view and projection matrices within a different part of the code. I can render whole meshes no problem but its just getting this vertex buffer to not only render, but render into world space!

My view and projection matrix code is below, I have simple controls to let me look around but other than that it is pretty standard;

    //Set view matrix    D3DXVECTOR3 vFromPt   = D3DXVECTOR3( 0.0f, 10.0f, -20.0f );    D3DXVECTOR3 vLookatPt = D3DXVECTOR3( fCamLR, fCamUD, fCamFB );    D3DXVECTOR3 vUpVec    = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );    D3DXMatrixLookAtLH( &matView, &vFromPt, &vLookatPt, &vUpVec );    m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );    // Set the projection matrix    D3DXMATRIX matProj;    FLOAT fAspect = ((FLOAT)m_d3dsdBackBuffer.Width) / m_d3dsdBackBuffer.Height;    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 1000.0f );    m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
I do set up the view and projection matrices within a different part of the code. I can render whole meshes no problem but its just getting this vertex buffer to not only render, but render into world space!

My view and projection matrix code is below, I have simple controls to let me look around but other than that it is pretty standard;

    //Set view matrix    D3DXVECTOR3 vFromPt   = D3DXVECTOR3( 0.0f, 10.0f, -20.0f );    D3DXVECTOR3 vLookatPt = D3DXVECTOR3( fCamLR, fCamUD, fCamFB );    D3DXVECTOR3 vUpVec    = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );    D3DXMatrixLookAtLH( &matView, &vFromPt, &vLookatPt, &vUpVec );    m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );    // Set the projection matrix    D3DXMATRIX matProj;    FLOAT fAspect = ((FLOAT)m_d3dsdBackBuffer.Width) / m_d3dsdBackBuffer.Height;    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 1000.0f );    m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
Sorry guys but I have to bump this thread. I have been tearing my hair out thinking why nothing will render, everything seems perfect from what I can see! Does anyone have any idea at all?
A few things i think. The first, when you load your pos vector into the vertex buffer, why are you loading the z value into the y value place. Second, you should load a matrix that is an identity into the world transform. And third, your view transform isn't right. Your "vFromPt" vector is where the camera position is. That one looks right. Your "vUpVec" also looks right. But your "vLookatPt" vector is wrong. That vector should be where the camera is looking at. So just plug in the center of the terrain mesh into that position and it should work out right. Hope that helps.
Thanks for the reply!

Quote:
The first, when you load your pos vector into the vertex buffer, why are you loading the z value into the y value place


The reason I put the Z position into the y position was so that when it draws it would draw directly in front of me, but this didnt work and I forgot to change it back before I posted.

Quote:
Second, you should load a matrix that is an identity into the world transform.


Not sure if I get what you mean as I have set an identity matrix before I render from the buffer. I have also tried plugging in the position of each vertex before I render but still nothing.

Quote:
And third, your view transform isn't right. Your "vFromPt" vector is where the camera position is. That one looks right. Your "vUpVec" also looks right. But your "vLookatPt" vector is wrong. That vector should be where the camera is looking at. So just plug in the center of the terrain mesh into that position and it should work out right.


The variables that I have in the "vLookatPt" vector are all intialised at 0 and they are incremented via the arrow buttons as appropriate just so I can look around!

Any more ideas anyone?
I was reviewing your code, and didn't notice the FVF definition. Could you show it so I can take a peek at it.
No problem, here it is;

//Custome Vertex for Terrainstruct TERRAINVERTEX{    D3DXVECTOR3 vInfo;	D3DCOLOR color;};#define D3DFVF_TERRAINVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
for (int z = 0; z < numCellsHigh; z++)
{
for (int x = 0;x < numCellsWide; x++)
{
// first triangle
Indices[count++] = (WORD)vIndex;
Indices[count++] = (WORD)(vIndex + 1);
Indices[count++] = (WORD)(vIndex + numVertsX);

// second triangle
Indices[count++] = (WORD)(vIndex + numVertsX);
Indices[count++] = (WORD)(vIndex + 1);
Indices[count++] = (WORD)(vIndex + numVertsX + 1);

vIndex++;
}

vIndex++;
}
I thought the problem might be with your FVF too, but it seems fine. Instead I now think the problem lies with your index buffer. Its very early in the morning so I could be wrong, but I think you going to be getting invalid vertex pointers at the end the of this code...but before you try that firstly try setting your cullmode to none:
pDevice -> SetRenderState (D3DRS_CULLMODE, D3DCULL_NONE);
If that doesnt fix anything try rendering with just a vertex buffer, just put a single triangle in it (got the impression you were still using the index buffer when you tried that)
Other than that I can't offer any advice, it all looks right to me: what I would do is strip down the code until it works and then build it up again. Good luck!
Computers provide a reality second to none!

This topic is closed to new replies.

Advertisement