I'm trying to add triplanar mapping to the OGRE Terra system to avoid texture stretching on cliffs.
So far, my implementation seems to work on the edge case (a "cube" terrain), but miserably fail on a real case.
Here you can see the heightmap that creates a giant cube terrain and the triplanar mapping in action:


Instead, here you can see a less fake terrain heightmap and how poorly the triplanar mapping performs:


(in the example above I've used a dot texture instead of a checker one just to better show the distortion)
This is how I've modified the Terra HLSL shaders.
Firstly, I've added a Custom_piece_vs_piece_ps.hlsl file:
Code: Select all
@piece( custom_VStoPS )
@property( triplanar )
float3 worldPos : TEXCOORD@counter(texcoord);
@end
@end
@piece( custom_vs_posExecution )
@property( triplanar )
outVs.worldPos = worldPos;
@end
@end
@piece( triplanar_swizzle0 )yz@end
@piece( triplanar_swizzle1 )xz@end
@piece( triplanar_swizzle2 )xy@end
Code: Select all
/// Sample detail maps
@foreach( 4, n )
@property( detail_map@n )
float3 detailCol@n = textureMaps[@value(detail_map@n_idx)].Sample(
samplerStates[@value(detail_map@n_idx)],
float3( inPs.uv0.xy * material.detailOffsetScale[@value(currOffsetDetail)].zw +
material.detailOffsetScale[@value(currOffsetDetail)].xy,
@value(detail_map@n_idx_slice) ) ).xyz;
@end @property( !detail_map@n )
Code: Select all
@property( triplanar )
float3 blending = pow( terrainNormals.Sample( terrainNormalsSamplerState, inPs.uv0.xy ).xyz * 2.0f - 1.0f, 4.0 );
blending /= dot( blending, float3( 1.0, 1.0, 1.0 ) );
@end
/// Sample detail maps
@foreach( 4, n )
@property( detail_map@n )
@property( triplanar )
@foreach( 3, m )
float3 detailCol@nTri@m = textureMaps[@value( detail_map@n_idx )].Sample( samplerStates[@value( detail_map@n_idx )], float3( inPs.worldPos.@insertpiece( triplanar_swizzle@m ) * material.detailOffsetScale[@value( currOffsetDetail )].zw, @value( detail_map@n_idx_slice ) ) ).xyz;
@end
float3 detailCol@n = detailCol@nTri0 * blending.x + detailCol@nTri1 * blending.y + detailCol@nTri2 * blending.z;
@end @property( !triplanar )
float3 detailCol@n = textureMaps[@value(detail_map@n_idx)].Sample(
samplerStates[@value(detail_map@n_idx)],
float3( inPs.uv0.xy * material.detailOffsetScale[@value(currOffsetDetail)].zw +
material.detailOffsetScale[@value(currOffsetDetail)].xy,
@value(detail_map@n_idx_slice) ) ).xyz;
@end
@end @property( !detail_map@n )
Code: Select all
{
"Terra":
{
"Terrain002":
{
"detail_weight":
{
"texture": "Red.png"
},
"detail0":
{
"scale": [0.05, 0.05],
"diffuse_map": "CheckerDots.jpg",
"roughness_map": "White.png"
}
}
}
}
Code: Select all
...
float3 blending = pow( terrainNormals.Sample( terrainNormalsSamplerState, inPs.uv0.xy ).xyz * 2.0f - 1.0f, 4.0 );
blending /= dot( blending, float3( 1.0, 1.0, 1.0 ) );
/// Sample detail maps
float3 detailCol0Tri0 = textureMaps[1].Sample( samplerStates[1], float3( inPs.worldPos.yz * material.detailOffsetScale[0].zw, 0 ) ).xyz;
float3 detailCol0Tri1 = textureMaps[1].Sample( samplerStates[1], float3( inPs.worldPos.xz * material.detailOffsetScale[0].zw, 0 ) ).xyz;
float3 detailCol0Tri2 = textureMaps[1].Sample( samplerStates[1], float3( inPs.worldPos.xy * material.detailOffsetScale[0].zw, 0 ) ).xyz;
float3 detailCol0 = detailCol0Tri0 * blending.x + detailCol0Tri1 * blending.y + detailCol0Tri2 * blending.z;
...
Code: Select all
psOut.colour0.xyz = blending;
return psOut;

Look at the small hill in the center: it's greenish where is flattest (normal is pointing to world Y) and it's redish/bluish where there's some slope (normal is pointing to world X/world Z).
I was expecting a less intense red/blue since the hill isn't so steep and the world plane XZ should prevaricate the XY and YZ world planes (and infact, in the fourth image from the top, the stretched dots are the most visible ones).
I'm really lost and I've ended ideas.
My only doubt (hope!) is that terrainNormals.Sample( terrainNormalsSamplerState, inPs.uv0.xy ).xyz * 2.0f - 1.0f isn't the normal in world space.
Here are some references about triplanar mapping:
https://medium.com/@bgolus/normal-mappi ... bf39dca05a
https://gamedevelopment.tutsplus.com/ar ... edev-13821
https://developer.nvidia.com/gpugems/GP ... _ch01.html
Disclaimer: this is a work-in-progress task.
Some optimizations are missing (e.g.: don't re-sample the terrainNormals texture) and the triplanar mapping of other textures (diffuse map, roughess maps, metalness maps and normal maps) has to be done yet.