Why Do Android Devices Hate This Shader?

Hi,

I've just started Unity Android development and found out that one of the modified shaders that our project is using is causing the devices to crash.

The shader is a modified cutout soft-edge shader. I removed the color component out of the shader computation (at least I think I did) because I didn't need to do any color modulation.

When using the vanilla Soft-Edge shader it works fine, but only when I try to use this optimized soft-edge shader I run into problems. For now I'm just using the vanilla one. However, is there a reason why this version doesn't work? It works fine in the Editor, it just creates a Signal 11 crash when I run it on my HTC Nexus One device. Any help would be appreciated so that I can better understand what I did wrong.

Thanks!

Properties {
    _MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {}
    _Cutoff ("Base Alpha cutoff", Range (0,.9)) = .5
}

SubShader {
    Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }
    Lighting off

    // first pass:
    //   render any pixels that are more than [_Cutoff] opaque
    Pass {  
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata_t {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };

            struct v2f {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Cutoff;

            v2f vert (appdata_t v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }

            float4 _Color;
            half4 frag (v2f i) : COLOR
            {
                half4 col = tex2D(_MainTex, i.texcoord);
                clip(col.a - _Cutoff);
                return col;
            }
        ENDCG
    }

    // Second pass:
    //   render the semitransparent details.
    Pass {
        Tags { "RequireOption" = "SoftVegetation" }

        // Dont write to the depth buffer
        ZWrite off

        // Set up alpha blending
        Blend SrcAlpha OneMinusSrcAlpha

        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata_t {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };

            struct v2f {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Cutoff;

            v2f vert (appdata_t v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }

            float4 _Color;
            half4 frag (v2f i) : COLOR
            {
                half4 col = tex2D(_MainTex, i.texcoord);
                clip(-(col.a - _Cutoff));
                return col;
            }
        ENDCG
    }
}

SubShader {
    Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }
    Lighting off

    // first pass:
    //   render any pixels that are more than [_Cutoff] opaque
    Pass {  
        AlphaTest Greater [_Cutoff]
        SetTexture [_MainTex] {
            combine texture 
        }
    }

    // Second pass:
    //   render the semitransparent details.
    Pass {
        // Dont write to the depth buffer
        ZWrite off

        // Only render pixels less or equal to the value
        AlphaTest LEqual [_Cutoff]

        // Set up alpha blending
        Blend SrcAlpha OneMinusSrcAlpha

        SetTexture [_MainTex] {
            Combine texture 
        }
    }
}

This does not answer your question, but here's what I was talking about, in my comment (sorry, I don't know Cg or feel a need to learn it presently):

Shader "Transparent/Cutout/Soft Edge Unlit +" {

Properties {
    _MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {}
    _Cutoff ("Base Alpha cutoff  (Use Script)", Float) = 1
    _CutoffInverseQuarter ("Cutoff inverse / 4  (Use Script)", Float) = 1
}

Category {
    Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}

    SubShader {
        Pass {
            GLSLPROGRAM
            varying mediump vec2 uv;

            #ifdef VERTEX
            void main() {
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
                uv = gl_MultiTexCoord0.xy;
            }
            #endif

            #ifdef FRAGMENT
            uniform lowp sampler2D _MainTex;
            uniform lowp float _Cutoff;
            void main() {
                vec4 texture = texture2D(_MainTex, uv);
                if (texture.a < _Cutoff) discard;
                gl_FragColor = texture;
            }
            #endif      
            ENDGLSL
        }
        Pass {
            ZTest Less  ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha

            GLSLPROGRAM
            varying mediump vec2 uv;

            #ifdef VERTEX
            void main() {
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
                uv = gl_MultiTexCoord0.xy;
            }
            #endif

            #ifdef FRAGMENT
            uniform lowp sampler2D _MainTex;
            uniform lowp float _Cutoff;
            void main() {
                vec4 texture = texture2D(_MainTex, uv);
                gl_FragColor = vec4(texture.rgb, texture.a / _Cutoff);
            }
            #endif      
            ENDGLSL
        }   
    }

    SubShader {
        Pass {
            AlphaTest GEqual[_Cutoff]
            SetTexture[_MainTex]
        }
        Pass {
            ZTest Less  ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            SetTexture[_MainTex] {
                ConstantColor(0,0,0, [_CutoffInverseQuarter])
                Combine texture, texture * constant Quad
            }
        }
    }
}

}

The material inspector is inadequate for this, though; an EditorWindow is usable:

using UnityEngine;
using UnityEditor;

class SoftEdgePlusCutoffWindow : EditorWindow {

static SoftEdgePlusCutoffWindow window;
static Material material;

[MenuItem("Assets/Adjust Soft Edge + Cutoff", true)] static bool Validate () {
    if (window) return false;

    try {material = (Selection.activeObject as GameObject).renderer.sharedMaterial;}
    catch {material = Selection.activeObject as Material;}
    return material ? material.HasProperty("_CutoffInverseQuarter") : false;
}

[MenuItem ("Assets/Adjust Soft Edge + Cutoff", false, 2000)] static void Open () {
    window = GetWindow<SoftEdgePlusCutoffWindow>(true, material.name);
    window.autoRepaintOnSceneChange = true;
}

// The alpha channel of the texture needs to be scaled so that that it is white at the cutoff value.
// That way, there will always be a full invisible-opaque transition,
// instead of there being a visible alpha tested edge with lower cutoff values.
// You can only make the alpha 4x as bright, with a fixed function shader, 
// hence the .25 here, and Quad in the shader. 
bool listeningForGuiChanges;
void OnGUI () {
    Event currentEvent = Event.current;
    if (currentEvent.type == EventType.MouseDown && currentEvent.button == 0) {
        Undo.SetSnapshotTarget(material, material.name + " Cutoff Adjustment");
        Undo.CreateSnapshot();
        Undo.ClearSnapshotTarget();
        listeningForGuiChanges = true;
    }

    material.SetFloat("_Cutoff", EditorGUILayout.Slider("Cutoff", material.GetFloat("_Cutoff"), .25F, 1));
    material.SetFloat("_CutoffInverseQuarter", .25F / material.GetFloat("_Cutoff"));

    if (listeningForGuiChanges && GUI.changed) {
        Undo.SetSnapshotTarget(material, material.name + " Cutoff Adjustment");
        Undo.RegisterSnapshot();
        listeningForGuiChanges = false;     
    }   
}

}

This works on iOS. Please let us know what happens on Android.

In case anyone stumbles across this like I did, Android has issues with AlphaTest and clip(), which can be resolved by editing the shader above to read:

Shader "Transparent/Cutout/Soft Edge Unlit +" {
 
Properties {
    _MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {}
    _Cutoff ("Base Alpha cutoff  (Use Script)", Float) = 1
    _CutoffInverseQuarter ("Cutoff inverse / 4  (Use Script)", Float) = 1
}
 
Category {
    Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
 
    SubShader {
        Pass {
            GLSLPROGRAM
            varying mediump vec2 uv;
 
            #ifdef VERTEX
            void main() {
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
                uv = gl_MultiTexCoord0.xy;
            }
            #endif
 
            #ifdef FRAGMENT
            uniform lowp sampler2D _MainTex;
            uniform lowp float _Cutoff;
            void main() {
                vec4 texture = texture2D(_MainTex, uv);
                if (texture.a < _Cutoff) discard;
                gl_FragColor = texture;
            }
            #endif      
            ENDGLSL
        }
        Pass {
            ZTest Less  ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
 
            GLSLPROGRAM
            varying mediump vec2 uv;
 
            #ifdef VERTEX
            void main() {
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
                uv = gl_MultiTexCoord0.xy;
            }
            #endif
 
            #ifdef FRAGMENT
            uniform lowp sampler2D _MainTex;
            uniform lowp float _Cutoff;
            void main() {
                vec4 texture = texture2D(_MainTex, uv);
                gl_FragColor = vec4(texture.rgb, texture.a / _Cutoff);
            }
            #endif      
            ENDGLSL
        }   
    }
 
    SubShader {
        Pass {
            ZTest Less  ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            SetTexture[_MainTex] {
                ConstantColor(0,0,0, [_CutoffInverseQuarter])
                Combine texture, texture * constant Quad
            }
        }
    }
}
 
}