Specular shader on iOS

I'm trying to use the specular shader on iOS to create a Earth object. As texture I have a normal earth surface color in the RGB channel and a specular color in the alpha channel. (I have used the textures from http://learningwebgl.com/blog/?p=1778 ).

In the editor I get the desired effect:

Specular shader in Editor

But when I run the program on my iPad I get much different effect (much more specular):

Specular shader on iOS

I know that there are differences between shaders running different devices. But what is the exact reason why this don't work? And where can I find a detailed description of the differences between the two platforms?

Additional info:

  • I have used a mesh with many polygons (it seems the light are computed in the vertex shader).
  • I have tried to use different image compression methods for iOS, but it didn't change anything
  • I have used Unity 3.3 Pro + iPhone iOS (not Pro)

There is a slight problem with the BlinnPhong lighting model and OpenGLES. If you check the source code of the Mobile shaders, you will see that they provide an alternative lighting model “MobileBlinnPhong”.

I was able to isolate the issue to these lines in BlinnPhong:

inline fixed4 LightingBlinnPhong (SurfaceOutput s, fixed3 lightDir, fixed3 viewDir, fixed atten)
{
   fixed3 h = normalize (lightDir + viewDir); //normalize light direction added to the view direction

    fixed diff = max (0, dot (s.Normal, lightDir));

    float nh = max (0, dot (s.Normal, h)); //calculate the dot product of the surface normal and our normalized light+view, then make sure it is no smaller than 0 (black)
    float spec = pow (nh, s.Specular*128.0) * s.Gloss;

    fixed4 c;
    c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten * 2);
    c.a = s.Alpha + _LightColor0.a * _SpecColor.a * spec * atten;
    return c;
}

The mobile version MobileBlinnPhong:

inline fixed4 LightingMobileBlinnPhong (SurfaceOutput s, fixed3 lightDir, fixed3 halfDir, fixed atten)
{
    fixed diff = max (0, dot (s.Normal, lightDir));
    fixed nh = max (0, dot (s.Normal, halfDir)); //Instead of injecting the normalized light+view, we just inject view, which is provided as halfasview in the initial surface shader CG parameters
    fixed spec = pow (nh, s.Specular*128) * s.Gloss;

    fixed4 c;
    c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten*2);
    c.a = 0.0;
    return c;
}

So by comparison we can see that the GPU seems to fumble on the standard BlinnPhong model, and UT’s mobile version accounts for and corrects it.

For a quick fix, I suggest that any time you use OpenGLES (either 1.1 or 2.0) use a shader which employs the mobile-safe version of BlinnPhong lighting model as opposed to the standard.

If you need me to I’ll go more in-depth, I just wanted to get this out quickly.

Hope this helps!

==

Another great solution would be to create a specularity look-up table as described in here: iOS shader tricks, or it's 2001 all over again · Aras' website
It gives per-pixel specularity without the performance hit.