Search code examples
unity-game-enginehlslcg

Multiple SubShaders, only one is rendering


I am trying to add multiple sub shaders to one shader. One SubShader is just the standard Unity surface shader, and the second SubShader is a transparent outline that I have modified from somewhere I found online. Here is the code that I have so far:

Shader "Custom/MetallicOutline" {

Properties {
    _Color ("Color", Color) = (1,1,1,1)
    _MainTex ("Albedo (RGB)", 2D) = "white" {}
    _Glossiness ("Smoothness", Range(0,1)) = 0.5
    _Metallic ("Metallic", Range(0,1)) = 0.0


        // Added this : Ben Hoffman
        [Space(10)][Header(xxxxxxxxxxxxxxxx)][Header((Outline))]_OutlineWidth("Width", Float) = 0.5
        _OutlineWidthControl("Width Control", 2D) = "white" {}

        [Space(8)][Toggle(ENABLE_OPO)] _EOPO("Enable Outline Offset", Float) = 0
        _OutlineOffset("Outline Offset", Vector) = (0,0,0)

        [Space(8)]_OutlineColor("Color", Color) = (0,0,0,1)

        [Space(8)]_OutlineNoiseIntensity("Noise Intensity", Range(0, 1)) = 0
        [MaterialToggle] _DynamicNoiseOutline("Dynamic Noise Outline", Float) = 0

        _OutlineOpacity("Outline Opacity", Range(0, 1)) = 1
}


SubShader {
    Tags { "RenderType" = "Opaque" }
    LOD 200

    CGPROGRAM
    // Physically based Standard lighting model, and enable shadows on all light types
    #pragma surface surf Lambert

    // Use shader model 3.0 target, to get nicer looking lighting
    #pragma target 3.0

    sampler2D _MainTex;

    struct Input {
        float2 uv_MainTex;
    };

    half _Glossiness;
    half _Metallic;
    fixed4 _Color;

    // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    // #pragma instancing_options assumeuniformscaling
    UNITY_INSTANCING_BUFFER_START(Props)
        // put more per-instance properties here
    UNITY_INSTANCING_BUFFER_END(Props)

    void surf (Input IN, inout SurfaceOutputStandard o) {
        // Albedo comes from a texture tinted by color
        fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
        o.Albedo = c.rgb;
        // Metallic and smoothness come from slider variables
        o.Metallic = _Metallic;
        o.Smoothness = _Glossiness;
        o.Alpha = c.a;
    }
    ENDCG
}


SubShader {

    Tags {
        "RenderType" = "Opaque"
    }

    Pass {
        Name "Outline"
        Tags {
            "Queue" = "Transparent"
        }

        //ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha

        Cull Front

        Stencil {
            Ref[_RefVal]
            Comp[_Compa]
            Pass[_Oper]
            Fail[_Oper]
        }

CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
    #include "UnityCG.cginc"
    #pragma fragmentoption ARB_precision_hint_fastest
    #pragma multi_compile_shadowcaster
    #pragma multi_compile_fog
    #pragma multi_compile_instancing
    #pragma only_renderers d3d9 d3d11 glcore gles3 metal d3d11_9x xboxone ps4 switch
    #pragma target 3.0
    #pragma shader_feature ENABLE_OPO
        uniform sampler2D _Texture; uniform float4 _Texture_ST;
    uniform float4 _OutlineColor;

    uniform fixed _Transparent;

    uniform float _OutlineNoiseIntensity;
    uniform fixed _DynamicNoiseOutline;
    uniform fixed _TexturePatternStyle;
    uniform sampler2D _OutlineWidthControl; uniform float4 _OutlineWidthControl_ST;
    uniform float _OutlineWidth;
    uniform float3 _OutlineOffset;

    // Transparency options
    uniform float _OutlineOpacity;


    struct VertexInput {
        float4 vertex : POSITION;
        float3 normal : NORMAL;
        float2 texcoord0 : TEXCOORD0;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };
    struct VertexOutput {
        float4 pos : SV_POSITION;
        float2 uv0 : TEXCOORD0;
        float4 projPos : TEXCOORD1;
        UNITY_FOG_COORDS(2)
    };
    VertexOutput vert(VertexInput v) {
        VertexOutput o = (VertexOutput)0;
        o.uv0 = v.texcoord0;
        UNITY_SETUP_INSTANCE_ID(v);
        float3 viDir = normalize(_WorldSpaceCameraPos.xyz - o.pos.xyz);
        float4 viDirVP = mul(UNITY_MATRIX_VP, float4(viDir.xyz, 1));
        float4 node_9780 = _Time;
        float node_5371_ang = node_9780.g;
        float node_5371_spd = 0.002;
        float node_5371_cos = cos(node_5371_spd*node_5371_ang);
        float node_5371_sin = sin(node_5371_spd*node_5371_ang);
        float2 node_5371_piv = float2(0.5,0.5);
        float2 node_5371 = (mul(o.uv0 - node_5371_piv,float2x2(node_5371_cos, -node_5371_sin, node_5371_sin, node_5371_cos)) + node_5371_piv);
        float2 _DynamicNoiseOutline_var = lerp(o.uv0, node_5371, _DynamicNoiseOutline);
        float2 node_7493_skew = _DynamicNoiseOutline_var + 0.2127 + _DynamicNoiseOutline_var.x*0.3713*_DynamicNoiseOutline_var.y;
        float2 node_7493_rnd = 4.789*sin(489.123*(node_7493_skew));
        float node_7493 = frac(node_7493_rnd.x*node_7493_rnd.y*(1 + node_7493_skew.x));
        float4 _OutlineWidthControl_var = tex2Dlod(_OutlineWidthControl,float4(TRANSFORM_TEX(o.uv0, _OutlineWidthControl),0.0,0));
        o.pos = UnityObjectToClipPos(float4(v.vertex.xyz + v.normal*(lerp(1.0,node_7493,_OutlineNoiseIntensity)*(clamp(_OutlineWidth,0.0,1000.0)*0.01)*_OutlineWidthControl_var.rgb),1));

 #ifdef ENABLE_OPO
        o.pos.xyz = o.pos.xyz - _OutlineOffset.xyz*viDirVP.xyz*0.1;
 #endif

        UNITY_TRANSFER_FOG(o,o.pos);
        o.projPos = ComputeScreenPos(o.pos);
        COMPUTE_EYEDEPTH(o.projPos.z);
        return o;
    }

    fixed4 frag(VertexOutput i) : COLOR{

        float2 sceneUVs = (i.projPos.xy / i.projPos.w);
        float2 _TexturePatternStyle_var = lerp(i.uv0, float2((sceneUVs.x * 2 - 1)*(_ScreenParams.r / _ScreenParams.g), sceneUVs.y * 2 - 1).rg, _TexturePatternStyle);
        float4 _Texture_var = tex2D(_Texture,TRANSFORM_TEX(_TexturePatternStyle_var, _Texture));
        clip(lerp(1.0, _Texture_var.a, _Transparent) - 0.0);

        // Set the opacity of the outline
        fixed4 col = fixed4(_OutlineColor.rgb, 0);
        col.a = _OutlineOpacity;

        return col;

    } // End frag

        ENDCG
        }   // End outline pass

    }

    FallBack "Diffuse"
}

I know that the logic for the outline works for certain. Whatever SubShader is above the other in the code gets renderered, and the other does not.

Does anyone know why this is happening?


Solution

  • I had the exact same problem. I fixed it by moving my pass in the second subshader into the first subshader, just below the first pass, and deleting my second subshader.

    I'm pretty new to Unity, but I think it's because Unity only loads one subshader. It's likely that different subshaders are designed to give you the flexibility to handle different situations or platforms, but only one will be active at a time. Try putting both passes into the same subshader and see if that fixes your problem.