Sign function not producing expected results

I’m trying to use the sign function instead of an if becuase it is faster. But it isnt working as expected. This code…


if (sign(max(0,shininess)) == 0) {
  specCoef *= 0;
} else if (sign(max(0, shininess)) == 1) {
  specCoef *= 1;
}

…behaves as expected. specCoef is set to 0 when shininess is zero and left as is otherwise. But this code…


specCoef *= sign(max(0, shininess));

…doesn’t behave as expected. specCoef is sometimes (during the same draw call) set to 0 and sometimes isn’t which doesn’t make any sense. The sign of 0 should always be 0.

This almost seems like a problem with my OpenGL implementation.

Machine: mid-2013, 13-inch MacBook Air
OS: MacOS El Capitan
OpenGL version: 4.1 INTEL-10.20.23
GLSL version: 4.10
GPU: Intel HD Graphics 5000

According to this, sign can be -1, 0 or +1.

The fact that it can change during the same draw call seems to indicate that shininess value changes.

So, what is shininess ? An uniform ? In that case, it looks strange, right. A varying ? In that case, it looks less strange. A simple variable ? In that case, is it well initialized and/or calculated ?

-0 is a valid floating-point number.

by the way, “shininess” (or as it is named in the wavefront .obj format: Ns) is not allowed to be smaller than 1
so you dont need “sign” or “if”, just use:

float shininess = max(1, material.Ns);
vec3 specularIntensity = pow(..., shininess);

Haven’t tried it thought, however I would expect that the GLSL sign function would return 0 both when given +0 or -0 as argument. Otherwise this function will be far less attractive.

John, when shininess is zero, the specular component shouldn’t be used. i.e. multiplied by zero.

i would use the specular component anyway, but i’d make sure that only “reasonable” values are calculated
for example use the GLSL function “clamp(…, 0, 1)” for each light source’s base intensity, and “max(0, …)” for the diffuse / specular factor (the calculated cosine of any angle) as well as for the shininess

why would you discard the specular light ?

The CPU side sets shininess to 0 when it wants an object to be rendered with lambertian shading.

The sign of 0 is zero but the sign of 0.000001 is 1. So any rounding errors will be magnified enormously. Given that a valid shininess shouldn’t be less than one, I’d suggest just using clamp() or smoothstep().