I have a terrain surface with a normal for each point on the terrain.
I have a second detail normal map to be applied to the terrain.
These normals are in 3-space.
The Y value of both normals is always positive.
The X,Z values of both normals can be positive/negative/zero.
The 1st normal vector (blue) that we are rotating the 2nd vector (orange) by, can be almost horizontal.
I am okay with an approximate solution if it makes it easier/faster to compute.
In the above image, you see the blue surface normal (from the 1st normal map), the orange normal map normal (from the 2nd normal map), and the green desired result normal.
The amount that the orange vector is rotated should be roughly (or if possibly exactly) equal to the angle that the blue normal vector forms with the XZ plane (where Y is up, like the DirectX coordinate system).
Here is a second scenario:
In the above image, the blue surface normal is almost horizontal, so the 2nd normal map is being applied to an almost vertical surface, thus the orange normal map vector is rotated further.
The rotation is being implemented in a HLSL shader.
How do I rotate the 1st orange normal based on the direction of the 2nd blue normal?
Edit: Maybe I need a tangent and bitangent as well as the normal?
Here's how I get the normal:
float4 ComputeNormals(VS_OUTPUT input) : COLOR
{
float2 uv = input.TexCoord;
// top left, left, bottom left, top, bottom, top right, right, bottom right
float tl = abs(tex2D(HeightSampler, uv + TexelSize * float2(-1, -1)).x);
float l = abs(tex2D(HeightSampler, uv + TexelSize * float2(-1, 0)).x);
float bl = abs(tex2D(HeightSampler, uv + TexelSize * float2(-1, 1)).x);
float t = abs(tex2D(HeightSampler, uv + TexelSize * float2( 0, -1)).x);
float b = abs(tex2D(HeightSampler, uv + TexelSize * float2( 0, 1)).x);
float tr = abs(tex2D(HeightSampler, uv + TexelSize * float2( 1, -1)).x);
float r = abs(tex2D(HeightSampler, uv + TexelSize * float2( 1, 0)).x);
float br = abs(tex2D(HeightSampler, uv + TexelSize * float2( 1, 1)).x);
// Compute dx using Sobel filter.
// -1 0 1
// -2 0 2
// -1 0 1
float dX = tr + 2*r + br - tl - 2*l - bl;
// Compute dy using Sobel filter.
// -1 -2 -1
// 0 0 0
// 1 2 1
float dY = bl + 2*b + br - tl - 2*t - tr;
// Compute cross-product and renormalize
float3 N = normalize(float3(-dX, NormalStrength, -dY));
// Map [-1.0 , 1.0] to [0.0 , 1.0];
return float4(N * 0.5f + 0.5f, 1.0f);
}
How might I get the tangent and bitangent vectors then?
Is it enough to take the cross product of the normal with the Z axis unit vector to find the tangent vector? (Since the normal.Y is always positive, where Y is up, and Z is pointing into your screen).
And then take that tangent vector and cross it with the normal to obtain the bitangent?
And then take the normal, tangent and bitangent together to form a rotation matrix to rotate the orange normal map vector?
Even if that works, this seems like a lot of computation for a pixel shader. Does this work, and is there a more efficient way?
Edit:
This image may help you understand what I'm trying to do:
If you know what normal mapping is, then this should be straightforward, I think.
I'm trying to take the normal map, which contains various normals, and apply them to a surface. The surface has it's own normals. The normal map will contain many more normals than the surface, so several normal map normals are sampled across a single part of the surface that has only a single normal.