Shade Based on Normal Map World Position Angle (Updated)


I have been reading for days to try and figure this out, but I can’t find a way to make this happen. I’m a decent shader programmer I’m just not familiar with how to get angles through shader scripting.

Maybe this:

float3 viewN = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);

How can I shade based on the normal map and world angle so that a texture is only rendered at the normal map angles? From what I understand normals don’t render past a certain angle, unless I’m mistaken. How do you do this through shaders?

I’d like to have a diffuse shader with normals that would be used to calculate the angle for the overlay texture to render onto. So I’d have a diffuse, normal, and an overlay that would be in the middle because it would only render according to the normals of the texture.

For a visual something like the video below, except this would only be based off the normal map not heightmaps:

Update Newer:
Alright I’ve got a decent shader working, but it only works because the main snow texture is partially transparent. The bump acts as a map for the snow to lay, so it kind of works. I also have to have 2 materials, the original bump specular, and the snow shader. This also allows your to control the alpha level of the texture. This way is unpractical as I can’t make a transparent texture for every texture in the game, the shader needs to do it itself.

How can I make it so I can place just a normal transparent white texture and the bump map will guide that white texture to lay where it’s supposed to, according to the bumps only. Also only laying till a certain angle to act like snow. I thought I’d receive more help on Unity Answers, I’ve been doing everything myself. It’d be nice to get some help as I’m literally just guessing with most of this stuff.

Update Old:
So I managed to make some progress. I found a shader on the Unity wiki that shades the object based on light shinning on the normals of the texture. It gives a similar looking effect, we just need to change it so it only works on certain angles, is always on; not just affected by light, and to make sure the density can be controlled.

Here’s a screen shot:


Here’s the shader, that allows the object’s normals to be affected by by light, we can use this as a reference as this is the closest thing I’ve found as a starting point:

This link contains all the parameters and shader inputs needed to make this happen:

shader "Bump Spec Rim" {

 Properties {
    _Color ("Main Color", Color) = (1,1,1,0.5)
    _SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
    _Shininess ("Shininess", Range (0.03, 1)) = 0.078125
    _MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
    _BumpMap ("Bumpmap (RGB) Rim-Light Ramp (A)", 2D) = "bump" {}
    _RimLightColor ("Rimlight Color", Color) = (0.6, 0.6, 0.7, 1.0)
    _RimLightRamp ("Rimlight Ramp", 2D) = "white" {}

 SubShader {
      //Self-Illumination Depending on Facing Rotation
      Pass {
           Tags {"LightMode" = "PixelOrNone"}
        Blend AppSrcAdd AppDstAdd
           Color [_PPLAmbient]

           // profiles arbfp1
           #pragma vertex vert
           #pragma fragment frag
           #pragma fragmentoption ARB_fog_exp2

           #include "UnityCG.cginc"

           sampler2D _BumpMap;
           sampler2D _RimLightRamp;
           sampler2D _MainTex;
           float4 _RimLightColor;
           float4 _Color;

           struct v2f {
                float2  uv;
                float3  tangentSpaceLightDir;

           v2f vert (appdata_tan v)
                v2f o;
                PositionFog( v.vertex, o.pos, o.fog );
                o.uv = TRANSFORM_UV(0);
                float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));
                float3 binormal = cross( normalize(v.normal), 
           normalize( );
           float3x3 rotation = float3x3(, binormal, v.normal );
           o.tangentSpaceLightDir = mul(rotation, viewDir);

                return o;
           half4 frag (v2f i) : COLOR
           half3 tangentSpaceNormal = (tex2D(_BumpMap, i.uv).rgb * 2.0) - 1.0;
           half4 result = float4(0, 0, 0, 1);
           //You might want to normalize tangentSpaceNormal and  
           //but for most meshes this will most likely have minimal, if any, impact  
           on quality.
           float rampSample = dot(tangentSpaceNormal, i.tangentSpaceLightDir);
           float intensity = tex2D(_RimLightRamp, rampSample.xx).r;
           result.rgb = intensity * _RimLightColor.rgb;
           result.rgb += tex2D(_MainTex, i.uv).rgb * _PPLAmbient.rgb;
           return result;
      UsePass "Bumped Specular/PPL"

 FallBack "Bumped Specular", 1

internally for shader any normal-mapped surface is flat, in your case you need (as i understand) to hide some areas from surface by another ones based on normal-map.

the problem is shader while rendering surface’s pixel can’t get any information about any other surface’s pixels. so it can’t calculate overlapping by other pixel.

the solution is:

  • make a geometry-based big areas and normal-map based small details
  • make a polygon with normal-map more detailed (more vertexes and tris) and use vertex shader to move verts along normals
  • limit view angle and don’t let user to look at surface in sharp angles