Recovering detailed normals from photo textures.
By Scott Warren
I've authored many image-based normal maps for our game and I thought it was time I document how I'm doing it.
It started from a technique one of our character modelers, Sean McBride, started playing with, then I just changed how I started the process and made it simpler for myself.
So basically, it's like this:
1. Author a diffuse texture or recover one from a photograph to begin. In my example, It'll be this rock material:
2. Take your texture into Photoshop and convert it to 16bit color, and then desaturate it.
- We work in 16bit color space with normal maps to avoid color banding later on due to the nature of this process.
- Depending on the texture, you may need to hand-paint different grayscale values to get the black and white image to correctly represent the height of the diffuse texture.
Optional. To prevent having to make the final texture tilable, use this suggestion by Armitage Shanks: Make sure your color texture is already tileable. Tile the image at least 9 times into a blank canvas which is three times the width and height of the source image. Doing this before starting the creation of the blurred overlays will ensure that the central copy of the image will already be perfectly tiled once you complete the normal map. The final step would be simply cropping the image to the center copy and saving it out.
3. Run the Nvidia normal map filter on your tweaked grayscale image.
I usually start off with a base height of "5" in the filter options. It's enough to see a result but not high enough to make things too sharp. This initial pass will act as the foundation for the rest of the process.
At this point, if your normal map looks too noisy, like this:
You'll need to run a surface blur on it to remove the extreme noise, but don't use too much of a surface blur so that it starts to eat away the larger details. You need to experiment to find out what works best for your texture. (You can also use 3x3 or 5x5 as the Filter Type, instead of '4 Sample', this way you also get a normalmap with less noise)
So now we have our base normal. This is where it gets fun. Depending on the surface you're recovering a normal from, this next step will change.
For the rock example, we can see in the diffuse that it's mainly broad areas of shading, crevices and cracks, not too many fine details. You can always add a fine detail overlay in your game engine if you want close details. We really want to focus on the more broad result we want the normal map to give us.
4. This is when we start making things happen.
- Take your base normal map, duplicate it, put the duplicate on top of the background layer, and set it to overlay mode. Overlay mode is a non-destructive addition of the normal colors. By overlaying it onto itself, you've just made it twice as intense as it was before.
5. - Take that layer copy, and duplicate it, and put it above the first duplicate.
Now depending on the type of surface, the amount you blur this new layer will be different. For the rocks, let's try something like a 3 pixel gaussian blur.
6. Run a 3 pixel blur on this 3rd layer copy, and drag it to the top of the layer stack. Each new layer you make will go above the one below it in the stack.
7. Stack this layer on top of itself once, then duplicate it, and blur it with a 6 pixel gaussian blur.
What we're doing is essentially creating our own "steps" of elevation in the normal map by overlaying blurred copies of the normal map on top of itself. Duplicate a layer, blur it a little more than the last one, put it on top, duplicate that copy, blur it, drag it on top, etc. etc..
How much you blur the layer copies really depends on the texture itself, so there's no "proper" amount to always use. You'll just need to decide what's best. (You can also use 'Copy Merged' to copy the whole canvas into a new layer, this way you get a stronger effect much quicker)
The end result should look like this:
This final composite will need to be re-tiled by offsetting the texture and clone stamping it, or by using a program like Seamless Texture Generator Pro to help you out.
Note: After you have finished with this process, you'll need to recover the blue channel for the normal map. To do this, flatten your image, run it through the Nvidia filter again but set the filter to "Normalize Only", the height input does not matter for this. Press okay, and voila, instant blue channel.
You can see the normalmap is a but less saturated after the Normalize.
The reason for the normalize step is a bit complicated. In short, the normalmap is a texture which contains the 'normal vectors' of the surface. The direction of each vector is defined by the red, green and blue channel, the length of the vector is always equal to 1. Because we have been changing the colors, the values might no longer be correct. The normalize step solves this problem, it will make sure each vector has a proper length of 1.
Here's a comparison of just running the normal map through the filter once, and what it looks like after doing a nice recovery of the normals by hand:
You can see that instead of a fine grained pattern, the normalmap defines very large changes in surface normals. This also shows when we look at the final result rendered in the Unreal Engine 3:
And since normalmaps always look much better in motion, here is a movie showing just that:
Avi Video (6MB)
Here is another example, this time only the end result and the normalmaps to show the difference:
Normalmap from NVidia Filter:
Normalmap created with Overlay Layers:
Result in Unreal Engine 3
Video: Avi Video (3MB)
This is the foundation for recovering normals from photos. I hope this gives some insight as to my process with recovering photo normals. if you have any questions, ask away, and if something isn't clear, I'll tweak the tutorial to make it easier to understand.
Scott Warren - www.hirezstudios.com
Copyright 2007 Scott Warren