One of my favorite things to work on in Computer Graphics is Procedural Terrain Generation1. But in order to play with Terrain Generation, it really helps to be able to render those terrains. So that is what this project is all about.
I’m not necessarily aiming to create a game-quality, high efficiency rendering engine here. What I am looking to accomplish is creating a tool that lets me visualize height maps at a reasonable quality and efficiency level.
So what are my intentions/goals with this project?
1. I want to render the height map in a black and white 2D texture view. I want to work with height maps of more or less arbitrary size, determined at run time. The test height maps I’m actually using are 2048×2048 and 4096×4096.
2. I want a sort of bird’s eye view, looking down at the terrain from far away and at an angle so you can see the entire terrain at once. I’ll be treating the height map as being 1 pixel per 1m2.
3. I want a first person view so I can run around on the terrain. I’ll implement simple mouse look and lock the camera to be a certain distance from the surface.
4. I’m going to be using Direct3D 12.0 for this. It isn’t necessary since I’m not trying to eke out every last drop of performance and I really have no reason to make this multi-threaded, but I wanted to learn a bit about how it works and this is as good an opportunity to learn the basics as any.
5. I want to implement tessellation. I’ll only implement it in the first person view mode as the bird’s eye view mode camera is too far away from the terrain to be visible anyway. I haven’t decided at this point whether or not I want to implement any sort of Level of Detail system. I think it depends on the FPS I’m getting. Long term, the tessellation would be part of the LOD system and would automatically be taken into account so there would be no difference between the 2 3D view modes I want. I don’t know if I’ll implement that right away or not.
6. In terms of texturing the terrain, I’d prefer not to use textures, but rather just use a decent colour palette.
This video from lundbekegholm’s channel is one of my favourites demonstrating glacial erosion at work in a simulation. It also demonstrates a great colour palette instead of texturing the terrain. Using a colour palette means I don’t need to worry about texture stretching at all. Of course, it really only looks as good as it does because it is rendered at an incredibly high level of detail. I’m not sure I’ll be anywhere near that quality.
7. I’d like to implement self shadowing. I want the entire terrain to be considered in this, not a local algorithm that may not take into account the mountain 1km away from the camera. As I won’t be rendering any other objects in this project, I’m not concerned with the terrain casting shadows on other objects or those objects being able to cast shadows on the terrain, but it would be nice to implement a system that can handle that.
There will be only one source of light: the Sun. It would be nice, however, to be able to support arbitrary directions for the Sun, so that I can have a day-night cycle and treat the height map as though it is at an arbitrary position on the globe.
Shamus Young talks about a simple implementation of shadowing terrain that works if you assume the terrain is at the equator and is perfectly flat. I may simply implement that and move on, but I’m also considering how it might be expanded to handle the arbitrary cases.
I’m also thinking about Shadow Maps and Shadow Volumes. Given the limited nature of this project, one or both may be fine. In a real project with a world full of objects and potential light sources, I doubt either would be efficient enough to be able to handle the entirety of a 4kmx4km terrain.
8. While I’m not terribly worried about efficiency with this project, I’d still like to maintain a frame rate at or above 60fps. Best case, I’d like it to stay above 120fps. I’ll be using Visual Studio’s Graphics debugger to determine frame rate, so obviously there is other overhead involved besides the program itself.
My desktop will be my target platform. I’m running Windows 10 Pro, 32GB of RAM, a GTX680 with 4GB of video RAM, and a 4K monitor. So any target fps I aim for will be on that computer. As I’ve already made mention to, I’m working in Visual Studio 2015 and using Direct3D 12.0, although my card actually only supports feature level 11.0 so I won’t be using any more advanced features. I really have no reason to in this project, anyway.
EDIT – I have a 4K monitor, but for most of the performance info I mention, I’m actually only rendering a 1920×1080 window.
The code for this project can be downloaded from GitHub.
Next post, I’ll talk a bit about the initial setup of the project. It’ll be mostly about what tutorials got me going with DirectX 12 and getting a window and rendering context up and running.
Table of Contents
- Part 1 – Initial Setup
- Part 2 – Loading a height map and Initializing a Pipeline
- Part 3 – Drawing the Height map in 2D
- Part 4 – Moving to 3D
- Part 5 – Updating our Shaders for 3D
- Part 6 – Adding Camera Controls and Fixing Normals
- Part 7 – Fixing an annoying Bug
- Part 8 – Adding Tessellation
- Part 9 – Dynamic Level of Detail
- Part 10 – View Frustum Culling
- Part 11 – A Bit of Refactoring
- Part 12 – Lighting, Lights and a Simple Day/Night Cycle
- Part 13 – Basic Shadow Maps, The Not Quite Right Edition
- Part 14 – Improving Shadows and The Day/Night Cycle
- Part 15 – Skirts and Other Additions
- Part 16 – Getting Started on Cascaded Shadow Maps
- Part 17 – More CSM and Fixing Mistakes
- Part 18 – Stable CSM, Finally!
- Part 19 – Shadow Frustum Culling
- Part 20 – Normal and Displacement Mapping
- Part 21 – Triplanar Mapping and adding a Detail Map
- Part 22 – A Quick Fix For AABB
- Part 23 – Height and Slope Based Colours
- Part 24 – Height and Slope Based Normal Mapping
- Part 25 – Fixing More Bugs with Shadows
- Part 26 – Improving Performance
- Part 27 – Making Things Look Better
- Part 28 – Refactoring Redux
- Part 29 – Loading Fewer Files
- Part 30 – Refactor Round Three
- Part 31 – Conclusion