Hi everyone,
I've been working on a quadtree LOD terrain system lately and up until now, things have been going pretty smoothly. You can see a couple of screenshots showing the kind of basic result I'm getting in this post.
I recently started working on a different computer and I just copied my VC++ project directly across, opened it and re-compiled it to check it would work. That's when I ran into a very strange issue that I don't really know how to diagnose. My terrain mesh, which rendered perfectly well on the previous computer, now appears as a bunch of random flashing squares instead of a complete mesh. I've made a gif from a few frame captures which shows you the kind of result I'm getting:
I've isolated the issue to my Vertex Buffer locking calls, where I specify the flags D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE. If I remove D3DLOCK_NOOVERWRITE, the issue is resolved but my frame rate drops dramatically. It is for performance reasons that I used D3DLOCK_NOOVERWRITE in the first place, so I'd like to keep using it if possible!
So, my question is, can anyone think of a reason why my code which worked perfectly fine on a different computer just yesterday is suddenly so broken? I guess it's some sort of hardware issue (I can post specs if you think it may help). Or perhaps there's a code issue which was somehow masked on the previous computer?
I'll explain how the program works. Basically the terrain is constructed using a bunch of square tiles which recursively subdivide or un-subdivide into four more tiles depending on the camera distance each frame. When I have created the list of tiles to render for a given frame, I send them, one by one, into my vertex buffer and I draw them individually using D3DPT_TRIANGLESTRIP. This means that the vertex buffer is emptied and re-filled a great deal of times each frame, holding a maximum of four vertices at any one time. Here is some code which may be useful:
TerrainVertex structure (each terrain tile has an array of four of these (i.e. TerrainVertex vertices[4];) which are filled when the tile is created):
struct TerrainVertex
{
D3DXVECTOR4 pos;
D3DXVECTOR2 texCoords;
D3DXVECTOR3 normal;
TerrainVertex()
{pos = D3DXVECTOR4(0, 0, 0, 1); texCoords = D3DXVECTOR2(0, 0); normal = D3DXVECTOR3(0, 1, 0);}
TerrainVertex(D3DXVECTOR4 p, D3DXVECTOR2 txc, D3DXVECTOR3 n)
{pos = p; texCoords = txc; normal = n;}
};
Vertex declaration/buffer setup:
D3DVERTEXELEMENT9 elements[] =
{
{0, sizeof(float)*0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, sizeof(float)*4, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0, sizeof(float)*6, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
D3DDECL_END()
};
vertexDecleration = 0; //This is a LPDIRECT3DVERTEXDECLARATION9 declared elsewhere in the program
if (FAILED(d3ddev->CreateVertexDeclaration(elements, &vertexDecleration))){return false;}
if (FAILED(d3ddev->CreateVertexBuffer(4*sizeof(TerrainVertex), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &vertexBuffer, 0))){return false;}
Rendering loop which should render all the tiles for a given frame, one after the other:
//Note that renderQueue is just a list of tiles which is re-filled on each frame. Each element in renderQueue has four vertices as described above
for (unsigned rqc = 0; rqc < renderQueue.size(); rqc++)
{
void* pVoid;
if (FAILED(vertexBuffer->Lock(0, 0, (void**)&pVoid, D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE))){return false;}
memcpy(pVoid, renderQueue[rqc]->vertices, sizeof(renderQueue[rqc]->vertices));
if (FAILED(vertexBuffer->Unlock())){return false;}
if (FAILED(d3ddev->SetVertexDeclaration(vertexDecleration))){return false;}
if (FAILED(d3ddev->SetStreamSource(0, vertexBuffer, 0, sizeof(TerrainVertex)))){return false;}
if (FAILED(d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2))){return false;}
}