I use triplanar texture mapping because it works nicely for procedural geometry.
This is the technique I'm currently using:
http://http.develope...gems3_ch01.html (Example 1-3. Texture Planar Projection)
This works rather well for diffuse texturing, and they have even provided a way to do bump mapping.
Their method is very different from what I'm used to doing though.
Usually I would generate a TBN matrix and multiply the tangent space normal (from the normal map) with it to get my normal vector.
However this does not work with triplanar texture projection.
Not only do I not know the tangent and bitangent vectors to do this, but since I'm using 3 projections simultaniously there is no unique correct TBN matrix.
The method illustrated in the gpu gems article does the following:
- Generate 3 sample coords: (Position being the object space vertex position)
float2 coord1 = Position.yz * TexScale;
float2 coord2 = Position.zx * TexScale;
float2 coord3 = Position.xy * TexScale;
- Get 3 tangent space normals from a normal map (with half intensity)
float3 nor1 = TNormal1.Sample(TextureSampler, coord1).rgb - 0.5;// * 2.0 - 1.0;
float3 nor2 = TNormal1.Sample(TextureSampler, coord2).rgb - 0.5;// * 2.0 - 1.0;
float3 nor3 = TNormal1.Sample(TextureSampler, coord3).rgb - 0.5;// * 2.0 - 1.0;
- Bring the 3 normal vectors into object/world space
float3 Normal1 = float3(0, nor1.x, nor1.y);
float3 Normal2 = float3(nor2.y, 0, nor2.x);
float3 Normal3 = float3(nor3.x, nor3.y, 0);
Then all 3 normals are blended together depending on the vertex normal and added onto the vertex normal.
According to the article this is designed for bump mapping, not normal mapping, but I don't understand why their bump map would have 2 channels.
It is the last step I am having trouble understanding, what exactly is going on here?
float3 Normal1 = float3(0, nor1.x, nor1.y);
float3 Normal2 = float3(nor2.y, 0, nor2.x);
float3 Normal3 = float3(nor3.x, nor3.y, 0);
There is no way this can produce even remotely correct normal vectors, which would explain why my results are okay-ish, but far from what I want:
- The left image is roughly what I want to achieve (to create the image I cheated and used a TBN matrix that is roughly correct for a single projection that is completely dominant over the other 2 in this specific location)
- The right image is what I'm getting using the bump technique from gpu gems (normals don't line up with the diffuse map, also note the repetitive pattern in the background and the different light intensity on the mountain in the foreground)
Now I understand that it is most likely impossible to do "proper" normal mapping, as it seems to be a hideously complicated task to make the normals line up with the diffuse maps.
So I guess what I'm asking is:
- What exactly does this do:
float3 Normal1 = float3(0, nor1.x, nor1.y);
float3 Normal2 = float3(nor2.y, 0, nor2.x);
float3 Normal3 = float3(nor3.x, nor3.y, 0);
- And is there any way to generate better normal vectors (either by improving this method or using a completely different approach)
Here's my current code for reference: (TDiffuse2 does not use a normal map which is why there is no TNormal2)
void TriplanarMapping( in float3 VertexNormal,
in float3 Position,
in float TexScale,
in float BumpIntensity,
in Texture2D TDiffuse1,
in Texture2D TDiffuse2,
in Texture2D TNormal1,
in SamplerState TextureSampler,
out float3 TriDiffuse1,
out float3 TriDiffuse2,
out float3 TriNormal1)
{
// Triplanar Texture Projection
float3 BlendWeights = abs(VertexNormal);
BlendWeights = (BlendWeights - 0.2f) * 7;
BlendWeights = max(BlendWeights, 0);
BlendWeights /= (BlendWeights.x + BlendWeights.y + BlendWeights.z);
// Triplanar sample coords
float2 coord1 = Position.yz * TexScale;
float2 coord2 = Position.zx * TexScale;
float2 coord3 = Position.xy * TexScale;
// Diffuse sampling
float3 col1 = TDiffuse1.Sample(TextureSampler, coord1).rgb;
float3 col2 = TDiffuse1.Sample(TextureSampler, coord2).rgb;
float3 col3 = TDiffuse1.Sample(TextureSampler, coord3).rgb;
float3 col4 = TDiffuse2.Sample(TextureSampler, coord1).rgb;
float3 col5 = TDiffuse2.Sample(TextureSampler, coord2).rgb;
float3 col6 = TDiffuse2.Sample(TextureSampler, coord3).rgb;
// Normal sampling
float3 nor1 = TNormal1.Sample(TextureSampler, coord1).rgb - 0.5;// * 2.0 - 1.0;
float3 nor2 = TNormal1.Sample(TextureSampler, coord2).rgb - 0.5;// * 2.0 - 1.0;
float3 nor3 = TNormal1.Sample(TextureSampler, coord3).rgb - 0.5;// * 2.0 - 1.0;
// Transform normals (this step is very crude)
float3 Normal1 = float3(0, nor1.x, nor1.y);
float3 Normal2 = float3(nor2.y, 0, nor2.x);
float3 Normal3 = float3(nor3.x, nor3.y, 0);
// Triplanar blending
TriDiffuse1 = col1 * BlendWeights.x +
col2 * BlendWeights.y +
col3 * BlendWeights.z;
TriDiffuse2 = col4 * BlendWeights.x +
col5 * BlendWeights.y +
col6 * BlendWeights.z;
TriNormal1 = Normal1 * BlendWeights.x +
Normal2 * BlendWeights.y +
Normal3 * BlendWeights.z;
// Bump vertex normal
TriNormal1 = normalize(VertexNormal + TriNormal1 * BumpIntensity);
}
Cheers,
Hyu