在 unity3d 的 CG Shader 内部的两个通道之间共享一个函数

Share a function between two passes inside CG Shader for unity3d

我正在用 CG 语言为 Unity3d 编写着色器。
如果您为透明对象制作着色器,则需要在 SubShader 中创建两个相似的通道。第一个只渲染背面(Cull Front),第二个只渲染正面(Cull Back)。但是顶点和片段函数的代码对于两次遍历是相同的。

是否可以不将代码加倍并声明一些函数,这些函数将在各遍之间共享?
我想在我的代码示例中使用类似的东西:

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: 了解如何使用 include。
但是可以在一个文件里面做吗?

回答我自己的问题。怪人!
希望对其他人有所帮助。

您可以将 CGPROGRAMENDCG 之间的所有内容写在单独的 *.cginc 文件中,并将其包含在每个过程中。
重要!但是你需要写 #pragma vertex vert#pragma fragment frag 在你的主着色器文件中,否则它会编译但不会工作。我想原因是 pragma'ssinclude's.

之前被处理

这是我的代码示例。
着色器定义文件:

    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.cginc:

#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

您可以使用 CGINCLUDE 在一个文件中完成。如果您查看 Unity 的 MobileBlur ("Hidden/FastBlur") 着色器,它在顶部共享代码并在下方传递。

这里只是关键部分 - 注意 CGINCLUDE/ENDCG 在 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
        }
    }
}