Shader looks terrible on iOS but fine on Windows

188 views Asked by At

I'm working on a cross platform renderer for Windows and iOS. For an example application I wrote a shader that worked without problems on both platform (shader version “#version 120” on Windows and “#version 100” on iOS).

Next I added two more light sources and on iOS strange things began to happen. I altered my code several times but it never showed me the expected result (the torch is rendered using a shader with only one light, that's why it looks fine on iOS).

(1) Sometimes everything was one color:

enter image description here

(2) And sometimes it looked just terrible in any way:

enter image description here

On Windows it looks like I expected it to look:

enter image description here

Does anyone know why my shader does this on iOS?

This is my fragment shader for (2):

//Light
uniform mediump float  numLights;
//L0
uniform mediump vec4   lightPosition_0;
uniform mediump vec3   lightColor_0;
uniform mediump float  lightIntensity_0;
uniform mediump float  lightAttenuation_0;
//L1
/*same as for light 0 */
//L2
/*same as for light 0 */

uniform mediump vec3    ambientColor;

uniform mediump vec3 Ka;
uniform mediump vec3 Kd;
uniform mediump vec3 Ks;

uniform sampler2D NormalMap;
uniform sampler2D DiffuseMap;
uniform sampler2D SpecularMap;

varying highp vec4 texCoordVarying;

varying highp vec4 posWorldSpace;       // pos in View Space

varying highp vec3 tangentSurface2light_0;
varying highp vec3 tangentSurface2light_1;
varying highp vec3 tangentSurface2light_2;

void main()
{
    //normal based on normal map
    highp vec3 normalNormalMap = normalize(texture2D(NormalMap, texCoordVarying.st).xyz *2.0 - 1.0);

    //ambient light
    highp vec3 ambient  = clamp(ambientColor + Ka, 0.0, 1.0);

    //diffuse light
    highp vec3 diffuse;

    // light 0
    if(numLights >= 1.0)
    {
        //light intensity based on distance from light to object
        highp float distance = distance(posWorldSpace, lightPosition_0);
        highp float intensityBasedOnDist = lightIntensity_0/(lightAttenuation_0*distance*distance);
        intensityBasedOnDist = clamp(intensityBasedOnDist, 0.0, 1.0);

        //light intensity based on angle between normal and light vector
        highp float intensity = max(dot(normalNormalMap,tangentSurface2light_0), 0.0) ;
        intensity = clamp(intensity, 0.0, 1.0);

        //diffuse light
        diffuse  += lightColor_0 * intensity * intensityBasedOnDist;
    }
    // light 1
    if(numLights >= 2.0)
    {
        /*same as for light 0 */
    }
    // light 2
    if(numLights >= 3.0)
    {
       /*same as for light 0 */
    }

    diffuse = diffuse * Kd * texture2D(DiffuseMap, texCoordVarying.st).xyz;

    gl_FragColor = vec4(clamp(ambient + diffuse, 0.0, 1.0), 1.0);
}

I made a lot of stuff highp or mediump. When I made evrything highp it sometimes almost looked right, but now not even that trick doesn't seem to help anymore ...

1

There are 1 answers

3
Pidhorskyi On BEST ANSWER
  1. You must not use uninitialized variables. Look at the diffuse variable, you add a value to uninitialized variable. Just replace:

    highp vec3 diffuse;
    

    with:

    highp vec3 diffuse = vec3(0,0,0);
    

    If you use an uninitialized variable, behavior can differs much from driver to driver.

  2. Avoid if statements as much as you can. For your case it would be better to create three separate shaders for one, two and three lights. You may use preprocessor to keep single source file.