0

I just tried implementing specular highlights. The issue is that when moving far away from the surface, the highlight becomes stronger and stronger and the edge of the highlight becomes very harsh. When moving too near to the surface, the highlight completely disappears.

This is the related part of my fragment shader. All computations are in view space. I use a directional sun light.

// samplers
vec3  normal    = texture2D(normals,   coord).xyz;
vec3  position  = texture2D(positions, coord).xyz;
float shininess = texture2D(speculars, coord).x;

// normalize directional light source
vec3 source;
if(directional) source = position + normalize(light);
else source = light;

// reflection
float specular = 0;
vec3 lookat = vec3(0, 0, 1);
float reflection = max(0, dot(reflect(position, normal), lookat));
int power = 5;
specular = shininess * pow(reflection, power);

// ...

// output
image = color * attenuation * intensity * (fraction + specular);

This is a screenshot of my lighting buffer. You can see that the foremost barrel has no specular highlight at all while the ones far away shine much too strong. The barrel in the middle is lighted as desired.

far highlights are too strong and near highlights disappear

What am I doing wrong?

danijar
  • 32,406
  • 45
  • 166
  • 297
  • Show your client side code , ,especially light vectors. Make sure you don't confuse positions with directions. – Michael IV Jan 23 '14 at 22:38
  • For directional light sources, I treat the position as direction. For example, the sun has the position `0.5, 1.0, 1.5`. Does this make problems? The issue is the same for direction lights and point lights though. – danijar Jan 23 '14 at 22:40
  • 1
    Not enough code .Show how you construct model view matrices .for example , if your look at vector is ls like x, y, z, 1 it can be a problem – Michael IV Jan 23 '14 at 22:44
  • You should edit the question and specify the coordinate system, the viewer and light states. `source`, `directional`, `light`, `arriving` and `faced` are not used in the final equation! `vec3 lookat = vec3(0, 0, 1);` looks like a directional light – a.lasram Jan 23 '14 at 23:51
  • @a.lasram `lookat` is the direction the camera is looking towards. Since I do all computations in view space, as stated in the question, it is pointing straight forwards. `source` is the light position, for point lights it is just set by the `light` position uniform, for directional lights, it is set to surface position plus light direction. `arriving` is the normalized vector from light to surface and it's used in `reflection` calculation. What do you mean by "viewer and light states"? I'll add that to the question then. – danijar Jan 24 '14 at 08:26
  • I don't see `arriving` anymore in the code! I'll try to write an answer and hope it would make sense – a.lasram Jan 24 '14 at 19:14

2 Answers2

2

You're calculating the reflection vector from the object position instead of using the inverted light direction (pointing from object to light source).

It's like using the V instead of the L in this diagram:

Also, I think shininess should be the exponent of your expression not something that multiplies linearly the specular contribution.

Community
  • 1
  • 1
Pedro Boechat
  • 2,446
  • 1
  • 20
  • 25
  • Thanks. When using `float reflection = max(0, dot(reflect(normalize(source - position), normal), lookat));` there are no visible highlights anymore. When I multiply `specular` by 10 some sort of highlight appears but it is still disoriented some way. How can I further debug my problem? I know that the matrices are correct since diffuse lighting works with point lights. – danijar Jan 23 '14 at 23:29
  • I think you should use: specular = pow(reflection, shininess); Btw, I also find it hard to debug shaders... I usually do "color debugging" (i.e.: http://en.wikibooks.org/wiki/Cg_Programming/Unity/Debugging_of_Shaders) – Pedro Boechat Jan 23 '14 at 23:41
  • What would be the range for the `shininess` values then? I have surfaces without specular reflection at all. When setting `shininess` to zero, the pow function would become one and that gets added to the lighting, not multiplied. I can make screenshots of single steps of the shader printed to the screen. What stages would be helpful? – danijar Jan 24 '14 at 08:29
  • Okay, problem solved. I had to use the negative vector `reflect(-normalize(source - position), normal)`. Moreover, I use the shininess parameter for both, linear factor and exponent now `min(shininess, 1) * pow(reflection, shininess)`. It works well. – danijar Jan 24 '14 at 08:45
  • There's one more thing I noticed: you're using lookat vector as (0,0,1), while in RHS the viewer's always looking towards the negative Z axis. – Pedro Boechat Jan 24 '14 at 11:07
  • Thanks a lot. With the correct lookat vector, I don't have to invert the light vector anymore. – danijar Jan 24 '14 at 15:31
1

I think variables naming is confusing you. From what I'm reading (assuming you're in camera space and without handedness knowledge)

vec3 lookat = vec3(0, 0, 1);
float reflection = max(0, dot(reflect(position, normal), lookat));

lookat is a directional light and position is the actual lookat.

Make sure normal(it's probably already normalized) and position(the lookat) are normalized.

A less confusing code would be:

vec3 light_direction = vec3(0, 0, 1);
vec3 lookat = normalize(position-vec3(0,0,0));
float reflection = max(0, dot(reflect(light_direction, normal), -lookat));

Without normalizing position, reflection will be biased. The bias would be strong when position is far from the camera vec3(0,0,0)

Note how lookat is not a constant; it changes for each and every position. lookat = vec3(0,0,1) is looking toward a single position in view space.

a.lasram
  • 4,371
  • 1
  • 16
  • 24
  • wouldn't (position - vec3(0, 0,0)) return a vector from the 'camera' to the point, when we need a vector from the point to the camera? –  Jun 11 '15 at 22:26
  • @racarate (position - vec3(0, 0,0)) is the vector from the camera to the position and this is the "look at". Yet you're right: the dot should be between the reflected ray and the vector from position pointing to the camera (-lookat) – a.lasram Jun 14 '15 at 02:53