Hi guys,
I have one of those bugs that is driving me up a wall.
I'm taking out all the error handling in the code I'm about to display for brevity, but I do check the return codes, and no errors are returned.
The problem I'm getting is with my terrain. When I draw more than about 1800 terrain tris, everything is fine. However, when I draw less than 1800 tris, I get artifacts. Here are links to two screens with the terrain in wireframe to better show the problem.
This is a normal shot
Normal
And this is one that shows the artifacts
Artifacts
During initialization, this is how I create the VB and IB for the terrain:
r = Direct3D.D3DDevice->CreateVertexBuffer(40960*sizeof(GENERIC3DVERTEX),D3DUSAGE_WRITEONLY, D3DFVF_GENERIC3DVERTEX, D3DPOOL_DEFAULT, &TerrainVertexBuffer);
r = Direct3D.D3DDevice->CreateIndexBuffer(40960*sizeof(WORD), D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &TerrainVertexIndexBuffer);
Late during initialization, the terrain VB gets loaded. This happens only once, and then the VB never gets touched again (there is, ATM, only one landblock for the player to walk around in)
GENERIC3DVERTEX *Vertices = NULL;
LandBlock.NumVertices = 0;
//set up the vertex buffer
r = TerrainVertexBuffer->Lock(0, 0, (BYTE**)&Vertices, D3DLOCK_DISCARD);
for (unsigned int i=0; i<LandBlock.Vertices.size(); i++)
{
*Vertices++ = Init3DVertex(LandBlock.Vertices[i].VertexPoint, LandBlock.Vertices[i].VertexNormal,LandBlock.Vertices[i].tU, LandBlock.Vertices[i].tV);
LandBlock.NumVertices++;
}
r = TerrainVertexBuffer->Unlock();
Okay, then I set up the index list. This happens whenever the camera moves. This is a bit complex, but just before this routine I first determine the terrain bounding box visiblities (using a BSP sort of system). Here I am just culling out the non-visible terrain tris and adding the rest of their indeces to the index list. The whole thing with the MAXINT is just a leaf node detector, ignore it, it's not part of the problem:
WORD *Indeces = NULL;
LandBlock.NumChildTris = 0;
LandBlock.NumCulledTris = 0;
//set up the index buffer
r = TerrainVertexIndexBuffer->Lock(0, 0, (BYTE**)&Indeces, D3DLOCK_DISCARD);
for (unsigned int i=0; i<LandBlock.Triangles.size(); i++)
LandBlock.Triangles[i].IsVisible = true;
for (unsigned int i=0; i<LandBlock.BoundingBoxes.size(); i++)
{
if (LandBlock.BoundingBoxes[i].IsVisible == false)
{
for (unsigned int j=0; j<LandBlock.BoundingBoxes[i].BoundTriangleIndeces.size(); j++)
{
LandBlock.Triangles[LandBlock.BoundingBoxes[i].BoundTriangleIndeces[j]].IsVisible = false;
}
}
}
for (unsigned int i=0; i<LandBlock.Triangles.size(); i++)
{
if (LandBlock.Triangles[i].LeftChild == MAXINT && LandBlock.Triangles[i].RightChild == MAXINT)
{
if (LandBlock.Triangles[i].IsVisible == true)
{
*Indeces++ = LandBlock.Triangles[i].Vertex[0];
*Indeces++ = LandBlock.Triangles[i].Vertex[1];
*Indeces++ = LandBlock.Triangles[i].Vertex[2];
LandBlock.NumChildTris++;
}
else
{
LandBlock.NumCulledTris++;
}
}
}
r = TerrainVertexIndexBuffer->Unlock();
if (FAILED(r))
{
D3DXGetErrorString (r, string, 250);
sprintf(OutputString, "Failed to Unlock Terrain Vertex Index Buffer: %s", string);
MessageBox(NULL, OutputString, "D3DClass::SetTriangleList()", MB_OK);
return;
}
And finally, every frame we actually draw the terrain. Toward the beginning in the "if camera moved" block, I actually call the routine I just showed to set the terrain indeces:
float Aspect = Direct3D.WorldViewport.Width / Direct3D.WorldViewport.Height;
D3DXMatrixPerspectiveFovLH(&ProjectionMatrix, D3DX_PI/4, Aspect, 1.0f, 200.0f);
Direct3D.GetD3DDevice()->SetTransform(D3DTS_PROJECTION, &ProjectionMatrix);
D3DXMatrixLookAtLH(&ViewMatrix, &CameraEyePoint, &CameraLookAt, &CameraUp);
Direct3D.GetD3DDevice()->SetTransform(D3DTS_VIEW, &ViewMatrix);
D3DXMatrixIdentity(&WorldMatrix);
Direct3D.GetD3DDevice()->SetTransform(D3DTS_WORLD, &WorldMatrix);
if (CameraMoved == true)
{
ExtractFrustumPlanes(&ProjectionMatrix, &ViewMatrix);
DetermineBoxVisibilities();
Direct3D.SetTriangleIndexList();
CameraMoved = false;
}
//Set up render state
r = Direct3D.GetD3DDevice()->CaptureStateBlock(SavedStateBlock);
r = Direct3D.GetD3DDevice()->ApplyStateBlock(LandBlockStateBlock);
r = Direct3D.GetD3DDevice()->SetMaterial( &WorldMaterial );
r = Direct3D.GetD3DDevice()->SetVertexShader(D3DFVF_GENERIC3DVERTEX);
r = Direct3D.GetD3DDevice()->SetTexture(0, LandScapeTexture);
Direct3D.GetD3DDevice()->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(AmbientLightLevelR,AmbientLightLevelG,AmbientLightLevelB));
r = Direct3D.GetD3DDevice()->SetStreamSource(0, Direct3D.TerrainVertexBuffer, sizeof(GENERIC3DVERTEX));
r = Direct3D.GetD3DDevice()->SetIndices(Direct3D.TerrainVertexIndexBuffer, 0);
r = Direct3D.GetD3DDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 3*NumChildTris, 0, NumChildTris);
r = Direct3D.GetD3DDevice()->ApplyStateBlock(SavedStateBlock);
return S_OK;
Any suggestions as to why the artifacts? I can't seem to figure it out. The bounding boxes (visible vs not visible) are working just fine, I've run a bunch of tests on them.
It really does seem to be the case that if the terrain tris are bigger than about 1800 triangles, everything draws just fine, but otherwise I get these artifacts where it seems like one vertex of every triangle goes somewhere it's not supposed to.
Advice is much appreciated.
Ron
[edited by - RonHiler on February 7, 2004 8:40:44 AM]
[edited by - RonHiler on February 7, 2004 8:43:14 AM]