A landscape displayed from a heightmap and single diffuse texture. Landscapes were from 4-8 million vertices. Regions consisted of 4096 vertices and could be drawn as anywhere from 2 tris to 8 thousand tris. Distance to camera and intrinsic detail bias based determination of which level-of-detail to use. A normal map was also calculated at first load to show consistent lighting despite changing LOD.
I created a stitching system to allow connected regions to differ in LOD. This required 16 different stitch patterns for each level of detail based on which touching regions were at a different LOD. This code follows:
void LODLandscape::CreateIndexBuffers() { /** * Create space for all the index buffers. And * the ids/lengths for talking to the GPU. * * iBuffers gets enough memory for the largest * possible index buffer. * * VERTCHUNKWIDTH - Number of heightvals across in each chunk * NUMSUBSAMPLES - Number of LOD levels being used * * NORTH, SOUTH, EAST, WEST: 1, 2, 4, 8 */ unsigned short *iBuffers = new unsigned short[VERTCHUNKWIDTH*VERTCHUNKWIDTH*NUMSUBSAMPLES]; iBuffIds = new size_t*[NUMSUBSAMPLES+1]; iBuffLengths = new size_t*[NUMSUBSAMPLES+1]; for( int i=1 ; i<=NUMSUBSAMPLES ; ++i ) { iBuffIds[i] = new size_t[16]; iBuffLengths[i] = new size_t[16]; for( int dir=0 ; dir <= (NORTH|EAST|SOUTH|WEST) ; ++dir ) { int currIndexSize=0; #define HEIGHT (VERTCHUNKWIDTH+1) #define STEP (1<<(NUMSUBSAMPLES-i)) #define PUSHBACK(n) iBuffers[ currIndexSize++ ] = n for( int y=0 ; y < VERTCHUNKWIDTH ; y+=STEP ) for( int x=0 ; x < VERTCHUNKWIDTH ; x+=STEP ) { if( !(( x/STEP+y/STEP )%2) ) { if( y==(VERTCHUNKWIDTH-STEP) && dir&NORTH ) { PUSHBACK( (y+STEP)*HEIGHT + x+STEP ); PUSHBACK( (y )*HEIGHT + x ); PUSHBACK( (y+STEP)*HEIGHT + x-STEP ); } else if( !(x==0 && dir&WEST) ) { PUSHBACK( (y )*HEIGHT + x ); PUSHBACK( (y+STEP)*HEIGHT + x ); PUSHBACK( (y+STEP)*HEIGHT + x+STEP ); } if( x==(VERTCHUNKWIDTH-STEP) && dir&EAST ) { PUSHBACK( (y+STEP)*HEIGHT + x+STEP ); PUSHBACK( (y-STEP)*HEIGHT + x+STEP ); PUSHBACK( (y )*HEIGHT + x ); } else if( !(y==0 && dir&SOUTH)) { PUSHBACK( (y+STEP)*HEIGHT + x+STEP ); PUSHBACK( (y )*HEIGHT + x+STEP ); PUSHBACK( (y )*HEIGHT + x ); } } else { if( y==0 && dir&SOUTH ) { PUSHBACK( (y )*HEIGHT + x-STEP ); PUSHBACK( (y+STEP)*HEIGHT + x ); PUSHBACK( (y )*HEIGHT + x+STEP ); } else if( (x==0 && dir&WEST) ) { PUSHBACK( (y-STEP)*HEIGHT + x ); PUSHBACK( (y+STEP)*HEIGHT + x ); PUSHBACK( (y )*HEIGHT + x+STEP ); } else { PUSHBACK( (y )*HEIGHT + x ); PUSHBACK( (y+STEP)*HEIGHT + x ); PUSHBACK( (y )*HEIGHT + x+STEP ); } if( !( y==(VERTCHUNKWIDTH-STEP) && dir&NORTH ) && !( x==(VERTCHUNKWIDTH-STEP) && dir&EAST )) { PUSHBACK( (y+STEP)*HEIGHT + x+STEP ); PUSHBACK( (y )*HEIGHT + x+STEP ); PUSHBACK( (y+STEP)*HEIGHT + x ); } } } iBuffIds[i][dir] = Renderer::GetInstance()->CreateIndexId( iBuffers, currIndexSize ); iBuffLengths[i][dir] = currIndexSize; } } delete [] iBuffers; #undef HEIGHT #undef STEP #undef PUSHBACK }