Share function between two passes inside CG Shader for unity3d

I am writing a CG shader for Unity3d.
If you are creating a shader for a transparent object, you need to create two similar passes in SubShader

. The first is to display only the front surfaces (c Cull Front

), and the second is to display only the front surfaces (c Cull Back

). But the code for the vertex and fragment function is the same for the two passes.

Is it possible not to double the code and declare some functions that will be shared between passes?
I want to have something like in my example code:

Shader "cool shader" {
Properties {
    ...
}
SubShader {

    CGPROGRAM
    // need to declare vertexOutput somewhow here
    float4 sharedFragFoo(vertexOutput i) : COLOR  // How to make smth like this?
    {
        ....
        return float4(...);
    }
    ENDCG

    pass {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        vertexOutput vert(vertexInput v) {
            vertexOutput o;     
            ...
            return o;
        }

        float4 frag(vertexOutput i) : COLOR
        {
            return sharedFragFoo(i); // call the shared between passes function
        }

        ENDCG
    }

    pass {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        vertexOutput vert(vertexInput v) {
            vertexOutput o;
            ...
            return o;
        }

        float4 frag(vertexOutput i) : COLOR
        {
            return sharedFragFoo(i); // call the shared between passes function
        }

        ENDCG
    }
}
}

      

UPD: Find out how to do it using include. But is it possible to make one file inside ?

+3


source to share


3 answers


Answering my question. Wierdo!
Hope this helps someone else.

You can write everything betwee CGPROGRAM

and ENDCG

in a separate * .cginc file and include it in each pass.
Important! But you need to write #pragma vertex vert

also #pragma fragment frag

inside the main shader file, otherwise it will compile but won't work. I believe the reason is because the pragma is being processed before inclusion.

Here is my sample code.
Main shader definition file:



    Shader "cool shader" {
    Properties {
        // properties
    }
    SubShader {
        ...

        pass {
            Cull Front
            ZWrite Off
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "shared.cginc"
            ENDCG
        }

        pass {
            Cull Back
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "shared.cginc"
            ENDCG
        }
    }
}

      

Shared shared.cginc file :

#ifndef SHARED_FOO
#define SHARED_FOO

uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform float4 _Color;
// other variables....

struct vertexInput {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
};

struct vertexOutput {
    float4 pos : SV_POSITION;
    float4 tex : TEXCOORD0;
    float4 posWorld : TEXCOORD1;
    float4 posInObjectCoords : TEXCOORD2;
    float3 normalDir : TEXCOORD3;
};

vertexOutput vert(vertexInput v) {
    vertexOutput o;
    // do staff 
    return o;
}

float4 frag(vertexOutput i) : COLOR
{
    // do staff 
    return float4(...);
}
#endif // SHARED_FOO

      

+5


source


You can do it in one file using CGINCLUDE

. If you look at the shader for MobileBlur ("Hidden / FastBlur") from Unity, it has generic code at the top and goes below.

Here are just the key parts - note CGINCLUDE

/ ENDCG

outside SubShader / Pass



Shader "YourShader"
{
    ...

    CGINCLUDE

    #include "UnityCG.cginc"

    struct shared_v2f
    {
        float4 pos : SV_POSITION;
    }

    shared_v2f myVert( appdate_img v )
    {
        shared_v2f o;

        o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

        return o;
    }

    fixed4 myFrag( shared_v2f i ) : SV_Target
    {
        return fixed4( 1.0, 0.5, 0.0, 1.0 );
    }

    ENDCG

    SubShader
    {
        ...

        Pass
        {
            CGPROGRAM 

            #pragma vertex myVert
            #pragma fragment myFrag

            ENDCG
        }
    }
}

      

+6


source


If you don't want to have multiple files, you can add generic declarations or generic functions at the beginning of your shader using the keyword CGINCLUDE

:

Shader "Custom/YourShader"
{

Properties
{
    _MainTex("Texture", 2D) = "white" {}
}

CGINCLUDE
//This code is available to all passes in your shader below

    sampler2D _MainTex;
    float4 _MainTex_TexelSize;

    struct appdata
    {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };

    struct v2f
    {
        float2 uv : TEXCOORD0;
        float4 vertex : SV_POSITION;
    };

    float4 aSamplingFunction(sampler2D tex, float2 uv, float4 size)
    {
        return SOMETHING;
    }

ENDCG

SubShader
{
    Cull On
    ZWrite Off 
    ZTest LEqual

    Pass// #0
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"

        v2f vert(appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            o.uv = v.uv;
            return o;
        }

        float4 frag(v2f i) : SV_Target
        {
            float4 col = aSamplingFunction(_MainTex, i.uv, _MainTex_TexelSize);
            return col;
        }
        ENDCG
    }

    Pass// #1
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"

        v2f vert(appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            o.uv = v.uv;
            return o;
        }

        float4 frag(v2f i) : SV_Target
        {
            float4 col = aSamplingFunction(_MainTex, i.uv, _MainTex_TexelSize);
            return col;
        }
            ENDCG
        }
    }
}

      

0


source







All Articles