• entries
232
1462
• views
959434

# Craters and normal maps

1676 views

Normal maps on the GPU

In the last journal, I was explaining that one of the main benefits of working on the GPU instead of the CPU is the ability to create normal maps. Of course, it would be technically possible to generate them on the CPU too, but it would be far too costly, even with multithreading ( which the engine already supports ).

How does it work ? Well, each time the terrain quadtree gets subdivided ( as the viewer zooms in ), I'm rendering to a temporary F32 2D texture the heightmap for the new terrain patch. The shader generates, for each pixel of this heightmap, procedural height values that are a function of the XYZ position on the spherical surface. Then for each terrain node, I create a unique RGBA8 texture and render the normal map into it by deriving the heightmap of the previous step's temporary buffer.

The resolution of the per-patch normal map is depending on the depth level of the patch in the quadtree. At the top-most level, the map is 1024^2. For levels 1 and 2, it uses 512^2. Finally, for all other levels, the resolution is 256^2.

To maximize precision, I wanted to use lighting in tangent space, but due to various lighting artifacts and the tangent space not matching on the planet's cube faces, I ended up using object-space normal maps / lighting. It looks pretty good except on the very last depth levels ( it looks very noisy ), but I'm not sure yet if the bad lighting is coming from lack of precision in the XYZ inputs of the planet ( remember: it's using relatistic scales, and on the GPU I cannot use fp64 ), the lack of precision in the procedural heights generation, or the lack of precision in the object-space normals. Or maybe a combination of the 3...

In the coming week(s) I'll continue to try to increase the precision in the last depth levels, and reimplement diffuse texturing ( still lacking in the following pictures ).

Craters

I've finally been able to produce a decent crater noise function, based on the cell noise ( see previous journal ). Each crater has a perfectly circular shape but then is deformed by a few octaves of fBm, to make it more natural. In the following pics, I'm combining some fractals for the land base and 3 octaves of crater noise. I'm still not 100% happy with it though, as I think the craters's distribution is too uniform, so I will probably continue to play with it a bit.

For the fun, here's the final procedural function that generates all the pics in this journal:

float height(in vec3 world){    float land = gpuFbm3D(6, world * 2.0, 2.0, 0.7);    float land2 = gpuMultiFractal3D(16, world * 5.18, 0.8, 2.0, 0.05) * 0.5 - 2.5;    land = (land + land2 * 0.5) * 4.0;    float n0 = gpuFbm3D(10, world * 8.0, 2.5, 0.5) * 0.05;    vec2 c0 = gpuCellCrater3DB((world + n0 * 2.0) * (4.0 + n0 * 16.0) * vec3(1, 1, 1), 3.0, 0.5);    land += c0.x * 3.0;    c0 = gpuCellCrater3DB((world + n0 * 1.0) * (16.0 + n0 * 1.0) * vec3(1, 1, 1), 3.0, 0.5);    land += c0.x * 2.0;    c0 = gpuCellCrater3DB((world + n0 * 0.5) * (64.0 + n0 * 1.0) * vec3(1, 1, 1), 3.0, 0.5);    land += c0.x * 1.0;    return land + 1.0;}

Pictures

Awesome shots! That looks very realistic to me. The fine detail is wonderful.

I don't really mind the uniform-ish distribution of craters. I guess each square kilometre of a planet has the same probability of an asteroid impact... or does the motion of the planet itself play a significant role here? Anyway, maybe you could use a lookup function into your cell noise function, so that some areas are denser than others because more cells are mapped onto that region... do I make sense? :)

I'm wondering why you decided to use normal maps of different sizes at different quadtree levels, instead of simply making them all, say, 256^2?

As always, cool stuff. Makes me want to play around with my own terrain generator again, but unfortunately I don't have my desktop pc here and my laptop is too crappy to run it :(

Quote:
 Original post by thomastc Anyway, maybe you could use a lookup function into your cell noise function, so that some areas are denser than others because more cells are mapped onto that region... do I make sense? :)

I already tried that, but it doesn't work in practise. Because craters end up with a different radius, they don't match anymore ( when they're close to each other in two adjacent voronoi regions ) and you get nasty seams.

Quote:
 Original post by thomastc I'm wondering why you decided to use normal maps of different sizes at different quadtree levels, instead of simply making them all, say, 256^2

256^2 doesn't give a pixel perfect (1:1 ratio) match with the screen resolution (especially in high res, like 1680x1050). 512^2 for all nodes would cost too much memory, so I decided to give 256^2 in "standard" but to increase the resolution a bit in high-altitude views, so that when you're looking at the whole planet, you can see all the fine details.

man. im jealous. you stuff looks absolutely SICK!

great work. cant wait for you guys to finish!

oops. double post

My only problem with that is those planets appear to be capable of sustaining liquids and gases in significant amounts, which typically means a few things:

1. Erosion plays in and should eliminate most major artifacts of crater formation except on newer planets, or in the case of newer craters.
2. Tectonic activity will also tend to eliminate many artifacts as the shifting terrain will naturally tend to erase, stretch, level out, and otherwise erase such details.

Other than that, looking good as always.

Fantastic progress!

When you say normal maps are too slow on the CPU, is it because of the square roots?

How are you solving the issue where you have two adjacent quadtree nodes having different mesh levels - which gives you visible seams because the finer mesh is using different vertices to calculate the normals than the larger mesh next too it?

Do you just have the smaller mesh use the larger meshes' edge vertex normals?

I've been trying to figure out a good way to do this in my own implementation of the quadtree planet (CPU based) and currently each quadtree node mesh has an extra outer edge of vertices for calculating the edge vertex normals properly so there isn't an obvious seam going from low res meshes to high res meshes. I'm very curious about how you solved this especially on the GPU - I'm sure it's much more efficient and well thought thru.

Just a minor thing, but in some previous posts you actually were using a combination of a generated on the fly height map (using fbm) and an existing heightmap data - from the grand canyon I think. Do you still plan on implementing this capability in the GPU version? I imagine it would be important if you ever wanted to give artists a way to customize a planet's heightfield.

Again, brilliant work.