《Ray Tracing in One Weekend》笔记 - 【Chapter 9】:Dielectrics

这篇笔记介绍了如何在光线追踪中实现会发生折射的材质,特别是Dielectric类。当光线与这类材质表面碰撞时,根据折射定律决定是否生成折射光线。全内反射现象也被考虑在内,当入射角大于临界角时,光线不会折射而是全部反射。代码示例展示了Dielectric材料如何判断并生成折射或反射光线。
摘要由CSDN通过智能技术生成

《Ray Tracing in One Weekend》 笔记 - Chapter9:会发生折射的材质

该小节中实现了表面会发生折射现象的材质。

模型假设
1.文章在实现上做了一些简化,每当光线与该类材质物体表面发生碰撞,便在折射光线和反射光线之间做一次选择,仅生成一种光线。

2.折射光线的生成需要满足折射定律。

在这里插入图片描述
在这里插入图片描述
3. 全内反射:
“又称全反射(total internal reflection,TIR),是一种光学现象。当光线从较高折射率的介质进入到较低折射率的介质时,如果入射角大于某一临界角θc(光线远离法线)时,折射光线将会消失,所有的入射光线将被反射而不进入低折射率的介质。"【百科】

实现

在这里插入图片描述
// -------- dielectric.h -------- //

#ifndef DIELECTRIC_H
#define DIELECTRIC_H

#include "material.h"
#include "metal.h"

class dielectric : public material
{
public:
	dielectric(float ri) :ref_idx(ri) {}
	virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const;
	float ref_idx;  // 相对空气介质的折射系数
};
#endif // ! DIELECTRIC_H

// -------- dielectric.cpp -------- //

#include "dielectric.h"

// 判断是否会发生全反射
bool refract(const vec3& v, const vec3& n, float ni_over_nt, vec3& refracted) {
    // 先将入射光线转化为单位向量
    vec3 uv = unit_vector(v);
    float dt = dot(uv, n);
    float discriminat = 1.0 - ni_over_nt * ni_over_nt * (1.0 - dt * dt);
    if (discriminat > 0) {
        refracted = ni_over_nt * (uv - n * dt) - n * sqrt(discriminat);
        return true;
    }
    // discriminat < 0,则说明方向向量无实根,即没有实际的折射光线,认为出现全反射
    else {
        return false;
    }
}

bool dielectric::scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const {
    vec3 outward_normal;
    vec3 reflected = reflect(r_in.getDirection(), rec.normal);
    float ni_over_nt;  // 折射介质与空气介质折射率的比值
    attenuation = vec3(1.0, 1.0, 1.0);

    vec3 refracted;

    // 入射方向与小球表面法向量点乘大于0,说明光线从球体内部射入空气
    if (dot(r_in.getDirection(), rec.normal) > 0) {
        outward_normal = -rec.normal;
        ni_over_nt = ref_idx;
    }
    else {
        outward_normal = rec.normal;
        ni_over_nt = 1.0 / ref_idx;
    }

    // 若未发生全反射,生成折射光线,否则生成反射光线
    if (refract(r_in.getDirection(), outward_normal, ni_over_nt, refracted)) {
        scattered = ray(rec.p, refracted);
    }
    else {
        scattered = ray(rec.p, reflected);
        return false;
    }
    return true;
}

// -------- main.cpp -------- //

	hitable *list[4];
	list[0] = new sphere(vec3(0,0,-1), 0.5, new lambertian(vec3(0.8, 0.3, 0.3)));
	list[1] = new sphere(vec3(0, -100.5, -1), 100, new lambertian(vec3(0.8, 0.8, 0.0))); // 在半部分放一个大球作为地面
	list[2] = new sphere(vec3(1, 0, -1), 0.5, new metal(vec3(0.8, 0.6, 0.2)));
    list[3] = new sphere(vec3(-1, 0, -1), 0.5, new dielectric(1.5));

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值