## Cloth Shading

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: $D={\frac{1}{\pi(1+4 \alpha ^2)}}(1+\frac{4 \exp(-\frac{\cot^2\theta}{\alpha ^2})}{\sin ^4\theta})$

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: $D=\frac{\left(2+\frac{1}{\alpha}\right)\sin^{\frac{1}{\alpha}}\theta}{2\pi}$

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

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

This entry was posted in Graphics, Lighting. Bookmark the permalink.

### 9 Responses to Cloth Shading

1. seblagarde says:

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

Like

• seblagarde says:

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

Like

• Krzysztof Narkowicz says:

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 🙂

Like

• seblagarde says:

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:”

Like

• Krzysztof Narkowicz says:

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

Like

2. StGabe says:

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.

Like

3. François Guthmann (@frguthmann) says:

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.

Like

4. Krzysztof Narkowicz says:

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.

Liked by 1 person

• François Guthmann (@frguthmann) says:

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!

Like