Where'd my model go????? Damn you!

Started by
8 comments, last by Dirge 21 years, 10 months ago
That's what I said last night when i recompiled a project I had been working on and my model's wouldn't render anymore. I just had to reinstall Windows XP (don't ask), so reinstalled visual studio and DX and all that and finally got my project working again. Nothing is corrupted and it compiled perfectly. My skybox render perfectly and I have a hand made model that works fine (just Vertex Buffer and Index Buffer), but when I try to render using my Model Class, I get nothin. I've been stumped for about a day now and any help would be appreciated. I just need someone to check out my code and spot stuff that I might be doing wrong. Here's what I got (this will all be open source anyways so I don't care. Email me if you want the whole project). This is the Model Class btw, where I initialize and then render the model. I checked my model loader and it's working perfectly, so it's GOTTA be in here somewhere. Thanks again anyone for any help!
  
// 3DModel.cpp: A Class that represents a 3D Model.

// Date: 4/20/02

// Created by: Aurelio Reis


#include "3DModel.h"
using namespace AURELIO_REIS;

// Convert from our color type to D3D's.

// To convert, rip out the individual color values by bitshifting then normalize those

// values by their max value (which should be 255) as a float to cast it implicitly.

#define DWORD_TO_D3DCOLORVALUE( D3DColorVal, dwColor ) {		\
		D3DColorVal.r = (( dwColor >> 16 ) & 0xFF) / 255.0f;
		D3DColorVal.g = (( dwColor >> 8 ) & 0xFF) / 255.0f;
		D3DColorVal.b = (( dwColor >> 0 ) & 0xFF) / 255.0f;
		D3DColorVal.a = (( dwColor >> 24 ) & 0xFF) / 255.0f; }


// Contructor.

C3DModel::C3DModel()
{
	m_iNumObjects = m_iNumMaterials = m_iNumTextures = 0;
	m_iNumVerticesInModel = m_iNumFacesInModel = 0;
}

// Destructor.

C3DModel::~C3DModel()
{
}

#ifdef AR_USING_DIRECT3D
// Initialize the Direct3D objects of this Model.

//

//	[return]		Whether initialization was successful or not.

BOOL C3DModel::InitializeD3D()
{
	int i = 0, j = 0, k = 0;
	int iOffset = 0;
	int iIndex = 0;
	C3DObject *pObject = NULL;
	CMaterial *pMaterial = NULL;

	// Create the Vertex Buffer to hold the Models Vertices.

	if ( FAILED( D3DManagerSingleton::Instance()->CreateVertexBuffer( m_iNumVerticesInModel * sizeof( MODELVERTEX ), D3DFVF_MODELVERTEX, &m_pVertexBuffer ) ) )
		return FALSE;

	// Lock the current Vertex Buffer for modification.

	MODELVERTEX *v = NULL;
	m_pVertexBuffer->Lock( 0, 0, (BYTE**)&v, 0 );

	// Go through all the objects and collect their vertices into the one vertex buffer.

	for ( i = 0; i < m_iNumObjects; i++ )
	{
		pObject = m_ObjectList[i];

		// Store this Object's current vertex offset.

		pObject->m_iVertexBufferOffset = iOffset;

		// Transfer over all the Vertices.

		for ( j = 0; j < pObject->m_iNumVertices; j++ )
		{
			// Transfer the Vertex and Vertex Normal.

			v[j].p.x  = pObject->m_pVertices[j].m_X;
			v[j].p.y  = pObject->m_pVertices[j].m_Y;
			v[j].p.z  = pObject->m_pVertices[j].m_Z;
			v[j].n.x = pObject->m_pVertexNormals[j].m_X;
			v[j].n.y = pObject->m_pVertexNormals[j].m_Y;
			v[j].n.z = pObject->m_pVertexNormals[j].m_Z;

			// Make sure the model is pure white (so even if we modulate the texture remain the same).

			v[j].color = 0xFFFFFFFF;

			// Make sure this Object actually has Texture Mapping Coordinates, then set them.

			if( pObject->m_pTexCoords )
			{
				v[j].tu = pObject->m_pTexCoords[j].m_fU;
				v[j].tv = pObject->m_pTexCoords[j].m_fV;
			}
		} // end for.


		// Increment the number of vertices to keep track of the object vertex offset.

		iOffset += pObject->m_iNumVertices;
	}

	// Unlock the Vertex Buffer for use.

	m_pVertexBuffer->Unlock();

	// Create the Index Buffer.

	// The number of Indices is the total number of faces * 3 (since each face has 3 vertices).

	if ( FAILED( D3DManagerSingleton::Instance()->m_pd3dDevice->CreateIndexBuffer( m_iNumFacesInModel * 3 * sizeof(DWORD),
											D3DUSAGE_WRITEONLY, D3DFMT_INDEX32,
											D3DPOOL_DEFAULT, &m_pIndexBuffer ) ) )
		return FALSE;

	// Lock the current Index Buffer for modification.

	DWORD *pIndices = NULL;
	m_pIndexBuffer->Lock( 0, 0, (BYTE**)&pIndices, 0 );

	// Reset the Index and Offset values.

	iIndex = 0;
	iOffset = 0;

	// Go through the Model's objects and collect all the face's vertices

	// (including individual x, y z elements) into the one long Index Buffer,

	// making sure to keep track where every object's indices actually starts.

	for ( i = 0; i < m_iNumObjects; i++ )
	{
		pObject = m_ObjectList[i];

		// Set the Index Buffer offset for this object (which is actually the current index).

		pObject->m_iIndexBufferOffset = iIndex;

		// Transfer over all the indices to the index buffer.

		for ( j = 0; j < pObject->m_iNumFaces; j++ )
		{
			// Get the index for each vertex of the face.

			pIndices[iIndex]		= (DWORD)pObject->m_pFaces[j].m_iVerticesIndex[0];
			pIndices[iIndex + 1]	= (DWORD)pObject->m_pFaces[j].m_iVerticesIndex[1];
			pIndices[iIndex + 2]	= (DWORD)pObject->m_pFaces[j].m_iVerticesIndex[2];

			// Move ahead to the next face.

			iIndex += 3;
		}

		// Now's a good time to read in our Materials too!

		// If we found a valid material for this object, load all material attributes to

		// the Direct3D Material structure now so we don't have to do it in run-time, otherwise

		// just go to the next object.

		if ( pObject->m_iMaterialIndex == -1 )
			continue;

		// Fetch the material using the Object's Material Index/ID.

		pMaterial = m_MaterialList[pObject->m_iMaterialIndex];

		// Convert and assign all the values.

		DWORD_TO_D3DCOLORVALUE( pObject->m_D3DMaterial.Ambient, pMaterial->m_dwAmbientColor );
		pObject->m_D3DMaterial.Diffuse = pObject->m_D3DMaterial.Ambient;
		DWORD_TO_D3DCOLORVALUE( pObject->m_D3DMaterial.Emissive, pMaterial->m_dwEmissiveColor );
		DWORD_TO_D3DCOLORVALUE( pObject->m_D3DMaterial.Specular, pMaterial->m_dwSpecularColor );
	}

	// Unlock the Index Buffer for use.

	m_pIndexBuffer->Unlock();

	return TRUE;
}
#endif

// Initialize this model and any vertex arrays/buffers it may use.

//

//	[return]		Whether initialization was successful or not.

BOOL C3DModel::Initialize()
{
	BOOL bRet = TRUE;

#ifdef AR_USING_DIRECT3D
	// Initialize using Direct3D.

	bRet = InitializeD3D();
#endif

	// If Initializaton failed, return the error.

	if ( !bRet )
		return bRet;

	// Success.

	return TRUE;
}

// Release all the memory associated with this model.

void C3DModel::Release()
{
	unsigned int i = 0;

	// If there are Objects allocated for this Model, release them.

	for ( i = 0; i < m_ObjectList.size(); i++ )
	{
		if ( m_ObjectList[i] )
		{
			m_ObjectList[i]->Release();
			delete m_ObjectList[i];
			m_ObjectList[i] = NULL;
		}
	}

	// If there are Materials allocated for this Model, release them.

	for ( i = 0; i < m_MaterialList.size(); i++ )
	{
		if ( m_MaterialList[i] )
		{
			delete m_MaterialList[i];
			m_MaterialList[i] = NULL;
		}
	}

	// If there are Textures allocated for this Model, release them.

	for ( i = 0; i < m_TextureList.size(); i++ )
	{
		if ( m_TextureList[i] )
		{
			delete m_TextureList[i];
			m_TextureList[i] = NULL;
		}
	}

	m_iNumObjects = m_iNumMaterials = m_iNumTextures = 0;
	m_iNumVerticesInModel = m_iNumFacesInModel = 0;

#ifdef AR_USING_DIRECT3D
	// Release Direct3D Allocated Objects (the Vertex and Index buffers).

	ReleaseD3D();
#endif
}

// Add a new Object to the Object List.

int C3DModel::AddObject( C3DObject *pObject )
{
	// Add the Object to our list.

	m_ObjectList.push_back( pObject );

	// Increment the Object count.

	m_iNumObjects++;

	// Increment the model Vertex Count.

	m_iNumVerticesInModel += pObject->m_iNumVertices;
	
	// Increment the model Face Count.

	m_iNumFacesInModel += pObject->m_iNumFaces;

	return m_iNumObjects - 1;
}

// Add a new Material to the Object List.

int C3DModel::AddMaterial( CMaterial *pMaterial )
{
	// Add the Material to our list.

	m_MaterialList.push_back( pMaterial );

	// Increment the Material count.

	m_iNumMaterials++;

	return m_iNumMaterials - 1;
}

// Add a new Texture to the Object List.

int C3DModel::AddTexture( CTexture *pTexture )
{
	// Add the Texture to our list.

	m_TextureList.push_back( pTexture );

	// Increment the Texture count.

	m_iNumTextures++;
	
	return m_iNumTextures - 1;
}

// Scale this model by a scaling factor (1.0 is same size, 0.5 is half, 2 is double the size ).

//

//	[in]		fScalingFactor			How much to scale this model by.

void C3DModel::Scale( float fScalingFactor )
{
	// CRITICAL NOTE: Not sure if I scaled the normals right. Better check that later.


	C3DObject *pObject = NULL;
	int i = 0, j = 0;

	// Go through every model and it's objects and scale it's Vertices.

	for ( i = 0; i < m_iNumObjects; i++ )
	{
		pObject = m_ObjectList[i];

		// Go through all it's vertices.

		for ( j = 0; j < pObject->m_iNumVertices; j++ )
		{
			// Scale the Vertex.

			pObject->m_pVertices[j] *= fScalingFactor;
			
			// Scale the Normal?

			pObject->m_pVertexNormals[j] *= fScalingFactor;
		}
	}

#ifdef AR_USING_DIRECT3D
	// If a Vertex Buffer has already been made, refresh it with the new data.

	if ( m_pVertexBuffer )
	{
		// Lock the current Vertex Buffer for modification.

		MODELVERTEX *v = NULL;
		m_pVertexBuffer->Lock( 0, 0, (BYTE**)&v, 0 );

		int iOffset = 0;

		// Go through all the objects.

		for ( i = 0; i < m_iNumObjects; i++ )
		{
			pObject = m_ObjectList[i];

			// Go through all it's vertices.

			for ( j = 0; j < pObject->m_iNumVertices; j++ )
			{
				// Instead of scaling these guys again (2 mults) we just keep track of the offset (1 add)

				// and assign the changed vertices.

				v[iOffset].p.x = pObject->m_pVertices[j].m_X;
				v[iOffset].p.y = pObject->m_pVertices[j].m_Y;
				v[iOffset].p.z = pObject->m_pVertices[j].m_Z;
				v[iOffset].n.x = pObject->m_pVertexNormals[j].m_X;
				v[iOffset].n.y = pObject->m_pVertexNormals[j].m_Y;
				v[iOffset].n.z = pObject->m_pVertexNormals[j].m_Z;

				iOffset++;
			}
		}

		// Unlock the Vertex Buffer for use.

		m_pVertexBuffer->Unlock();
	}
#endif
}

// If you decide to keep your models textures in a different directory, you must specify it.

//

//	[in]		strDirectory			The directory the textures are in.

void C3DModel::SetTexturePath( const char *strDirectory )
{
	// Make sure we have valid text.

	if ( !strDirectory )
		return;

	// Go through all the Materials, if they have a texture, append this directory path to 

	// the beginning of the texture file name.

	for ( int i = 0; i < m_iNumMaterials; i++ )
	{
		CMaterial *pMaterial = m_MaterialList[i];

		// Make sure we have a valid material.

		if ( !pMaterial )
			continue;

		// If the name is greater than 1 character, we got a texture.

		if ( strlen( pMaterial->m_strFile ) > 0 )
		{
			// Keep a temporary copy of the name since _snprintf doesn't let you assign

			// to an argument you're using (unless you want it to crash).

			char strFileName[128];
			_snprintf( strFileName, 128, "%s", pMaterial->m_strFile );

			// Append the directory path to the beginning of the file name.

			_snprintf( pMaterial->m_strFile, 128, "%s/%s", strDirectory, strFileName );
		}
	}
}

#ifdef AR_USING_DIRECT3D
// Render this Model.

void C3DModel::RenderD3D()
{
	C3DObject *pObject = NULL;
	
	// Render all the Objects/Vertex Buffers.

	for( int i = 0; i < m_iNumObjects; i++ )
	{
		pObject = m_ObjectList[i];

		// Set the precreated material if there is a material at all

		if ( pObject->m_iMaterialIndex != -1 )
		{
			CD3DManager::m_pd3dDevice->SetMaterial( &pObject->m_D3DMaterial );

			// If this Object has a Texture, use it.

			if( pObject->m_bHasTexture )
			{
				// Obtain the material used by this object.

				CMaterial *pMaterial = m_MaterialList[pObject->m_iMaterialIndex];

				// Make sure this material has a valid texture index into the texture list.

				if ( pMaterial->m_iTextureIndex != -1 )
				{
					// Use the materials texture index with the list of textures, then get the

					// the Texture ID from the texture we found. Now we know which texture to use.

					int iTextureID = m_TextureList[pMaterial->m_iTextureIndex]->GetID();

					// Fetch and set the texture if it was valid.

					if ( iTextureID != -1 )
					{
						// Now use this textures ID with the Texture Manager to fetch the "REAL" texture.

						LPDIRECT3DTEXTURE8 pTexture = CD3DTextureManager::Instance()->GetTexture( iTextureID );

						// Set the texture.

						CD3DManager::m_pd3dDevice->SetTexture( 0, pTexture );
					}
				}
			}
			else
				CD3DManager::m_pd3dDevice->SetTexture( 0, NULL );
		}

		// Render the Model using the Vertex and Index Buffer.

		if ( m_pVertexBuffer && m_pIndexBuffer )
		{
			CD3DManager::m_pd3dDevice->SetVertexShader( D3DFVF_MODELVERTEX );
			CD3DManager::m_pd3dDevice->SetStreamSource( 0, m_pVertexBuffer, sizeof( MODELVERTEX ) );
			CD3DManager::m_pd3dDevice->SetIndices( m_pIndexBuffer, 0 );
			CD3DManager::m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, pObject->m_iVertexBufferOffset,
															pObject->m_iNumVertices, pObject->m_iIndexBufferOffset, pObject->m_iNumFaces );
		}

		// Reset textures (so next object or polygon render won't use this texture too).

		CD3DManager::m_pd3dDevice->SetTexture( 0, NULL );
		// Reset materials.

		D3DMATERIAL8 mat;
		ZeroMemory( &mat, sizeof (D3DMATERIAL8 ) );
		CD3DManager::m_pd3dDevice->SetMaterial( &mat );
	}
}

// Release all Direct3D allocated objects for this Model.

void C3DModel::ReleaseD3D()
{
	// Release the Vertex and Index buffers.

	if ( m_pVertexBuffer ) { m_pVertexBuffer->Release();	m_pVertexBuffer = NULL; }
	if ( m_pIndexBuffer ) { m_pIndexBuffer->Release();	m_pIndexBuffer = NULL; }
}
#endif

void C3DModel::Render()
{
#ifdef AR_USING_DIRECT3D
	RenderD3D();
#endif
}

  
[edited by - Dirge on June 8, 2002 12:44:14 PM]
"Artificial Intelligence: the art of making computers that behave like the ones in movies."www.CodeFortress.com
Advertisement
My god!

Do you have any idea how much people hate reading code? My advice to you is to insert statements almost whenever a variable is changed, etc. that will pop up a box with the new value. Look carefully at pointers cuz you might have a null somewhere. But don'' give us 500 lines of code to search.
where are you setting the transforms? if you don''t set the view or world matrices, the model will probably draw on top of the viewpoint and not be visible....
Use your debugger with the aid of the debug DX runtime and debug your own code instead of dumping it here.
---visit #directxdev on afternet <- not just for directx, despite the name
In my experience with models, it could be the way you are setting up your index buffer. Thats one thing that stumped me for ages. I don't have time to read through all your code, but I will give an example, and if it does apply to your problem, it shouldnt be too hard for you to integrate it.

The index buffer in my case was for 16 vertices (a 4 sided cube with the top and bottom not included) but the index buffer needed 24 indices in it because some vertices are used more than once in the rendering process. Also because some vertices are used more than once a straightforward pattern of 1,2,3,4,5,6 doesnt occur. This is how my index buffer ended up:


    WORD Indices[24] = { 0,1,2,3,2,1,4,5,6,7,6,5,8,9,10,11,10,9,12,13,14,15,14,13};    


completely manually inputting the index data of course, but perhaps if you havent set your index buffer up in that format using code to create the structure, that might be whats causing the problem. The program will draw nothing if it doesnt follow that kind of pattern because it's attempting to draw the vertices in the wrong sequence. Also I found that you have to make sure that the data type you're using for all your pointers/index buffer structures are compatible, I think one of my problems at one point was that I was using a wrong data type and the information being passed when I locked the index buffer was getting messed up, despite the program compiling with zero errors.

Hope something in that lot helps (though I'm guessing if it worked before and doesnt now it's prolly something else),

Steve AKA Mephs

There will be people who say 'it can't be done, it's impossible' and I will say "WATCH ME!"

[edited by - mephs on June 8, 2002 2:25:03 PM]
Cheers,SteveLiquidigital Online
If you don''t like reading other people''s code than you might have a hard time working in a project which involves a team of people (...the whole game industry). You should practice :-)

I think you guys kinda missed the point though, but I was vague. The project was working perfectly. 3D Models where appearing textured and everything in their correct world space positioning. Plus, even the main Player Entity (A spaceship) was Rendering and Translating/Rotating beautifuly. After my reinstall of everything, suddenly they are not. Could this be something that was not being caught before but now it is a problem (Before, I upgraded from W2K to XP, but this was a fresh install).

Basically in my D3D Specific Intialize, I transfer all the Vertices and Faces I loaded from a 3ds file into their respectice Buffers (Vert and Index buffers). I use a 32-bit(DWORD) Index buffer btw. I think it could very well be an incorrect format Mephs, I need to check that out. The Indices are correct though because I''ve already rendered with them. This is a D3D Specific problem for me (or so I believe) involving the buffers and maybe some other D3D Rendering mechanisms.

Here''s some slightly less intimidating code to llustrate what I''ve done though. No one''s forcing you to read it but I appreciate any help offered. And yes, of course I''ve debugged the application, that''s how I know the loader is fine. I''ve found it difficult to debug COM objects though so I can''t tell if the Buffers are actually storing the data correctly. Constructive help people, thats what the forums are for (thanks Mephs :-).

Here I load the Vertices and Indices (Material Loading and comments excluded)

  	// Lock the current Vertex Buffer for modification.	MODELVERTEX *v = NULL;	m_pVertexBuffer->Lock( 0, 0, (BYTE**)&v, 0 );	for ( i = 0; i < m_iNumObjects; i++ )	{		pObject = m_ObjectList[i];		pObject->m_iVertexBufferOffset = iOffset;		for ( j = 0; j < pObject->m_iNumVertices; j++ )		{			v[j].p.x  = pObject->m_pVertices[j].m_X;			v[j].p.y  = pObject->m_pVertices[j].m_Y;			v[j].p.z  = pObject->m_pVertices[j].m_Z;			v[j].n.x = pObject->m_pVertexNormals[j].m_X;			v[j].n.y = pObject->m_pVertexNormals[j].m_Y;			v[j].n.z = pObject->m_pVertexNormals[j].m_Z;			v[j].color = 0xFFFFFFFF;			if( pObject->m_pTexCoords )			{				v[j].tu = pObject->m_pTexCoords[j].m_fU;				v[j].tv = pObject->m_pTexCoords[j].m_fV;			}		} // end for.		iOffset += pObject->m_iNumVertices;	}	// Unlock the Vertex Buffer for use.	m_pVertexBuffer->Unlock();  


Create the Index Buffer and Transfer over.

  	if ( FAILED( D3DManagerSingleton::Instance()->m_pd3dDevice->CreateIndexBuffer( m_iNumFacesInModel * 3 * sizeof(DWORD),											D3DUSAGE_WRITEONLY, D3DFMT_INDEX32,											D3DPOOL_DEFAULT, &m_pIndexBuffer ) ) )		return FALSE;	DWORD *pIndices = NULL;	m_pIndexBuffer->Lock( 0, 0, (BYTE**)&pIndices, 0 );	iIndex = 0;	iOffset = 0;	for ( i = 0; i < m_iNumObjects; i++ )	{		pObject = m_ObjectList[i];		pObject->m_iIndexBufferOffset = iIndex;		for ( j = 0; j < pObject->m_iNumFaces; j++ )		{			pIndices[iIndex]		= (DWORD)pObject->m_pFaces[j].m_iVerticesIndex[0];			pIndices[iIndex + 1]	= (DWORD)pObject->m_pFaces[j].m_iVerticesIndex[1];			pIndices[iIndex + 2]	= (DWORD)pObject->m_pFaces[j].m_iVerticesIndex[2];			iIndex += 3;		}	}	m_pIndexBuffer->Unlock();  


Render the Buffers.

  	// Render all the Objects/Vertex Buffers.	for( int i = 0; i < m_iNumObjects; i++ )	{		pObject = m_ObjectList[i];		// Render the Model using the Vertex and Index Buffer.		if ( m_pVertexBuffer && m_pIndexBuffer )		{			CD3DManager::m_pd3dDevice->SetVertexShader( D3DFVF_MODELVERTEX );			CD3DManager::m_pd3dDevice->SetStreamSource( 0, m_pVertexBuffer, sizeof( MODELVERTEX ) );			CD3DManager::m_pd3dDevice->SetIndices( m_pIndexBuffer, 0 );			CD3DManager::m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, pObject->m_iVertexBufferOffset,															pObject->m_iNumVertices, pObject->m_iIndexBufferOffset, pObject->m_iNumFaces );		}	}  


"Artificial Intelligence: the art of making computers that behave like the ones in movies."www.CodeFortress.com
If it was working before and is not now, the problem MUST be in the installation of windows, VC++ or the DirectX SDK, as its the only thing that could have changed. I suggest uninstalling and reinstalling each in turn, preferably windows last as thats just a pain in the butt!! I can''t see how it could be a problem with the code if it has remained the same,

just my 2 cents,

Steve
Cheers,SteveLiquidigital Online
ok this might be stupid of me.. but did you include the directx or whatever api your using in the "includes" directory of your compiler after you reinstalled it? bump!
Ok, found the problem, thought I should mention it here in case anyone else ever has the same problem (and is smart enough to search the forums). The problem had to do with the Index Buffer. All I had to do was change the format from 32 bit DWORD to a 16 bit WORD. Apparently somewhere I was using the index buffer as WORD values, so this incompatibility is what blocked the models from being render properly! Strange that it was not caught before but only after a reinstall of my operating system. Very strange.
"Artificial Intelligence: the art of making computers that behave like the ones in movies."www.CodeFortress.com
Its too bad I didn''t see this sooner. I was just reading through this and it occured to me that the problem was the 32 bit indices. Dang I hate it when I solve a problem thats already been solved!

Moe''s site

This topic is closed to new replies.

Advertisement