Sign in to follow this  
  • entries
  • comments
  • views

Creating a GPU-Friendly Terrain Renderer

Sign in to follow this  


In yesterday's entry I went over some of my experiences and thoughts in regards to the Terrain Rendering Using GPU-Based Geometry Clipmaps algorithm. In the process of working with this algorithm, I was actually faced with the fact that I my video card could easily thrash a great deal of geometry being thrown at it without breaking much of a sweat. In thinking more about this revelation, I decided to carry out my musings in regards to the usefulness of the geoclipmap implementation as opposed to something far more simplistic with less overhead and, presumably, more room for variation.

I've always been a big fan of the Geometrical MipMapping algorithm for terrain rendering to the point where I asked its creator, Willem de Boer, to write the foreword to my book. Geomipmapping was, far and away, my favorite of the three algorithms which I discussed in my book, and was also one of the two algorithms I chose to write about in my Graphics Programming Methods chapter. So, when trying to figure out a very GPU-friendly way of handling this D3D10 terrain renderer it should come as no surprise that the base of the implementation would be geomipmapping. I think the mesh structure is absolutely perfect for GPU optimization, something that I didn't really have the resources to rely on four years ago.

So, the first part of the implementation that I worked on was the basic mesh structure; I don't have much of a need for a dataset larger than 2048x2048 height set, so I created a mesh structure of sixteen by sixteen mesh blocks of 128x128 vertex resolution. Since I'm developing with Direct3D 10, I get the absolutely joyous knowledge that I'm guaranteed functionality for vertex textures, so I can create a single vertex buffer for the 128x128 resolution block, and that's all that is required as far as vertices are concerned. I'm planning on having about four to five LOD levels, so I'm planning on creating one index buffer per LOD level. So, given all of this, I can manage to render the entire terrain in one draw call per LOD level. I can render all of the blocks of a given LOD by just instancing their origin into the shader and the vertex shader should be able to take care of all of the rendering details (I think I may be able to handle crack-fixing within the VS as well, but I'm not sure about that quite yet).

One of the oddities I ran into last night was that the non-instanced rendering of the mesh (I'm not using any LOD management yet) seems to be running about thirty to forty frames-per-second faster than the instanced rendering. I'm going to try slimming down the instance data (I'm currently using a transformation matrix, but I should be able to just pack the data into two short values instead), but I'm not sure if that will solve the differences or not. Shots below (non-instanced on the left and instanced on the right):

Once I had the base rendering working, I then shifted my attention to getting the height values being read in correctly from the height data by sampling the texture in the terrain's vertex shader. This actually ended up being more difficult than I had expected, due entirely to the fact that getting information from the DirectX10 Documentation is about as straightforward as using an extra-large porcupine for a bob-sled. Here's the current vertex shader (still under heavy coding):

VS_OUTPUT RenderVS( VS_INPUT vsInput )
VS_OUTPUT vsOutput;

//Get the world origin using the instance data.
float2 v2WorldPos = vsInput.v2GridPos*v4ScaleFactor.xy + vsInput.v2Transform_Inst;

//Convert from grid XY to world XY coordinates.
//ScaleFactor.xy: Grid scale.

// //Compute coordinates for vertex texture.
float2 v2UV = v2WorldPos + float2( v4ScaleFactor.z, v4ScaleFactor.z );
v2UV.x*= v4ScaleFactor.w;
v2UV.y*= v4ScaleFactor.w;

float y = texFineLevel.SampleLevel( samFineLevel, float2( v2UV ), 0 ).r*128;

vsOutput.v4Position = mul( float4( v2WorldPos.x, y, v2WorldPos.y, 1 ), matWorldViewProj );
vsOutput.v2TexCoord = v2UV;

return vsOutput;

Anyway, here's a look at the terrain as it exists right now:

Sign in to follow this  


Recommended Comments

Original post by Emmanuel Deloget
Is it me or the terrain is huge? It seems that there is a lot of details...

Well, the texture for that is a 2048 pixel resolution one, and the height texture is 1024 pixel resolution one which has a 1:1 mapping with the terrain vertices right now. In that image, the mesh is being rendered entirely at its finest detail level.

I'm currently working on making the terrain's mesh render cohesively with multiple LODs before I write my next update and it's being a bit more of a pain in the ass than I'd prefer, but I think it's only an hour or so of tweaking away from being presentable.

Share this comment

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now