AQUATERRA | |||||
ABOUT | |||||
I started out wanting to improve on my past attempts and make some nice water. For a while this project doubled as an assignment for a computer graphics class, so that was great. Since then I’ve kind of gotten carried away and worked on the environment too.
aQuaterra requires a video card capable of running DX9 SM 2.0 shaders. In other words, Geforce FX 5200 or Radeon 9500 or above. I didn’t bother implementing fall backs because hey, those cards have been out for three years and this isn’t a game, it’s a tech demo. |
|||||
SCREENSHOTS | |||||
|
|||||
CONTROLS | |||||
Move – Arrow keys or WASD Boost - Shift Look – Mouse Toggle look / Selection mode – Right click |
|||||
PERFORMANCE | |||||
aQuaterra uses a lot of pixel power, with the extra reflection pass and all the alpha tested vegetation. The program defaults to the highest settings that your card can support, but not necessarily handle. If you have a low-end card like the Geforce FX 5200, the fill rate just won’t be enough. Edit ‘aQuaterra Dx.cfg’ and ‘aQuaterra.cfg’ to turn down the resolution and anti-aliasing.
|
|||||
TECHNIQUES | |||||
Water | |||||
Reflection & Refraction
These are pretty standard for a water effect so I won’t go into detail. The refraction is done in the same pass as the main scene. Usually this results in objects in front of the water surface being distorted, but I’m using a masking technique that does a good job of hiding these artifacts. Specular highlight The specular reflection from the sun was particularly hard to get right, and I’m still not really satisfied with it. It takes a ridiculously high power to imitate the sun. Underwater scattering Light scatters in any medium, especially a cloudy one like the water. Light scatters exponentially as it enters the water, hits the surface and reflects to the eye. The method I used approximates the scattering from both of these bounces, not just the depth as many implementations do. As a result, you can see things that are very near you even when you are fairly deep in the water, just like real life. Caustics I used a scrolling texture on the lake floor to imitate caustics. It looks pretty good even though not physically accurate. Edge fadeout The worst thing about doing reflection as a projective texture and then distorting the coordinates is that it causes glitches where the distorted reflection allows you to see ‘under’ the terrain. I tried a lot of things to fight this, and eventually found one that works. I scale the terrain’s heightmap to an appropriate range so that the result is 1 inside the water area, abruptly fading out to 0 at the shore. Then I use this to scale the distortion and the fresnel term. As a result, the water isn’t distorted at the shore, fixing the reflection glitch, and the reflection fades out, getting rid of the hard water edges. Bloom I really wanted to do streaks instead, but bloom was a lot cheaper performance wise. I tried to keep it pretty subtle, play with the slider if you don’t notice it. |
|||||
Vegetation | |||||
Dynamic Grid
The grass is based on a square grid around the camera. The grid is made up of cells that contain the buffers for the grass. Cells are moved to the other side of the grid as the camera moves, keeping the grass only where it matters. Using cells allows the program to batch and frustum cull the grass efficiently. Planting When a cell is moved to the other side of the grid, grass must be replanted in it. Grass is then randomly distributed and constrained to the density function. The density function, and any other grass attribute, is painted on the terrain beforehand to control the way the grass grows. Texture atlas I used a big texture atlas for all the grass since that was the only thing breaking up batches. Thanks to the way the original textures were created I was able to minimize the texture filtering glitches associated with atlases by flipping the odd rows up-side-down. Screendoor blend Alpha blended grass looks nice but causes major efficiency problems since it has to be drawn back to front, breaking up batches. I opted to just use alpha testing instead. To blend the grass out then I used the dissolve effect, which modulates noise and camera distance with the alpha channel of the grass. It’s very subtle which is nice, but still not as good as alpha blending. Data Structure All trees and bushes are placed in the terrain quadtree, which is used for efficient frustum culling. This way hundreds of objects can be culled or accepted with a single test. Vegetation has several levels of detail, which are chosen by viewer distance. Edge feathering Alpha testing produces hard, aliased edges that don’t look good from up close. One trick to alleviate this problem is to render the highest quality LOD vegetation using alpha blending in a second pass. Alpha testing is still used in this pass, but the threshold is lowered, so that only the edges of the branches are drawn again. The result is a more natural transition. Animation All vegetation is animated as if there was a gentle breeze. Each plant and tree gets its own random factors so there is a lot of variation. |
|||||
Fish | |||||
Rendering
The fish are skinned on the GPU, and then lit with the Phong model. Flocking They follow the normal rules of flocking, which are: avoid crowding, match velocities and steer toward the average position of neighbors. I don’t think any fresh water fish flock, but what the heck. Environment avoidance The flocking behavior really gets interesting when the fish have a low priority target to keep them moving around, and they have to avoid colliding with the environment together. I added in a little ‘fear of humans’ for good measure. |
|||||
INSPIRATION | |||||
My main inspiration for the water was the Typhoon Tech Demo, which has some really sexy water. The guy that made that, Stefano Lanza, wrote an article in ShaderX 3 that was really useful, particularly for the underwater scattering. Yann Lombard wrote a good basic water article for Gamedev. Half Life 2 has great water and Far Cry has the water and the amazing vegetation. One of the Far Cry programmers, Tiago Sousa, wrote a great article in GPU Gems 2 that was very useful too. He’s the one that came up with the refraction mask so that refraction doesn’t require an extra pass. Also in that book is the article on vegetation rendering, which helped me figure out the most efficient way to render the grass, and edge feathering for the trees. Craig Reynolds came up with flocking and has a good description of it on his site.
Some thank yous for free media and tools: Caustics Generator – Caustic texture Loopix-Project - Model packs Llewellyn and Juliana - Music |
|||||
IMPROVEMENTS | |||||
I really wanted to get volumetric lighting above the water, and god rays below. All the methods that I’ve seen are prohibitively expensive and not very easy to implement though, so I’ll keep looking. I think 4-directional streaks (like a faint star on each bright spot) would look better than the bloom. The biggest overall improvement I could make would be to get more defined shadows on the vegetation, even dynamic ones. I need to find a good terrain LOD scheme that respects water boundaries so that I can have bigger levels. I tried Geo-Mipmapping, which is very efficient, but it messes up the shorelines. I should batch the trees and bushes better too by using instancing or packing everything in the same area into the same vertex buffer. So much cool stuff to do, but no time to do it! |