Over the holiday break I had some time to play with interesting ideas presented during the last SIGGRAPH. One thing which caught my attention was new analytical cloth BRDF from Sony Pictures Imageworks [EK17], which they use in movie production.

# AshikhminD

Current state of the art of cloth shading in games still seems to be Ashikhmin velvet BRDF [AS07], which was popularized in games by Ready at Dawn [NP13]. It basically boils down to skipping geometry term, replacing traditional microfacet BRDF denominator by a smoother version and using an inverted Gaussian for the distribution term:

Full shader code (microfacet BRDF denominator and geometry term is included in V term):

float AshikhminD(float roughness, float ndoth) { float m2 = roughness * roughness; float cos2h = ndoth * ndoth; float sin2h = 1. - cos2h; float sin4h = sin2h * sin2h; return (sin4h + 4. * exp(-cos2h / (sin2h * m2))) / (PI * (1. + 4. * m2) * sin4h); } float AshikhminV(float ndotv, float ndotl) { return 1. / (4. * (ndotl + ndotv - ndotl * ndotv)); } vec3 specular = lightColor * f * d * v * PI * ndotl;

# CharlieD

Imageworks’ presentation proposes a new cloth distribution term, which they call “Charlie” sheen:

This term has more intuitive behavior with changing roughness and solves the issue of harsh transitions (near ndotl = 1) of Ashikhnim velvet BRDF:

Although Charlie distribution term is simpler than Ashikhmin’s, Imageworks’ approximation for the physically based height correlated Smith geometry term is quite heavy for real-time rendering. Nevertheless, we can just use CharlieD and follow the same process as in [AS07] for the geometry term and BRDF denominator:

float CharlieD(float roughness, float ndoth) { float invR = 1. / roughness; float cos2h = ndoth * ndoth; float sin2h = 1. - cos2h; return (2. + invR) * pow(sin2h, invR * .5) / (2. * PI); } float AshikhminV(float ndotv, float ndotl) { return 1. / (4. * (ndotl + ndotv - ndotl * ndotv)); } vec3 specular = lightColor * f * d * v * PI * ndotl;

This results in a bit better looking, more intuitive to tweak and faster replacement of standard Ashikhmin velvet BRDF. See this Shadertoy for an interactive sample with full source code.

# References

[NP13] David Neubelt, Matt Pettineo – “Crafting a Next-Gen Material Pipeline for The Order: 1886”, SIGGRAPH 2013

[AS07] Michael Ashikhmin, Simon Premoze – “Distribution-based BRDFs”, 2007

[EK17] Alejandro Conty Estevez, Christopher Kulla – “Production Friendly Microfacet Sheen BRDF”, SIGGRAPH 2017

Hey,

Looks like you don’t use the formula provide in the paper. (see equation 2) of http://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_sheen.pdf , you have inverse the 1/r on the sin theta.

In the code you have: pow(sin2h, invR * .5), there is an extra * 0.5. Any reasons?

Also there is no reference to “Charlie” where do you see this name ? 🙂

Thanks

LikeLike

>In the code you have: pow(sin2h, invR * .5), there is an extra * 0.5. Any reasons?

Ah sorry, come from the sin2 🙂

LikeLike

Hello,

I don’t get what do you mean by that I have an inverse 1/r on the sin theta. Formula in the paper also has sin^(1/r) there.

Name comes from the presentation. See “We call it the “charlie” sheen” on page 60 of http://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf 🙂

LikeLike

Ha ok, got it for Charlie Seen 🙂

Regarding the formula, yes you use the correct one. It is just the latex version that is wrong after the sentence:

“Imageworks’ presentation proposes a new cloth distribution term, which they call “Charlie” sheen:”

LikeLike

Ah, I see now. I thought code was wrong. Just fixed the latex formula, thanks!

LikeLike

Great writeup, thank you very much! One thing I noticed in your shadertoy implementation the CharlieV function gives bad (NaN) values where N dot L is <= 0.0. Fixed this by adding an epsilon to the denominator of the return value.

LikeLike

Hey, very interesting article! This might be a stupid question but where does the “PI” come from in the specular computation? “vec3 specular = lightColor * f * d * v * PI * ndotl;”

I noticed that in the Filament engine that uses the same distribution it got removed.

LikeLike

Hello,

Standard Lambert + Cook-Torrance:

Cdiff/Pi + DFG/4*ndotl*ndotv

After multiplying both sides by Pi for convenience:

Cdiff + Pi * DFG/4*ndotl*ndotv

BTW ClothD terms have a 1/Pi inside, so you can merge all terms and Pi will cancel out in the merged equation.

LikeLike

Oh right, sorry. I’m really used to having my diffuse divided by PI. Plus with your implementation, I suppose you have to divide all your light intensities by PI or something if you’re using physical units. Thanks for your answer!

LikeLike