Search Unity

Multipass shader not working after 4.2 Update

Discussion in 'Shaders' started by tosi, Jul 23, 2013.

  1. tosi

    tosi

    Joined:
    Jul 5, 2012
    Posts:
    45
    Hi there,

    I recently updated to Unity 4.2 and after that, my shader with more than one pass is not working anymore. Unity just shows the first pass (or the second, if you count in the grab pass. My object is completely black. If I comment out this pass, Unity renders the manipulated grab pass, that I use in my further pass. If I comment out this pass, then I see the calculations of my last pass. What is going on here?

    Code (csharp):
    1. Shader "Glas"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Main Color", Color) = (0.3529412,0.3529412,0.3529412,1)
    6.         _GlossNoYes("_GlossNoYes", Range(0,1) ) = 0
    7.         _Spraying("Base (RGB) Gloss (A)", 2D) = "white" {}
    8.         _Metalization("_Metalization", 2D) = "black" {}
    9.         _Painting("_Painting", 2D) = "black" {}
    10.         _UVOffset("_UVOffset", Range(0,1) ) = 0.5
    11.         _Reflection("_Reflection", Cube) = "black" {}
    12.         _BumpMap("Normalmap", 2D) = "bump" {}
    13.         _Distorsion("_Distorsion", Range(0,0.5) ) = 0
    14.         _Refraction("_Refraction", Range(0,1) ) = 0
    15.         _Shininess("Shininess", Range(0.01,1) ) = 1
    16.         _FresnelPower("_Fresnel Power", Range(0.1,3) ) = 0.45
    17.    
    18.     }
    19.  
    20.    
    21.     SubShader
    22.     {
    23.        
    24.         Tags
    25.         {
    26.             "Queue"="Transparent+10"
    27.             "IgnoreProjector"="False"
    28.             "RenderType"="Transparent"
    29.         }
    30.  
    31.        
    32.        
    33.         //--------------------------1---------------------- Original-Hintergrund als Textur sichern
    34.         GrabPass { "_GrabTexture1" }
    35.  
    36.  
    37.  
    38.         //--------------------------2---------------------- Bereich des Objektes schwarz färben
    39.         //------------------------------------------------- Grundlage für den nächsten Pass, der additiv arbeitet - sonst würde alles überstrahlt werden
    40.        
    41.         Blend One Zero
    42.         ZWrite Off
    43.         Lighting Off
    44.        
    45.         CGPROGRAM
    46.         #pragma surface surf Lambert
    47.        
    48.         struct Input
    49.         {
    50.             float4 color : COLOR;
    51.         };
    52.        
    53.         void surf( Input IN, inout SurfaceOutput o )
    54.         {
    55.             o.Albedo = 0;
    56.         }
    57.        
    58.         ENDCG
    59.  
    60.  
    61.  
    62.         //--------------------------3---------------------- Transparenz wird mit GrabTexture #1 simuliert
    63.         //------------------------------------------------- Refraction wird errechnet aus der Oberflächen-Normale (Richtung der Brechung)
    64.         ZWrite Off
    65.         Lighting On
    66.        
    67.         CGPROGRAM
    68.         #pragma surface surf Lambert
    69.        
    70.         struct Input
    71.         {
    72.             float4 screenPos;
    73.             float3 viewDir;
    74.             float3 worldNormal;
    75.             float2 uv_Spraying;
    76.         };
    77.        
    78.         sampler2D _GrabTexture1;
    79.         float _Refraction;
    80.         sampler2D _BumpMap;
    81.         float _Distorsion;
    82.                
    83.         void surf( Input IN, inout SurfaceOutput o )
    84.         {
    85.             float3 laseringDistorsion = UnpackNormal( tex2D( _BumpMap, IN.uv_Spraying ) ) * _Distorsion;
    86.            
    87.             float3 obj = mul( (float3x3)_Object2World, float3( 0,0,0 ) );
    88.             float3 view = float3( IN.viewDir.x, 0, IN.viewDir.z );
    89.             float3 middle = obj + normalize( IN.viewDir );
    90.             float3 offsetVector = obj + normalize( IN.worldNormal );
    91.             float deltaX = max( offsetVector.x - middle.x, offsetVector.z - middle.z );
    92.             float deltaY = ( offsetVector.y - middle.y );
    93.            
    94.             float2 screenPosition = ( IN.screenPos.xy / IN.screenPos.w ).xy - float2( deltaX, deltaY ) * pow( _Refraction, 3 ) + laseringDistorsion;
    95.             float3 bgColor = tex2D( _GrabTexture1, screenPosition ).rgb;
    96.            
    97.             o.Albedo = 0;
    98.             o.Emission = bgColor;
    99.         }
    100.        
    101.         ENDCG
    102.        
    103.    
    104.        
    105.         //--------------------------4---------------------- Blende Farbe (Spraying), Transparenz (Metalization) und Painting drüber
    106.         //------------------------------------------------- Hier wird in den Z-Buffer geschrieben und sicher gestellt, das undurchsichtige Bereiche auch undurchsichtig und im Vordergrund angezeigt werden
    107.         Blend SrcAlpha OneMinusSrcAlpha
    108.         ZWrite On
    109.         Lighting On
    110.                
    111.         CGPROGRAM
    112.         #pragma surface surf BlinnPhongEditor  
    113.         #pragma target 3.0
    114.        
    115.         float4 _Color;
    116.         float _GlossNoYes;
    117.         sampler2D _Spraying;
    118.         sampler2D _Metalization;
    119.         sampler2D _Painting;
    120.         float _UVOffset;
    121.         samplerCUBE _Reflection;
    122.         sampler2D _BumpMap;
    123.         float _Distorsion;
    124.         float _Refraction;
    125.         float _Shininess;
    126.         float _FresnelPower;
    127.         sampler2D _GrabTexture1;
    128.        
    129.         struct EditorSurfaceOutput {
    130.             half3 Albedo;
    131.             half3 Normal;
    132.             half3 Emission;
    133.             half3 Gloss;
    134.             half Specular;
    135.             half Alpha;
    136.         };
    137.  
    138.         inline half4 LightingBlinnPhongEditor_PrePass( EditorSurfaceOutput s, half4 light )
    139.         {
    140.             half3 spec = light.a * s.Gloss;
    141.             half4 c;
    142.             c.rgb = ( s.Albedo * light.rgb + light.rgb * spec );
    143.             c.a = s.Alpha;
    144.             return c;
    145.         }
    146.  
    147.         inline half4 LightingBlinnPhongEditor( EditorSurfaceOutput s, half3 lightDir, half3 viewDir, half atten )
    148.         {
    149.             half3 h = normalize( lightDir + viewDir );
    150.            
    151.             half diff = max( 0, dot( lightDir, s.Normal ) );
    152.            
    153.             float nh = max( 0, dot( s.Normal, h ) );
    154.             float spec = pow( nh, s.Specular * 128.0 );
    155.            
    156.             half4 res;
    157.             res.rgb = _LightColor0.rgb * diff;
    158.             res.w = spec * Luminance( _LightColor0.rgb );
    159.             res *= atten * 2.0;
    160.            
    161.             return LightingBlinnPhongEditor_PrePass( s, res );
    162.         }
    163.  
    164.         struct Input {
    165.             float2 uv_Spraying;
    166.             float3 viewDir;
    167.             float3 worldNormal;
    168.             INTERNAL_DATA
    169.         };
    170.  
    171.         void surf( Input IN, inout EditorSurfaceOutput o )
    172.         {
    173.             float3 sprayColor = tex2D( _Spraying, IN.uv_Spraying );
    174.             float3 metal = tex2D( _Metalization, IN.uv_Spraying ).rgb;
    175.            
    176.             //float3 n = UnpackNormal( tex2D( _BumpMap, IN.uv_Spraying ) ) * _Distorsion;
    177.            
    178.             o.Normal = float3( 0, 0, 1 ); // wird hart gesetzt für Fresnel-Effekt
    179.            
    180.             float fresnel = ( 1.0 - dot( normalize( IN.viewDir ), o.Normal ) );
    181.             float fresnelPower = max( 0.2, pow( fresnel, _FresnelPower ) );
    182.             float3 reflectionVector = -reflect( IN.viewDir, IN.worldNormal );
    183.             float3 reflectionColor = texCUBE( _Reflection, reflectionVector ).rgb;
    184.            
    185.             float2 uvChoords = float2( IN.uv_Spraying.x + _UVOffset, IN.uv_Spraying.y );
    186.             float4 paintingColor = tex2D( _Painting, uvChoords );
    187.             float3 emissiveColor = lerp( sprayColor, reflectionColor, fresnelPower );
    188.            
    189.             o.Emission = lerp( emissiveColor, paintingColor.rgb, paintingColor.a );
    190.             o.Alpha = max( fresnelPower, max( metal.r, max( paintingColor.a, _Color.a ) ) );
    191.            
    192.             o.Specular = _Shininess;
    193.             o.Gloss = sprayColor * _GlossNoYes.xxxx;  
    194.            
    195.         }
    196.        
    197.         ENDCG
    198.        
    199.     }
    200.    
    201.    
    202. //  Fallback "Transparent"
    203.    
    204.    
    205. }
     
  2. gustavolsson

    gustavolsson

    Joined:
    Jan 14, 2011
    Posts:
    339
    I seem to have a similar problem with my multipass shader with blending and 4.2.

    I added a pass that should theoretically contribute nothing (Blend Zero One, Zero One; BlendOp Add, Add) and it did change the result. Could you maybe try the same thing?

    Could be a problem on my side, but I thought I should post here anyway.
     
  3. tosi

    tosi

    Joined:
    Jul 5, 2012
    Posts:
    45
    This seems to help, but unfortunately it does not entirely repair my shader. My last pass is still not computed and my refraction pass does not work as it did before.

    In my desperation, I turned on my windows machine to look, if there is any difference - I usually work on a Mac. It turns out, that there might be a problem with the line 89:
    Code (csharp):
    1.  o.Emission = lerp( emissiveColor.rgb, paintingColor.rgb, paintingColor.a );
    There is a bunch of errors in the console, all telling something like this:
    D3D shader assembly failed with: (19): error X5561: (first source param) Negate or abs modifiers not permitted on source parameters to texld*

    This does not mean anything to me and google's output is meager.
    If I comment out the line, the errors are gone. But if I look inside the computed shader and search for "texld", I get 76 results. It is quite hard to debug.
     
    Last edited: Jul 24, 2013
  4. gustavolsson

    gustavolsson

    Joined:
    Jan 14, 2011
    Posts:
    339
    If the shader code worked on windows with 4.1, this seems to be a bug.

    So the above changed the result for you too? That is really strange, because it should not affect the image at all. It should just keep the current color and alpha. (SrcColor * 0 + DstColor * 1)

    I just can't figure out what's going on. I will try to move all my passes to seperate shaders and see if this solves the problem.
     
  5. gustavolsson

    gustavolsson

    Joined:
    Jan 14, 2011
    Posts:
    339
    Ok, I tried moving all my passes into separate shaders and materials, and this solves the problem for me!

    This seems to be a Unity 4.2 bug related to multipass shaders and blending then. I can't find any other things our shaders have in common. Also, my shaders are not surface shaders (just plain CG).

    EDIT: I think I have pin-pointed the bug to using Zero for DstColor or DstAlpha in a pass other than the first one.

    NEW EDIT: This just keeps getting weirder. The number of passes needed for the bug to show up seems to vary, when going from projects or relaunching unity.

    Here is a shader that showcases the bug. Can anyone try this and see if they get the same result?

    Code (csharp):
    1. Shader "Custom/Shader" {
    2.     SubShader {
    3.         Tags { "RenderType"="Opaque" }
    4.        
    5.         // Multipass blending bug in Unity 4.2
    6.         //
    7.         // If the shader DOES show up as yellow for you, try to duplicate the first pass
    8.         // and place the copy after this comment. It should not matter for the "proof".
    9.         // The number of passes needed for the bug to show up seem to vary from time
    10.         // to time (between loading different projects and relaunching unity).
    11.         //
    12.         //        1st pass: Just render black
    13.         //        2nd pass: Just zero screen color and add red
    14.         //        3rd pass: Just add green
    15.         // Expected result: Yellow
    16.         //   Actual result: Red!!!
    17.         //
    18.         // Nothing should happen to the output if we were to remove the first pass,
    19.         // but if we try, the expected yellow appears.
    20.         //
    21.         // 1. The bug seems to be caused by using "Blend Something Zero" AFTER the first pass.
    22.         //
    23.         // 2. The bug seems to be there when working with the alpha channel too.
    24.         //
    25.         // 3. The bug is GONE if each pass gets it's own shader!
    26.        
    27.         Pass
    28.         {
    29.             ZTest Always
    30.            
    31.             CGPROGRAM
    32.             #pragma vertex vert
    33.             #pragma fragment frag
    34.            
    35.             float4 vert(float4 p : POSITION) : SV_POSITION
    36.             {
    37.                 return mul(UNITY_MATRIX_MVP, p);
    38.             }
    39.            
    40.             float4 frag() : COLOR
    41.             {
    42.                 return float4(0.0f, 0.0f, 0.0f, 1.0f);
    43.             }
    44.            
    45.             ENDCG
    46.         }
    47.        
    48.         Pass
    49.         {
    50.             ZTest Always
    51.             Blend One Zero // <- Zero causes the bug!
    52.            
    53.             CGPROGRAM
    54.             #pragma vertex vert
    55.             #pragma fragment frag
    56.            
    57.             float4 vert(float4 p : POSITION) : SV_POSITION
    58.             {
    59.                 return mul(UNITY_MATRIX_MVP, p);
    60.             }
    61.            
    62.             float4 frag() : COLOR
    63.             {
    64.                 return float4(1.0f, 0.0f, 0.0f, 1.0f);
    65.             }
    66.            
    67.             ENDCG
    68.         }
    69.        
    70.         Pass
    71.         {
    72.             ZTest Always
    73.             Blend One One
    74.            
    75.             CGPROGRAM
    76.             #pragma vertex vert
    77.             #pragma fragment frag
    78.            
    79.             float4 vert(float4 p : POSITION) : SV_POSITION
    80.             {
    81.                 return mul(UNITY_MATRIX_MVP, p);
    82.             }
    83.            
    84.             float4 frag() : COLOR
    85.             {
    86.                 return float4(0.0f, 1.0f, 0.0f, 1.0f);
    87.             }
    88.            
    89.             ENDCG
    90.         }
    91.     }
    92. }
     
    Last edited: Jul 25, 2013
  6. tosi

    tosi

    Joined:
    Jul 5, 2012
    Posts:
    45
    I can confirm that. If I just change Blend One Zero to Blend One One in my second pass, all passes are computed and shown correctly. At least under OpenGL. Direct3D is another problem, that maybe only I have.

    Aras, please save our souls.
     
  7. gustavolsson

    gustavolsson

    Joined:
    Jan 14, 2011
    Posts:
    339
    Ok, I've submitted a bug report with the example shader from my previous post. Hope it's fixed soon!
     
  8. reddotgames

    reddotgames

    Joined:
    Apr 5, 2011
    Posts:
    707
    Yeah we have got the same problem with 4.2 and FurFX where we use multipass with blending - all shaders which work on 4.1 are broken on 4.2.
     
  9. [RV]CWolf

    [RV]CWolf

    Joined:
    Jan 24, 2013
    Posts:
    33
    We're getting some serious shader issues with webplayer after upgrading from 4.1.2 to 4.2. Lots of unpredictable issues and broken / missing shaders.

    EDIT: Things seem to work fine in the editor however - just Webplayer shaders are not working well.
     
    Last edited: Aug 7, 2013
  10. Pangamini

    Pangamini

    Joined:
    Aug 8, 2012
    Posts:
    54
    The only problem i found so far is that GrabPass doesn't work. In editor, it often grabs the other view (game<->Scene) and in the build it grabs nothing
     
  11. gustavolsson

    gustavolsson

    Joined:
    Jan 14, 2011
    Posts:
    339
    I just received a reply from Unity concerning my bug report. They confirmed that this was indeed a bug and that it should be fixed in future versions of Unity :)
     
  12. chingwa

    chingwa

    Joined:
    Dec 4, 2009
    Posts:
    3,790
    I see this in my projects as well... it's definitely related to grabpass in my case. It seems like a shader compiling issue, as I can edit the shader and then it performs exactly as expected... that is until I shut down Unity and start it up again. :(
     
  13. Frieza

    Frieza

    Joined:
    Aug 29, 2008
    Posts:
    68
    We have had similar issues but with single pass shaders. On seemingly random occasion unity seems to zero values passed into our shader. i.e. any colors come out black, any transform_tex's come out as zero (i.e. one massive pixel across the entire surface usually) even if you force values EVERY FRAME from code, it still zeros out. However, this is not consistent, as a scene reload may well have it render correctly.

    The issue is most noticeable on iPod Touch 4, but it may well happen on any platform.

    The *only* way we've managed to work around this is by hard coding values into the shader. Far from ideal.