Triplanar mapping

Discussion area about developing with Ogre2 branches (2.1, 2.2 and beyond)
Post Reply
User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 177
Joined: Wed Apr 23, 2014 3:49 pm
x 20

Triplanar mapping

Post by TaaTT4 » Thu Oct 05, 2017 6:34 pm

Hello everybody,

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:
Image
Image

Instead, here you can see a less fake terrain heightmap and how poorly the triplanar mapping performs:
Image
Image
(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
Then, I've replaced in the PixelShader_ps.hlsl file the code below:

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 )
with:

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 )
This is the material I'm using for the terrain:

Code: Select all

{
	"Terra":
	{
		"Terrain002":
		{
			"detail_weight":
			{
				"texture": "Red.png"
			},
			
			"detail0":
			{
				"scale": [0.05, 0.05],
				"diffuse_map": "CheckerDots.jpg",
				"roughness_map": "White.png"
			}
		}
	}
}
Also the compiled pixel shader seems to be correct (or at least, is what I'm expecting):

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;

...
I've already checked blending value, and visually it appears correct either.

Code: Select all

	psOut.colour0.xyz = blending;
	return psOut;
Image
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.
0 x
Senior game programmer at Vae Victis
Working on Racecraft

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1064
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 83

Re: Triplanar mapping

Post by xrgo » Thu Oct 05, 2017 7:09 pm

definitely should be more green than anything

try this blending I used to use

Code: Select all

	vec3 getTriPlanarBlend(vec3 _wNorm){
	    // in wNorm is the world-space normal of the fragment
	    vec3 blending = abs( _wNorm );
	    blending = normalize(max(blending, 0.00001)); // Force weights to sum to 1.0
	    float b = (blending.x + blending.y + blending.z);
	    blending /= vec3(b, b, b);
	    return blending;
	}
edit: just noticed that this code is the same as the one in the second link (that's where I get it) so maybe you already tried it..
0 x

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 177
Joined: Wed Apr 23, 2014 3:49 pm
x 20

Re: Triplanar mapping

Post by TaaTT4 » Thu Oct 05, 2017 7:36 pm

xrgo wrote: try this blending I used to use

Code: Select all

	vec3 getTriPlanarBlend(vec3 _wNorm){
	    // in wNorm is the world-space normal of the fragment
	    vec3 blending = abs( _wNorm );
	    blending = normalize(max(blending, 0.00001)); // Force weights to sum to 1.0
	    float b = (blending.x + blending.y + blending.z);
	    blending /= vec3(b, b, b);
	    return blending;
	}
edit: just noticed that this code is the same as the one in the second link (that's where I get it) so maybe you already tried it..
Yep, I've begun with your blending at the beginning, but I switched to pow approach because I liked it more (looking at the example images).
Btw, those are the results:
Image
Image
More or less, the same crop circles festival as before :evil:
0 x
Senior game programmer at Vae Victis
Working on Racecraft

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1064
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 83

Re: Triplanar mapping

Post by xrgo » Thu Oct 05, 2017 9:00 pm

what if you output the normals...?
I had a problem with that while ago
http://www.ogre3d.org/forums/viewtopic. ... 64#p538419
but few moments later matias pushed a fix
0 x

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 177
Joined: Wed Apr 23, 2014 3:49 pm
x 20

Re: Triplanar mapping

Post by TaaTT4 » Thu Oct 05, 2017 9:18 pm

xrgo wrote: what if you output the normals...?
Here they are:
Image
They appear to be correct, I guess...

What is not really clear to me is the purpouse of the * 2.0f - 1.0f in the sampling of the normals texture (terrainNormals.Sample( terrainNormalsSamplerState, inPs.uv0.xy ).xyz * 2.0f - 1.0f).
Btw, this operation is present even in GLSL so I presume is needed for something.
0 x
Senior game programmer at Vae Victis
Working on Racecraft

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1064
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 83

Re: Triplanar mapping

Post by xrgo » Thu Oct 05, 2017 9:31 pm

TaaTT4 wrote:What is not really clear to me is the purpouse of the * 2.0f - 1.0f
that's usually how you get normals from unsigned textures, normals at some point might be negative, but textures usually goes from 0 to 1, by multipliying by 2 and substracting 1 you recenter the values.. so if you have a value of 0.3 for one channel (axis) of the texture after applying thistransform becomes 0.3*2-1= -0.4 and you get your negative value =D
0 x

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 177
Joined: Wed Apr 23, 2014 3:49 pm
x 20

Re: Triplanar mapping

Post by TaaTT4 » Thu Oct 05, 2017 9:38 pm

xrgo wrote:
TaaTT4 wrote:What is not really clear to me is the purpouse of the * 2.0f - 1.0f
that's usually how you get normals from unsigned textures, normals at some point might be negative, but textures usually goes from 0 to 1, by multipliying by 2 and substracting 1 you recenter the values.. so if you have a value of 0.3 for one channel (axis) of the texture after applying thistransform becomes 0.3*2-1= -0.4 and you get your negative value =D
It makes sense.

So, everything is correct in theory, but sucks practically... WTF
0 x
Senior game programmer at Vae Victis
Working on Racecraft

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1064
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 83

Re: Triplanar mapping

Post by xrgo » Thu Oct 05, 2017 9:55 pm

I feel there's something wrong about your normals... I use the same map as you and it looks like this:
Image
as you can see its mostly green (tried to mimic the height, and in fact looks more height than yours, still greener)
are you sure you have the fix I told you before applied?

or maybe its the lightning affecting the screenshot, try returning right after showing the normals

Code: Select all

@property( !detail_maps_normal )
	// Geometric normal
	nNormal = texture( terrainNormals, inPs.uv0.xy ).xyz * 2.0 - 1.0;

outColour.xyz = nNormal.xyz*10;
return;
....
0 x

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 177
Joined: Wed Apr 23, 2014 3:49 pm
x 20

Re: Triplanar mapping

Post by TaaTT4 » Thu Oct 05, 2017 10:12 pm

Lighting doesn't affect visualization.

Mmhhh... I have a script that copies and builds Terra example as a lib for my project.
I'm not at PC right now, but I have to double check it hasn't silently failed for some reason.

The other difference between you and me is the Render System (I presume you're with OpenGL), but it shouldn't affect normals.
I'll continue the investigation tomorrow morning.
Thanks for the help.
0 x
Senior game programmer at Vae Victis
Working on Racecraft

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 177
Joined: Wed Apr 23, 2014 3:49 pm
x 20

Re: Triplanar mapping

Post by TaaTT4 » Fri Oct 06, 2017 11:08 am

TaaTT4 wrote: Mmhhh... I have a script that copies and builds Terra example as a lib for my project.
I'm not at PC right now, but I have to double check it hasn't silently failed for some reason.
I'm a moron: my script has miserably failed without logging any warning/error.
Now that I've put Matias fix inside everything works OK.

Thanks for the help xrgo.
I really appreciated it.
0 x
Senior game programmer at Vae Victis
Working on Racecraft

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1064
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 83

Re: Triplanar mapping

Post by xrgo » Fri Oct 06, 2017 1:27 pm

Awesome! I would like a screenshot :3
0 x

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 177
Joined: Wed Apr 23, 2014 3:49 pm
x 20

Re: Triplanar mapping

Post by TaaTT4 » Tue Oct 10, 2017 4:51 pm

xrgo wrote:Awesome! I would like a screenshot :3
Unfortunately, you'll have to wait a bit for artists :wink:
0 x
Senior game programmer at Vae Victis
Working on Racecraft

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1064
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 83

Re: Triplanar mapping

Post by xrgo » Tue Oct 10, 2017 4:58 pm

TaaTT4 wrote: Unfortunately, you'll have to wait a bit for artists :wink:
xD I meant the one with the circles, just to compare... but only if it takes you 10 seconds, don't bother too much ;D
0 x

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 177
Joined: Wed Apr 23, 2014 3:49 pm
x 20

Re: Triplanar mapping

Post by TaaTT4 » Tue Oct 10, 2017 5:13 pm

Here they are:
Image
Image

It's perfect!
I've added another image where the terrain has a bit of slope since in the small hill the triplanar mapping is barely visible now.
0 x
Senior game programmer at Vae Victis
Working on Racecraft

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1064
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 83

Re: Triplanar mapping

Post by xrgo » Tue Oct 10, 2017 6:21 pm

Niiiiiiiice!!!!!!!
0 x

Post Reply