Silhouette Outlined shader - stop the silhouette from showing up on children objects?

Hey guys, I found this nice old shader here:
http://wiki.unity3d.com/index.php?title=Silhouette-Outlined_Diffuse

And tested it on mobile to find its fairly decent and does what I need, which is to have a players/AI cars show up behind structures as a silhouette when its hidden from view:

And that is great, but an issue I’m having is that the tires of the vehicles are also using this shader, and when they are partially hidden under the body of the car, they are trying to draw the silhouette:

I’m not particularly good with shaders, but as I understand there should be a way I can change the Z render order to allow the silhouette to be hidden under the vehicles body… but visible when the car goes behind a structure.

Any chance one of you shader wizards have a quick solution to this, or at least can point me in the right direction? I’ve seen some similar posts, but none that don’t rely on the standard shader - and since I’m working on a mobile game I can’t use standard shader for performance reasons :confused:

@bgolus - I’ve seen you talking in several threads about possible solutions - could you elaborate what might work for me?

I’ve made a bit of possible progress, though I still need to test more, but I edited the shader like this (notice edit to it at line 34) :

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Outlined/Silhouetted Diffuse" {
    Properties {
        _Color ("Main Color", Color) = (.5,.5,.5,1)
        _OutlineColor ("Outline Color", Color) = (0,0,0,1)
        _Outline ("Outline width", Range (0.0, 0.03)) = .005
        _MainTex ("Base (RGB)", 2D) = "white" { }
    }
CGINCLUDE
#include "UnityCG.cginc"
struct appdata {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
};
struct v2f {
    float4 pos : POSITION;
    float4 color : COLOR;
};
uniform float _Outline;
uniform float4 _OutlineColor;
v2f vert(appdata v) {
    // just make a copy of incoming vertex data but scaled according to normal direction
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);
    float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
    float2 offset = TransformViewToProjection(norm.xy);
    o.pos.xy += offset * o.pos.z * _Outline;
    o.color = _OutlineColor;
    return o;
}
ENDCG
    SubShader {
        Tags { "Queue" = "Geometry+5" } //Transparent" }   // EDIT HERE!!!!!!!!!
        // note that a vertex shader is specified here but its using the one above
        Pass {
            Name "OUTLINE"
            Tags { "LightMode" = "Always" }
            Cull Off
            ZWrite Off
            ZTest Always
            ColorMask RGB // alpha not used
            // you can choose what kind of blending mode you want for the outline
            Blend SrcAlpha OneMinusSrcAlpha // Normal
            //Blend One One // Additive
            //Blend One OneMinusDstColor // Soft Additive
            //Blend DstColor Zero // Multiplicative
            //Blend DstColor SrcColor // 2x Multiplicative
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
half4 frag(v2f i) :COLOR {
    return i.color;
}
ENDCG
        }
        Pass {
            Name "BASE"
            ZWrite On
            ZTest LEqual
            Blend SrcAlpha OneMinusSrcAlpha
            Material {
                Diffuse [_Color]
                Ambient [_Color]
            }
            Lighting On
            SetTexture [_MainTex] {
                ConstantColor [_Color]
                Combine texture * constant
            }
            SetTexture [_MainTex] {
                Combine previous * primary DOUBLE
            }
        }
    }
    SubShader {
        Tags { "Queue" = "Transparent" }
        Pass {
            Name "OUTLINE"
            Tags { "LightMode" = "Always" }
            Cull Front
            ZWrite Off
            ZTest Always
            ColorMask RGB
            // you can choose what kind of blending mode you want for the outline
            Blend SrcAlpha OneMinusSrcAlpha // Normal
            //Blend One One // Additive
            //Blend One OneMinusDstColor // Soft Additive
            //Blend DstColor Zero // Multiplicative
            //Blend DstColor SrcColor // 2x Multiplicative
            //CGPROGRAM
            //#pragma vertex vert
            //#pragma exclude_renderers gles xbox360 ps3
            //ENDCG
            SetTexture [_MainTex] { combine primary }
        }
        Pass {
            Name "BASE"
            ZWrite On
            ZTest LEqual
            Blend SrcAlpha OneMinusSrcAlpha
            Material {
                Diffuse [_Color]
                Ambient [_Color]
            }
            Lighting On
            SetTexture [_MainTex] {
                ConstantColor [_Color]
                Combine texture * constant
            }
            SetTexture [_MainTex] {
                Combine previous * primary DOUBLE
            }
        }
    }
    Fallback "Diffuse"
}

Can anybody confirm/deny this should be ok? Again - I am shooting in the dark here :stuck_out_tongue:

EDIT: Seems to do the trick…


In the gif above, it does still show the silhouette of the body on the police cars lights, but thats just because I forgot to add the shader to the object… it is working as expected now :slight_smile:

I ran into another semi-related issue only on mobile:

Here you can see the arrow that points the player towards the goal has its outline all sorts of messed up - but I found a suggestion on UA that has a possible solution:

And so I edited that into my variant of the shader here:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Outlined/Silhouetted Diffuse" {
    Properties {
        _Color ("Main Color", Color) = (.5,.5,.5,1)
        _OutlineColor ("Outline Color", Color) = (0,0,0,1)
        //_Outline ("Outline width", Range (0.0, 0.03)) = .005
        _Outline ("Outline width", Float) = 4 // CHANGED
        _MainTex ("Base (RGB)", 2D) = "white" { }
    }
CGINCLUDE
#include "UnityCG.cginc"
struct appdata {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
};
struct v2f {
    float4 pos : POSITION;
    float4 color : COLOR;
};
uniform float _Outline;
uniform float4 _OutlineColor;
 /*
v2f vert(appdata v) {
    // just make a copy of incoming vertex data but scaled according to normal direction
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);
    float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
    float2 offset = TransformViewToProjection(norm.xy);
    o.pos.xy += offset * o.pos.z * _Outline;
    o.color = _OutlineColor;
    return o;
}
*/
v2f vert(appdata v) {
     v2f o;
     o.pos = v.vertex;
     o.pos.xyz += v.normal.xyz *_Outline*0.01;
     o.pos = UnityObjectToClipPos(o.pos);
     o.color = _OutlineColor;
     return o;
 }
ENDCG
    SubShader {
        Tags { "Queue" = "Geometry+5" } //Transparent" }   // EDIT HERE!!!!!!!!!
        // note that a vertex shader is specified here but its using the one above
        Pass {
            Name "OUTLINE"
            Tags { "LightMode" = "Always" }
            Cull Off
            ZWrite Off
            ZTest Always
            ColorMask RGB // alpha not used
            // you can choose what kind of blending mode you want for the outline
            Blend SrcAlpha OneMinusSrcAlpha // Normal
            //Blend One One // Additive
            //Blend One OneMinusDstColor // Soft Additive
            //Blend DstColor Zero // Multiplicative
            //Blend DstColor SrcColor // 2x Multiplicative
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
half4 frag(v2f i) :COLOR {
    return i.color;
}
ENDCG
        }
        Pass {
            Name "BASE"
            ZWrite On
            ZTest LEqual
            Blend SrcAlpha OneMinusSrcAlpha
            Material {
                Diffuse [_Color]
                Ambient [_Color]
            }
            Lighting On
            SetTexture [_MainTex] {
                ConstantColor [_Color]
                Combine texture * constant
            }
            SetTexture [_MainTex] {
                Combine previous * primary DOUBLE
            }
        }
    }
    SubShader {
        Tags { "Queue" = "Transparent" }
        Pass {
            Name "OUTLINE"
            Tags { "LightMode" = "Always" }
            Cull Front
            ZWrite Off
            ZTest Always
            ColorMask RGB
            // you can choose what kind of blending mode you want for the outline
            Blend SrcAlpha OneMinusSrcAlpha // Normal
            //Blend One One // Additive
            //Blend One OneMinusDstColor // Soft Additive
            //Blend DstColor Zero // Multiplicative
            //Blend DstColor SrcColor // 2x Multiplicative
            //CGPROGRAM
            //#pragma vertex vert
            //#pragma exclude_renderers gles xbox360 ps3
            //ENDCG
            SetTexture [_MainTex] { combine primary }
        }
        Pass {
            Name "BASE"
            ZWrite On
            ZTest LEqual
            Blend SrcAlpha OneMinusSrcAlpha
            Material {
                Diffuse [_Color]
                Ambient [_Color]
            }
            Lighting On
            SetTexture [_MainTex] {
                ConstantColor [_Color]
                Combine texture * constant
            }
            SetTexture [_MainTex] {
                Combine previous * primary DOUBLE
            }
        }
    }
    Fallback "Diffuse"
}

NOTE: You may need to adjust the width of the outline depending on your use, but for things I just wanted a silhouette on I used 0, and for things I wanted an outline also I used 15.

If you don’t see me replying again with more issues, that means it worked on mobile :stuck_out_tongue:

1 Like