Big progress on geo clipmaps and terrain

First I have to mention that three weeks ago, I attended an IGDA meetup in my town and it went pretty well. I got to catch up with a friend I met at a previous meetup, and even managed to meet a developer who I only previous knew about on YouTube. The topic for the meetup was game jam survival techniques. It provided some insight on making games under a very tight deadline, and we got to hear some humbling experiences from people that have gone through many of those battles and how they managed through it.

It’s reassuring to know that completing the game is not the only important goal, but moreso knowing how to work as a team and re-evaluating your strengths and weaknesses. The bottleneck that developers overlook, is not their game’s performance but their own performance. Figure out what you can cut to reduce your time in meeting your goals is important. You can shave off some milliseconds in a scene render, but it’s better to cut down on days or weeks in your work for the sake of completion.

Last time I mentioned that I wanted to make a racing game. It will be an off-road racing game with an emphasis on speed, long courses, and arcade-like action. So if the DiRT series is considered to fall somewhere between sim and arcade, I consider my own game to be between arcade and DiRT. I’ve had a few other game ideas in the past, and mostly that puzzle game which I finished but lacked the will to polish it, add more levels and modes, etc. I would want to get back to doing that eventually, but for now I’d like to continue on my main project with a terrain engine and editor for the other game.

Keeping this in mind I decided to take a more headstrong approach in my progress. Working too long at one feature is mind numbing and demotivating, and I seem to work better rearranging and re-organizing my task priorities, to ignore the ones that seem more wasteful. Guess this can be considered agile programming for one person.

A start on geo clipmaps

With that said, I wanted to shift focus on finishing the initial bugs and shortcomings on the terrain. It was tempting to start a map editor alongside it, but that had problems of its own with me trying to get viewports playing nicely with graphic device states and other controls (WinForms definitely isn’t my strongest point). So I continued headstrong into making my terrain look and perform better.

Previously I said that I would start making a basic clipmap system for the terrain. So that’s what I’ve worked on the past few days, and man did I sure make a lot of progress. Remember that desert scene that I had at the beginning? I went back to square one and tested some clipmapping out with wireframes.

First I created a new InnerClipmap class which is responsible for setting vertices for only a portion of the terrain given a position which acts as the center. The Terrain class is responsible for keeping the entire heightmap in memory and drawing whatever the clipmaps send to it. I made the camera and the dude be the center in various tests, and the terrain meshes move in stepped increments along with it.

clipmaps1

You cannot see it here, but all those grids are solid squares- they overlap each other in the center. Obviously we cannot draw redundant vertices, as it’s wasteful and produces ugly Z-fighting.

The next step was to “punch” a hole right through those outer clipmaps. I’ve read a few articles about geo clipmaps but I didn’t follow any exactly to a tee. For instance the GPU Gems article suggests to split the clipmaps into parts, and moving those parts individually. That seemed too thorough to me- all I know is, if each clipmap increases in size by a power of two, each hole will be (roughly) between 1/4 and 3/4 of the grid’s width and height dimensions. So, if the vertices fall in those areas, they won’t be added to the index buffer.

clipmaps2

Bam, holes are cut! But they are too big- some sides don’t align completely, so inner rows and columns need to be inserted according to some specific positioning rules, which I didn’t get to fix until much later. There’s also another thing to note. I only update the vertex and index buffers when the clipmaps should move, instead of re-calculating every frame. This wasn’t as tough to accomplish. I store its previous center position and if the current position passes a threshold (usually the grid cell size) we re-draw the map.

I went back into triangle fillmode and re-loaded the scene. I intentionally chose a camera position and direction where the clipmaps have little space in between, but there’s still the matter of broken seams as a result of height values not being averaged out where they meet at the ends. But still, things are starting to look good again.

clipmaps3

I also decided to switch to a heightmap with more consistent rolling hills and mounds. Basically just a tileable Perlin noise texture that I found online. This allowed me to make the terrain much larger.

Textures, trees and more

Now, there is where I decided to move in another direction for a while. Since I’m now starting to do more serious work with terrain, I figured, it needs a few subtle things to make it even better. So for the first time, my scenes have depth fog. I hardcoded some values for color and exponential depth in the composite shader, so everything that is rendered in the previous passes gets the fog treatment. These values will be user-assignable later on.

Also, I got tired of seeing deserts so I switched to a grass texture. It’s the same one found on Riemer’s tutorial, which did help cut time on getting started with heightmaps. But, man, does it look terrible in the distance.

terrain1

I solved this problem with a quick fix: sampling the same texture twice on the GPU. The first time, scale the texture small for close distances, and then scale it for farther distances. Then blend those with a similar formula used for the fog. The result is that the ground looks less repetitive in any area.

terrain2

There’s a basic but very useful function in my terrain code, adapted from an official XNA sample called Tank on a Heightmap. This was another real timesaver for me. Basically, it “pins” down a tank to the surface height no matter where it is on the map. It also adjusted the angle based on the interpolation of normals, but that’s not something I need right now. But I consider this a crucial step to efficiently building worlds and levels for my game.

How do I start using it? Well, for starters, all the previous screenshots are from builds where the dude is always walking on the ground. Basically, I use a function called Terrain.GetHeight(Vector3 position) and it returns the height, which I reassign as the position’s Y component. But wait, I can use it to place many objects on the ground in a loop, and what does a landscape need? Trees! I looked into a folder of tree models that I downloaded for free online, and loaded a pine tree into my project. Added a random with a seed, and set it to a loop. That was fast.

terrain3

All of a sudden, my efforts became a lot more fruitful. Looking at these trees, even if they’re not real, gave me a feeling of enlightenment and a better focus. I have a much clearer sense of direction for how to approach this project. Here’s another view, with depth of field added. (The speck in the lower left clouds isn’t a glitch- it’s a floating box I forgot to remove)

terrain4

Unfortunately, this silver lining has its cloud. What you don’t notice from these screenshots is that the trees (or rather, their polygon and vertex count) has slowed the rendering to a crawl. I place anywhere between 1000 and 1500 instanced trees and everything is now running chuggy. At its worst it can drop somewhere below 10 FPS. This is largely contributed by the cascaded shadow mapping, because it re-draws a lot of those trees for every split. But hey, now at least we’re getting somewhere. The engine is now getting a lot of heavy duty work, so it’s time to strengthen it and put it through its paces. Part of the problem is due to the tree meshes, though. Each one is 2992 triangles, heavy on the polycount if they are to be drawn a very large number of times.

I could find a better tree that’s much lighter on polygons, but still, some optimizations are in order. LOD grouping and occlusion culling to the rescue? I know I can brute-force cull 10,000 simple cubes with no problem, so for now brute-force culling isn’t slowing me down. So yeah, on to mesh LODs for one of the solutions, and then to get into some serious editing.

About these ads
Tagged with: , ,
Posted in Game development, Graphics, Meteor Engine, XNA
11 comments on “Big progress on geo clipmaps and terrain
  1. LUCCIN Karim says:

    You could use imposters for that. Just render like 20 trees and the rest from sprites, you won’t see the difference. And for the 20 “real” trees, instancing is the way to go.

    • Chris says:

      Hey, that’s not a bad idea. I already use instancing for most things (I’ve edited the article to point that out), but using impostors is something I overlooked. I have done some things similar to impostoring so fetching and caching on texture atlases is not new to me. I’ll write about this later as I apply it.

      BTW, nice game that you’re making. I’ve always wanted a WipEout-like game on the 360!

  2. Wow, you are working incredibly fast and your results are looking great! A lot better than mine! And those shadows help a lot!

    I am currently working on pretty much the same thing, large terrain and detail clutter, only I went for boulders first, not trees.

    I added fog too to handle the view distance, but I can’t manage that high of a view distance because I have only raw terrain, without any LOD technique like your geo clipmaps.

    Anyway, no time for that because I have other things to fix: I am running out of RAM because of physics.

    • Chris says:

      Thanks, I was working hardcore on the terrain for most of the weekend XD

      I would like to improve the viewing distance to several km, but can’t do it with traditional logarithmic depth space. In some of your old tech demos, your terrain looked pretty large. Were you splitting your terrain in equal-sized squares?

      • Yes, I am splitting up the terrain into 16×16 chunks for a map of 2048×2048. I can’t currently generate larger because the algorithm needs the whole map in memory currently and I’m running out of RAM. I misplaced my awesome implementation of Perlin noise that could generate each point independently, so you only needed the input parameters and you could get any point at any coordinate.

        But I only consider 60-90 chunks around the player for rendering and use culling to further reduce the number sent to the GPU. I am using exponential fog to hide the distant chunks that have the appearance of rectangular cut outs.

        The terrain sample 4 diffuse maps and 4 normal maps to texture the whole thing and is a performance bottleneck, especially when I’ll add point light support to it. I read you posts and I’m not sure i can fit tri-planar texturing into the shader too.

        Currently walking at the normal speed in my game it takes 17 minutes to walk diagonally from one corner to another. I want 1:30 hours for the final implementation :). Running at max speed takes under 2 minutes.

        I am making some progress with memory so I am also trying to improve view distance a bit.

      • Chris says:

        The only persistent heightmap data that I load are the elevations, which can be stored in a byte or short array. You should probably consider using geo-clipmaps for huge terrains.

        The beauty of this method that their memory storage per buffer increases only linearly with more levels. Because each clipmap uses the same number of vertices, using 6 clipmap levels will render a terrain 2 ^ (6 – 3) or eight times larger using only twice (6 / 3) as much memory as 3 clipmaps. Vertex coordinates are computed as needed when the the clipmaps need to move.

  3. Finally solved my RAM issues! Fit in the map and 17000 full physics response static boulders on the 4 square kilometer map in reasonable RAM level. Almost fits on Xbox. That was fairly challenging, but BEPU took care of most of the nasty business related to physics!

    If that tree mesh is free, care to share it? I have some tree meshes, but I would like to add the same tree so we can compare screenshots. Now that boulders are supported, I want to add all kinds of clutter until the map looks good. Making those trees physics enabled will be fun!

  4. DrHeinous says:

    I had much the same thing going on with the shadow map cascades; redrawing everything each time was expensive.

    About that time I added simple frustum culling to my drawing. Of course that didn’t work for the shadow step as something can be out of view but still cast shadows over things that are, so I temporarily removed culling when doing the shadows.

    Then it dawned on me that, in the shadow code, it was calculating a camera and hence a boundingFrustum for each cascade. In my draw code I was testing objects against the camera boundingFrustum. I simply changed this to a boundingFrustum passed in, and passed the main camera when drawing normally, the calculated camera when drawing the shadows.

    I don’t know exactly how you’re handing the shadows, but I expect something quite similar should work for you.

    • DrHeinous says:

      Well, never mind; I just looked in your code and you do pretty much that…

    • Chris says:

      For each cascade split, I create a frustum to render the shadows from the light’s POV. So now I am trying to do a separate frustum cull for each cascade.

      I was also reading this CryEngine presentation and one of their optimization tricks is to skip rendering the farthest cascades every few frames (page 21 in the slides). Since the viewer’s focus is much more on the foreground stuff, it makes sense that you don’t need to care much about updating detail very far away. I’m going to try this- the biggest obstacle is how to cache parts of a shadow map and access them between updates, as I’m using a texture atlas.

      I’ve also messed around before with variance shadow maps a bit, but not together with CSM, so that could be another option.

  5. Tiba says:

    Hi mate just wanted to say for the trees i have started to use speed tree and it works very well i said on JC’s blog that i should have a new video up in a few days.

    The new video shows off some nice palm trees with a good layer of grass and smaller trees, i also moved over to poisson disk shadow sampling thanks to u!

    I had a look at the CMS shader code but i cant get my head a round it as it is a lil different to how JC is doing his and i dont think ill but up to building my own shadow shaders just yet.

    I also wanted to say i fixed my LOD terrain issues and im now running at 70-80fps with 4 textures on the terrain and around 2000 tress\grass\plants\other world objects.

    here is a pic of a small part of the lvl im building

    http://imageshack.us/photo/my-images/715/newlpp.jpg/

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: