2
\$\begingroup\$

I´m trying to implement a microfacet BDRF with GGX density function in my renderer. I have read almost all the papers out there in the last week, and I have a bunch of equations that should work fine, but I think they don´t. My problem is that the normalized functions of the BDRF are returning specular values way over 1:

I´m using Schlick's approximation for the fresnel term, the only one that is returning values in the range [0-1]:

F = oSpecular + ( 1.0 - oSpecular ) * ( 1.0 - L.H )^5 ;

The normalized GGX distribution function with a being the roughness:

D = a^2 / ( PI * N.H^2 * ( a^2 - 1.0 ) + 1.0 )^2

The Geometric factors I´m using:

G1 = 1.0 + sqrt( 1.0 + a^2 *( ( 1.0 - N.L^2 ) / ( N.L^2 ) ) ) ;
G2 = 1.0 + sqrt( 1.0 + a^2 *( ( 1.0 - N.V^2 ) / ( N.V^2 ) ) ) ;

And the full BDRF:

nSpecular = D * F * G1 * G2 / ( 4.0 * N.L * N.V )

I have seen this setup used widely. But even with the N.L factor it returns values over way 100.0 in the hotspot of the light reflection. I have tryed other Geometric terms with no luck. The BDRF is always overburned. It seems that I´m missing some important point here. Any idea?

Edit:

Thanks for the answer. So for area lights using representative points energy conservation is only an aproximation, wich explains why with low intensity lights the reflection can be still a lot brighter than the light source itself, wich is a pitty, and does not look right at all. I will try to look for another method. Any suggestion?

Returning to the original question about point lights with GGX and energy conservation, there is a thing I´m still missing. As the NDF returns a density probability function, wich can have values way over 1, that means that you can´t use the value as returned from the NDF directly in the shader, can you? As the specular component is later multiplied by the light source power, it should be really in the range 0-1, or you will have specular reflections 400 times brighter than the light source itself, with has no sense. Tell me only about one real life situation when a reflection in a dx returns 400 more energy than it receives and we can do business. The density probability function should be weighted or interpreted somehow to return it to a propper 0-1 range? If so, why nobody does that?

\$\endgroup\$
  • \$\begingroup\$ This seems to be an exact duplicate of GGX specular BRDF is way over 1! BTW, the short answer is: this is perfectly OK and expected. It's supposed to go over 1 and have large values in the specular hotspot. \$\endgroup\$ – Nathan Reed Aug 3 '14 at 19:15
  • \$\begingroup\$ Yes, but people there found a solution that was not posted. I tryed to ask there, but the moderator closed my post because it was not an answer. \$\endgroup\$ – Sikowsky Aug 3 '14 at 19:20
  • \$\begingroup\$ Anyway after your response my question reformulates: If the specular is a reflection of the light source, and my light source has a power of 0.5 for example, How you mange a hotspot of 300? That has no sense to me. There are some step I´m missing before I use that value to render the pixel? This is not very much important when you are rendering point lights, as your eye hardly notice the diference once you are already overburned, but for area lights is giving me headaches, as it is not possible for me to get a propper and credible reflection of dimm lights. \$\endgroup\$ – Sikowsky Aug 3 '14 at 19:25
  • \$\begingroup\$ Ahh, area lights are a bit different from point lights. Can you say more about how you're rendering area lights? Are you using something like Brian Karis' "representative point" approximation, or something else? \$\endgroup\$ – Nathan Reed Aug 3 '14 at 19:38
  • \$\begingroup\$ Thats right. I´m using representative point. But I have not a clue about how to moderate the specular brightness. I have been trying the Unreal 4 aproach from here blog.selfshadow.com/publications/s2013-shading-course/karis/… but the specular reflection still gets too hot. \$\endgroup\$ – Sikowsky Aug 3 '14 at 19:52
3
\$\begingroup\$

(Based on the comments, the question is really about using BRDFs with area lights.)

This is a subtle issue. First of all, there's a difference between what the "color of a light source" means for point lights versus area lights: the color of a point light is an irradiance, while the color of an area light is a radiance.

So when using the representative-point method for rendering area lights, we actually need to convert the color (radiance) of the light source to an irradiance, so we can treat it as a point light. So we need to calculate (or approximate) the irradiance received the shaded point from the area light.

For uniform spherical area lights, a result that's quoted in Brian Karis' course notes is that the irradiance is the same as a point light of the same total power. So you can calculate the power of the spherical light π * area * radiance, then calculate the resulting irradiance at the shaded point power / (4π * distance²) (for physical 1/r² falloff, or substitute your own attenuation function if you like). For other shapes of area lights it will be more difficult, but you can hopefully work out some approximate irradiance formula.

Note that the irradiance will be numerically smaller than the radiance when the shaded point is far enough from the light, so this will help cut down the intensity of the reflection.

The other factor here is that the representative-point method isn't energy-conserving by itself. Karis recommends altering the GGX normalization factor to approximately fix this; see equations 10 and 14 in his course notes. This will also reduce the brightness of the reflection. Between these two factors, the intensity should be cut down to something more reasonable.

\$\endgroup\$
  • \$\begingroup\$ I have added an edit to the original question based on your answer. Thanks. \$\endgroup\$ – Sikowsky Aug 4 '14 at 10:11
  • \$\begingroup\$ @Sikowsky To comment on your follow-up question, "in reality" (or rather in the mathematical framework of geometric optics) the BRDF and incoming radiance have to be integrated over the whole hemisphere. Just like a probablity density has to integrate to 1, the NDF has to integrate to 1, so the total energy reflected is always ≤ the incoming energy. \$\endgroup\$ – Nathan Reed Aug 4 '14 at 15:55
  • \$\begingroup\$ @Sikowsky And you can indeed use the BRDF directly in the shader, with point lights. Point lights are kind of a limit, in which an area light gets smaller while also getting brighter to maintain the same total power. In the limit the size goes to zero and the brightness (radiance) goes to infinity. Point lights have infinite radiance (actually the radiance is a delta function) so when convolved with the NDF they do correctly output very high values—just as an extremely small, extremely bright area light physically would. \$\endgroup\$ – Nathan Reed Aug 4 '14 at 15:58
0
\$\begingroup\$
G1 = N.L + sqrt( 1.0 + a^2 * (( 1.0 - N.L^2 ) / ( N.L^2 )) );
G2 = N.V + sqrt( 1.0 + a^2 * (( 1.0 - N.V^2 ) / ( N.V^2 )) );

Full BDRF should be for Smith GGX:

nSpecular = D * F / (G1 * G2)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.