(8条消息) 着色模型简介和实现(上)_子宽的专栏-CSDN博客_着色模型
现象总结(个人总结)
- Anisotropy是高光部分,横纵比
- clearcoat 是第二层specular
- Subsurface 是第二层diffuse
- sheen 是加强版的菲涅尔
Anisotropy
- 上图左:各向同性金属球;右:各向异性金属球。
- 如上图, 高光部分被打横了, 菲尼尔效应更强了.
Clear Coat
- Clear Coat模型是多层材质的一种最简单的形式。
- Clear Coat Layer一般是透明的,光线会透过Clear Coat Layer照射到Base Layer,为了模拟Clear Coat材质,一般将这两层材质按照下图的方式建模:
- Clear Coat Layer会产生Specular反射,剩余的光线照射到Base Layer产生Specular和Diffuse反射。
- 因此,相比于基础BRDF模型,Clear Coat模型多一个由Clear Coat Layer产生的specular项。
- Clear Coat模型,需要两个额外的参数,一个是
ClearCoat系数,另一个是ClearCoatRoughness,指明Clear Coat Layer的粗糙度。
Subsurface
- Subsurface模型也是一种多层材质,它可以很复杂(如用于绘制皮肤的SSSS模型),也可以很简单(如Disney在Principled BRDF中的实现)。
- Subsurface模型描述的是名为次表面散射(subsurface scattering)的物理现象。
- 次表面散射现象指的是光线进入材质内部,经过多次反射、吸收,最终折射出材质表面的现象。
- 这个物理现象在BRDF模型中我们是用Diffuse分量来描述的,但是无论是Lambert模型还是Burley模型,都无法表现材质对光线的吸收作用,或者说,无法表现出“通透”效果。
- 下图展示了采用Subsurface scattering模型的皮肤(右上)和未采用(右下)的对比。
- subsurface模型都是通过添加一层额外的diffuse layer来近似表现次表面散射现象。这一点刚好跟Clear Coat模型相反——Clear Coat模型添加了额外的specular层,而subsurface添加了额外的diffuse层。
Cloth(sheen)
- 因为布料的组成形式是纤维相互堆叠,纤维之间还存在空隙,不符合微表面理论。
- 模拟Cloth的BRDF模型大致可以分为三类:
- 基于观察的empirical models
- 基于微表面理论的模型
- 微圆柱体模型(micro-cylinder model)
- 基于微表面理论的模型
- 常用的布料模型中的法向分布函数是Ashikhmin[3]提出的,用逆高斯分布来拟合法向分布,经过后续的补充,最终的形态为:
- 常用的布料模型中的法向分布函数是Ashikhmin[3]提出的,用逆高斯分布来拟合法向分布,经过后续的补充,最终的形态为:
- α控制逆高斯函数的宽度kamp控制幅度。f(l,v,h)已经包含了diffuse和specular两部分。
float D_Ashikhmin(float roughness, float NoH) {
// Ashikhmin 2007, "Distribution-based BRDFs"
float a2 = roughness * roughness;
float cos2h = NoH * NoH;
float sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16
float sin4h = sin2h * sin2h;
float cot2 = -cos2h / (a2 * sin2h);
return 1.0 / (PI * (4.0 * a2 + 1.0) * sin4h) * (4.0 * exp(cot2) + sin4h);
}
- 另一种布料模型是Estevez和Kulla提出的Charlie模型,Charlie模型采用的是正弦函数的幂来拟合,而不是逆高斯函数。它的实现更简单、外观更柔和。
float D_Charlie(float roughness, float NoH) {
// Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF"
float invAlpha = 1.0 / roughness;
float cos2h = NoH * NoH;
float sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16
return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);
}