2019独角兽企业重金招聘Python工程师标准>>>
这里说的并不是什么新技术,都是很古老很古老的东西。
一般我们用的cg软件上面大量使用的漫反射模型Lambert’s model,是一个让光线向各个角度都均匀辐射的模型。这个均匀实在太不可思议了,真实物体表面理应不是这样的。这里介绍一下Oren/Nayar model。
其实以下内容基本来自于Advance RenderMan。
Advance RenderMan提到一个极端的例子,就是月球表面。假如你用Lambert来模拟月球,地球等宏观表面,会发现怎么样也做不好。在月圆的时候,月球看起来更像一块发光的平板,而不是一个球体。
另外一个现象就是,即使在灯光方向不变的情况下,观察物体的角度不同,物体表面光强、颜色也会发生变化(一般粗糙物体正光光强比背光光强要强)。就是光线向各个角度并非均匀辐射。
这个现象应该算是BRDF(Bidirectional Reflectance Distribution Function)现象的一部分。这个函数想用数学方式表述好像很困难,大概只能通过光学测量求得,而且各种物体表面辐射的情况超级复杂,而且差异很大, 比较难一一概括。
关于BRDF,看以下连接:http://www-modis.bu.edu/brdf/brdfexpl.html
Oren/Nayar model 这个主要来自于Michael Oren和Shree K. Nayar在SIGGRAPH94上发表的论文Generalization of Lambert’s Reflectance Model。里面通过统计的等手段总结出比较接近真实粗糙表面的数学公式,然后Advance RenderMan提供了相应实现的函数。其实3dmax好像也带这个Oren/Nayar model ,不过maya却没有的样子。
以下是论文的连接:http://www1.cs.columbia.edu/CAVE/publications/pdfs/Oren_SIGGRAPH94.pdf
一些另外的连接: http://www.cs.utah.edu/~wyman/classes/BRDF/orn_nyr.html
我这里提供一个简单的sl代码(根本就只是在Advance RenderMan上抄下来而已)。可以在pixie,prman使用,其他兼容rm应该也没有问题。
surface OrenNayar (float Ka = 1, Kd = 1, roughness=0.5)
{
/*
* Oren and Nayar’s generalization of Lambert’s reflection model.
* The roughness parameter gives the standard deviation of angle
* orientations of the presumed surface grooves. When roughness=0,
* the model is identical to Lambertian reflection.
*/
normal Nf = faceforward (normalize(N),I);
vector In = normalize(-I);
color LocIllumOrenNayar (normal N; vector V; float roughness;)
{
/* Surface roughness coefficients for Oren/Nayar’s formula */
float sigma2 = roughness * roughness;
float A = 1 - 0.5 * sigma2 / (sigma2 + 0.33);
float B = 0.45 * sigma2 / (sigma2 + 0.09);
/* Useful precomputed quantities */
float theta_r = acos (V . N); /* Angle between V and N */
vector V_perp_N = normalize(V-N*(V.N)); /* Part of V perpendicular to N */
/* Accumulate incoming radiance from lights in C */
color C = 0;
extern point P;
illuminance (P, N, PI/2) {
/* Must declare extern L & Cl because we’re in a function */
extern vector L; extern color Cl;
float nondiff = 0;
lightsource ("__nondiffuse", nondiff);
if (nondiff < 1) {
vector LN = normalize(L);
float cos_theta_i = LN . N;
float cos_phi_diff = V_perp_N . normalize(LN - N*cos_theta_i);
float theta_i = acos (cos_theta_i);
float alpha = max (theta_i, theta_r);
float beta = min (theta_i, theta_r);
C += (1-nondiff) * Cl * cos_theta_i * (A + B * max(0,cos_phi_diff) * sin(alpha) * tan(beta));
}
}
return C;
}
Ci = Cs * (Ka * ambient() + Kd *LocIllumOrenNayar(Nf,In,roughness));
Oi = Os; Ci *= Oi;
}
以下是用pixie渲染的,左边是matte,就是普通的Lambert(别以为白色暴掉的地方是高光,没有高光)。右边的是OrenNayar ,roughness在0.4左右。
另外,下面是正光背光的对比
最后,其实OrenNayar已经是10多年前的东西了,现在应该也有了更新的论文跟光照模型。那些迟点看到再说了。