How to blend World Space Normals

I am trying to blend two world space normals inside a shader. One comes from a tangent space normal map converted into world space using a classic TBN matrix and the other one is a mesh normal map in world space.

I found some interesting resources here :

But those blending technics seem to be only available for tangent space normals, especially the Reoriented Normal Mapping (RNM). I tried to apply the RNM technic with unpack already done.

n1 += vec3(0, 0, 1);
n2 *= vec3(-1, -1, 1);

return n1 * dot(n1, n2) / n1.z - n2;


But this doesn't give expected results and I don't get why. Is there a way to apply the RNM blending on world space normals ?

Thanks a lot.

Edit: Here are some output and the result I am having with RNM. The A normal is not disturbed by the B normal, it gives some strange massively reoriented results.

float3 nv = dot(normal, viewDir);
color.rgb = nv;


• Do you have any physical interpretation for the two normal maps? e.g. one is high-frequency and one is low-frequency and applied "on top of it" (which is the Reoriented Normal Mapping case)? I would expect that you would need to feed the mesh's normal/tangent/bitangent into the equation somehow. You might consider simply transforming the world space normal into tangent space, applying RNM, then transforming the result to world space—that's only one extra 3x3 mul. Apr 19 '16 at 14:17
• Thanks for your answer @JohnCalsbeek but using baked tangent space normal doesn't provide good enough results that's why I am using a world space normal, especially a world space bent normal map, and I try to apply on top of if the regular normal map.
– MaT
Apr 19 '16 at 19:24
• I've added some screenshot to illustrate the issue I am having.
– MaT
Apr 19 '16 at 20:01

Huge thanks to @MJP who answered this.
The aim is to avoid the simplification made when using tangent space normals. Here is the paper : Blending in detail

But only implement equation (4) which gives you this.

float3 ReorientNormal(in float3 u, in float3 t, in float3 s)
{
// Build the shortest-arc quaternion
float4 q = float4(cross(s, t), dot(s, t) + 1) / sqrt(2 * (dot(s, t) + 1));
// Rotate the normal
return u * (q.w * q.w - dot(q.xyz, q.xyz)) + 2 * q.xyz * dot(q.xyz, u) + 2 * q.w * cross(q.xyz, u);
}