0

In OpenGL ES 2.0 for Android, I am drawing a sphere. The sphere appears on the screen as a circle, so I need to add lighting. When I added lighting, instead of it being smooth, like it would be in real life, it is a fine line between light and dark, as shown here:
enter image description here
However, I want it to look like this, where the shading is much smoother and blended:

Here is my vertex shader code:

uniform mat4 u_Matrix;
uniform vec3 u_VectorToLight;

attribute vec4 a_Position;
attribute vec3 a_Color;
attribute vec3 a_Normal;

varying vec3 v_Color;

void main() {
  v_Color = a_Color;
  vec3 scaledNormal = a_Normal;
  scaledNormal = normalize(scaledNormal);
  float diffuse = max(dot(scaledNormal, u_VectorToLight), 0.0);
  v_Color *= diffuse;
  float ambient = 0.1;
  v_Color += ambient;
  gl_Position = u_Matrix * a_Position;
}

And my fragment shader:

precision mediump float;

varying vec3 v_Color;

void main() {
  gl_FragColor = vec4(v_Color, 1.0);
}

The normal is calculated by getting the vector from the center of the sphere to the point on the sphere, then normalizing it (giving it a length of 1)

Here is how I set the colors:

vertices[offset++] = Color.red(color);
vertices[offset++] = Color.green(color);
vertices[offset++] = Color.blue(color);

Where color is 0xffea00.

vcapra1
  • 1,988
  • 3
  • 26
  • 45
  • Possibly related: http://stackoverflow.com/questions/4703432/why-does-my-opengl-phong-shader-behave-like-a-flat-shader – Morrison Chang Nov 28 '14 at 19:33
  • @MorrisonChang - But even in that question, when the sphere is not smooth, the light gradually changes from the lightest point to the darkest, it doesn't just "snap" at the middle. – vcapra1 Nov 28 '14 at 19:34
  • Can you also post your fragment shader and the snippet of code that calculates the normals? – tiguchi Nov 28 '14 at 19:36
  • What's the value you are setting for `u_VectorToLight`? – Reto Koradi Nov 28 '14 at 19:48
  • It's been a while for me, but if I am not completely mistaken, you also need to multiply your normals with a dedicated normal matrix, which is basically derived from the model-view matrix (see http://www.arcsynthesis.org/gltut/Illumination/Tut09%20Normal%20Transformation.html and https://www.udacity.com/course/viewer#!/c-cs291/l-101410106/m-118429131). I'm still not entirely sure what to think about those jagged artifacts. It's pretty strange. – tiguchi Nov 28 '14 at 19:48
  • @RetoKoradi - `u_VectorToLight` is set to {1.0, 1.0, 0.0} – vcapra1 Nov 28 '14 at 19:49
  • That vector should be normalized. But I don't think it completely explains the effect. – Reto Koradi Nov 28 '14 at 19:51
  • @RetoKoradi - Sorry - forgot to add that it is being normalized, which should make it about {0.707, 0.707, 0} – vcapra1 Nov 28 '14 at 19:52
  • What about `a_Color`? What's the value of that? I have a feeling that one of the values in that diffuse calculation is way larger than it should be, so that the color immediately saturates as soon as it crosses 0.0. – Reto Koradi Nov 28 '14 at 20:46
  • @RetoKoradi - `a_Color` is set to {Color.red(0xffea00), Color.green(0xffea00), Color.blue(0xffea00)} – vcapra1 Nov 28 '14 at 20:49
  • @RetoKoradi - That was it! - Color.red() returns a value between 0 and 255, instead of 0 and 1, same with green() and blue(), so I need to divide by 0xff (255). – vcapra1 Nov 28 '14 at 20:57
  • That would probably explain it. What type are you using when you specify the color vertex attribute? `GL_FLOAT`? You probably end up with colors in the range 0..255 in the shader, while you need colors in the range 0.0..1.0. I can add an answer if you provide the details of how the colors are specified in your code. – Reto Koradi Nov 28 '14 at 20:57
  • I'll put itin my post – vcapra1 Nov 28 '14 at 20:59
  • @RetoKoradi - I put it in – vcapra1 Nov 28 '14 at 21:06

1 Answers1

2

The problem is with the range of color values you use. OpenGL operates with color component values in the range [0.0, 1.0]. But you are specifying colors in the range [0, 255] in your Java code.

You have two options to fix this:

  • Divide the color values you get from the Color class by 255.0f.
  • Specify the colors with type GL_UNSIGNED_BYTE. To do this, store the values in an array/buffer with element type byte, store those values in a VBO, and then set up the vertex attribute with:

    glVertexAttribPointer(attrLoc, 3, GL_UNSIGNED_BYTE, GL_TRUE, stride, 0);
    

    Note the value for the 4th argument. While it does not matter for GL_FLOAT attributes, it is critical that you use GL_TRUE in this case, because the byte values need to be normalized.

Reto Koradi
  • 53,228
  • 8
  • 93
  • 133