【Ray-Tracing In One Weekend】第8章 金属材质

本节对材质进行抽象并且定义了两个材质,一个是lambertian材质,另一个是metal材质。本节材质之间的不同在于材质的颜色【Ray-Tracing In One Weekend】第8章 金属材质和材质表面微元的反射光线生成。假若按照入射光线严格的生成完美反射光线,那么就是理想的反射,在现实的生活中不存在理想的反射,入射光线与出射光线分别位于法线的两侧,但是夹角并不相等。对于金属材质来说我们对这个反射光线加了一个随机挠动fuzz。下面来对比几种效果:

【Ray-Tracing In One Weekend】第8章 金属材质【Ray-Tracing In One Weekend】第8章 金属材质【Ray-Tracing In One Weekend】第8章 金属材质

左图是分列左右两边的金属球均加了fuzz,一个加了0.3,一个是1.0,中间的是右侧的球没有使用fuzz和随机的出射光线挠动,呈现的是完美反射,右侧是两边球都是完美反射。

代码使用VS2015编写,能过如下链接下载:

链接:https://pan.baidu.com/s/1LRSyDTk5hguETX3_gCE6IQ 
提取码:akw9 
 

【材质】

我们对每个物体绑定了一个材质,材质确定了当入射光线照射这个物体形成交点的时候,我们该如何反射出射光线,假如光线被完全吸收,那么物体就是黑色,因为没有任何的散射,就是黑洞了。光照射一个物体时,分为反射与折射两个方面,本节我们分析折射,完美的折射和没有完美的完全吸收没有任何折射都是很难的。完美的折射如下图:

【Ray-Tracing In One Weekend】第8章 金属材质

其中入射光线V,出射光线是红色的,它们与法线的夹角符号相反,值相同。当已知入射光线V,和N,来求出射光线(红色部分),可以看出其等于【Ray-Tracing In One Weekend】第8章 金属材质

代码实现如下:

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);
}