【Ray-Tracing In One Weekend】第8章 金属材质
本节对材质进行抽象并且定义了两个材质,一个是lambertian材质,另一个是metal材质。本节材质之间的不同在于材质的颜色和材质表面微元的反射光线生成。假若按照入射光线严格的生成完美反射光线,那么就是理想的反射,在现实的生活中不存在理想的反射,入射光线与出射光线分别位于法线的两侧,但是夹角并不相等。对于金属材质来说我们对这个反射光线加了一个随机挠动fuzz。下面来对比几种效果:
左图是分列左右两边的金属球均加了fuzz,一个加了0.3,一个是1.0,中间的是右侧的球没有使用fuzz和随机的出射光线挠动,呈现的是完美反射,右侧是两边球都是完美反射。
代码使用VS2015编写,能过如下链接下载:
链接:https://pan.baidu.com/s/1LRSyDTk5hguETX3_gCE6IQ
提取码:akw9
【材质】
我们对每个物体绑定了一个材质,材质确定了当入射光线照射这个物体形成交点的时候,我们该如何反射出射光线,假如光线被完全吸收,那么物体就是黑色,因为没有任何的散射,就是黑洞了。光照射一个物体时,分为反射与折射两个方面,本节我们分析折射,完美的折射和没有完美的完全吸收没有任何折射都是很难的。完美的折射如下图:
其中入射光线V,出射光线是红色的,它们与法线的夹角符号相反,值相同。当已知入射光线V,和N,来求出射光线(红色部分),可以看出其等于
代码实现如下:
vec3 reflect(const vec3 &v, const vec3& n)
{
return v - 2 * dot(v, n)*n;
}
【lambertian材质】
lambertian对反射方向加了挠动:
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const
{
vec3 target = rec.p + rec.normal + random_in_unit_sphere();
scattered = ray(rec.p, target - rec.p);
attenuation = albedo;
return true;
}
【metal材质】
metal材质对这种挠动进行缩放,其中fuzz是[0, 1]之间的数字。
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3 & attenuation, ray& scattered) const
{
vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal);
scattered = ray(rec.p, reflected + fuzz*random_in_unit_sphere());
attenuation = albedo;
return (dot(scattered.direction(), rec.normal) > 0);
}
【光线跟踪函数】
对于光线跟踪来说,我们对每个相交的点的材质计算出出射光线scattered,再进行跟踪。在这里还需要将材质中的颜色取出用于着色,材质本身的颜色在材质的vec3 albedo;中存储,在scatter中传递给了attenuation
vec3 color(const ray& r, hitable* world, int depth)
{
hit_record rec;
if (world->hit(r, 0.001f, FLT_MAX, rec))
{
ray scattered;
vec3 attenuation;
if (depth < 50 && rec.mat_ptr->scatter(r, rec, attenuation, scattered))
{
return attenuation*color(scattered, world, depth + 1);
}
}
else
{
vec3 unit_direction = unit_vector(r.direction());
float t = 0.5f * (unit_direction.y() + 1.0f);
return (1.0f - t)*vec3(1.0f, 1.0f, 1.0f) + t*vec3(0.5f, 0.7f, 1.0f);
}
return vec3(0.0f, 0.0f, 0.0f);
}