0

I've got an issue with changing the specular power component in my opengl 4.3 shader. What happens is the specular is working fine when I use a shininess value of between 0-10, however, as the value is increased to make the material more shiny, the lighting decreases in intensity. Here is my code:

    //Direct Lighting
vec3 L = normalize(worldPos.xyz - lightPos.xyz);
vec3 D = normalize(lightDir.xyz);
float dist = length(-L);
float I = max(dot(N.xyz, -L), 0.0);

vec3 h = normalize(-L.xyz + E);
float specLighting = 0.0;
specLighting = pow(max(dot(N.xyz, h), 0.0),50.0);

fColor.xyz = vec3(specLighting);

So if increase the shininess value to something like 50, there is no lighting at all. By the way, in this code, I am only displaying specular to debug the problem.

[EDIT] Sorry for the lack of detail in the explanation, I have attached some screenshots of the results of changing the specular shininess value from 1 to 7. As you can see, as the specular highlight reduces in size (which is what I want), the lighting also fades (which is not what I want). It gets to the point where after about 10, it becomes completely black.

By the way, I am doing this entirely in the pixel/fragment shader.

I have also added a screenshot from my directx 11 test engine using the exact same code for specular lighting but with a shininess factor of 100.

specLighting = pow(max(dot(N.xyz, h), 0.0),1.0);

specLighting = pow(max(dot(N.xyz, h), 0.0),2.0);

specLighting = pow(max(dot(N.xyz, h), 0.0),3.0);

specLighting = pow(max(dot(N.xyz, h), 0.0),5.0);

specLighting = pow(max(dot(N.xyz, h), 0.0),7.0);

directx 11 specular highlight

Directx 11:

Community
  • 1
  • 1

4 Answers4

3

If you want to maintain a minimal lighting-based illumination, you should add a non-specular compenent. The specular component is typically used to add highlights to a material, not as the sole contributor.

Anyway, the darkening you report is a natural result of increasing the exponent. Think about it: because the vectors are pre-normalized, dot(N.xyz, h) is no more than 1.0. Raising a number between 0 and 1 to a high power will naturally tend to make the result very small very quickly... which is exactly what you want for a sharp specular highlight!

Of course, reducing the size of the highlight will reduce the average specular reflection (unless you made the maximum specular value much brighter, of course...). But, very few actual objects have only specular reflection. And, if an object did have only specular reflection, it would look very dark except for the specular spots.


Another way to look at it: your formula gives you a specular brightness whose maximum value is 1.0 (which is in some ways practically convenient for conventional, low-dynamic range computer graphics where each color channel maxes out at 1.0). However, in the real world, a shinier surface will typically cause the specular highlights to get brighter as well as smaller, such that the average specular brightness stays the same. It is the contrast between these to cases which makes the situation confusing. For practical purposes the formula is "working as designed -- will not fix"; typically, the artist will simply adjust the specular exponent and brightness until he gets the appearance he wants.

comingstorm
  • 25,557
  • 3
  • 43
  • 67
  • Thanks for your detailed explanation. After about 20 for the value of the specular highlight, if I multiply the result by 1000, it still comes out as completely black. – gboxentertainment Feb 16 '13 at 01:47
  • So naturally, dot(N.xyz, h) being between 0 and 1 means that the overall specular highlight should be decreasing exponentially as its power is increased. So now I don't understand how in the directx11 version, that the centre of the highlight stays at 1.0, while everything else reduces to zero. – gboxentertainment Feb 16 '13 at 01:56
0

If you increase the "shininess" you're material will be less shiny.

Anthony
  • 255
  • 3
  • 7
  • Missing punctuation, incorrect punctuation and wrong information. My -1 – enhzflep Feb 16 '13 at 02:23
  • The Phong reflection model includes a specular reflection term that can simulate such highlights on shiny surfaces; it even includes a parameter to specify a shininess of the material. The shininess specifies how small the highlights are: the shinier, the smaller the highlights. source : https://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Specular_Highlights I was right no ? – Anthony Feb 19 '13 at 08:20
  • Mm-hmm, I implemented it in software on a 386 20 years ago, I'm familiar with the model and it's calculation. Yes, precisely - the more shiny the material, the smaller the specular highlights will be. B.B.B.b.but, the material will still be more shiny! If you'd said "If you increase the 'shininess', your material's specular highlights will be smaller." I'd agree in a heartbeat. But you didn't, that's what my point is. So in closing, no! You *were* incorrect, but your comment's 2nd sentence is indeed accurate. :) – enhzflep Feb 19 '13 at 08:53
  • Ok thanks for that explanation. I indeed confused shiny and highlights. – Anthony Feb 19 '13 at 09:33
  • You're most welcome. Consider my -1 vote recalled. (I say 'consider', since I can't reverse it now - I voted too long ago, SO won't allow it) – enhzflep Feb 19 '13 at 09:38
0

I originally wrote this answer before the question was updated with enough information. So it's obviously not the right answer in this case, but may apply to someone with a similar problem...

One possible explanation as to why specular lighting would decrease in intensity with increasing power, is if you are calculating it at a vertex level, rather than per-pixel. If the highlight point happens to fall in the middle of a polygon, rather than right at a vertex, then as it decreases in size with increasing shininess, the vertex contributions will drop off rapidly, and the highlight will disappear. Really for good specular (and really for good lighting generally), you need to calculate per-pixel, and only interpolate things that actually vary smoothly across the polygon, such as position or normal.

JasonD
  • 16,464
  • 2
  • 29
  • 44
0

Thanks for all your help guys,

It turned out that it was just a silly mistake in the vertex shader:

instead of:

    fNorm = vec4(mat3(worldSpace)*vNorm.xyz,0);

I had just:

fNorm = vNorm;