Sign in to follow this  
Aqua Costa

Specular Power = 0

Recommended Posts

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...

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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)".

Share this post


Link to post
Share on other sites
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 :-)

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this