Reflection and Refraction
Chapter 11
The Ray Tracer Challenge: A Test-Driven Guide to Your First 3D Renderer (Pragmatic Bookshelf)
- 作者:Buck, Jamis
- 発売日: 2019/03/12
- メディア: ペーパーバック
反射、屈折。
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
反射と屈折の割合を近似的に計算する。本のままなので書くことがない。
結果
本の中で図示されている画像と同じ条件でレンダリングしたかったのだけれど、それが書かれないなかったので、てきとーにやった。 なので、これで正しくレンダリングできているかがいまいちはっきりしない。個別の単体テストは通っているので、大丈夫だと思うことにする。