title: GLSL - a shader does not work using mediump precision
body: <p>I have a shader of atmospheric scattering that I found through the Internet. In fact, this is the WebGL(three.js) shader. I try to run it on mobile devices. I found out that it works great on <code>Qualcomm</code> and <code>KIRIN</code> chipsets when I use <code>hihgp</code> precision and doesn't work on <code>Mali</code> chipsets at all (just black screen). Athouth, it compiles without any errors. I assume that this happens because <code>Mali</code> GPUs (or similar ones) have not enough <code>highp</code> precision for this shader. If I use mediump precision it doesn't work on all devices (just black screen). Is it possible to make this(any) shader works using <code>mediump</code> precision? Or how to make this shader works on all popular chipsets?</p>
  
  <p>Vertex shader:</p>
  
  <pre><code>attribute vec3 a_position;
  attribute vec2 a_texCoord0;\n"+         
  
  uniform mat4 u_worldTrans;
  uniform mat4 u_projTrans;
  
  varying vec3 vWorldPosition;
  
  void main() {               
    vec4 worldPosition = u_worldTrans * vec4( a_position, 1.0 );
    vWorldPosition = worldPosition.xyz;
    gl_Position = u_projTrans * worldPosition;
  }
  </code></pre>
  
  <p>Fragment shader:</p>
  
  <pre><code>#ifdef GL_ES
  precision highp float;  
  #endif 
  
  uniform vec3 sunPosition;
  
  varying vec3 vWorldPosition;
  
  const float turbidity = 3.2; 
  const float reileigh = 2.7; 
  const float luminance = 1.0; 
  const float mieCoefficient = 0.007; 
  const float mieDirectionalG = .990; 
  
  #define e 2.718281828459 
  #define pi 3.141592653589 
  
  #define n 1.0003
  
  #define pn 0.035
  
  const vec3 lambda = vec3(0.00000068, 0.00000055, 0.00000045); 
  
  const vec3 K = vec3(0.686, 0.678, 0.666); 
  
  const vec3 up = vec3(0.0, 1.0, 0.0); 
  
  #define v 4.0 
  
  #define rayleighZenithLength 8400.0 
  #define mieZenithLength 1250.0 
  
  #define EE 1000.0 
  #define sunAngularDiameterCos 0.999956676946 
  
  #define cutoffAngle pi/1.95 
  #define steepness 1.5 
  
  
  vec3 simplifiedRayleigh()
  {
      return 0.0005 / vec3(94., 40., 18.);
  }
  
  float rayleighPhase(float cosTheta)
  {    
      return (3.0 / (16.0*pi)) * (1.0 + pow(cosTheta, 2.0));          
  }
  
  vec3 totalMie(vec3 lambda, vec3 K, float T)
  {
      float val = 10E-18; 
      float c = (0.2 * T ) * val;
      return 0.434 * c * pi * pow((2.0 * pi) / lambda, vec3(v - 2.0)) * K;
  }
  
  float hgPhase(float cosTheta, float g)
  {           
      return (1.0 / (4.0*pi)) * ((1.0 - pow(g, 2.0)) / pow(abs(1.0 - 2.0*g*cosTheta + pow(g, 2.0)), 1.5));
  }
  
  float sunIntensity(float zenithAngleCos)
  {
      return EE * max(0.0, 1.0 - exp(-((cutoffAngle - acos(zenithAngleCos))/steepness)));
  }
  
  
  #define A 0.15
  #define B 0.50 
  #define C 0.10 
  #define D 0.20 
  #define E 0.02 
  #define F 0.30 
  #define W 1000.0 
  vec3 Uncharted2Tonemap(vec3 x)
  {
     return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
  }
  
  void main() 
  {
  
      vec3 cameraPos = vec3(0., 0., -500.);
      float sunfade = 1.0-clamp(1.0-exp((sunPosition.y/4000.0)),0.0,1.0);
  
      float reileighCoefficient = reileigh - (1.0* (1.0-sunfade));
      vec3 sunDirection = normalize(sunPosition);
  
      float sunE = sunIntensity(dot(sunDirection, up));
  
      vec3 betaR = simplifiedRayleigh() * reileighCoefficient;
  
      vec3 betaM = totalMie(lambda, K, turbidity) * mieCoefficient;
  
      float zenithAngle = acos(max(0.0, dot(up, normalize(vWorldPosition - cameraPos))));
      float sR = rayleighZenithLength / (cos(zenithAngle) + 0.15 * pow(abs(93.885 - ((zenithAngle * 180.0) / pi)), -1.253));
      float sM = mieZenithLength / (cos(zenithAngle) + 0.15 * pow(abs(93.885 - ((zenithAngle * 180.0) / pi)), -1.253));
  
      vec3 Fex = exp(-(betaR * sR + betaM * sM));
  
      float cosTheta = dot(normalize(vWorldPosition - cameraPos), sunDirection);
  
      float rPhase = rayleighPhase(cosTheta*0.5+0.5);
      vec3 betaRTheta = betaR * rPhase;
  
      float mPhase = hgPhase(cosTheta, mieDirectionalG);
      vec3 betaMTheta = betaM * mPhase;
  
  
      vec3 Lin = pow(abs(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * (1.0 - Fex)),vec3(1.5));
      Lin *= mix(vec3(1.0),pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * Fex,vec3(1.0/2.0)),clamp(pow(1.0-dot(up,sunDirection),5.0),0.0,1.0));
  
      vec3 L0 = vec3(0.1) * Fex;
  
      float sundisk = smoothstep(sunAngularDiameterCos,sunAngularDiameterCos+0.00002,cosTheta);
  
      L0 += (sunE * 19000.0 * Fex)*sundisk;
  
      vec3 whiteScale = 1.0/Uncharted2Tonemap(vec3(W));
  
      vec3 texColor = (Lin+L0);   
      texColor *= 0.04 ;
      texColor += vec3(0.0,0.001,0.0025)*0.3;
  
      vec3 curr = Uncharted2Tonemap((log2(2.0/pow(luminance,4.0)))*texColor);
      vec3 color = curr*whiteScale;
  
      vec3 retColor = pow(color,vec3(1.0/(1.2+(1.2*sunfade))));
  
      gl_FragColor.rgb = retColor;
  
      gl_FragColor.a = 1.0;
  }
  </code></pre>
  
  <p>I'm using LibGDX, so my shader class is bellow:</p>
  
  <pre><code>public class SkyShader implements Shader{
  
  ShaderProgram program;
  Camera specCamera;
  int WIDTH, HEIGHT;
  
  int u_projTrans;
  int u_worldTrans;
  
  int u_sunPosition;
  int u_res;
  
  int u_luminance;
  int u_turbidity;
  int u_reileigh;
  int u_mieCoefficient;
  int u_mieDirectionalG;
  
  public Vector3 sunDirection = new Vector3();
  
  Matrix4 viewInvTraMatrix = new Matrix4();
  
  
  @Override
  public void init() {
  
      program = new ShaderProgram(vert, frag);    
      if (!program.isCompiled())throw new RuntimeException(program.getLog());
  
      else Gdx.app.log("sky program", "shader compiled successfully!");
  
  
      u_projTrans = program.getUniformLocation("u_projTrans");
      u_worldTrans = program.getUniformLocation("u_worldTrans");
  
      u_sunPosition = program.getUniformLocation("sunPosition");
  
      u_res = program.getUniformLocation("u_res");
  }   
  
  
  
  @Override
  public void dispose() {
      if(program!=null){
          program.dispose();
          program = null;
      }
  }
  
  static final float delta = 0.0028526667f;
  
  Matrix4 projectionMatrix = new Matrix4();
  
  @Override
  public void begin(Camera camera, RenderContext context) {               
      program.begin();
  
      projectionMatrix.set(camera.projection);        
      if(Settings.landscape)
          projectionMatrix.rotate(0, 1, 0, (Settings.EarthRotation-100) * .4f);       
      else projectionMatrix.rotate(0, 1, 0, (Settings.EarthRotation-100) * .7f);              
      program.setUniformMatrix(u_projTrans, projectionMatrix);        
  
      if(Settings.EnableSlightShadowGradient)
          program.setUniformf(u_res, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
  
  
      float rotation = Settings.EarthRotation * delta -.0375f;//- .00674f;
      float azimuth = rotation; //_azimuth;
  
  
      float inclination = .3f; //skyParams[i][4];
      float theta = (float) (Math.PI * ( inclination - 0.5f ));
      float phi = (float) (2f * Math.PI * ( azimuth - 0.5f ));
  
      float distance = 4000;//400000;
      sunDirection.x = (float) (distance * Math.cos( phi ));
      sunDirection.y = (float) (distance * Math.sin( phi ) * Math.sin( theta ));
      sunDirection.z = (float) (distance * Math.sin( phi ) * Math.cos( theta ));
  
  
      context.setDepthTest(GL20.GL_LEQUAL);   
      context.setCullFace(GL20.GL_FRONT);     
  }
  
  
  @Override
  public boolean canRender(Renderable arg0) {
      return true;
  }
  
  @Override
  public int compareTo(Shader arg0) {     
      return 0;
  }
  
  @Override
  public void end() {
      program.end();      
  }
  
  
  
  @Override
  public void render(Renderable renderable) {     
      program.setUniformMatrix(u_worldTrans, renderable.worldTransform);
  
      program.setUniformf(u_sunPosition, sunDirection);
  
      renderable.mesh.render(program, renderable.primitiveType, 
              renderable.meshPartOffset, renderable.meshPartSize);
  }
  
  }
  </code></pre>
  
  <p>And finally, I render it using the following code:</p>
  
  <pre><code>modelBatch.begin(cam);  
  modelBatch.render(sphere, skyShader);
  modelBatch.end();
  </code></pre>
  
  <p>Where sphere is:</p>
  
  <pre><code>public ModelInstance createSphere() {
      ModelBuilder modelBuilder = new ModelBuilder();
  
      float radius = 4500;//450000;
  
      Model tempSphere;
      tempSphere = modelBuilder.createSphere(radius, radius, radius, 32, 8,
              new Material(),
              VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal | VertexAttributes.Usage.TextureCoordinates
      );
  
      return new ModelInstance(tempSphere,0,0,0);       
  }
  </code></pre>
  
  <p>Original shader is <a href="https://threejs.org/examples/webgl_shaders_sky.html" rel="nofollow noreferrer">here</a></p>
  
  <p><strong>EDIT</strong>
  If I run original shader(link is above) on <code>problem</code> devices in browser it works perfect! </p>
  
  <p>Thanks in advance.</p>