Reflection and Refraction

Chapter 11

反射、屈折。

Reflection

今まではある Shape 上の 1 点の色は ambient, diffuse, および specular で決まっていた。これに reflection (反射)の分が加わる。

ambient を除けば、diffuse は Light の方向、specular は Light の反射方向(と視線ベクトル)で決まる。これに対して、新たに加わる reflection は視線(Ray)の反射方向を用いる。

    fn reflected_color(
        &self,
        is: &IntersectionState,
        remaining: usize,
    ) -> Color {
        if is.object.material().reflective == 0.0 {
            return Color::BLACK;
        }
        if remaining <= 0 {
            return Color::BLACK;
        }

        let reflect_ray = Ray::new(is.over_point.clone(), is.reflectv.clone());
        let color = self.color_at(&reflect_ray, remaining - 1);

        &color * is.object.material().reflective
    }

ここで、反射先でまた反射となる場合に再帰が無限に深くなってしまう可能性があるため、一定の深さで再帰を打ち切っている。

Transparency and Refraction

透明な Shape に対して更に refection (屈折)の分を加える。

refraction の場合も基本的な考え方は reflection と変わらない。ただ、reflection は視線の反射方向が Shape によらず視線と法線ベクトルから簡単に求まるのに対して、refraction は Shape ごとに異なる屈折率(refractive index)を用いて計算しなくてはならない。

しかも、単一の Shape ではなく、視線が出ていく Shape と次に視線が入る Shape の 2 つを考慮するため、reflection よりも大分複雑になる。

        let n_ratio = is.n1 / is.n2;
        let cos_i = is.eyev.dot(&is.normalv);
        let sin2_t = n_ratio * n_ratio * (1.0 - cos_i * cos_i);
        if sin2_t > 1.0 {
            return Color::BLACK;
        }

        let cos_t = (1.0 - sin2_t).sqrt();
        let direction =
            &(&is.normalv * (n_ratio * cos_i - cos_t)) - &(&is.eyev * n_ratio);

それ以外は reflection と変わらないため、方向ベクトルを求める部分を除けば reflected_color() とほぼ同じになる。

Fresnel Effect

反射と屈折の割合を近似的に計算する。本のままなので書くことがない。

結果

f:id:mtXTJocj:20210429181957p:plain

本の中で図示されている画像と同じ条件でレンダリングしたかったのだけれど、それが書かれないなかったので、てきとーにやった。 なので、これで正しくレンダリングできているかがいまいちはっきりしない。個別の単体テストは通っているので、大丈夫だと思うことにする。

f:id:mtXTJocj:20210429153207p:plain