I'm writing an OpenGL program that visualizes caves, so when I visualize the surface terrain I'd like to make it transparent, so you can see the caves below. I'm assuming I can normalize the data from a Digital Elevation Model into a grid aligned to the X/Z axes with regular spacing, and render each grid cell as two triangles. With an aligned grid I could avoid the cost of sorting when applying the painter's algorithm (to ensure proper transparency effects); instead I could just render the cells row by row, starting with the farthest row and the farthest cell of each row.
That's all well and good, but my question for OpenGL experts is, how could I draw the terrain most efficiently (and in a way that could scale to high resolution terrains) using OpenGL? There must be a better way than calling glDrawElements()
once for every grid cell. Here are some ways I'm thinking about doing it (they involve features I haven't tried yet, that's why I'm asking the experts):
glMultiDrawElements
Idea
- Put all the terrain coordinates in a vertex buffer
- Put all the coordinate indices in an element buffer
- To draw, write the starting indices of each cell into an array in the desired order and call
glMultiDrawElements
with that array.
This seems pretty good, but I was wondering if there was any way I could avoid transferring an array of indices to the graphics card every frame, so I came up with the following idea:
Uniform Buffer Idea
This seems like a backward way of using OpenGL, but just putting it out there...
- Put the terrain coordinates in a 2D array in a uniform buffer
- Put coordinate index offsets 0..5 in a vertex buffer (they would have to be floats, I know)
- call
glDrawArraysInstanced
- each instance will be one grid cell - the vertex shader examines the position of the camera relative to the terrain and determines how to order the cells, mapping
gl_instanceId
to the index of the first coordinate of the cell in the Uniform Buffer, and settinggl_Position
to the coordinate at this index + the index offset attribute
I figure there might be shiny new OpenGL 4.0 features I'm not aware of that would be more elegant than either of these approaches. I'd appreciate any tips!