Search code examples
unity-game-engineshaderhlslcg

Can vertex alpha be set for a surface shader appdata input?


My shader does some math to determine vertex alpha, so I've got a function to do that before the data gets passed into my surf function.

    #pragma surface surf Standard alpha
    #pragma target 3.0

    struct Input
    {
        float2 uv_MainTex;
        float tranparency;
    };

    void foo(inout appdata_full v, out Input o) {
        UNITY_INITIALIZE_OUTPUT(Input, o);
        float someAlpha;
        [...some maths to create someAlpha value...]
        v.color.a = someAlpha;
        o.transparency = v.color.a;
    }

    half _Glossiness;
    half _Metallic;
    fixed4 _Color;

    UNITY_INSTANCING_BUFFER_START(Props)
    UNITY_INSTANCING_BUFFER_END(Props)

    void surf (Input IN, inout SurfaceOutputStandard o)
    {
        fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
        o.Albedo = c.rgb;
        o.Metallic = _Metallic;
        o.Smoothness = _Glossiness;
        o.Alpha = c.a;
    }

Then when I use Input IN I want someAlpha to be reflected when the alpha is set:

o.Alpha = c.a; //Can I do c.a * IN.transparency ?

Currently, absolutely nothing happens. How can I use the alpha value I want in surf?


Solution

  • Yes. You can add a COLOR semantic to your Input object:

    struct Input {
        float4 uv_MainTex;
        float4 color : COLOR;
        };
    

    Then assign to it in foo (although this may not be necessary if you have #pragma surface surf):

    void foo(inout appdata_full v, out Input o) {
        UNITY_INITIALIZE_OUTPUT(Input, o);
        float someAlpha;
        [...some maths to create someAlpha value...]
        v.color.a = someAlpha;
    
        o.color = v.color;
    }
    

    Then use it in surf:

    void surf (Input IN, inout SurfaceOutputStandard o)
    {
        fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
        fixed4 vertexColor = IN.color;
        o.Albedo = c.rgb;
        o.Metallic = _Metallic;
        o.Smoothness = _Glossiness;
        o.Alpha = vertexColor.a * c.a; 
    }
    

    Finally, tell Unity to use foo as a vertex shader before the surface shader by changing #pragma surface surf Standard alpha to:

    #pragma surface surf Standard alpha vertex:foo