Specular Power = 0

Started by
3 comments, last by Zoner 11 years, 9 months ago
Hi,

Today I found a new bug in my engine, after some debugging I found that it happened because I added a new material that had a specular power = 0, so when the HdV = 0 it caused an exception 0^0, and the luminance calculated at those pixels was a NaN and the average luminance of the scene was also NaN so the tonemapped scene resulted in black screen.

I fixed it by adding a small value (0.0001) to the specular power stored in the gbuffer before doing HdV^power, but I was wondering if this is usual or I'm doing something else wrong...
Advertisement
ya i had the same problem and stuck an if (isnan(blabla)) in my pixel shader as a temporary fix, I am interested to hear better ways to solve this.

Stefano Casillo
TWITTER: [twitter]KunosStefano[/twitter]
AssettoCorsa - netKar PRO - Kunos Simulazioni

Yeah that will happen because of the way GPU's typically approximate the pow() function. A lot of renderers I know of won't actually work with specular power for the most part, and will instead work with some [0, 1] value that they call "glossiness" or "shininess". This is usually more intuitive for artists, and is also more conducive to storing the value in a G-Buffer or a specular map. Then as a final step you just convert it to a specular power if you're doing Blinn-Phong, and as part of that you can make sure that your power never goes below 1.0. So for instance you might do something simple like "specPower = 1.0f + glossiness * 4095.0f", or something a little more complicated like "specPower = exp2(glossiness * 12.0f)".
Exactly, I ran into this a dozen times. But not only with specular shaders, also everywhere else, where you call the pow() function. Just be sure NOT to call it with a negative number as the first parameter. Clamp. It's similar as with not dividing by zero :-)
zero bases break pow as well on GPUs since the pow is basically:

float pow(float base, float exponent)
{
return exp2(log2(v), exponent);
}

The fix is to either call max(v, very_small_number ) or something like


float mypow(float base, float exponent)
{
return base > very_small_number ? exp2(log2(v), exponent) : 0;
}


And you get to sit down and tune your own very_small_number for whatever you are working on.
http://www.gearboxsoftware.com/

This topic is closed to new replies.

Advertisement