在CG Shader内的两次传递之间共享一个函数用于unity3d

Tem*_*mak 5 shader function unity-game-engine

我正在为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
    }
}
}
Run Code Online (Sandbox Code Playgroud)

UPD:找出如何使用包含做到这一点.
但是有可能在一个文件里面做?

Hug*_*ade 11

您可以使用一个文件来完成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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Tem*_*mak 8

回答我自己的问题.Wierdo!
希望它会帮助别人.

你可以写所有betwee CGPROGRAMENDCG单独的*.cginc文件,包括它每道内.
重要!但是,你需要写 #pragma vertex vert#pragma fragment frag你的主着色器文件中,否则会编译,但将无法正常工作.我想原因是pragma'ssinclude之前被处理了.

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

    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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

共享文件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
Run Code Online (Sandbox Code Playgroud)