Vector3D/Point3D

相変わらず作りたいものはないのだけれど、少し前に "The Ray Tracer Challenge: A Test-Driven Guide to Your First 3D Renderer" という本を買った。

この本はテストケースのみを提示して、特定の言語を対象とせずにシンプルな Raytracer を実装することを目的としている。Rust を使ってこの本を読んでいけば良い経験になる... といいなあ。

とにかくやってみよう。

リポジトリはここ github.com

Tuples, Points, and Vectors

Chapter1 は Point と Vector の実装。本では Point と Vector を tuple を使った 4 つ組みで表現しているが、x, y, z の添字でアクセスしたいこと、Point と Vector の区別ができるなら w 成分は不要なことから、struct で表現する。

各成分には float として f32 を用いる。使用者が f32f64 の好きな方を使えるようにしたいけれど、あまり良い方法が思いつかない。

type Float = f32;

とでもしておいた方が良かったか。

浮動小数点関連は誤差はつきもののため、誤差を考慮した比較用関数も用意しておく。

const EPSILON: f32 = 0.0001;

fn approx_eq(a: f32, b: f32) -> bool {
    (a - b).abs() < EPSILON
}

また、Vector という名前にすると Vec と間違えそうなので、それぞれ Point3D, Vector3D という名前にした。

Point3D

struct の定義は非常に簡単。

#[derive(Debug, Clone)]
pub struct Point3D {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

x, y, z の各メンバに直接アクセスしたいので、pub を付けて公開している。

Vector3D

基本的には Point3D と変わらない。

#[derive(Debug, Clone)]
pub struct Vector3D {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

こちらも x, y, z の各メンバに直接アクセスしたいので、pub を付けて公開している。

Operation

Point3D と Vector3D に関する演算を定義する。実装自体に難しいところはないから、ソースを見るだけで何をしているのか分かるはず。

一方、Rust による演算子オーバーロードの仕様についてよく分からない点があり、それは別途記事にするつもり。 f:id:mtXTJocj:20190810173658p:plain