Shardelab/CG shaders not working on iOS

I have little experience writing GLSL shaders, but no experience at all with shaderlab or CG shaders.

I’ve written a couple of shaders in shaderlab/cg that works well on desktop, an Asus 7 android tablet, but does not work on an iPhone 4S and an old Samgung Galaxy S. They look wrong or just black.

So, I’ve rewritten them in GLSL and they work perfectly in all devices (except windows, of course). But I can see in the shaders properties in the unity inspector that the CG one’s are more complex, so I’m probably doing something wrong.

I post one here:

CG version:

Shader "Custom/HudboxCG" {
 	Properties {
    	_Color ("Color", Color) = (1,1,1,.5)
 	}
 
	SubShader {
		Tags { "RenderType" = "Opaque" }
      
    	CGPROGRAM
    	#pragma surface surf Lambert vertex:vert
    	struct Input {          
    		float lum;
    	};
     
    	void vert (inout appdata_full v, out Input o) {
    		UNITY_INITIALIZE_OUTPUT(Input,o);
        	// (0,1,-2) normalized
        	o.lum = dot(float3(0, 0.447214, -0.894427), v.normal) * 1.1;
    	}
     
    	float4 _Color;      
    	void surf (Input IN, inout SurfaceOutput o) {
    		o.Albedo = _Color;
        	o.Emission = _Color * IN.lum;          
    	}
    	ENDCG      
	}
}

alt text

GLSL version:

Shader "Custom/Hudbox" {
	Properties {
    	_Color ("Color", Color) = (1,1,1,.5)
 	}
 
 	SubShader {
    	Tags { "RenderType" = "Opaque" }
      	Pass {      
      		GLSLPROGRAM
            #ifdef VERTEX
            	varying float lum;
            	uniform vec4 _Color;

            	void main() {
            		vec4 avertex = gl_Vertex;
            		lum = dot(vec3(0, 0.447214, -0.894427), gl_Normal) * 1.1;            	
                	gl_Position = gl_ModelViewProjectionMatrix * avertex;
            	}
            #endif

            #ifdef FRAGMENT
            	varying float lum;
            	uniform vec4 _Color;

            	void main() {
                	gl_FragColor = _Color * lum;                
            	}            
            #endif

            ENDGLSL                   
    	}
    }    
    Fallback "Custom/HudboxCG"
}

alt text

So how should I write the cg shader so the generated GLSL is similar to the one I’ve hand-written?

You’re right - the CG version is more complex, because you’ve created a surface shader (which you did with the line #pragma surface surf). Surface shaders are like a template (or shader “wizard”, if you prefer) that allow you to write the base functionality of a shader, and then when Unity compiles it it will automatically generate additional shader code to handle interaction with lighting, deferred rendering etc. (in fact, if you change the lighting in your scene, you may be able to notice the difference in behaviour between the two shaders above). This extra auto-generated stuff won’t be included with the GLSL shader, which just defines a vertex/fragment shader pair.

Differences between shader types is explained at: Unity - Manual: Shaders

To create equivalent code to your GLSL, you need to define a vertex/fragment shader, like this:

Shader "Custom/HudboxCG_2" {
    Properties {
    	_Color ("Color", Color) = (1,1,1,.5)
    }
     
    SubShader {
    	Tags { "RenderType" = "Opaque" }
     	Pass {
    	CGPROGRAM
    	#pragma vertex vert
    	#pragma fragment frag
    	#include "UnityCG.cginc"
   		struct v2f {
			float4 pos : SV_POSITION;
            float lum : TEXCOORD;
    	};
     
    	v2f vert (appdata_base v) {
    		v2f o;
    		o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    		o.lum = dot(float3(0, 0.447214, -0.894427), v.normal) * 1.1;
    		return o;
    	}

    	float4 _Color;
    	half4 frag (v2f IN) : COLOR {
    		return _Color * IN.lum;
	    }
    	ENDCG
    	}
    }	
}