Normal Based Texture Shader For Unity

Normal Based Texturing

This shader uses the normals of the mesh to determine what texture is to be applied.
We will get to know how to access normal data in the shader as well as how to apply a texture based on it.
This is what we will end up with after getting normal data :
Image Shows Normals Of Objects
Now let's look the structs needed :
struct appdata
{
 float4 vertex : POSITION;
 float2 uv : TEXCOORD0;
 float3 normal : NORMAL;
};
struct v2f
{
 float2 uv : TEXCOORD0;
 fixed4 norm : COLOR;
 float4 vertex : SV_POSITION;
};
As you can see I added an appdata member called float3 normal of type 'NORMAL', this will be used in the vertex shader to then later on pass to the fragment shader.
In the v2f struct I added a member called fixed4 norm of type COLOR, this will be used in fragment shader to do the actual work.
Let's see what the vertex shader is doing now:
v2f vert (appdata v)
{
 v2f o;
 o.vertex = UnityObjectToClipPos(v.vertex);
 o.norm.xyz = v.normal;
 o.norm.w = 1.0;
 o.uv = TRANSFORM_TEX(v.uv, _Tex1);
 return o;
}
It's taking in an appdata struct and outputting a v2f struct - which will be used in fragment shader.
We are assigning the norm value with the actual normal data from the mesh.
As norm is actually a colour RGB is XYZ, so o.norm = v.normal will assign the RGB values directly and o.norm.w = 1.0 makes sure alpha is at 100%.
So if you want the output from the image you saw before you make the fragment shader output the 'norm' value :
fixed4 frag (v2f i) : SV_Target
{
 return abs(i.norm);
}
We are using abs(i.norm) because we don't want dark or black parts to show up on the object.
Now we will see how to add textures based on the normal in the fragment shader.
We will end up with something that looks like this:
3 textures based on x , y and z axis
We need to add three texture properties:
Properties
{
 _Tex1 ("Texture 1", 2D) = "white" {}
 _Tex2("Texture 2", 2D) = "white"{}
 _Tex3("Texture 3", 2D) = "white"{}
}
What are they:
sampler2D _Tex1;
sampler2D _Tex2;
sampler2D _Tex3;
float4 _Tex1_ST;
Now finally... the fragment shader:
fixed4 frag (v2f i) : SV_Target
{
 fixed4 col1 = tex2D(_Tex1, i.uv);
 fixed4 col2 = tex2D(_Tex2, i.uv);
 fixed4 col3 = tex2D(_Tex3, i.uv);
 col1 *= abs(dot(i.norm.xyz, float3(0, 0, 1)));
 col2 *= abs(dot(i.norm.xyz, float3(0, 1, 0)));
 col3 *= abs(dot(i.norm.xyz, float3(1, 0, 0)));
 return ((col1 +col2 + col3)/3) * 1.2;
}
After we take the three colours from the UV map we then multiply each of those with a value that shows how close the normal is to the X, Y & Z axis.
col1 *= abs(dot(i.norm.xyz, float3(0, 0, 1)));
The dot function between the normal and an axis will return a value between -1.0 and +1.0 then we use the abs ( absolute ) function which gives only the magnitude without the sign.
We then use that value and multiply with the colour.
return ((col1 +col2 + col3)/3) * 1.2;
We return a colour which is the average of all those colours and we multiply by a value because the image is a bit dark.
You can get source code HERE.
If you like programming shaders make sure you check these out : Shader Tutorials
Support Bitshift Programmer by leaving a like on Bitshift Programmer Facebook Page and be updated as soon as there is a new blog post.
If you have any questions that you might have about shaders or unity development in general don't be shy and leave a message on my facebook page or down in the comments.