Jump to content
  • Advertisement
Sign in to follow this  
Alundra

PI or not to PI ?

This topic is 1133 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

We always removed PI in lighting equations, artist who set 1.0 in reality set PI.

Is it really needed to add PI in the lighting equation which cause the intensity of light to be PI times less than before ?

Here code without PI :

float3 Diffuse_Lambert( in float3 DiffuseColor )
{
  return DiffuseColor;
}

// [Walter et al. 2007, "Microfacet models for refraction through rough surfaces"].
float D_GGX( in float Roughness, in float NoH )
{
  float m = Roughness * Roughness;
  float m2 = m * m;
  float d = ( NoH * m2 - NoH ) * NoH + 1.0f;
  return m2 / ( d * d );
}

Here code with PI :

float3 Diffuse_Lambert( in float3 DiffuseColor )
{
  return DiffuseColor * ( 1.0f / 3.14159f );
}

// [Walter et al. 2007, "Microfacet models for refraction through rough surfaces"].
float D_GGX( in float Roughness, in float NoH )
{
  float m = Roughness * Roughness;
  float m2 = m * m;
  float d = ( NoH * m2 - NoH ) * NoH + 1.0f;
  return m2 / ( 3.14159f * d * d );
}

 

 

 

Edited by Alundra

Share this post


Link to post
Share on other sites
Advertisement

The solution of divide outside the shader only work if a diffuse texture is not used and if "Metallic" is constant since for a PBR diffuse color is computed like that :

FinalBaseColor.rgb - (FinalBaseColor.rgb * Metallic);

I conclude if PI is used, the correct way is :

float4 DiffuseData = DiffuseMap.Sample(LinearSampler, Input.TexCoord);
float3 FinalColor = (DiffuseData.rgb - (DiffuseData.rgb * Metallic)) / PI;

Does the use of PI doesn't destabilizes artists ?

Edited by Alundra

Share this post


Link to post
Share on other sites

Does the use of PI doesn't destabilizes artists ?

Just set the light power to PI instead. That's one "proper" way of handling energy conservation in LDR pipelines.
Light emits PI colour, and perpendicular white surfaces only reflect 1 around the hemisphere; so when you look it with the camera, you get full brightness.

Instead of avoiding to divide by PI in the surface, multiply the light source by PI (which you can do CPU side). Edited by Matias Goldberg

Share this post


Link to post
Share on other sites

The specular color (sent in fresnel PBR formula of Schlick 1994) has to use the diffuse color after the divide of PI to be correct if PI used, is it correct ?

float3 DiffuseLambert = Diffuse_Lambert(FinalBaseColor.rgb);
SurfaceData.DiffuseColor = DiffuseLambert - (DiffuseLambert * Metallic);
SurfaceData.SpecularColor = lerp(0.08f * Specular, DiffuseLambert, Metallic);

Formula Schlick 1994 :

// [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"]
float3 F_Schlick( in float3 SpecularColor, in float VoH )
{
  float Fc = pow( 1.0f - VoH, 5.0f );
  return saturate( 50.0f * SpecularColor.g ) * Fc + ( 1.0f - Fc ) * SpecularColor;
}
Edited by Alundra

Share this post


Link to post
Share on other sites

The specular color (sent in fresnel PBR formula of Schlick 1994) has to use the diffuse color after the divide of PI to be correct if PI used, is it correct ?

Deriving the specular component out of the diffuse one with a single "metallic" variable is just a very convenient, artist-friendly hack.

The specular colour should be ideally be in the [0; 1] range as normally the formulas are adjusted that way, so it should be done before dividing by PI. But being a hack, there is no "right" way.

 

Really, as long as the final output isn't > 1, it's good. (which in order to find out, one has to resolve difficult double integrals along a hemisphere, or use a monte carlo simulation if you're not good at math or lazy).

 

More important is to look at what the other guys are doing (particularly the artist tools like Marmoset and Allegorithmic) so that your math equations do not diverge too much and your artists can paint in these tools and then export to your engine without significant deviations.

Edited by Matias Goldberg

Share this post


Link to post
Share on other sites
If you're doing GI, you need the Pi in the BRDF (not the light) or your bounced light will be too bright.

Also, it's common for BRDFs to involve a divide by PI (Lambert, GGX, Normalized Blinn, etc) but it is not universal! If you switch to another BRDF, you may find that it's normalization term does not include 1/Pi at all. This is a problem if your engine supports many different BRDFs. In that situation, you'll need to do the individual normalizations in your BRDF's, instead of relying on a common one in the light.

Share this post


Link to post
Share on other sites
If you're doing GI, you need the Pi in the BRDF (not the light) or your bounced light will be too bright.

Ok, it sounds important to divide by PI since the GI will be common on next gen I guess.

About the specular color :

SurfaceData.SpecularColor = lerp(0.08f * Specular, Diffuse, Metallic);

One opinion about what is better : Pi or not to PI on the diffuse value ?

Edited by Alundra

Share this post


Link to post
Share on other sites

I don't think you should divide by PI in that particular case because it's not related to the normalization of the brdf itself.

You just derive a fresnel reflectance value from some min value that you pick and the color (which has nothing to do with Diffuse) that should be present if metal = 100%

 

As for diffuse light I just do this at the end:

Diffuse *= (DiffMapSample.rgb * BaseColor) / PI;
Edited by lipsryme

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!