Search code examples
unity-game-enginegraphicsshaderhlsl

Vertex shader compilation error from DX9 to DX11 (Unity 5.6 to 2017.4)


I have a Unity image post effect using a custom shader that throws an error when migrating from Unity 5.6 to Unity 2017.4

Assertion failed: Failed to create DX11 vertex declaration; something wrong with vertex shader input data? (hr=80070057)

It appears to be a fault in this script.

Shader "SG/Stretch Shadows" {
Properties {
    _MainTex ("Light texture", 2D) = "white" {}
}
SubShader {
    LOD 100
    Blend One Zero
    Cull Off
    ZWrite Off
    Lighting Off

    Pass {    // 0 Blacken source
        CGPROGRAM
            #pragma target 3.0

            #include "UnityCG.cginc"
            #pragma vertex processVerts
            #pragma fragment drawFrag

            #pragma glsl_no_auto_normalization

            struct vertdata {
                float2 uv : TEXCOORD0;
                float2 uvScaled : TEXCOORD1;
                float4 vertex : POSITION;
            };

            struct frag_v2f {
                float4 vertex : SV_POSITION;
                half2 uv : TEXCOORD0;
            };

            uniform sampler2D _MainTex;

            frag_v2f processVerts (vertdata v){
                frag_v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                 o.uv = v.uv;
                return o;
            }

            half4 drawFrag (frag_v2f i) : SV_Target {
                fixed4 shadow = tex2D(_MainTex, i.uv);
                half intensity = max(shadow.r, max(shadow.g, shadow.b));
                intensity = step(intensity,0.1);
                return 1-intensity;
            }

        ENDCG
    }

    Pass {    // 1 Stretch
        CGPROGRAM
            #pragma target 3.0

            #include "UnityCG.cginc"
            #pragma vertex processVerts
            #pragma fragment drawFrag

            #pragma glsl_no_auto_normalization

            struct vertdata {
                float2 uv : TEXCOORD0;
                float2 uvScaled : TEXCOORD1;
                float4 vertex : SV_POSITION;
            };

            struct frag_v2f {
                float4 vertex : SV_POSITION;
                half2 basePos : TEXCOORD0;
                half2 zoomPos : TEXCOORD1;
            };

            uniform sampler2D _ObstacleTex;
            uniform sampler2D _MainTex;
            half4 _SunPos;
            #ifdef UNITY_HALF_TEXEL_OFFSET
            #endif

            frag_v2f processVerts (vertdata v){
                frag_v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                 o.basePos = v.uv;
                o.zoomPos = v.uv * _SunPos.zw + (_SunPos.xy -_SunPos.zw*0.5);
                return o;
            }

            half4 drawFrag (frag_v2f i) : SV_Target {
                half2 basePos = i.basePos;
                half2 zoomPos = i.zoomPos;
                half4 tex = tex2D(_MainTex, i.basePos);

                half sub = 1.0/60;
                half len = length((basePos - zoomPos));

                half4 col = tex*tex.a;
                col = half4(0,0,0,0);
                half pos = 1;
                half power = 0.5;

                for(int i = 0; i < 60; i++){
                    pos -= sub;
                    half4 obstacle = tex2D(_MainTex, lerp(zoomPos, basePos, pos));
                    obstacle *= pow(pos, power);
                    col = max(col, obstacle);
                }

                return 1-col;//half4(half3((basePos - zoomPos).x*20), 1);//tex2D(_ObstacleTex, basePos);
            }

        ENDCG
    }

    Pass {    // 2 Blacken alpha
        CGPROGRAM
            #pragma target 3.0

            #include "UnityCG.cginc"
            #pragma vertex processVerts
            #pragma fragment drawFrag

            #pragma glsl_no_auto_normalization

            struct vertdata {
                float2 uv : TEXCOORD0;
                float2 uvScaled : TEXCOORD1;
                float4 vertex : SV_POSITION;
            };

            struct frag_v2f {
                float4 vertex : SV_POSITION;
                half2 uv : TEXCOORD0;
            };

            uniform sampler2D _MainTex;

            frag_v2f processVerts (vertdata v){
                frag_v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                 o.uv = v.uv;
                return o;
            }

            half4 drawFrag (frag_v2f i) : SV_Target {
                fixed4 shadow = tex2D(_MainTex, i.uv);
                half4 intensity = half4(0,0.2,0.2,shadow.a);
                intensity = lerp(shadow, intensity, shadow.a);

                return intensity;
            }

        ENDCG
    }

    Pass {    // 3 Draw fully zoomed shadow and half zoomed shadow
        // Each pass duplicates previous pass, doubling drawn shadows
        CGPROGRAM
            #pragma target 3.0

            #include "UnityCG.cginc"
            #pragma vertex processVerts
            #pragma fragment drawFrag

            #pragma glsl_no_auto_normalization

            struct vertdata {
                float2 uv : TEXCOORD0;
                float2 uvScaled : TEXCOORD1;
                float4 vertex : SV_POSITION;
            };

            struct frag_v2f {
                float4 vertex : SV_POSITION;
                half2 basePos : TEXCOORD0;
                half2 zoomPos : TEXCOORD1;
            };

            uniform sampler2D _ObstacleTex;
            uniform sampler2D _MainTex;
            half4 _SunPos;
            half _Offset;                                            // frational lerp value. Decrease by powers of two each pass
            #ifdef UNITY_HALF_TEXEL_OFFSET
            #endif

            frag_v2f processVerts (vertdata v){
                frag_v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                 o.basePos = v.uv;
                o.zoomPos = v.uv * _SunPos.zw + (_SunPos.xy -_SunPos.zw*0.5);
                return o;
            }

            half4 drawFrag (frag_v2f i) : SV_Target {
                half2 basePos = i.basePos;
                half2 zoomPos = i.zoomPos;
                half firstPass = tex2D(_MainTex, basePos).a;
                half secondPass = tex2D(_MainTex, zoomPos).a-0.85;
                half4 output = half4(0,0,0,max(firstPass, secondPass));
                secondPass = tex2D(_MainTex, lerp(zoomPos, basePos, 0.65)).a-0.3;
                output.a = max(output.a, secondPass);
                secondPass = tex2D(_MainTex, lerp(zoomPos, basePos, 0.4)).a-0.45;
                output.a = max(output.a, secondPass);
                secondPass = tex2D(_MainTex, lerp(zoomPos, basePos, 0.25)).a-0.6;
                output.a = max(output.a, secondPass);
                secondPass = tex2D(_MainTex, lerp(zoomPos, basePos, 0.1)).a-0.7;
                output.a = max(output.a, secondPass);

                return output;//half4(half3((basePos - zoomPos).x*20), 1);//tex2D(_ObstacleTex, basePos);
            }

        ENDCG
    }

Pass {    // 4 Single pass. Ping-pong
        // Each pass duplicates previous pass, doubling drawn shadows
        CGPROGRAM
            #pragma target 3.0

            #include "UnityCG.cginc"
            #pragma vertex processVerts
            #pragma fragment drawFrag

            #pragma glsl_no_auto_normalization

            struct vertdata {
                float2 uv : TEXCOORD0;
                float2 uvScaled : TEXCOORD1;
                float4 vertex : SV_POSITION;
            };

            struct frag_v2f {
                float4 vertex : SV_POSITION;
                half2 basePos : TEXCOORD0;
                half2 zoomPos : TEXCOORD1;
            };

            uniform sampler2D _ObstacleTex;
            uniform sampler2D _MainTex;
            half4 _SunPos;
            half _Offset;                                            // frational lerp value. Decrease by powers of two each pass
            #ifdef UNITY_HALF_TEXEL_OFFSET
            #endif

            frag_v2f processVerts (vertdata v){
                frag_v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                 o.basePos = v.uv;
                o.zoomPos = v.uv * _SunPos.zw + (_SunPos.xy -_SunPos.zw*0.5);
                return o;
            }

            half4 drawFrag (frag_v2f i) : SV_Target {
                half firstPass = tex2D(_MainTex, i.basePos).a;
                half secondPass = tex2D(_MainTex, lerp(i.zoomPos, i.basePos, _Offset)).a;
                half4 output = half4(0,0,0,max(firstPass, secondPass));
                return output;
            }

        ENDCG
    }
}

The build tools don't provide any details as to what script or line number is at fault. Documentation on Unity post effects doesn't cover anything about specifics. Google doesn't find anyone else with the same problem. The only thing I've found is someone suggest SV_POSITION should be replaced with POSITION, which I've tried all sorts of combinations of without success.

I also created a new image effect shader in Unity to compare and the code looks the same.

What's the correct form for creating a suitable vertex shader for a post effect? Or is that even the problem with my code?


Solution

  • You're close! The SV_POSITION semantic is for the vertex position passed to the fragment shader.

    Remove all SV_ prefixes from SV_POSITION in your vertdata structs. For example:

    struct vertdata
    {
        float2 uv : TEXCOORD0;
        float2 uvScaled : TEXCOORD1;
        float4 vertex : POSITION;    // <- Remove here
    };
    
    struct frag_v2f
    {
        float4 vertex : SV_POSITION; // <- Keep here
        half2 uv : TEXCOORD0;
    };