LandscapeA 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.

LOD-Lighting

Lighting Demonstration

LOD-Stitching

Level-Of-Detail and Stitching

LOD-Landscape

A Second Landscape

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
 
}