Jump to content
  • Advertisement
Sign in to follow this  

Index buffer not working

This topic is 4335 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a very strange problem with indexed geometry. It only works on my computer, not two others that I tested it on (a 98 and XP home). Without using indexing, all the computers render nicely. With indexing, only my computer renders it correctly, the others render, but wierd. I wrote my own geometry exporter for max 8, here is the code that handles the index and vertex arrays:
int nIndexedVertices = 0;
if (bUseIndexing == true)
{
	for (int i = 0; i < nNumIndices; i++)
	{
		bool bUsed = false;
		int nUsed = 0;
		for (int n = 0; n < nIndexedVertices; n++)
		{
			if (IndexedVertices[n].x == VD.x && IndexedVertices[n].y == VD.y &&
				IndexedVertices[n].z == VD.z && IndexedVertices[n].u == VD.u &&
				IndexedVertices[n].v == VD.v && IndexedVertices[n].w == VD.w)
			{
				nUsed = n;
				bUsed = true;
				break;
			}
		}

		if (bUsed == false)
		{
			IndexedVertices[nIndexedVertices].x = VD.x;
			IndexedVertices[nIndexedVertices].y = VD.y;
			IndexedVertices[nIndexedVertices].z = VD.z;
			IndexedVertices[nIndexedVertices].u = VD.u;
			IndexedVertices[nIndexedVertices].v = VD.v;
			IndexedVertices[nIndexedVertices].w = VD.w;
			ID = nIndexedVertices; 
			nIndexedVertices++;
		}
		else
		{
			ID = nUsed;
		}
	}
}

ID is the index array, IndexedVertices is the vertices array that ID indexes into. VD is all the vertexdata, which gets shrunk into IndexedVertices and indexed by ID. When using indexing, I write IndexedVertices and ID out to a file (in binary), and read it back in to my vertex and index buffers. This is trivial, so I don't think I messed it up. The only thing I thought of was the other computers weren't reading it in right, but I checked the return values of the fread()'s and everything was working as it should on the other computers. Same exact file, same exact executable, and it won't work on my other two family computers. If you want to see my loading code, here it is:
int CModel::LoadModel(char* FileName, IDirect3DDevice9* pD3DDevice)
{
	m_pD3DDevice = pD3DDevice;

	FILE * fp = fopen(FileName,"rb");
	if (fp == NULL)
		return 1;

	char buf[3];
	fread(&buf,1,3,fp);
	if (buf[0] != 'M' || buf[1] != 'D' || buf[2] != 'L')
	{
		OutputDebugString("Invalid Format\n");
		return 1;
	}
	int NumMaterials = 0;
	fread(&NumMaterials,1,4,fp);
	fread(&m_nMeshObjects,1,4,fp);

	m_pTexture = new IDirect3DTexture9*[NumMaterials];

	for (int i = 0; i < NumMaterials; i++)
	{
		char MaterialName[256];
		for (int j = 0; j < 256; j++)
			MaterialName[j] = NULL;
		int Length = 0;
		fread(&Length,1,4,fp);
		fread(&MaterialName,1,Length,fp);

		//TODO: check that files exist where they should be
		D3DXCreateTextureFromFileEx(m_pD3DDevice, MaterialName, D3DX_DEFAULT, D3DX_DEFAULT, 1, 0, 
			D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &m_pTexture);
	}
	
	m_nVertices = new int[m_nMeshObjects];
	m_nIndices = new int[m_nMeshObjects];
	m_nMaterial = new int[m_nMeshObjects];

	m_pVertexBuffer = new IDirect3DVertexBuffer9*[m_nMeshObjects];
	m_pIndexBuffer = new IDirect3DIndexBuffer9*[m_nMeshObjects];

	float x = 0, y = 0, z = 0, u = 0, v = 0, w = 0;

	//OutputDebugString("About to cycle through mesh objects\n");

	for (int MeOb = 0; MeOb < m_nMeshObjects; MeOb++)
	{
		char Buf;
		int r = 0, g = 0, b = 0;
		fread(&Buf,1,1,fp);
		m_nMaterial[MeOb] = -1;
		if (Buf == 'M')
		{
			fread(&m_nMaterial[MeOb],1,4,fp);
			//sprintf(TestString,"M, m_nMaterial = %i\n",m_nMaterial[MeOb]);
		}
		else if (Buf == 'V')
		{
			fread(&r,1,4,fp);
			fread(&g,1,4,fp);
			fread(&b,1,4,fp);
			//sprintf(TestString,"V, r = %i g = %i b = %i\n",r,g,b);
		}
		
		fread(&m_nVertices[MeOb],1,4,fp);
		int NumTexVerts = 0;
		fread(&NumTexVerts,1,4,fp);
		fread(&m_nIndices[MeOb],1,4,fp);

		CUSTOMVERTEX *VertexData = new CUSTOMVERTEX[m_nVertices[MeOb]];
		DWORD *IndexData = new DWORD[m_nIndices[MeOb]];

		if( FAILED( m_pD3DDevice->CreateVertexBuffer(m_nVertices[MeOb]*sizeof(CUSTOMVERTEX), 
			0, CUSTOMVERTEX::FVF_FLAGS, D3DPOOL_DEFAULT, &m_pVertexBuffer[MeOb], NULL)))
		{
			OutputDebugString("m_pD3DDevice->CreateVertexBuffer failed in CModel::LoadModel\n");
			return 1;
		}
		
		if( FAILED(m_pVertexBuffer[MeOb]->Lock(0, 0, (void**)&VertexData, 0)))
		{
			OutputDebugString("m_pVertexBuffer->Lock failed in CModel::LoadModel\n");
			return 1;
		}
		for (int i = 0; i < m_nVertices[MeOb]; i++)
		{
			fread(&x,1,4,fp);
			fread(&y,1,4,fp);
			fread(&z,1,4,fp);
			if (NumTexVerts != 0)
			{
				fread(&u,1,4,fp);
				fread(&v,1,4,fp);
				fread(&w,1,4,fp);
			}
			
			if (Buf == 'M')
				VertexData.color = 0xFFFFFFFF;
			else if (Buf == 'V')
				VertexData.color = D3DCOLOR_ARGB(255,r,g,b);
			VertexData.x = x;
			VertexData.y = y;
			VertexData.z = z;
			if (NumTexVerts != 0)
			{
				VertexData.tu = u;
				VertexData.tv = v;
				VertexData.tw = w;
			}
		}
		m_pVertexBuffer[MeOb]->Unlock();
		
		if (m_nIndices[MeOb] != 0)
		{
			if (FAILED(m_pD3DDevice->CreateIndexBuffer(4*m_nIndices[MeOb],0,D3DFMT_INDEX32,D3DPOOL_DEFAULT,
				&m_pIndexBuffer[MeOb],NULL)))
			{
				OutputDebugString("m_pD3DDevice->CreateIndexBuffer failed in CModel::LoadModel\n");
				return 1;
			}
			
			if (FAILED(m_pIndexBuffer[MeOb]->Lock(0, 4*m_nIndices[MeOb],(void**)&IndexData,0)))
			{
				OutputDebugString("m_pIndexBuffer->Lock failed in CModel::LoadModel\n");
				return 1;
			}
			
			DWORD index = 0, indextwo = 0, indexthree = 0;
			for (i = 0; i < m_nIndices[MeOb]; i++)
			{
				fread(&index,1,4,fp);
				IndexData = indexthree;
			}
			m_pIndexBuffer[MeOb]->Unlock();
		}

		VertexData = NULL;
		IndexData = NULL;

		delete[] VertexData;
		delete[] IndexData;
	}
	
	fclose(fp);

	return 0;
}

I'm out of ideas, can anyone think of why/how this could be happening? Your help would be appreciated. Dev578

Share this post


Link to post
Share on other sites
Advertisement
Without reading more than the first paragraph, I'm going to venture a guess that the other machines are using ATI hardware, or older cards with software transformation, and that you're developing on nVidia hardware.

If that is right, then look at MinIndex and NumVertices in your draw call as the likely problem.

MinIndex is the lowest index used in the part of the index buffer you are referring to (ie: from StartIndex to StartIndex+PrimCount*3 for a TriList). NumVertices is the highest vertex index used, minus MinIndex, plus 1.

ie:
Index buffer = 0,1,2, 2,3,0, 4,5,1, 1,6,4

If StartIndex = 6, and primcount = 2, then

MinIndex = 1 (lowest index seen in (4,5,1,1,6,4))
NumVertices = 6 (highest index = 6, - minindex = 5, plus 1 = 6)
ie: In the worst case, vertices 1,2,3,4,5, and 6 would need transforming.


ATI hardware, software transformation, and REF all require it to be correct. nVidia hardware ignores these arguments entirely in anything with hardware processing.

Share this post


Link to post
Share on other sites
Actually, I have an ATI Radeon 9550. The other two computers that I am testing on have old nVidia cards. I am just calling DrawIndexedPrimitive() one time for each mesh. If a model has more than one mesh, then I use multiple vertex and index buffers, one for each mesh. The only thing I can think of that would be screwing it up is the way the other computers are reading in the file. fopen() and all the fread()'s are returning exactly what they are supposed to. I don't know what else it could be. Here is my rendering code if it has any relevance:


int CModel::RenderModel()
{
m_pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
m_pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
m_pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);

for (int i = 0; i < m_nMeshObjects; i++)
{
if (m_nMaterial != -1)
m_pD3DDevice->SetTexture(0, m_pTexture[m_nMaterial]);
else
m_pD3DDevice->SetTexture(0, NULL);
m_pD3DDevice->SetStreamSource( 0, m_pVertexBuffer, 0, sizeof(CUSTOMVERTEX) );
m_pD3DDevice->SetFVF( CUSTOMVERTEX::FVF_FLAGS );
if (m_nIndices != 0)
{
m_pD3DDevice->SetIndices( m_pIndexBuffer);
m_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,m_nVertices,0,m_nIndices/3);
}
else
{
m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,m_nVertices/3);
}
}

m_pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
m_pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
m_pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

return 0;
}



Any ideas?

-Dev578

Share this post


Link to post
Share on other sites
Namethatnobodyelsetook gave you a good hint. It's most likely due to subtle differences between ATI and NVidia.
True, they mostly do as they're supposed to, but there are some borderline cases where one will accept things that the other sees as an error.
As in the example he gave, ATI requires some parameters to be correct, that NVidia just ignores because they're not technically neccesary.

And presumably, the opposite is also sometimes the case. So most likely, your code contains an error that only shows up on NVidia hardware.

Share this post


Link to post
Share on other sites
A couple of things I see that I don't like. You're relying on defaults, not completely setting up your color and alpha operations and arguments and disabling the next stage. You set ALPHAOP to DISABLE, which is invalid on any stage where there is a COLOROP. Since you're doing this AFTER drawing, it shouldn't be a problem, but it is completely and utterly wrong. ;)

The likely cause of your trouble though, is that you are using 32 bit indices. Many cards don't support them. Use unsigned short and INDEX16.

Share this post


Link to post
Share on other sites
Your right, it was the 32 bit index buffers, kind of dumb that it lets you create a 32 bit index buffer if you can't use it with the graphics card. So how am I supposed to get around this? Should I break up large models into different vertex and index buffers, or is there a way to use the parameters in drawindexedprimitive() to draw with one large vertex and index buffer, but only small chunks at at time. The Max SDK gives you all the indices as DWORD's, which is why I was doing it that way.

How can I render without using the defaults? My current approach is to set the rendering states, render, then set everything back to thier defaults, every time I render something. Hmm, just typing that in a sentence makes it seem wrong, but I don't know of any other way of doing it.

-Dev578

Share this post


Link to post
Share on other sites
Quote:
Original post by dev578
kind of dumb that it lets you create a 32 bit index buffer if you can't use it with the graphics card.
Checking D3DCAPS9::MaxVertexIndex should have told you that you can't [wink]

Quote:
MaxVertexIndex
Maximum size of indices supported for hardware vertex processing. It is possible to create 32-bit index buffers; however, you will not be able to render with the index buffer unless this value is greater than 0x0000FFFF.


On my GeForce 6800 the value is 220 - I can't use the full 232 range. I'd hazard a guess that your hardware is reporting 0x0000FFFF or less - but the cardcaps.xls seems to suggest the Radeon 9x00's expose 224 which is odd.

hth
Jack

Share this post


Link to post
Share on other sites
Not all cards default correctly, so relying on the defaults rather than setting up all the states yourself is asking for obscure problems on some hardware. Alphaop of disable on stage 0 is definately NOT the default as it's an invalid state.

Using basevertexindex you can offset past in 65535 using only 16 bit indices. You are still limited to using a 64K index range in one call, but you can change which range the indices refer to. Typically hardware without 32 bit index support isn't likely to do a good job of rendering many meshes with over 64K indices anyway. I'd look into splitting the meshes if you absolutely require that many indices.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!