今天讲这本书最后一种材质
Preface
水,玻璃和钻石等透明材料是电介质。当光线照射它们时,它会分裂成反射光线和折射(透射)光线。
处理方案:在反射或折射之间随机选择并且每次交互仅产生一条散射光线
(实施方法:随机取样,具体见后文)
调试最困难的部分是折射光线。如果有折射光线的话,我通常首先让所有的光折射。对于这个项目,我试图在我们的场景中放置两个玻璃球,我得到了这个:
上述图片是对的吗?显然,在实际生活中,那两个玻璃球看起来怪怪的,实际情况下,里面的内容应该将现在的进行上下颠倒,且没有黑色成分。
Ready
定量计算光的折射
-------------------------------------------- 数学分割线 --------------------------------------------
公式中的η为相对折射率:n2/n1
而由于入射光线方向的随机性和eta的不同,可能导致 1-η*η*(1-cosθ1 * cosθ1)小于0,此时取根号毫无意义
而事实上,这也就是全反射现象。即:当光线从光密介质进入光疏介质中如果入射角大于某个临界值的时候,就会发生全反射现象。
该临界角即折射角为90°时对应的入射角,也就是cosθ2恰好等于0的时候
------------------------------------------------ END ------------------------------------------------
正文
我们来封装一个电介质类
首先明确,它是材质的一种,即
#ifndef DIELECTRIC_H #define DIELECTRIC_H namespace rt { class dielectric :public material { public: dielectric(rtvar RI) :_RI(RI) { } virtual bool scatter(const ray& rIn, const hitInfo& info, rtvec& attenuation, ray& scattered)const; inline bool refract(const rtvec& rIn, const rtvec& n, rtvar eta, rtvec& refracted)const; private: rtvar _RI; //refractive indices }; bool dielectric::scatter(const ray& rIn, const hitInfo& info, rtvec& attenuation, ray& scattered)const { rtvec outward_normal; rtvec refracted; rtvar eta; attenuation = rtvec(1., 1., 1.); if (dot(rIn.direction(), info._n) > 0) { outward_normal = -info._n; eta = _RI; } else { outward_normal = info._n; eta = 1. / _RI; } if (refract(rIn.direction(), outward_normal, eta, refracted)) { scattered = ray(info._p, refracted); return true; } return false; } inline bool dielectric::refract(const rtvec& rIn, const rtvec& n, rtvar eta, rtvec& refracted)const { rtvec unitIn = rIn.ret_unitization(); rtvar cos1 = dot(-unitIn, n); rtvar cos2 = 1. - eta*eta*(1 - cos1*cos2); if (cos2 > 0) { refracted = eta * rIn + n*(eta*cos1 - sqrt(cos2)); return true; } return false; //全反射 } } #endif