World Space Mapping with Normals

I am trying to create a shader that will speed up the process of texturing static objects with repeat textures. In this case I’m working on a skirting board.

So far I have a shader that uses world positions to apply a diffuse map but when trying to use this same method to apply the normal map, the normal map isn’t working off the tangent.

As you can see, the normal map maps to the face as should be correct. (This is not Unpacked at this stage and is applied to the Albedo)

When changing from Albedo to Normal, it does this

See below for my shader

Shader "Custom/World Normal" {

	Properties 
	{
		_Tint ("Color", 2D) = "white" {}
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_Ramp ("Shading Ramp", 2D) = "white"{}
		_Normal ("Normal", 2D) = "bump"{}
	}
	
	SubShader 
	{
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Ramp
		#pragma target 3.0

		sampler2D _MainTex;
		sampler2D _Ramp;
		sampler2D _Tint;
		sampler2D _Normal;
		
		struct Input 
		{
			float2 uv_MainTex;
			float3 worldPos;
		};

		half4 LightingRamp (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
		{
			half NdotL = dot(s.Normal, lightDir);
			half diff = NdotL * 0.5 + 0.5;
			half3 ramp = tex2D(_Ramp,  float2(diff)).rgb;
						
			half4 c;
			
			c.rgb = s.Albedo * _LightColor0.rgb * (ramp * atten * 2);
			c.a = s.Alpha;
			return c;
		}

		void surf (Input IN, inout SurfaceOutput o) {
			
			half4 x = tex2D (_MainTex, IN.worldPos.yz);
			half4 y = tex2D (_MainTex, IN.worldPos.xz);
			half4 z = tex2D (_MainTex, IN.worldPos.xy);
			half4 c = tex2D (_Tint, IN.worldPos.xy);
			c = lerp(c,x,abs(o.Normal.r));
			c = lerp(c,y,abs(o.Normal.g));
			c = lerp(c,z,abs(o.Normal.b));
			
			half4 xn = tex2D(_Normal, IN.worldPos.zy);
			half4 yn = tex2D(_Normal, IN.worldPos.zx);
			half4 zn = tex2D(_Normal, IN.worldPos.xy);
			half4 cn = lerp(xn, yn, abs(o.Normal.g));
			cn = lerp(cn,zn,abs(o.Normal.b));
			half3 bump = UnpackNormal(cn);


			o.Normal = bump;
//			o.Albedo = bump;
			o.Albedo = c.rgb;
//			o.Alpha = c.a;
		}
		ENDCG
	} 
	FallBack "Diffuse"
}

It looks like your normal map already has the correct red and green channel and is not being compressed by unity. If you were to apply the normal map to the albedo and the channels were packed, it would not look “correct” but in your example it does look like the channels are correct already. If that exact output seen on the first screenshot is what you’re unpacking, you’re going to get something messed up for sure. Try just doing:
half3 bump = normalize( cn*2-1 ).rgb;

This might be a misconception by me though.

747823; No, that’s what UnpackNormal does.

Pru: Currently you’re lerping between projections based on o.Normal… before o.Normal even has something in it (and it will never have data that’s useful for lerping between because it’ll be in tangent space, not world space). It’s quite amazing your results get as far as they do.

You’ll likely want to have a custom vertex shader in there that spits out the worldNormal (taken from the vertex normals) and then use that to do your blending, rather than o.Normal.

Thanks for the replies

o.Normal only gives me data when using custom lighting. I knew it wasn’t the official way to do it but I’m finding it hard getting a foot hold on learning vertex shaders.

If anyone knows of any good tutorials or series of tutorials on vertex shaders that’d be a great help!

EDIT:
I’ve come up with this, it’s not perfect but it works pretty well…

Shader "World/Bump Gloss" {
	Properties {
		_MainTex ("Base (RGB), Gloss (A)", 2D) = "white" {}
		_Normal ("Normal", 2D) = "bump" {}
		_Offset ("Offset", Vector) = (0,0,0,0)
		_Repeat ("Repeat", Vector) = (1,1,1,0)
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Lambert vertex:vert

		sampler2D _MainTex;
		sampler2D _Normal;
		
		float3 _Offset;
		float3 _Repeat;

		struct Input 
		{
			float3 vertColors;
			float3 worldPos;
		};
		
		void vert (inout appdata_full v, out Input o)
		{
			o.vertColors = abs(v.normal);
		}

		void surf (Input IN, inout SurfaceOutput o) 
		{
			float3 uv = IN.worldPos.xyz;
			uv *= _Repeat;
			uv += _Offset;
			half4 x = tex2D (_MainTex, uv.zy);
			half4 y = tex2D (_MainTex, uv.zx);
			half4 z = tex2D (_MainTex, uv.xy);
			half4 c = float4(1,1,1,1);
			c = lerp(c,x,IN.vertColors.r);
			c = lerp(c,y,IN.vertColors.g);
			c = lerp(c,z,IN.vertColors.b);
			
			x = tex2D(_Normal, uv.zy);
			y = tex2D(_Normal, uv.zx);
			z = tex2D(_Normal, uv.xy);
			half4 n = float4(1,1,1,1);
			n = lerp(n,x,IN.vertColors.r);
			n = lerp(n,y,IN.vertColors.g);
			n = lerp(n,z,IN.vertColors.b);
			
			o.Normal = UnpackNormal(n);
			o.Albedo = c.rgb;
			o.Gloss = c.a;
		}
		ENDCG
	} 
	FallBack "Diffuse"
}