Per Pixel Lighting problems

I’m having issues with implementing per pixel lighting with GLSL. The problem is this; first I can’t get the specular highlight to work as it should. The highlight shows with an offset depending on my eye position. Second, my frames per second drops from around 550+ to a crippling 20-25 frames per second, is this to expect on a geForce 7800GT?

The fragment code results in the image below. The hightlight is not in the correct position. The star symbol is at the light’s location.

void pointLight(in int i, in vec3 N, in vec3 V,
                      in float shininess,
                      inout vec4 ambient,
                      inout vec4 diffuse,
                      inout vec4 specular){

  vec3 D = gl_LightSource[i].position.xyz - V;
  vec3 L = normalize(D);
  float dist = length(D);
  float att=calculateAttenuation(i, dist);
  float nDotL = dot(N,L);
  vec3 E = normalize(-V);	
  vec3 R = reflect(-L, N);
  float pf = pow(max(dot(E,R), 0.0), shininess);

  ambient  +=  gl_LightSource[i].ambient  * att;
  diffuse  +=  gl_LightSource[i].diffuse  * att * nDotL;
  specular +=  gl_LightSource[i].specular * att * pf;     
}

Any help appriciated!

How do you calculate V and N in vertex shader?

And yes, 20-25 FPS is way too slow for 7800GT. I don’t see anything in the shader that could cause such performance drop - it must be somewhere else.
On 7800GT fixed functionality is emulated using shaders, so using your own shaders costs you nothing, except when they’re complex shaders. Your shader is not complex - it should run very fast.

Thanks for the reply! The V and N are computed like this in the vertex shader:


varying vec3 N;
varying vec3 V;

N= normalize(gl_NormalMatrix * gl_Normal);
vec4 ecPos3=gl_ModelViewMatrix * gl_Vertex;
V= (vec3(ecPos3))/ecPos3.w;

However, I have got the specular highlight to work, still got the slowdowns. I had a look in my orange book and found out that to emulate fixed function point lighting I shouldn’t use the reflect function. Instead I should compute the halfVector, when I’d done that it sorted out most of my problems. The shader code looks like this now:


void pointLight(in int i,
                in vec3 N, in vec3 V,
                in float shininess,
                inout vec4 ambient,
                inout vec4 diffuse,
                inout vec4 specular)
{
  vec3 halfVector;
  vec3 D = gl_LightSource[i].position.xyz - V;
  vec3 L = normalize(D);
  float dist = length(D);
  float att = calculateAttenuation(i, dist);
  float nDotL = dot(N,L);    
  float pf=0.0;
  if(nDotL >0.0){
    halfVector=normalize(L+vec3(0.0,0.0,1.0));    
    float nDotHV = max(0.0,dot(N,halfVector));
    pf = pow(nDotHV,shininess);		
  }

  ambient += gl_LightSource[i].ambient * att;	
  diffuse += gl_LightSource[i].diffuse * nDotL * att;
  specular += gl_LightSource[i].specular * pf * att;	
}

I need to render boxes that got a shared normal for each corner of the box… In other words; the normal will originate from the center of the box, like this:

These normals will smooth out the box so the sides won’t be so defined. But my fragment shader screw up the specular highlight because of this… it ends the highlight prematurely (red arrows). The dot product between the normal and the light vector needs to span a wider range than nDotL>=0.0. But if I make 0.0 a negative value the specular will start to appear on places where there should be no highlight (i.e. back facing surfaces). If anyone got an idea how to solve this problem or how to speed things up I would be very grateful.

How it looks when the highlight ends prematurely:

No wonder your specular highlight ends prematurely - you have ‘if’ in your code and specular reflection always go a bit further than +/- 90 degrees.

I use reflect function for specular lighting.

My vertex shader:


varying vec3 lightVec;
varying vec3 eyeVec;
varying vec3 normalVec;

void main( void )
{
  normalVec = gl_NormalMatrix * gl_Normal;
  lightVec = normalize(gl_LightSource[0].position.xyz);
  eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz;

#ifdef __GLSL_CG_DATA_TYPES
  gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
#endif

  gl_Position = ftransform();
}

Fragment shader:


uniform float specular;
uniform vec4 diffuseColor;

varying vec3 lightVec;
varying vec3 eyeVec;
varying vec3 normalVec;

void main(void)
{
  vec3 lightVec2 = normalize(lightVec);
  vec3 eyeVec2 = normalize(eyeVec);
  vec3 normalVec2 = normalize(normalVec);
  vec4 color = diffuseColor;

  float l = clamp(dot(lightVec2, normalVec2), 0.0, 1.0);
  color.rgb = color.rgb * l;

  float spec = clamp( dot(lightVec2, reflect(normalize(eyeVec2), -normalVec2)), 0.0, 1.0);
  
  float specular2 = clamp(specular, 0.0, 10.0);
  color.rgb = color.rgb + vec3(1.2, 1.0, 0.8) * specular2 * pow(spec, 1.0 + 9.0 * specular2);

  gl_FragColor.rgb = color.rgb;
  gl_FragColor.a = diffuseColor.a;
}

What you’re interested in this shader is how I compute ‘spec’ value.

Note that this is pretty simple shader that ignores light color and other stuff. It’s not meant to emulate fixed function.
I have an attribute called ‘specular’ which is used for pow operation as well as to scale final specular highlight, after clamping to 0.0-10.0 - it’s a bit weird, but that’s what I wanted in this shader - a single value to control “not shiny” <-> “shiny”. I wanted it for my default shader, so I can quickly test object’s appearance in editor without having to play around with materials.

I have removed the “if” and replaced it with a clamp… but now the specular highlight shows as a “cone” on front facing polygons when the light source is occluded by geometry. A picture showing the problem:

If I use the reflect function the specular highlight moves around as I pan the camera (top screenshot on this page), doesn’t look right when the specular is offseted in that way. I think it looks better with halfVector. Only problem is this “cone” thing when lightsource is behind something. Everything looks OK when the lightsource is in front of the pillar.

I have removed the “if” and replaced it with a clamp

No, there should be no if/clamp there at all.
What you should clamp is nDotHV.

halfVector=normalize(L+vec3(0.0,0.0,1.0));

Are you sure this is how you calculate half vector?

V= (vec3(ecPos3))/ecPos3.w;

What is this for?

If I use the reflect function the specular highlight moves around as I pan the camera

It should.
When I looked at your first image I thought your problem was, that specular highlight moved in a wrong way when you moved camera. Now I’m starting to think that you don’t want the specular lighting to move at all. This is not correct - specular lighting is more less reflection of a light source and therefore it is heavily dependant on viewig angle.

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