Enabling and disabling a shader pass

Is there a way to reliably enable and disable a shader pass in a multi-pass shader?

I can’t seem to find a way to do that without experimenting with a bunch of hacks (or I’ve missed the documented method which could likely be the case :smile: ).

thanks…

No. Please try creating a text file with a bunch of UsePass lines, and let us know if you can create a material from that. I never tried. If it works, I’d use that method. Otherwise, I’d keep a bunch of shaders around that contain the UsePass lines you want.

5 years later, I’ve run into the same question… Is there a way to enable/disable a shader pass per-material at runtime?

I’ve got a shader with a lot of variants, and I’d like to add some VFX to the shader.

Rather than doubling the (already concerning) number of shader variants by adding new #pragma multi_compiles, I could apply some of these effects with a second pass - but only if I can turn it on/off as needed. Is there any way to do this?

Solution 1:
Use Material.SetPass

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MultiPass : MonoBehaviour
{

    public RenderTexture Source;
    public RenderTexture Destination;
    public Material material;
    public int pass;
   
    void Blit(RenderTexture source, RenderTexture destination, Material mat)
    {
        RenderTexture.active = destination;
        mat.SetTexture("_MainTex", source);
        GL.PushMatrix();
        GL.LoadOrtho();
        GL.invertCulling = true;
        mat.SetPass(0);
        GL.Begin(GL.QUADS);
        GL.MultiTexCoord2(0, 0.0f, 0.0f);
        GL.Vertex3(0.0f, 0.0f, 0.0f);
        GL.MultiTexCoord2(0, 1.0f, 0.0f);
        GL.Vertex3(1.0f, 0.0f, 0.0f);
        GL.MultiTexCoord2(0, 1.0f, 1.0f);
        GL.Vertex3(1.0f, 1.0f, 1.0f);
        GL.MultiTexCoord2(0, 0.0f, 1.0f);
        GL.Vertex3(0.0f, 1.0f, 0.0f);
        GL.End();
        GL.invertCulling = false;
        GL.PopMatrix();       
    }
   
    void Start ()
    {
       
    }
   
    void Update ()
    {
        Blit(Source,Destination,material);
    }
}
Shader "MultiPass"
{
    SubShader
    {
        CGINCLUDE
        #pragma vertex SetVertexShader
        #pragma fragment SetPixelShader       
        void SetVertexShader (inout float4 vertex:POSITION,inout float2 uv:TEXCOORD0)
        {
            vertex = UnityObjectToClipPos(vertex);
        }
        ENDCG
       
        Pass
        {
            CGPROGRAM           
            float4 SetPixelShader (float4 vertex:POSITION,float2 uv:TEXCOORD0) : SV_TARGET
            {
                return float4(1,0,0,1);
            }
            ENDCG
        }
       
        Pass
        {
            CGPROGRAM                       
            float4 SetPixelShader (float4 vertex:POSITION,float2 uv:TEXCOORD0) : SV_TARGET
            {
                return float4(0,0,1,1);
            }
            ENDCG
        }       
    }
}

Shader output (second pass):
3849478--325537--upload_2018-11-2_15-54-14.png

Render texture with first pass:
3849478--325540--upload_2018-11-2_15-56-10.png
so you can combine Blit with various passes.

Solution 2:
Use discard and Material.SetFloat:

Shader "MultiPass"
{
    SubShader
    {
        CGINCLUDE
        #pragma vertex SetVertexShader
        #pragma fragment SetPixelShader       
        void SetVertexShader (inout float4 vertex:POSITION,inout float2 uv:TEXCOORD0)
        {
            vertex = UnityObjectToClipPos(vertex);
        }
        ENDCG
       
        Pass
        {
            CGPROGRAM           
            float4 SetPixelShader (float4 vertex:POSITION,float2 uv:TEXCOORD0) : SV_TARGET
            {
                return float4(1,0,0,1);
            }
            ENDCG
        }
       
        Pass
        {
            CGPROGRAM                       
            float4 SetPixelShader (float4 vertex:POSITION,float2 uv:TEXCOORD0) : SV_TARGET
            {
                if (true)
                {
                    discard;               
                }
                return float4(0,0,1,1);
            }
            ENDCG
        }       
    }
}

Shader output:
3849478--325543--upload_2018-11-2_15-59-59.png

Solution 3:
Write custom native rendering plugin with multipass support. For OpenGL here is topic about compact code:
https://forum.unity.com/threads/unity-opengl-native-plugin-basic-source-code.570571/

Solution 4:
Play with various blending modes, to “hide” output of given pass:

2 Likes

Solution 5:
Use stencil buffer:

1 Like