Lighting computation

Hi guys,

I am trying to perform some custom lighting computation using shaders, and I encountered a problem of geometrical nature. The test application is simple:

  • the camera is at the origin: (0, 0, 0)
  • a simple square is displayed in the center of the screen: (0, 0, -2)
  • an array of N light sources is located just above this square:
    (x, 0.3, -2) with X in the range [-0.3, -0.3] with 0.1 increment

The fragment shader perfoms per-pixel lighting computation using a basic Phong illumination model. The problem is that the specular highlight does not look like it should. Since the N lights are forming a line, I am expecting to see the specular light as some sort of line, or maybe more something like a rectangle with rounded corners. But I clearly dont, as the following screenshots prove:
http://alexis.gatt.free.fr/Interactive3DSoftproofing/screenshots/

4 rotations around the x axis are provided at different angles. The spheres located at the top represent the array of lights (there are actually 2 arrays of lights, but the problem remain the same).

First, there should not be any specular highlights at 0 degrees, since the angle (light, eye) is orthogonal, but some weird lines appear from God knows where. Then, you can see the specular highlights starting to appear at larger angles, but it has a strange curved shape, starting at the bottom corners and passing though the center of the square. Common sense tells us that the specular highlights should create some sort of rectangle at such angles. Indeed, I wrote another test program using the fixed functionality lighting facilities of OpenGL, and it behaves as expected, i.e. you get a rectangular shape specular highlight.

Question 1: Does anybody have encountered such a problem before? Or maybe somebody has a clue of where the problem lies? I included below the code of the fragment shader if that helps (lighting computation done in calDiffuseSpecular function).

Question 2: I have a question concerning the coordinate system used in the fragment shader. Is it using the global coordinate system, or a local one? I am passing the coordinate of the lights and camera position straight from the main app, so they are not tranformed in any way, which might create the problem if another coordinate system is used.

Many thanks

Alexis

 ////////////////////
///// Preprocessor definition
////////////////////

#define PHONG_NB_PARAM              36
#define PHONG_EQUATION_NB_PARAM     5
#define GLOSS_NB_PARAM              9

#define LIGHT_NB                    16




////////////////////
///// Structure definition
////////////////////

struct Gloss
{
  float phongGloss_[PHONG_NB_PARAM];
  float phongExp_[PHONG_NB_PARAM];
  float phongEquation_[PHONG_EQUATION_NB_PARAM];
  vec3  refColor_[GLOSS_NB_PARAM];
  float refColorGloss_[GLOSS_NB_PARAM];
};

struct Light
{
   vec4 color;
   vec4 position;
   float constant;
   float linear;
   float quadratic;
};




////////////////////
///// Variables definition
////////////////////

uniform sampler2D decal;
uniform Gloss     gloss;
uniform Light     light[LIGHT_NB];
uniform vec4      cameraPosition;

varying vec2 textureCoordinate0;
varying vec3 vertexNormal;
varying vec4 vertexPosition;




////////////////////
///// misc routines
////////////////////

float ComputeGloss(vec3 color, inout float glossFraction)
{
 // some code ...
}




void calDiffuseSpecular(vec3 lightPosition, vec3 cameraPosition, vec3 surfacePosition, vec3 surfaceNormal,
                        float shininess, inout float diffuseOut, inout float specularOut)
{
   // Calculate required vectors
   vec3 lightVec = normalize(lightPosition  - surfacePosition);
   vec3 eyeVec   = normalize(cameraPosition - surfacePosition);
   vec3 halfVec  = normalize(lightVec + eyeVec);

   // Diffuse computation
   diffuseOut = max(dot(lightVec, surfaceNormal), 0.0);

   // Calculate specular with the attenuation.
   specularOut = pow(max(dot(halfVec, surfaceNormal), 0.0), shininess);

   // No diffuse, no specular.
   if(diffuseOut < 0.0) specularOut = 0.0;
}




void main(void)
{
  // 1st obtain fragment color from texture
  vec4 fragmentColor = texture2D(decal, textureCoordinate0);

  // then compute Phong exponent
  float glossFraction=0.0;
  float phongExp = ComputeGloss(fragmentColor.xyz, glossFraction);

  // Re-normalize normal
  vertexNormal = normalize(vertexNormal);

  // Calculate diffuse and specular for all lights.
  float diffuseLight, specularLight, diffuseSum, specularSum;
  for(int i=0; i<LIGHT_NB ; ++i)
  {
    calDiffuseSpecular(light[i].position.xyz, cameraPosition.xyz, vertexPosition.xyz, vertexNormal,
                       phongExp, diffuseLight, specularLight);
    diffuseSum += diffuseLight;
    specularSum += specularLight;
  }

  // Get final diffuse and specular values.
  float diffuse = diffuseSum / 8.0; // TODO
  float specular = 0.4 * specularSum / 2.0;

  // Set final light color.
  gl_FragColor.x = (fragmentColor.x * diffuse) + (specular);
  gl_FragColor.y = (fragmentColor.y * diffuse) + (specular);
  gl_FragColor.z = (fragmentColor.z * diffuse) + (specular);/**/
  gl_FragColor.w = 1.0;

  // DEBUG
  /*gl_FragColor.x = diffuse;
  gl_FragColor.y = diffuse;
  gl_FragColor.z = diffuse;/**/
} 

Looking at your images, my first guess would be that you are passing completely different normal vectors to each corner of the square. Shouldn’t each corner have the same normal, perpendicular to the plane of the square?

I’m not good enought at shaders in order to find out what could be the problem. Did you ensure what the previous one said ?

Also, a quick look at the shader reveals this:

// Diffuse computation
diffuseOut = max(dot(lightVec, surfaceNormal), 0.0);

// No diffuse, no specular.
if(diffuseOut < 0.0) specularOut = 0.0;

How could diffuseOut be less than zero ? At least it could be zero but greater, not lesser.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.