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:
(2) And sometimes it looked just terrible in any way:
On Windows it looks like I expected it to look:
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 ...
You must not use uninitialized variables. Look at the diffuse variable, you add a value to uninitialized variable. Just replace:
with:
If you use an uninitialized variable, behavior can differs much from driver to driver.