Question

I am going "backwards" for terrain generation: I am procedurally generating a terrain and its normals. I am then generating a bitmap of the terrain to be used as a 2D map. This is all working correctly and generating the results I want. But right now, the 2D map has "flat" shading -- how can I apply the terrain's generated normals to the 2D generated bitmap?

Ideally, I would like to apply lighting as if the "sun" were directly overhead (at "high noon"). I have searched this and other dev sites, as well as the general internet, but haven't found anything specific for my needs, just theory and concept information.

Can anyone tell me how to do this or point me in the right direction? You don't have to supply code (although pseudo-code would be nice) but I just need an idea of where to start. I am using C#/XNA for my game but welcome ideas from any language.

Was it helpful?

Solution

What you're attempting to do is to create a bump map.

http://www.gutgames.com/post/Normal-Map-Creation-Using-C.aspx

It assumes the Normal is always pointing in a specific direction (perpendicular to the face usually) and then offsets it based on the rgb values. There are lots of resources covering bump maps including the link above.

If you wanted to simplify things, you could store the actual normal values in the RGB of a new bitmap (note that you lose precision with this method).

If your range is [-1...1] then: Add 1 to your result and divide by 2, then multiply by 255.

So if you had the normal (0, 1, 0)

0 + 1 = 1 / 2 = 0.5 * 255 = 128 = Your new X value

1 + 1 = 2 / 2 = 1 * 255 = 255 = Your new Y value

0 + 1 = 1 / 2 = 0.5 * 255 = 128 = Your new Z value

Then you store (128,255,128) in your bitmap.

To return it to the correct value you would reverse the process:

128 / 255 = 0.5 * 2 = 1 - 1 = 0 = Your old X value

255 / 255 = 1 * 2 = 2 - 1 = 1 = Your old Y value

128 / 255 = 0.5 * 2 = 1 - 1 = 0 = Your old Z value

Precision is poor but it works well enough. You could also pack the values so that you get two bytes per X and Y. So X = RG and Y = BA of your RGBA values. Then you can do some magic to pull the Z value out to get the full normal. When you normalize a normal its length becomes 1. So 1 = sqrt(x*x + y*y + z*z). You know X and Y when reading them from the bitmap, so you can solve for Z. Improves the precision greatly and could also be used to improve the bump mapping precision as well depending on your needs.

OTHER TIPS

The Dot Product is the key! :)

For those interested, the solution I came up with is below. Thanks for the comments above. Also, here are 2 sites that greatly aided me:

https://stackoverflow.com/questions/3121815/what-are-the-dot-and-cross-product-of-vectors

http://www.tjhsst.edu/~dhyatt/supercomp/n310.html

//========================================

// change location of lightPosition as desired
// lightPosition Y may have to be positive for different implementations
Vector3 lightPosition = new Vector3(0, -1, 0); 
lightPosition.Normalize(); // not needed for above but this assumes normalized
float dotProduct = (Vector3.Dot(
    terrainPositionVector3Normalized, lightPosition) + 1) * 0.5f;
terrainColor.R = (byte)((float)terrainColor.R * dotProduct);
terrainColor.G = (byte)((float)terrainColor.G * dotProduct);
terrainColor.B = (byte)((float)terrainColor.B * dotProduct);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top