Drawing on a Canvas

Chapter2

github.com

Color

基本的には Point3DVector3D と変わらない。x, y, z の代わりに red, green, blue になっている。

pub struct Color {
    pub red: f32,
    pub green: f32,
    pub blue: f32,
}

また、Point3DVector3D と違い、Color 同士の演算しかないため、こちらの方が簡単かも。

Canvas

内部的には単純な Color の配列として実装する。

pub struct Canvas {
    width: usize,
    height: usize,
    colors: Vec<Color>,
}

これで width x heightCanvas を表現する。(x, y) の Color には width * y + x でアクセスする。また、Canvas の原点は左上。

PPM への出力

PPM は以前にも扱ったことがあるけれど、その時はバイナリ形式だった。

mtxtjocj.hatenablog.com

一方で今回はテキスト形式。また、Color は各成分が f32 であるため、出力時には [0.0, 1.0] を u8 の [0, 255] に変換しなくてはならない。

                let c = self.color_at(j, i);
                let r = (c.red * 255.0).round().min(255.0).max(0.0) as u8;
                let g = (c.green * 255.0).round().min(255.0).max(0.0) as u8;
                let b = (c.blue * 255.0).round().min(255.0).max(0.0) as u8;

そして、本では PPM の制限として 1 行 70 カラムまでというのを強調しており、わざわざ 70 カラムを越えないことを確認するテストケースまで用意していた。この点に関しては毎行 1 pixel にすれば気にせずに済むため、そのようにしている。
というか、一行が 70 カラムを越えない範囲でなるべく多くの情報を詰め込もうとした結果、行あたりの pixel 数が変わってしまったり、同じ pixel の red, green, blue の途中で改行したりといったことが起こり得る。それではせっかくテキストで出力しているのに、分かりにくくなってしまうのではなかろうか。

f:id:mtXTJocj:20191104012457p:plain