Problem Loading Rendering Heightmap Terrain

Started by
2 comments, last by sakky 18 years, 10 months ago
Hi Guys, I've writing a tank combat clone which loads heighmaps and creates and renders triangle list using a vertex and index buffer. there doesn't seem to be an error or anything but my terrain never gets rendered. defs.h

#ifndef DEFSH
#define DEFSH
#include <d3d8.h>
#include <d3dx8.h>
#include <stdio.h>

class IT_ErrorLogger{
FILE *fp;

public:
	IT_ErrorLogger(){
		if((fp=fopen("ErrorLog.txt", "w"))==NULL)exit(1);
	}
	~IT_ErrorLogger(){
		fclose(fp);
	}
void LogError(char* error){
	
	int len;
	len=strlen(error);
	fwrite(error, sizeof(char),len,fp);
	
}
void LogError(char* error, int num){
	
	fprintf(fp, error, num);
	
}
};


class IT_StatLogger{
FILE *fp;

public:
	IT_StatLogger(){
		if((fp=fopen("StatLog.txt", "w"))==NULL)exit(1);
	}
	~IT_StatLogger(){
		fclose(fp);
	}
void LogStat(char* Stat){
	
	int len;
	len=strlen(Stat);
	fwrite(Stat, sizeof(char),len,fp);
	
}
void LogStat(char* Stat, int num){
	
	
	fprintf(fp, Stat,num);
	
}
};

struct IT_3dPoint {
	double x;
	double y;
	double z;
};
struct IT_Vertex{
	float x;
	float y;
	float z;
	DWORD color;
	float u;
	float v;
	
};
#define HALF_PI = 1.57f
#define TWICE_PI = 6.28f
#define PI = 3.14f

#endif

The height map code I got at flipcode but the direct 3d code is mine. the logging code in the next source puts out seeming good data.There are other objects from other parts of the program which render fine. and the device seems to be valid. I'd sure I'm missing something stupid. As normal. IT_Terrain.h

#ifndef IT_TERRAINH
#define IT_TERRAINH
#include <d3dx8.h>
#include "defs.h"

class IT_Terrain{
private:
	LPDIRECT3DDEVICE8  device;
	IT_ErrorLogger* errlog;
	IT_StatLogger* statlog;
	LPDIRECT3DVERTEXBUFFER8 VBuffer;
	LPDIRECT3DINDEXBUFFER8  IBuffer;
	D3DMATERIAL8   material; 
	int numVertices;
	IT_Vertex *verts;

	int numIndices;
	unsigned short *indices;

	int numTris;
	int iSize;
	int iScale;

	float UTile;
	float VTile;

public:

	IT_Terrain(){device=NULL;
		VBuffer=NULL;
		IBuffer=NULL;
		errlog=new IT_ErrorLogger();
		statlog=new IT_StatLogger();
	}
	~IT_Terrain(){

			if( VBuffer != NULL )        
        VBuffer->Release();
	if( IBuffer != NULL )        
        IBuffer->Release();
	if( errlog != NULL )        
        delete errlog;
	if( statlog != NULL )        
        delete statlog;
	}
	

	void Init(PDIRECT3DDEVICE8  d){device = d;}
	bool LoadTerrain(char* filename, int size, int scale);
	void CalculateHeightfield(unsigned char *hmap);
	void SetTextureTiling(float u=1.0f, float v=1.0f){UTile = u; VTile = v;}
	void  _fastcall RenderTerrain();

};



#endif

IT_Terrain.cpp

#include <stdio.h>
#include "IT_Terrain.h"

bool IT_Terrain::LoadTerrain(char *filename, int size, int scale){

	FILE *fp;
	iSize=size;
	iScale=scale;
	
	unsigned char *hmap = new unsigned char[size * size];
	memset(hmap, 0, sizeof(unsigned char)*size*size);

	if((fp=fopen(filename, "rb"))==NULL)return false;
	fread(hmap, sizeof(unsigned char), size*size, fp);
	fclose(fp);

	CalculateHeightfield(hmap);

	if(hmap){delete hmap;hmap=NULL;}

	return true;

}

void IT_Terrain::CalculateHeightfield(unsigned char *hmap){

	numVertices = iSize*iSize;
	numTris=0;

	verts = new IT_Vertex[numVertices];
	memset(verts, 0, numVertices);

	float texdelta = 2.0f/iSize;

	IT_Vertex vert;
	int currVertex=0;

	for(int y=0; y< iSize; y++)
	{
			for(int x=0; x<iSize; x++)
			{
				currVertex = y*iSize+x;

				vert.x = (float)x * iScale;
				vert.z = (float)y * iScale;
				vert.y = (float)(hmap[currVertex]*(iScale/2));
				
				statlog->LogStat("vert.x = %d ",vert.x);
				statlog->LogStat("vert.z = %d ",vert.z);
				statlog->LogStat("vert.y = %d ",vert.y);
				
				vert.u = UTile * ((float)x*texdelta * 0.5f);
				vert.v = VTile * (1.0f - (float)y * texdelta * 0.5f);
				vert.color = 0xffffffff;

				statlog->LogStat("vert.u = %d ",vert.u);
				statlog->LogStat("vert.v = %d ",vert.v);
				statlog->LogStat("color = %d \n",vert.color);
				
				verts[currVertex] = vert;
				
			}
	}
	
	numIndices = (iSize-1)*(iSize-1)*6;
	indices = new unsigned short[numIndices];
	memset(indices, 0, numIndices);

	int idx = 0;
	for (y=0; y<iSize-1; y++)
	{
		for (int x=0; x<iSize-1; x++)
		{
			currVertex = y * (iSize) + x;
			indices[idx++] = currVertex;
			indices[idx++] = currVertex+1;
			indices[idx++] = currVertex + iSize;
			numTris++;	
			
			indices[idx++] = currVertex + iSize+1;
			indices[idx++] = currVertex + iSize;
			indices[idx++] = currVertex + 1;
			numTris++;
		}
	}

	ZeroMemory( &material, sizeof(D3DMATERIAL8) );
	material.Diffuse.r = material.Diffuse.r = 1.0f;
	material.Diffuse.g = material.Diffuse.g = 1.0f;
	material.Diffuse.b = material.Diffuse.b = 1.0f;
	material.Diffuse.a = material.Diffuse.a = 0.0f;


	if( FAILED( device->CreateVertexBuffer( iSize*iSize *sizeof(IT_Vertex),
                                              0, D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1,
                                              D3DPOOL_DEFAULT, &VBuffer ) ) )
    {
		errlog->LogError("Error: Terrain::CreateVBuffer()");
		return;
	}
	
	if( FAILED( device->CreateIndexBuffer( numIndices * sizeof(unsigned short),
                                              0, D3DFMT_INDEX16,
                                              D3DPOOL_DEFAULT, &IBuffer ) ) )
     {
		errlog->LogError("Error: Terrain::CreateIBuffer()");
		return;
	}

	VOID* pVertices;
    if( FAILED( VBuffer->Lock( 0, sizeof(verts), (BYTE**)&pVertices, D3DLOCK_DISCARD) ) )
        {
		errlog->LogError("Error: Terrain::VBufferLock()");
		return;
	}
	memcpy( pVertices, verts, numVertices );//sizeof(verts)
    VBuffer->Unlock();

	VOID* pIndices;
	if( FAILED( IBuffer->Lock( 0, sizeof(indices), (BYTE**)&pIndices, D3DLOCK_DISCARD) ) )
        {
		errlog->LogError("Error: Terrain::IBufferLock()");
		return;
	}
	memcpy( pIndices, indices, numIndices);//sizeof(indices)
    IBuffer->Unlock();

}

void IT_Terrain::RenderTerrain()
{

	if (device==NULL)
	{
		errlog->LogError("Error: Terrain::NoDevice()");
		return;
	}
	
	if( FAILED(device->SetMaterial(&material)))
	{
		errlog->LogError("Error: Terrain::Material()");
		return;
	}

	D3DXMATRIX matWorld;
	device->SetRenderState(D3DRS_LIGHTING, FALSE);
	device->SetTexture(0, NULL);
	D3DXMatrixIdentity(&matWorld);

	device->SetTransform(D3DTS_WORLD, &matWorld);
	device->SetVertexShader(D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1);
	
	if( FAILED(device->SetStreamSource( 0, VBuffer, sizeof(IT_Vertex) )))
	{
		errlog->LogError("Error: SetStreamSource()");
		return;
	}
	
	device->SetIndices(IBuffer, 0);
    	
	if( FAILED(device->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, numVertices,0,(numIndices/3))))
	{
		errlog->LogError("Error: Terrain::DrawPrim()");
		return;
	}
	
	device->SetRenderState(D3DRS_LIGHTING, TRUE);
	
}


Any commnets would be appreciated!!
Advertisement
Check out www.toymaker.info and look for the "Invisible Geometry" page on their site. It has a list of a ton of reasons why geometry might not be showing up on your screen. Are you sure your camera is in view of the terrain?

---------------------------------darkzim

Hi,
As a test I tried subbing 0.0f into y of vertex to create flat terrain
and my camera having y pos of 5.0f or better with pretty good pitch.
Checking your link now.
Thanks
One problem that I see is that you return false from IT_Terrain::LoadTerrain if you fail to open the file. This may be fine but look what you are doing right before that; do you see! You are allocating memory for the heightmap and not deleting it before you exit. I don't see where you delete it at all until you reach the end of you procedure. Memory leak!

How you are creating and calculating you're indices may be a problem too. You allocare ( iSize - 1 ) * ( iSize - 1 ) * 6, but that is not what you are looping through. When you are looping you doing that iSize - 1 thing again, why? Itsn't iSize the size as in wdth & height are the same, sizeo f the terrain? You may want to double check how you are creating the index buffer.

Now, if you rendering function I don't see how you are setting up you're projection matrices. Just world won't do! Well, at least id never did for me in anyn of my cases.

This is what I use:
// ---------------------------------------------------------------------------- //// Name		: D3DSetupEnvironment ( )// Desc		: Sets Direct3D environment variables & rendering states// ---------------------------------------------------------------------------- //HRESULT __stdcall D3DSetupEnvironment( void ){	D3DXMATRIX						 xWorld, xView, xProj ;	D3DXFONT_DESC					 D3Dfd ;	HDC								 hDC  ;	HRESULT							 hRet ;	D3DXMatrixIdentity( &xWorld ) ;	g_lpD3DDevice->SetTransform( D3DTS_WORLD, &( D3DMATRIX )xWorld ) ;	D3DXMatrixLookAtLH( &xView, &D3DXVECTOR3( 0.0F, 0.0F, 0.0F ),								&D3DXVECTOR3( 0.0F, 0.0F, 1.0F ),								&D3DXVECTOR3( 0.0F, 1.0F, 0.0F ) ) ;	g_lpD3DDevice->SetTransform( D3DTS_VIEW, &( D3DMATRIX )xView ) ;	D3DXMatrixPerspectiveFovLH( &xProj, ( D3DX_PI / 4 ), 1.33333333F, 1.0F, 1000.0F ) ;	g_lpD3DDevice->SetTransform( D3DTS_PROJECTION, &( D3DMATRIX )xProj ) ;	g_lpD3DDevice->SetRenderState( D3DRS_LIGHTING,	FALSE ) ;	g_lpD3DDevice->SetRenderState( D3DRS_ZENABLE,	TRUE  ) ;	hDC								 = GetDC( g_hWnd ) ;	memset( &D3Dfd, 0, sizeof( D3DXFONT_DESC ) ) ;	D3Dfd.Height					 = ( -MulDiv( 12, GetDeviceCaps( hDC, LOGPIXELSY ), 72 ) ) ;	D3Dfd.Weight					 = FW_NORMAL ;	D3Dfd.CharSet					 = ANSI_CHARSET ;	D3Dfd.OutputPrecision			 = OUT_DEFAULT_PRECIS ;	D3Dfd.PitchAndFamily			 = FIXED_PITCH | FF_MODERN ;	D3Dfd.Quality					 = PROOF_QUALITY ;	strcpy( D3Dfd.FaceName, "Comic Sans MS" ) ;	ReleaseDC( g_hWnd, hDC ) ;	if ( FAILED( hRet = D3DXCreateFontIndirect( g_lpD3DDevice, &D3Dfd, &g_lpD3DXFont ) ) )	{		return ( hRet ) ;	}	// ...	return ( D3D_OK ) ;}


Okay, now besides all this crap, this is the around about way you should be setting up you matrices...

D3DXMatrixIdentity( &xWorld ) ;
g_lpD3DDevice->SetTransform( D3DTS_WORLD, &( D3DMATRIX )xWorld ) ;

D3DXMatrixLookAtLH( &xView, &D3DXVECTOR3( 0.0F, 0.0F, 0.0F ),
&D3DXVECTOR3( 0.0F, 0.0F, 1.0F ),
&D3DXVECTOR3( 0.0F, 1.0F, 0.0F ) ) ;
g_lpD3DDevice->SetTransform( D3DTS_VIEW, &( D3DMATRIX )xView ) ;

D3DXMatrixPerspectiveFovLH( &xProj, ( D3DX_PI / 4 ), 1.33F, 1.0F, 1000.0F ) ;
g_lpD3DDevice->SetTransform( D3DTS_PROJECTION, &( D3DMATRIX )xProj ) ;


Notice that I setup up all three world, view and projection? You are only setting up world, so Direct3D may be wondering how to render you're heightmap.

Also, are you using depth buffering? I didn't see any states that altered it, but how you represent you geometry (i.e. the order of vertices) is important. I only state this fact to try and help you, if you already knew this please ingore what I just said. Well, depth buffering may give you some weird looking terrain that you can see through it it's not setup correctly.


I use this:
// ---------------------------------------------------------------------------- //// Name		: D3DInitialize( )// Desc		: Initializes Direct3D subsystem// ---------------------------------------------------------------------------- //HRESULT __stdcall D3DInitialize( void ){	D3DPRESENT_PARAMETERS			 D3Dpp ;	HRESULT							 hRet ;	if ( NULL == ( g_lpD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )	{		return ( E_FAIL ) ;	}	memset( &D3Dpp, 0, sizeof( D3DPRESENT_PARAMETERS ) ) ;	D3Dpp.AutoDepthStencilFormat	 = D3DFMT_D16 ;	D3Dpp.EnableAutoDepthStencil	 = TRUE ;	D3Dpp.PresentationInterval		 = D3DPRESENT_INTERVAL_IMMEDIATE ;	D3Dpp.BackBufferWidth			 = 640 ;	D3Dpp.BackBufferHeight			 = 480 ;	D3Dpp.BackBufferFormat			 = D3DFMT_UNKNOWN ;	D3Dpp.SwapEffect				 = D3DSWAPEFFECT_DISCARD ;	D3Dpp.Windowed					 = TRUE ;	if ( FAILED( hRet = g_lpD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd,											   D3DCREATE_SOFTWARE_VERTEXPROCESSING,											   &D3Dpp, &g_lpD3DDevice ) ) )	{		return ( hRet ) ;	}	if ( FAILED( hRet = D3DSetupEnvironment( ) ) )	{		return ( hRet ) ;	}	return ( D3D_OK ) ;


The display parameters are set up to use depth buffering. These two->

D3Dpp.AutoDepthStencilFormat = D3DFMT_D16 ;
D3Dpp.EnableAutoDepthStencil = TRUE ;

Also, I enable it with

g_lpD3DDevice->SetRenderState( D3DRS_ZENABLE, TRUE ) ;

I said before that the order of vertices are important, that is because Direct3D will cull(clip or and nnot render) them if you specify them in a certain order clock-wise(CW) or counter clock-wise(CCW). By default Direct3D culls CCW geometry. You can turn culling off too! So try that and see if you can see you're highmap.

Hope this helps.
Take back the internet with the most awsome browser around, FireFox

This topic is closed to new replies.

Advertisement