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:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | 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 } |