adding an outline to Unity 5 standard shader

Is it possible to add an outline to the new Unity 5 standard shader? Any suggestions on how to go about doing so?

1 Like

Bump, would love to know if anyone has done this

This would be greatly appreciated if anyone has figured it out.

Trying this as well, but haven’t had any luck.

You could use a post processing edge detect. Unity - Edge Detect Effect Normals
Or if you for some reason need to do it in the surface shader, find the source for Default shader and add another pass that draws the surface back-face extruded along the normal, you probably want that outline unlit and untextured also.

I’m NOT a graphics developer, and I just barely understand how surface / vert and frag shaders even work, let alone PBR.

That said, I did manage to hack together a modified version of the Standard shader to include an outline, that ā€œseem to workā€ in Forward rendering (breaks in other rendering paths).

It’s based on the additional pass with normal extrusion method, which works best for somewhat rounded meshes (acute angles expose the weakness in this method: it leaves gaps between the extruded faces).

Search for ā€œOutlineā€ to see comments in the code, where I marked the modifications I did to the Standard shader. Also, you can uncomment a line to get the ā€œsee throughā€ effect, where the filled silhouette is rendered on top of other things occluding the object.

Another limitation is that the Standard shader comes with a sweet custom editor, but it’s marked as ā€œinternalā€ so I can’t extend it, and I haven’t yet attempted recreating it from scratch. The workaround is to comment it (second-to-last line) to use the default shader editor that exposes the new ā€œOutline Extrusionā€ and ā€œOutline Colorā€ settings, or uncomment it to use the custom editor for the Standard shader and access the _Outline and _OutColor attributes via code (with GetComponent().material.SetFloat(ā€œ_Outlineā€, …) and GetComponent().material.SetColor(ā€œ_OutColorā€, …)

Here’s my little frankenstein of a shader:

Shader "Standard Outlined"
{
    Properties
    {
        [LM_Albedo] [LM_Transparency] _Color("Color", Color) = (1,1,1,1)  
        [LM_MasterTilingOffset] [LM_Albedo] _MainTex("Albedo", 2D) = "white" {}
      
        [LM_TransparencyCutOff] _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5

        [LM_Glossiness] _Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5
        [LM_Metallic] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
        [LM_Metallic] [LM_Glossiness] _MetallicGlossMap("Metallic", 2D) = "white" {}

         _BumpScale("Scale", Float) = 1.0
        [LM_NormalMap] _BumpMap("Normal Map", 2D) = "bump" {}

        _Parallax ("Height Scale", Range (0.005, 0.08)) = 0.02
        _ParallaxMap ("Height Map", 2D) = "black" {}

        _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
        _OcclusionMap("Occlusion", 2D) = "white" {}

        [LM_Emission] _EmissionColor("Color", Color) = (0,0,0)
        [LM_Emission] _EmissionMap("Emission", 2D) = "white" {}
      
        _DetailMask("Detail Mask", 2D) = "white" {}

        _DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {}
        _DetailNormalMapScale("Scale", Float) = 1.0
        _DetailNormalMap("Normal Map", 2D) = "bump" {}

        [Enum(UV0,0,UV1,1)] _UVSec ("UV Set for secondary textures", Float) = 0

        // UI-only data
        [KeywordEnum(None, Realtime, Baked)]  _Lightmapping ("GI", Int) = 1
        [HideInInspector] _EmissionScaleUI("Scale", Float) = 0.0
        [HideInInspector] _EmissionColorUI("Color", Color) = (1,1,1)

        // Blending state
        [HideInInspector] _Mode ("__mode", Float) = 0.0
        [HideInInspector] _SrcBlend ("__src", Float) = 1.0
        [HideInInspector] _DstBlend ("__dst", Float) = 0.0
        [HideInInspector] _ZWrite ("__zw", Float) = 1.0

        // Outline
        _Outline ("Outline Extrusion", Range(-1,1)) = 0.05
        _OutColor ("Outline Color", Color) = (1,1,1,1)
    }

    CGINCLUDE
        //@TODO: should this be pulled into a shader_feature, to be able to turn it off?
        #define _GLOSSYENV 1
        #define UNITY_SETUP_BRDF_INPUT MetallicSetup
    ENDCG

    SubShader
    {
        Tags { "RenderType"="Opaque" "PerformanceChecks"="False" }
        LOD 300

        // Outline addition starts here
        Cull Off
        ZWrite Off
        //ZTest Always // Uncomment for "see through"

        CGPROGRAM
            #pragma surface surf Solid vertex:vert
            struct Input {
                float4 color : COLOR;
            };

            fixed4 _OutColor;
            float _Outline;

        fixed4 LightingSolid (SurfaceOutput s, half3 lightDir, half atten) {
        return _OutColor;
        }

            void vert (inout appdata_full v) {
                v.vertex.xyz += v.normal * _Outline;
            }

            void surf (Input IN, inout SurfaceOutput o) {
                o.Albedo = _OutColor.rgb;
            }
        ENDCG

        Cull Back
        ZWrite On  
        ZTest LEqual
        // Outline addition ends here

        // ------------------------------------------------------------------
        //  Base forward pass (directional light, emission, lightmaps, ...)
        Pass
        {
            Name "FORWARD"
            Tags { "LightMode" = "ForwardBase" }

            Blend [_SrcBlend] [_DstBlend]
            ZWrite [_ZWrite]

            CGPROGRAM
            #pragma target 3.0
            // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            #pragma exclude_renderers gles
          
            // -------------------------------------
                  
            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _EMISSION
            //ALWAYS ON shader_feature _GLOSSYENV
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP
          
            #pragma multi_compile_fwdbase
            #pragma multi_compile_fog
              
            #pragma vertex vertForwardBase
            #pragma fragment fragForwardBase

            #include "UnityStandardCore.cginc"

            ENDCG
        }
        // ------------------------------------------------------------------
        //  Additive forward pass (one light per pass)
        Pass
        {
            Name "FORWARD_DELTA"
            Tags { "LightMode" = "ForwardAdd" }
            Blend [_SrcBlend] One
            Fog { Color (0,0,0,0) } // in additive pass fog should be black
            ZWrite Off
            ZTest LEqual

            CGPROGRAM
            #pragma target 3.0
            // GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            #pragma exclude_renderers gles

            // -------------------------------------

          
            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP
          
            #pragma multi_compile_fwdadd_fullshadows
            #pragma multi_compile_fog
          
            #pragma vertex vertForwardAdd
            #pragma fragment fragForwardAdd

            #include "UnityStandardCore.cginc"

            ENDCG
        }
        // ------------------------------------------------------------------
        //  Shadow rendering pass
        Pass {
            Name "ShadowCaster"
            Tags { "LightMode" = "ShadowCaster" }
          
            ZWrite On ZTest LEqual

            CGPROGRAM
            #pragma target 3.0
            // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            #pragma exclude_renderers gles
          
            // -------------------------------------


            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma multi_compile_shadowcaster

            #pragma vertex vertShadowCaster
            #pragma fragment fragShadowCaster

            #include "UnityStandardShadow.cginc"

            ENDCG
        }
        // ------------------------------------------------------------------
        //  Deferred pass
        Pass
        {
            Name "DEFERRED"
            Tags { "LightMode" = "Deferred" }

            CGPROGRAM
            #pragma target 3.0
            // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            #pragma exclude_renderers nomrt gles
          

            // -------------------------------------

            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _EMISSION
            //ALWAYS ON shader_feature _GLOSSYENV
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP

            #pragma multi_compile ___ UNITY_HDR_ON
            #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
            #pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
            #pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
          
            #pragma vertex vertDeferred
            #pragma fragment fragDeferred

            #include "UnityStandardCore.cginc"

            ENDCG
        }

        // ------------------------------------------------------------------
        // Extracts information for lightmapping, GI (emission, albedo, ...)
        // This pass it not used during regular rendering.
        Pass
        {
            Name "META"
            Tags { "LightMode"="Meta" }

            Cull Off

            CGPROGRAM
            #pragma vertex vert_meta
            #pragma fragment frag_meta

            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2

            #include "UnityStandardMeta.cginc"
            ENDCG
        }
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" "PerformanceChecks"="False" }
        LOD 150

        // ------------------------------------------------------------------
        //  Base forward pass (directional light, emission, lightmaps, ...)
        Pass
        {
            Name "FORWARD"
            Tags { "LightMode" = "ForwardBase" }

            Blend [_SrcBlend] [_DstBlend]
            ZWrite [_ZWrite]

            CGPROGRAM
            #pragma target 2.0
          
            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _EMISSION
            // ALWAYS ON shader_feature _GLOSSYENV
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP

            #pragma skip_variants SHADOWS_SOFT DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE

            #pragma multi_compile_fwdbase
            #pragma multi_compile_fog
  
            #pragma vertex vertForwardBase
            #pragma fragment fragForwardBase

            #include "UnityStandardCore.cginc"

            ENDCG
        }
        // ------------------------------------------------------------------
        //  Additive forward pass (one light per pass)
        Pass
        {
            Name "FORWARD_DELTA"
            Tags { "LightMode" = "ForwardAdd" }
            Blend [_SrcBlend] One
            Fog { Color (0,0,0,0) } // in additive pass fog should be black
            ZWrite Off
            ZTest LEqual
          
            CGPROGRAM
            #pragma target 2.0

            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP
            #pragma skip_variants SHADOWS_SOFT
          
            #pragma multi_compile_fwdadd_fullshadows
            #pragma multi_compile_fog
          
            #pragma vertex vertForwardAdd
            #pragma fragment fragForwardAdd

            #include "UnityStandardCore.cginc"

            ENDCG
        }
        // ------------------------------------------------------------------
        //  Shadow rendering pass
        Pass {
            Name "ShadowCaster"
            Tags { "LightMode" = "ShadowCaster" }
          
            ZWrite On ZTest LEqual

            CGPROGRAM
            #pragma target 2.0

            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma skip_variants SHADOWS_SOFT
            #pragma multi_compile_shadowcaster

            #pragma vertex vertShadowCaster
            #pragma fragment fragShadowCaster

            #include "UnityStandardShadow.cginc"

            ENDCG
        }

        // ------------------------------------------------------------------
        // Extracts information for lightmapping, GI (emission, albedo, ...)
        // This pass it not used during regular rendering.
        Pass
        {
            Name "META"
            Tags { "LightMode"="Meta" }

            Cull Off

            CGPROGRAM
            #pragma vertex vert_meta
            #pragma fragment frag_meta

            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2

            #include "UnityStandardMeta.cginc"
            ENDCG
        }
    }

    FallBack "VertexLit"
    //CustomEditor "StandardShaderGUI"
}
1 Like

The method above works for me, but it’s a very poor solution. Ideally, an outline should be done in Screen space instead of World space, so we could get rid of the acute angle gaps, and more importantly, set the width of the outline in pixels.

If anyone has any idea to improve the method I describe in the post above, or could ELI5 a way to implement a screen-space outline, I would really, REALLY appreciate it :slight_smile:

Hey!
I hope you guys will see this.
As I also wanted to add an outline to the standard shader, i had it working by adding the code from the ā€œToonBasicOutlineā€ shader like this :

Shader "Standard (Outlined)" {

        Properties
    {
        _Color("Color", Color) = (1,1,1,1)
        _MainTex("Albedo", 2D) = "white" {}
 
        _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5

        _Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5
        [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
        _MetallicGlossMap("Metallic", 2D) = "white" {}

        _BumpScale("Scale", Float) = 1.0
        _BumpMap("Normal Map", 2D) = "bump" {}

        _Parallax ("Height Scale", Range (0.005, 0.08)) = 0.02
        _ParallaxMap ("Height Map", 2D) = "black" {}

        _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
        _OcclusionMap("Occlusion", 2D) = "white" {}

        _EmissionColor("Color", Color) = (0,0,0)
        _EmissionMap("Emission", 2D) = "white" {}
 
        _DetailMask("Detail Mask", 2D) = "white" {}

        _DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {}
        _DetailNormalMapScale("Scale", Float) = 1.0
        _DetailNormalMap("Normal Map", 2D) = "bump" {}

        [Enum(UV0,0,UV1,1)] _UVSec ("UV Set for secondary textures", Float) = 0

        // UI-only data
        [HideInInspector] _EmissionScaleUI("Scale", Float) = 0.0
        [HideInInspector] _EmissionColorUI("Color", Color) = (1,1,1)

        // Blending state
        [HideInInspector] _Mode ("__mode", Float) = 0.0
        [HideInInspector] _SrcBlend ("__src", Float) = 1.0
        [HideInInspector] _DstBlend ("__dst", Float) = 0.0
        [HideInInspector] _ZWrite ("__zw", Float) = 1.0
 
        // -------------------------
        // Added Outline properties
        _OutlineColor ("Outline Color", Color) = (0,0,0,1)
        _Outline ("Outline width", Range (.002, 0.03)) = .005
        // -------------------------
    }

    CGINCLUDE
        #define UNITY_SETUP_BRDF_INPUT MetallicSetup
    ENDCG

/////////////////////////////////////////////////////////////////////////////////////////////

    SubShader
    {
        Tags { "RenderType"="Opaque" "PerformanceChecks"="False" }
        LOD 300

        // ----------------------
        // Start of Outline adding
    
        CGINCLUDE
        #include "UnityCG.cginc"
      
        struct appdata {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
        };
      
        struct v2f {
            float4 pos : SV_POSITION;
            UNITY_FOG_COORDS(0)
            fixed4 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 = mul(UNITY_MATRIX_MVP, v.vertex);

            float3 norm   = normalize(mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal));
            float2 offset = TransformViewToProjection(norm.xy);

            o.pos.xy += offset * o.pos.z * _Outline;
            o.color = _OutlineColor;
            UNITY_TRANSFER_FOG(o,o.pos);
            return o;
        }
        ENDCG      

        Pass {
            Name "OUTLINE"
            Tags { "LightMode" = "Always" }
            Cull Front
            ZWrite On
            ColorMask RGB
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            fixed4 frag(v2f i) : SV_Target
            {
                UNITY_APPLY_FOG(i.fogCoord, i.color);
                return i.color;
            }
            ENDCG
        }
 
        // End of Outline adding
        // ----------------------


        // ------------------------------------------------------------------
        //  Base forward pass (directional light, emission, lightmaps, ...)
        Pass
        {
            Name "FORWARD"
            Tags { "LightMode" = "ForwardBase" }

            Blend [_SrcBlend] [_DstBlend]
            ZWrite [_ZWrite]

            CGPROGRAM
            #pragma target 3.0
            // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            #pragma exclude_renderers gles
           
            // -------------------------------------
                   
            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP 
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP
           
            #pragma multi_compile_fwdbase
            #pragma multi_compile_fog
               
            #pragma vertex vertForwardBase
            #pragma fragment fragForwardBase

            #include "UnityStandardCore.cginc"

            ENDCG
        }
        // ------------------------------------------------------------------
        //  Additive forward pass (one light per pass)
        Pass
        {
            Name "FORWARD_DELTA"
            Tags { "LightMode" = "ForwardAdd" }
            Blend [_SrcBlend] One
            Fog { Color (0,0,0,0) } // in additive pass fog should be black
            ZWrite Off
            ZTest LEqual

            CGPROGRAM
            #pragma target 3.0
            // GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            #pragma exclude_renderers gles

            // -------------------------------------

           
            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP
           
            #pragma multi_compile_fwdadd_fullshadows
            #pragma multi_compile_fog
           
            #pragma vertex vertForwardAdd
            #pragma fragment fragForwardAdd

            #include "UnityStandardCore.cginc"

            ENDCG
        }
        // ------------------------------------------------------------------
        //  Shadow rendering pass
        Pass {
            Name "ShadowCaster"
            Tags { "LightMode" = "ShadowCaster" }
           
            ZWrite On ZTest LEqual

            CGPROGRAM
            #pragma target 3.0
            // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            #pragma exclude_renderers gles
           
            // -------------------------------------


            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma multi_compile_shadowcaster

            #pragma vertex vertShadowCaster
            #pragma fragment fragShadowCaster

            #include "UnityStandardShadow.cginc"

            ENDCG
        }
        // ------------------------------------------------------------------
        //  Deferred pass
        Pass
        {
            Name "DEFERRED"
            Tags { "LightMode" = "Deferred" }

            CGPROGRAM
            #pragma target 3.0
            // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            #pragma exclude_renderers nomrt gles
           

            // -------------------------------------

            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP

            #pragma multi_compile ___ UNITY_HDR_ON
            #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
            #pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
            #pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
           
            #pragma vertex vertDeferred
            #pragma fragment fragDeferred

            #include "UnityStandardCore.cginc"

            ENDCG
        }

        // ------------------------------------------------------------------
        // Extracts information for lightmapping, GI (emission, albedo, ...)
        // This pass it not used during regular rendering.
        Pass
        {
            Name "META" 
            Tags { "LightMode"="Meta" }

            Cull Off

            CGPROGRAM
            #pragma vertex vert_meta
            #pragma fragment frag_meta

            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2

            #include "UnityStandardMeta.cginc"
            ENDCG
        }
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" "PerformanceChecks"="False" }
        LOD 150

        // ------------------------------------------------------------------
        //  Base forward pass (directional light, emission, lightmaps, ...)
        Pass
        {
            Name "FORWARD" 
            Tags { "LightMode" = "ForwardBase" }

            Blend [_SrcBlend] [_DstBlend]
            ZWrite [_ZWrite]

            CGPROGRAM
            #pragma target 2.0
           
            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _EMISSION 
            #pragma shader_feature _METALLICGLOSSMAP 
            #pragma shader_feature ___ _DETAIL_MULX2
            // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP

            #pragma skip_variants SHADOWS_SOFT DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE

            #pragma multi_compile_fwdbase
            #pragma multi_compile_fog
   
            #pragma vertex vertForwardBase
            #pragma fragment fragForwardBase

            #include "UnityStandardCore.cginc"

            ENDCG
        }
        // ------------------------------------------------------------------
        //  Additive forward pass (one light per pass)
        Pass
        {
            Name "FORWARD_DELTA"
            Tags { "LightMode" = "ForwardAdd" }
            Blend [_SrcBlend] One
            Fog { Color (0,0,0,0) } // in additive pass fog should be black
            ZWrite Off
            ZTest LEqual
           
            CGPROGRAM
            #pragma target 2.0

            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP
            #pragma skip_variants SHADOWS_SOFT
           
            #pragma multi_compile_fwdadd_fullshadows
            #pragma multi_compile_fog
           
            #pragma vertex vertForwardAdd
            #pragma fragment fragForwardAdd

            #include "UnityStandardCore.cginc"

            ENDCG
        }
        // ------------------------------------------------------------------
        //  Shadow rendering pass
        Pass {
            Name "ShadowCaster"
            Tags { "LightMode" = "ShadowCaster" }
           
            ZWrite On ZTest LEqual

            CGPROGRAM
            #pragma target 2.0

            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma skip_variants SHADOWS_SOFT
            #pragma multi_compile_shadowcaster

            #pragma vertex vertShadowCaster
            #pragma fragment fragShadowCaster

            #include "UnityStandardShadow.cginc"

            ENDCG
        }

        // ------------------------------------------------------------------
        // Extracts information for lightmapping, GI (emission, albedo, ...)
        // This pass it not used during regular rendering.
        Pass
        {
            Name "META" 
            Tags { "LightMode"="Meta" }

            Cull Off

            CGPROGRAM
            #pragma vertex vert_meta
            #pragma fragment frag_meta

            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2

            #include "UnityStandardMeta.cginc"
            ENDCG
        }
    }

    FallBack "Standard"
    CustomEditor "CustomStandardShaderGUI"
}

Here’s the shader where I modified it (the rest is unchanged so I didn’t copy it all here).

And as you said, rev087, you can’t see the new properties in the inspector because of the custom editor made for the standard shader.
So I copied the ā€œStandardShaderGUI.csā€ script and modified it to add the Outline properties.

Here’s what i got now :

using System;
using UnityEngine;

namespace UnityEditor
{
    internal class CustomStandardShaderGUI : ShaderGUI
{
    private enum WorkflowMode
    {
        Specular,
        Metallic,
        Dielectric
    }

    public enum BlendMode
    {
        Opaque,
        Cutout,
        Fade,        // Old school alpha-blending mode, fresnel does not affect amount of transparency
        Transparent // Physically plausible transparency mode, implemented as alpha pre-multiply
    }

    private static class Styles
    {
        public static GUIStyle optionsButton = "PaneOptions";
        public static GUIContent uvSetLabel = new GUIContent("UV Set");
        public static GUIContent[] uvSetOptions = new GUIContent[] { new GUIContent("UV channel 0"), new GUIContent("UV channel 1") };

        public static string emptyTootip = "";
        public static GUIContent albedoText = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)");
        public static GUIContent alphaCutoffText = new GUIContent("Alpha Cutoff", "Threshold for alpha cutoff");
        public static GUIContent specularMapText = new GUIContent("Specular", "Specular (RGB) and Smoothness (A)");
        public static GUIContent metallicMapText = new GUIContent("Metallic", "Metallic (R) and Smoothness (A)");
        public static GUIContent smoothnessText = new GUIContent("Smoothness", "");
        public static GUIContent normalMapText = new GUIContent("Normal Map", "Normal Map");
        public static GUIContent heightMapText = new GUIContent("Height Map", "Height Map (G)");
        public static GUIContent occlusionText = new GUIContent("Occlusion", "Occlusion (G)");
        public static GUIContent emissionText = new GUIContent("Emission", "Emission (RGB)");
        public static GUIContent detailMaskText = new GUIContent("Detail Mask", "Mask for Secondary Maps (A)");
        public static GUIContent detailAlbedoText = new GUIContent("Detail Albedo x2", "Albedo (RGB) multiplied by 2");
        public static GUIContent detailNormalMapText = new GUIContent("Normal Map", "Normal Map");

        public static string whiteSpaceString = " ";
        public static string primaryMapsText = "Main Maps";
        public static string secondaryMapsText = "Secondary Maps";
        public static string renderingMode = "Rendering Mode";
        public static GUIContent emissiveWarning = new GUIContent ("Emissive value is animated but the material has not been configured to support emissive. Please make sure the material itself has some amount of emissive.");
        public static GUIContent emissiveColorWarning = new GUIContent ("Ensure emissive color is non-black for emission to have effect.");
        public static readonly string[] blendNames = Enum.GetNames (typeof (BlendMode));
    }

    MaterialProperty blendMode = null;
    MaterialProperty albedoMap = null;
    MaterialProperty albedoColor = null;
    MaterialProperty alphaCutoff = null;
    MaterialProperty specularMap = null;
    MaterialProperty specularColor = null;
    MaterialProperty metallicMap = null;
    MaterialProperty metallic = null;
    MaterialProperty smoothness = null;
    MaterialProperty bumpScale = null;
    MaterialProperty bumpMap = null;
    MaterialProperty occlusionStrength = null;
    MaterialProperty occlusionMap = null;
    MaterialProperty heigtMapScale = null;
    MaterialProperty heightMap = null;
    MaterialProperty emissionScaleUI = null;
    MaterialProperty emissionColorUI = null;
    MaterialProperty emissionColorForRendering = null;
    MaterialProperty emissionMap = null;
    MaterialProperty detailMask = null;
    MaterialProperty detailAlbedoMap = null;
    MaterialProperty detailNormalMapScale = null;
    MaterialProperty detailNormalMap = null;
    MaterialProperty uvSetSecondary = null;
    // Outline Add ------------------------------------------------------- //
    MaterialProperty _OutlineColor = null;
    MaterialProperty _Outline = null;

    MaterialEditor m_MaterialEditor;
    WorkflowMode m_WorkflowMode = WorkflowMode.Specular;

    bool m_FirstTimeApply = true;

    public void FindProperties (MaterialProperty[] props)
    {
        blendMode = FindProperty ("_Mode", props);
        albedoMap = FindProperty ("_MainTex", props);
        albedoColor = FindProperty ("_Color", props);
        alphaCutoff = FindProperty ("_Cutoff", props);
        specularMap = FindProperty ("_SpecGlossMap", props, false);
        specularColor = FindProperty ("_SpecColor", props, false);
        metallicMap = FindProperty ("_MetallicGlossMap", props, false);
        metallic = FindProperty ("_Metallic", props, false);
        if (specularMap != null && specularColor != null)
            m_WorkflowMode = WorkflowMode.Specular;
        else if (metallicMap != null && metallic != null)
            m_WorkflowMode = WorkflowMode.Metallic;
        else
            m_WorkflowMode = WorkflowMode.Dielectric;
        smoothness = FindProperty ("_Glossiness", props);
        bumpScale = FindProperty ("_BumpScale", props);
        bumpMap = FindProperty ("_BumpMap", props);
        heigtMapScale = FindProperty ("_Parallax", props);
        heightMap = FindProperty("_ParallaxMap", props);
        occlusionStrength = FindProperty ("_OcclusionStrength", props);
        occlusionMap = FindProperty ("_OcclusionMap", props);
        emissionScaleUI = FindProperty ("_EmissionScaleUI", props);
        emissionColorUI = FindProperty ("_EmissionColorUI", props);
        emissionColorForRendering = FindProperty ("_EmissionColor", props);
        emissionMap = FindProperty ("_EmissionMap", props);
        detailMask = FindProperty ("_DetailMask", props);
        detailAlbedoMap = FindProperty ("_DetailAlbedoMap", props);
        detailNormalMapScale = FindProperty ("_DetailNormalMapScale", props);
        detailNormalMap = FindProperty ("_DetailNormalMap", props);
        uvSetSecondary = FindProperty ("_UVSec", props);
        // Outline Add ------------------------------------------------------- //
        _OutlineColor = FindProperty ("_OutlineColor", props);
        _Outline = FindProperty ("_Outline", props);
    }

    public override void OnGUI (MaterialEditor materialEditor, MaterialProperty[] props)
    {
        FindProperties (props); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
        m_MaterialEditor = materialEditor;
        Material material = materialEditor.target as Material;

        ShaderPropertiesGUI (material);

        // Make sure that needed keywords are set up if we're switching some existing
        // material to a standard shader.
        if (m_FirstTimeApply)
        {
            SetMaterialKeywords (material, m_WorkflowMode);
            m_FirstTimeApply = false;
        }
    }

    public void ShaderPropertiesGUI (Material material)
    {
        // Use default labelWidth
        EditorGUIUtility.labelWidth = 0f;

        // Detect any changes to the material
        EditorGUI.BeginChangeCheck();
        {
            BlendModePopup();

            // Primary properties
            GUILayout.Label (Styles.primaryMapsText, EditorStyles.boldLabel);
            DoAlbedoArea(material);
            DoSpecularMetallicArea();
            m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap, bumpMap.textureValue != null ? bumpScale : null);
            m_MaterialEditor.TexturePropertySingleLine(Styles.heightMapText, heightMap, heightMap.textureValue != null ? heigtMapScale : null);
            m_MaterialEditor.TexturePropertySingleLine(Styles.occlusionText, occlusionMap, occlusionMap.textureValue != null ? occlusionStrength : null);
            DoEmissionArea(material);
            m_MaterialEditor.TexturePropertySingleLine(Styles.detailMaskText, detailMask);
            EditorGUI.BeginChangeCheck();
            m_MaterialEditor.TextureScaleOffsetProperty(albedoMap);
            if (EditorGUI.EndChangeCheck())
                emissionMap.textureScaleAndOffset = albedoMap.textureScaleAndOffset; // Apply the main texture scale and offset to the emission texture as well, for Enlighten's sake

            EditorGUILayout.Space();

            // Secondary properties
            GUILayout.Label(Styles.secondaryMapsText, EditorStyles.boldLabel);
            m_MaterialEditor.TexturePropertySingleLine(Styles.detailAlbedoText, detailAlbedoMap);
            m_MaterialEditor.TexturePropertySingleLine(Styles.detailNormalMapText, detailNormalMap, detailNormalMapScale);
            m_MaterialEditor.TextureScaleOffsetProperty(detailAlbedoMap);
            m_MaterialEditor.ShaderProperty(uvSetSecondary, Styles.uvSetLabel.text);

            EditorGUILayout.Space();

            // Outline properties --------------------------------------------------- //
            GUILayout.Label ("Outline Properties", EditorStyles.boldLabel);
            m_MaterialEditor.ColorProperty (_OutlineColor, "Outline Color");
            m_MaterialEditor.FloatProperty (_Outline, "Outline Width");
        }
        if (EditorGUI.EndChangeCheck())
        {
            foreach (var obj in blendMode.targets)
                MaterialChanged((Material)obj, m_WorkflowMode);
        }
    }

    internal void DetermineWorkflow(MaterialProperty[] props)
    {
        if (FindProperty("_SpecGlossMap", props, false) != null && FindProperty("_SpecColor", props, false) != null)
            m_WorkflowMode = WorkflowMode.Specular;
        else if (FindProperty("_MetallicGlossMap", props, false) != null && FindProperty("_Metallic", props, false) != null)
            m_WorkflowMode = WorkflowMode.Metallic;
        else
            m_WorkflowMode = WorkflowMode.Dielectric;
    }

    public override void AssignNewShaderToMaterial (Material material, Shader oldShader, Shader newShader)
    {
        base.AssignNewShaderToMaterial(material, oldShader, newShader);

        if (oldShader == null || !oldShader.name.Contains("Legacy Shaders/"))
            return;

        BlendMode blendMode = BlendMode.Opaque;
        if (oldShader.name.Contains("/Transparent/Cutout/"))
        {
            blendMode = BlendMode.Cutout;
        }
        else if (oldShader.name.Contains("/Transparent/"))
        {
            // NOTE: legacy shaders did not provide physically based transparency
            // therefore Fade mode
            blendMode = BlendMode.Fade;
        }
        material.SetFloat("_Mode", (float)blendMode);

        //DetermineWorkflow( ShaderUtil.GetMaterialProperties(new Material[] { material }) );
        MaterialChanged(material, m_WorkflowMode);
    }

    void BlendModePopup()
    {
        EditorGUI.showMixedValue = blendMode.hasMixedValue;
        var mode = (BlendMode)blendMode.floatValue;

        EditorGUI.BeginChangeCheck();
        mode = (BlendMode)EditorGUILayout.Popup(Styles.renderingMode, (int)mode, Styles.blendNames);
        if (EditorGUI.EndChangeCheck())
        {
            m_MaterialEditor.RegisterPropertyChangeUndo("Rendering Mode");
            blendMode.floatValue = (float)mode;
        }

        EditorGUI.showMixedValue = false;
    }

    void DoAlbedoArea(Material material)
    {
        m_MaterialEditor.TexturePropertySingleLine(Styles.albedoText, albedoMap, albedoColor);
        if (((BlendMode)material.GetFloat("_Mode") == BlendMode.Cutout))
        {
            m_MaterialEditor.ShaderProperty(alphaCutoff, Styles.alphaCutoffText.text, MaterialEditor.kMiniTextureFieldLabelIndentLevel+1);
        }
    }

    void DoEmissionArea(Material material)
    {
        bool showEmissionColorAndGIControls = emissionScaleUI.floatValue > 0f;
        bool hadEmissionTexture = emissionMap.textureValue != null;

        // Do controls
        m_MaterialEditor.TexturePropertySingleLine(Styles.emissionText, emissionMap, showEmissionColorAndGIControls ? emissionColorUI : null, emissionScaleUI);

        // Set default emissionScaleUI if texture was assigned
        if (emissionMap.textureValue != null && !hadEmissionTexture && emissionScaleUI.floatValue <= 0f)
            emissionScaleUI.floatValue = 1.0f;

        // Dynamic Lightmapping mode
        if (showEmissionColorAndGIControls)
        {
            bool shouldEmissionBeEnabled = ShouldEmissionBeEnabled(EvalFinalEmissionColor(material));
            EditorGUI.BeginDisabledGroup(!shouldEmissionBeEnabled);

            m_MaterialEditor.LightmapEmissionProperty (MaterialEditor.kMiniTextureFieldLabelIndentLevel + 1);

            EditorGUI.EndDisabledGroup();
        }

        if (!HasValidEmissiveKeyword(material))
        {
            EditorGUILayout.HelpBox(Styles.emissiveWarning.text, MessageType.Warning);
        }

    }

    void DoSpecularMetallicArea()
    {
        if (m_WorkflowMode == WorkflowMode.Specular)
        {
            if (specularMap.textureValue == null)
                m_MaterialEditor.TexturePropertyTwoLines(Styles.specularMapText, specularMap, specularColor, Styles.smoothnessText, smoothness);
            else
                m_MaterialEditor.TexturePropertySingleLine(Styles.specularMapText, specularMap);

        }
        else if (m_WorkflowMode == WorkflowMode.Metallic)
        {
            if (metallicMap.textureValue == null)
                m_MaterialEditor.TexturePropertyTwoLines(Styles.metallicMapText, metallicMap, metallic, Styles.smoothnessText, smoothness);
            else
                m_MaterialEditor.TexturePropertySingleLine(Styles.metallicMapText, metallicMap);
        }
    }

    public static void SetupMaterialWithBlendMode(Material material, BlendMode blendMode)
    {
        switch (blendMode)
        {
            case BlendMode.Opaque:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = -1;
                break;
            case BlendMode.Cutout:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.EnableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 2450;
                break;
            case BlendMode.Fade:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.EnableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
            case BlendMode.Transparent:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
        }
    }

    // Calculate final HDR _EmissionColor (gamma space) from _EmissionColorUI (LDR, gamma) & _EmissionScaleUI (gamma)
    static Color EvalFinalEmissionColor(Material material)
    {
        return material.GetColor("_EmissionColorUI") * material.GetFloat("_EmissionScaleUI");
    }

    static bool ShouldEmissionBeEnabled (Color color)
    {
        return color.grayscale > (0.1f / 255.0f);
    }

    static void SetMaterialKeywords(Material material, WorkflowMode workflowMode)
    {
        // Note: keywords must be based on Material value not on MaterialProperty due to multi-edit & material animation
        // (MaterialProperty value might come from renderer material property block)
        SetKeyword (material, "_NORMALMAP", material.GetTexture ("_BumpMap") || material.GetTexture ("_DetailNormalMap"));
        if (workflowMode == WorkflowMode.Specular)
            SetKeyword (material, "_SPECGLOSSMAP", material.GetTexture ("_SpecGlossMap"));
        else if (workflowMode == WorkflowMode.Metallic)
            SetKeyword (material, "_METALLICGLOSSMAP", material.GetTexture ("_MetallicGlossMap"));
        SetKeyword (material, "_PARALLAXMAP", material.GetTexture ("_ParallaxMap"));
        SetKeyword (material, "_DETAIL_MULX2", material.GetTexture ("_DetailAlbedoMap") || material.GetTexture ("_DetailNormalMap"));

        bool shouldEmissionBeEnabled = ShouldEmissionBeEnabled (material.GetColor("_EmissionColor"));
        SetKeyword (material, "_EMISSION", shouldEmissionBeEnabled);

        // Setup lightmap emissive flags
        MaterialGlobalIlluminationFlags flags = material.globalIlluminationFlags;
        if ((flags & (MaterialGlobalIlluminationFlags.BakedEmissive | MaterialGlobalIlluminationFlags.RealtimeEmissive)) != 0)
        {
            flags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack;
            if (!shouldEmissionBeEnabled)
                flags |= MaterialGlobalIlluminationFlags.EmissiveIsBlack;

            material.globalIlluminationFlags = flags;
        }
    }

    bool HasValidEmissiveKeyword (Material material)
    {
        // Material animation might be out of sync with the material keyword.
        // So if the emission support is disabled on the material, but the property blocks have a value that requires it, then we need to show a warning.
        // (note: (Renderer MaterialPropertyBlock applies its values to emissionColorForRendering))
        bool hasEmissionKeyword = material.IsKeywordEnabled ("_EMISSION");
        if (!hasEmissionKeyword && ShouldEmissionBeEnabled (emissionColorForRendering.colorValue))
            return false;
        else
            return true;
    }

    static void MaterialChanged(Material material, WorkflowMode workflowMode)
    {
        // Clamp EmissionScale to always positive
        if (material.GetFloat("_EmissionScaleUI") < 0.0f)
            material.SetFloat("_EmissionScaleUI", 0.0f);
  
        // Apply combined emission value
        Color emissionColorOut = EvalFinalEmissionColor (material);
        material.SetColor("_EmissionColor", emissionColorOut);

        // Handle Blending modes
        SetupMaterialWithBlendMode(material, (BlendMode)material.GetFloat("_Mode"));

        SetMaterialKeywords(material, workflowMode);
    }

    static void SetKeyword(Material m, string keyword, bool state)
    {
        if (state)
            m.EnableKeyword (keyword);
        else
            m.DisableKeyword (keyword);
    }
}

} // namespace UnityEditor

You can just copy and paste it in a new CS file, this will work (there are just a few added lines, might not be worth the scroll ^^).

After this, you need to change the last line of your modified Standard shader (the shader, not the .cs file) to this :

    CustomEditor "CustomStandardShaderGUI"

Change your material’s shader to the new ā€œStandard (Outlined)ā€ shader and this is it! The default Outline width is set to 0.005. I recommend you to keep it like this as I find it good but you can still try to set it differently (just don’t go too high as this will not work as intended).

Also, the ā€œToonBasicOutlineā€ shader included in Unity may not be the best outline shader, but it’s the best I could find. If you find another one, please let me know!

2 Likes

Hey, are you sure you pasted the full code of a shader? It looks like it missing some parts in the end.

No, as I said this is from Unity’s Standard shader, I pasted only the part I changed.

You can get it here : https://unity3d.com/get-unity/download/archive in the Built in shaders.
I think I’ll just edit it to paste the full shader, will be easier.

EDIT : Done, you can just copy/paste it in a new shader file now.

1 Like

Very cool. Thanks for sharing, MingJ.

Yeah, thanks for sharing. Good stuff. Is it possible to make it work on WebGL?

Nice work MingJ, much easier to work with than what I had.

1 Like

I didn’t try it, but I guess it should be.

Then I must have done something wrong because I can’t make it work in WebGL :stuck_out_tongue: It does work great in editor, but not in build.

Are you in deferred rendering mode ? For an unknown reason outlines don’t seem to work on deferred mode (on build). I have the same issue on Android. Even Unity’s ā€˜Toon’ shader doesn’t work. I’m not really experienced with shaders so I can’t understand why…
Try to use forward mode instead and see if it works.

1 Like

I believe I’ve tried both forward and deferred, but I’ll check again (just in case I missed forward) and post the result.

I Apologize if this question is too trivial or obvious… But How do I compile / import this modified shader into Unity 5?

You just have to create a new shader in your project and replace its content by the code I pasted above.

i think it’s also possible simply by writing a surface shader with 2 "dirty passes " meaning 2 CGPROGRAM blocks
the first one with a vertex function that extrudes vertexes along normals, full red, and the second rendering original geometry…

here is a draft…

Shader "Custom/victor_outline" {
   Properties {
        _MainColor ("Diffuse Color", Color) = (1,1,1,1)
        _MainTex ("Base layer (RGB)", 2D) = "white" {}

        _Dist ("Shift", Range(-1, 1)) = 0
    }

    SubShader {

        /// first pass
     
        Tags { "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
        LOD 200
        Blend SrcAlpha OneMinusSrcAlpha
        Lighting On
        ZWrite On
        ZTest LEqual
        cull Front
        CGPROGRAM

        #pragma surface surf StandardSpecular fullforwardshadows addshadow alphatest:_Cutoff vertex:vert
        #pragma target 3.0
        #include "UnityCG.cginc"
 

        float4 _MainColor;
        float _Dist;

     
        struct Input {
            float2 uv_MainTex;
        };
     
        void vert (inout appdata_full v) {
            v.vertex.xyz += float3(v.normal.xyz)*_Dist;     
        }
     
        void surf (Input i, inout SurfaceOutputStandardSpecular o) {
            o.Emission = _MainColor.rgb;  // main albedo color
            o.Specular =0;
            o.Smoothness = 0;
            o.Alpha = 1;
            ///////////////
        }
        ENDCG
        //// end first pass
     
        /// second pass

        Tags { "IgnoreProjector"="True" "RenderType"="Opaque"}
        Blend SrcAlpha OneMinusSrcAlpha
        Lighting On
        ZWrite On
        Cull Off


        CGPROGRAM
     
        #pragma surface surf StandardSpecular fullforwardshadows addshadow alphatest:_Cutoff
        #pragma target 3.0
        #include "UnityCG.cginc"

         sampler2D _MainTex;

     
        struct Input {
            float2 uv_MainTex;
            float3 norm :  TEXCOORD1;
        };
     
        void surf (Input i, inout SurfaceOutputStandardSpecular o) {

            // Main Albedo
            fixed4 tex = tex2D (_MainTex, i.uv_MainTex);
            o.Albedo = tex.rgb;  // main albedo
            o.Specular = 0;
            o.Smoothness = 0;
            o.Alpha = tex.a;
        }
        ENDCG
        // end first pass

  } //subshader
}//shader
1 Like