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...
Specular Power = 0
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.
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.
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.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement