在Unity3D中的CG Shader内共享函数以供两个通道使用

7
我正在为Unity3d编写CG语言着色器。
如果要为透明对象创建着色器,则需要在“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
    }
}
}

更新:找到了使用包含文件的方法。
但是是否可能在一个文件内完成呢?

2个回答

13

您可以使用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
        }
    }
}

10

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

你可以将 CGPROGRAMENDCG 之间的所有内容写在单独的*.cginc文件中,并在每个 pass 中包含它。
重要提示!但是,您需要在主着色器文件中编写#pragma vertex vert#pragma fragment frag,否则它会编译但无法工作。我认为原因是pragmainclude之前被处理。

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

    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

是的,#pragma vertex vert 是用来指定你想要着色器使用哪个顶点函数的,否则它会默认使用一些内置的函数而不是你在 .cginc 文件中定义的函数。 - Spectraljump

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接