# Modeling Light Sources

## Recommended Posts

Quat    568

I'm reworking my shaders to be "physically based".  In the old fixed function days, we had lights that emitted separate diffuse light, and specular light to give artistic control.  Should this still be done with physically based shading?  To me, a light source just gives off light.  Based on fresnel, a fraction will be reflected and based on roughness give the specular highlight.  Assuming opaque material, the "refracted" light will subsurface scatter and then re-emit from the surface to give diffuse reflectance.

However, is it still useful to have separate "diffuse light" and "specular light"?  Or should there just be one light color vector?

##### Share on other sites
MJP    19786

In my opinion you definitely don't want to have separate diffuse/specular controls for your lights. If you were to do this, you would essentially be allowing your lights to override the carefully-balanced response of a material. As an extreme example, imagine that you had a plastic surface and you set a light to have only specular response: the plastic will now basically look like a piece of metal, since it no longer has any diffuse.

Edited by MJP

##### Share on other sites
L. Spiro    25638
It is not necessary to separate specular and albedo colors for light sources.

L. Spiro

##### Share on other sites
Quat    568

Thanks.  I'm using Fresnel R in my specular to get the amount of light reflected.  For opaque objects, do you scale the diffuse result by (1-R) since that is the amount of light that enters to do "body reflectance" as real-time rendering calls it?  In Real-Time rendering, for their final modified Blinn-Phong equation, they do not multiply by (1-R).

##### Share on other sites
fries    385

It kinda depends on the specular BRDF, but it would be a good idea to have:

FinalColor = Specular * F + Diffuse * (1 - F)

The whole story is a bit more complex than that (involving microfacet reflectance models etc.), but this should look pretty good as an approximation.

##### Share on other sites
L. Spiro    25638

For opaque objects, do you scale the diffuse result by (1-R) since that is the amount of light that enters to do "body reflectance" as real-time rendering calls it?  In Real-Time rendering, for their final modified Blinn-Phong equation, they do not multiply by (1-R).

There is a large amount of misconception surrounding how the Fresnel term influences the diffuse term.
Frequently people will tell you to use F( R ) for specular and (1 - F( R )) for diffuse, but this only leads to confusion, because while it is partly true, the Fresnel function takes 2 parameters, not 1, and it is the 2nd parameter that needs attention here.

float SchlickFresnel( float _F0, float _fU ) {
return _F0 + (1.0 - _F0) * Pow5( 1.0 - _fU );
}
When calculating specular, you are interested in how much light is bounced off the surface as a result of Fresnel and into your eye, so you call this function via:
SchlickFresnel( R, VdotH )
This takes a view (or eye) vector and the half-vector, which makes it view-dependent.

How much is going into diffuse based on the Fresnel term has absolutely nothing to do with where the eye is. It has only to do with the angle at which the light hits the surface of the object, so diffuse uses the following call:
(1 - SchlickFresnel( R, LdotN ))
See equations 5 and 6 here: http://research.tri-ace.com/Data/course_note_practical_implementation_at_triace.pdf
That paper also provides a correct physically based Blinn-Phong.

Any BRDF that uses a Fresnel term in the specular should also scale down the diffuse in this same manner. If this is ever omitted in the diffuse term, it is only for performance issues.

L. Spiro Edited by L. Spiro

##### Share on other sites
fries    385

This takes a view (or eye) vector and the half-vector, which makes it view-dependent.

If you look at the math for refraction (the Fresnel equations and where we get the Schlick approximation from), there is no view dependency.

Note that since H = V + L, LdotH = VdotH.

Are you sure SchlickFresnel( R, VdotH ) is correct? this is not taking the surface normal into account which I don't think is correct. I think it should be SchlickFresnel( R, NdotH ) or SchlickFresnel( R, LdotN )

The problem comes from the fact that the microfacet model uses the half angle vector (V + L) instead of the normal, this is what gives you the view dependence. I’m not convinced that just because you're using the HAV for the microfacet model, you should also use it for the Fresnel term.

I think that even when using a microfacet model we should still use the normal and the light vector for the Fresnel approximation, not the HAV. The reason I believe this is because the microfacet model accounts for micro surface variations, this is not the job of the Fresnel term.

Edited by fries

##### Share on other sites
Hodgman    51328

Yeah it's pretty confusing, but when you're calculating specular using a microfacet-based BRDF, the macro-surface normal (N) is largely irrelevant.

Microfacet models say that only micro-surfaces that are facing exactly along the H vector are contributing to the specular lobe -- all other micro-surfaces have zero specular contribution.

If you want to calculate Fresnel's equation to find out exactly how reflective those microfacets are (not how reflective a perfectly flat macro-surface would be), you need to use the microfacet normal, which is H.

Most of the specular shading is calculating properties of those microfacets, and then weighting those results based on the probability that these kinds of microfacets actually exist within the macro-surface (which is where N comes in).

Also, physically based BRDFs should always obey helmholtz reciprocity, which means that if, right at the top of the BRDF code, you swap L and V:

e.g. temp = L; L = V; V = temp;

Then you'll get the exact same results.

Edited by Hodgman

##### Share on other sites
fries    385

If you want to calculate Fresnel's equation to find out exactly how reflective those microfacets are (not how reflective a perfectly flat macro-surface would be), you need to use the microfacet normal, which is H.

Im not sure this is strictly true, since the Fresnel equations are not just for reflection, but also for transmission - what is not reflected is transmitted. If we use H for the Fresnel reflection, then we are required to transmit less than 1-F. And since H is view dependent, that would make our transmittion (1-F) view dependent, which is clearly impossible, so we have a bit of a paradox.

After thinking about it, since the diffuse layer probably has an averaging effect on the transmission effects of the microfacets above, I would guess you can use a different Fresnel equation for reflectance and transmission. But then how do you make sure it's normalized?

Edited by fries

##### Share on other sites
Hodgman    51328
To get the transmission, you'd have to compute the Fresnel refraction value for every different Microfacet normal that exists within the pixel's area, and then average them all together... Aka numerically integrating that function... which obviously isn't feasible for real time use.

The most basic approximation is to just assume that this is going to be close to the result for the macro-normal. For perfectly smooth normals, the Microfacet normals will all be exactly equal to the macro-normal, so this will be correct.
For rough surfaces though, this approximation results in a value that is too high.
Many games deal with this by just adding a simple hack on top, where the Fresnel result is reduced by some arbitrary multiplier for rough surfaces.