What & How & Why

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
cg:books:rt_one_wk:book_1 [2022/07/28 09:46] – [镜面反射] codingharecg:books:rt_one_wk:book_1 [2024/01/12 05:46] (当前版本) – [Ray Tracing In one Weekend] codinghare
行 132: 行 132:
 现在利用点积的结合律对该等式进行扩展,我们可以得到一个关于 $t$ 的一元二次方程: 现在利用点积的结合律对该等式进行扩展,我们可以得到一个关于 $t$ 的一元二次方程:
 \\ \\  \\ \\ 
-\begin{align}+\[ 
 +\begin{align*}
 &dot((A + tb -C), (A + tb -C)) = r^2 \newline &dot((A + tb -C), (A + tb -C)) = r^2 \newline
 \Longrightarrow &dot(tb + {\color{Red}(A-C) }), (tb + {\color{Red}(A-C) }) = r^2 \newline \Longrightarrow &dot(tb + {\color{Red}(A-C) }), (tb + {\color{Red}(A-C) }) = r^2 \newline
-\Longrightarrow &t^2*\underbrace{{\color{Peach} dot}(b,b)}_\text{a} +t*\underbrace{2*{\color{Peach} dot} (b,(A-C))}_\text{b} +\ +\Longrightarrow &t^2 \cdot \underbrace{{\color{Peach} \cdot}(b,b)}_\text{a} +t \cdot \underbrace{2 \cdot {\color{Peach} } (b,(A-C))}_\text{b} +\ 
-\underbrace{{\color{Peach} dot}((A-C),(A-C))-r^2}_\text{c} = 0 +\underbrace{{\color{Peach} \cdot}((A-C),(A-C))-r^2}_\text{c} = 0 
-\end{align}+\end{align*} 
 +\]
 ==具体实现== ==具体实现==
 可见的是,射线与球体是否相交的问题,就可以转变为关于 $t$ 的方程是否存在根的问题。这种情况下使用判别式 $b^2 -4ac$ 判断即可。\\ \\  可见的是,射线与球体是否相交的问题,就可以转变为关于 $t$ 的方程是否存在根的问题。这种情况下使用判别式 $b^2 -4ac$ 判断即可。\\ \\ 
行 646: 行 648:
 </code> </code>
 ===镜面反射=== ===镜面反射===
-与漫反射不同,光滑的金属产生的是镜面反射。镜面反射产生的射线方向与大小可由下图的关系计算出:+与漫反射不同,光滑的金属产生的是**镜面反射**(//Mirrored reflection//。镜面反射产生的射线方向与大小可由下图的关系计算出:
 \\ \\ \\  \\ \\ \\ 
 {{ :cg:books:rt_one_wk:fig-1.11-reflection.jpg?400 |}} {{ :cg:books:rt_one_wk:fig-1.11-reflection.jpg?400 |}}
行 657: 行 659:
 v + 2 * dot(-v, n) \Longrightarrow v - 2 *dot(v, n) v + 2 * dot(-v, n) \Longrightarrow v - 2 *dot(v, n)
 $$ $$
 +实现:
 +<code cpp>
 +//in vec3.h
 +vec3 reflect(const vec3& v, const vec3& n) {
 +    return v - 2*dot(v,n)*n;
 +}
 +</code>
 +==metal 类==
 +''metal'' 类与 ''lambertain'' 类的结构类似,也需要重写 ''scatter'' 函数和添加衰减率的成员。与 ''lambertain'' 不同的是,''metal'' 生成的射线将按照镜面反射的规则来生成:
 +<code cpp>
 +class metal : public material {
 +    public:
 +        metal(const color& a) : albedo(a) {}
 +
 +        virtual bool scatter(
 +            const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered
 +        ) const override {
 +            //scatter direction
 +            vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal);
 +            //scatter ray
 +            scattered = ray(rec.p, reflected);
 +            attenuation = albedo;
 +            return (dot(scattered.direction(), rec.normal) > 0);
 +        }
 +
 +    public:
 +        color albedo;
 +};
 +</code>
 +===模糊镜面反射===
 +镜面反射的结果可以通过随机偏离反射射线的方向来进行模糊,达到一种类似**不光滑**表面金属的反射效果。我们将这种反射称为**模糊镜面反射**(//Fuzzy Reflection//)。反射射线方向的偏离实现与 //true lambertain// 类似,也是使用与相交点相切的单位球来生成随机的射线方向。
 +\\ \\ 
 +{{ :cg:books:rt_one_wk:fig-1.12-reflect-fuzzy.jpg?400 |}}
 +\\ \\ 
 +实现中,''metal'' 类添加了 ''fuzz'' 成员作为偏离的系数(越大越模糊)。该系数与 ''random_in_unit_sphere()'' 函数一起决定了反射射线最终的偏离量:
 +<code cpp>
 +//cstr
 +metal(const color& a, double f) : albedo(a), fuzz(f < 1 ? f : 1) {}
 +//scattered ray with fuzzy reflection
 +scattered = ray(rec.p, reflected + fuzz*random_in_unit_sphere());
 +</code>
 +===main 文件中的对应修改[9.6]===
 +==ray_color()==
 +由于我们已经将 material 抽象化,因此需要使用指针进行对应材质的调用。此处我们允许自行指定材质的衰减率:
 +<code cpp>
 + if (world.hit(r, 0.001, infinity, rec)) {
 +        ray scattered;
 +        color attenuation;
 +        if (rec.mat_ptr->scatter(r, rec, attenuation, scattered))
 +            return attenuation * ray_color(scattered, world, depth-1);
 +        return color(0,0,0);
 +    }
 +</code>
 +<WRAP center round box 100%>
 +之前一直不太明白为什么 ''scatter'' 都要返回一个 ''bool'',此处实际上给出了解答:**只有在反射射线与法线的方向同向的时候**,才会进行下一步的反射;否则将直接作为阴影处理。
 +</WRAP>
 +==场景的修改==
 +  * 改变了背景大球的颜色
 +  * 新增一左一右两球,材质为 metal
 +  * 改变了中间球的颜色
 +  * 模糊镜面反射版本需要提供额外的 ''fuzz''
 +<code cpp>
 +auto material_ground = make_shared<lambertian>(color(0.8, 0.8, 0.0));
 +auto material_center = make_shared<lambertian>(color(0.7, 0.3, 0.3));
 +auto material_left   = make_shared<metal>(color(0.8, 0.8, 0.8));
 +auto material_right  = make_shared<metal>(color(0.8, 0.6, 0.2));
 +
 +world.add(make_shared<sphere>(point3( 0.0, -100.5, -1.0), 100.0, material_ground));
 +world.add(make_shared<sphere>(point3( 0.0,    0.0, -1.0),   0.5, material_center));
 +world.add(make_shared<sphere>(point3(-1.0,    0.0, -1.0),   0.5, material_left));
 +world.add(make_shared<sphere>(point3( 1.0,    0.0, -1.0),   0.5, material_right));
 +</code>
 +