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;/**/
}