Combining Normal Maps

Hello! I’ve been trying to find out the best way to combine two normal maps together.
I’ve looked into this article, http://blog.selfshadow.com/publications/blending-in-detail/, and while it does confirm my expectations, that every pixel in the map has a normal vector (written in tangent space) coded in it, it sugests using Quaternions to represent the rotation of one surface normal into another (When you apply one normal map on top of another, what you want is to use the first map to rotate the surface normal, and then rotate the resulting normal with the second map). But I’m am not yet at ease with quaternion math, so I thought it would be easier (although less efficient, and more error-prone) to use rotation matrixes.

So I have thought of a different aproach:

Let’s say you want to combine a SECOND normal map on topo of a FIRST normal map. The first thing to do is to convert the color into a normal (written in tangent space). This is easy: n=(c-0.5)*2 (where “n” is the normal vector and c is the colour vector), because each channel is mapped to a coordinate of the normal vector with the following linear map: [0,1]->[-1,1].

Now, we want to calculate the transform that we want to apply to the surface, and I know that if I have a linear transform (and a rotation is a linear transform), I can write a matrix to represent that transform. I also know that, if you have a linear transform from one vector space A into another called B, where they both have the same dimension, the collumns of the matrix are the vectors that span B, represented in the coordinates of A.

In this case, the basis of A is the canonical basis {i,j,k}={(1,0,0), (0,1,0), (0,0,1)}, which is the tangent space basis written in tangent space coordinates (thus, the surface normal is (0, 0, 1), as it should be: a “flat” normal map has the colour (0.5,0.5, 1), which is the vector (0,0,1) ).

We know that the third component of the basis of B is n, the normal represented in the SECOND normal map. Now we just need to find the other two vectors. There are, however, infinite possibilities, assuming you want the basis of B to be orthogonal. I don’t have a mathematical justification for how I chose to do it, but here’s how I did it:
Let’s say the basis of B is {a,b,c}, then:

  • c=n, the normal represented in the SECOND normal map.
  • a=(jc)/||jc||, the cross product of j by c, normalized.
  • b=c*a, the cross product of c by a.

This gave good results.
Now, I write my transformation matrix:

T= a_1 b_1 c_1
a_2 b_2 c_2
a_3 b_3 c_3

where v_i = the ith component of the vector v.

Now, if my logic is correct, Ncombined = T(n1), that is: for every pixel, the resulting normal map is the result of applying transformation T to the FIRST normal map.

Then, the final, combined, normal map has its colour given by: colour=(Ncombined/2)+0.5.

I’ve implemented this method in blender using only nodes and got the results attatched.


What do you think of this method? Did I calculate correctly the vector spaces?

Note: I’ll be sharing the .blend file in one of the following days.

Attachments


Simple way: add red and green channel’s from each texture respectively(red+red, green+green) and multiply the blue channels. Re-combine all channels into one vector3. Then normalize in game engine.

Slightly more complex way: divide each of the red and green channels by 2 then add red to red, and green to green respectively. Multiply the blue channels then subtract 1 from the result, thus normalizing it.

There are also two samples on BlendSwap

Cycles Mixing Normal Maps

Combine Normal Maps Node Setup For Cycles

I had done this same formula from selfshadow.com in nodes sometime ago…
http://www.blenderartists.org/forum/showthread.php?349153-Baking-Normals-within-other-maps

the file with the nodegroup can be found here:

Stan Pancakes included also a factor input for more control