次は?

最後のシーン

この本のカバーにある画像を生成しよう ──ランダムな球をたくさん配置する:

hittable_list random_scene() {
  hittable_list world;

  auto ground_material = make_shared<lambertian>(color(0.5, 0.5, 0.5));
  world.add(make_shared<sphere>(point3(0,-1000,0), 1000, ground_material));

  for (int a = -11; a < 11; a++) {
    for (int b = -11; b < 11; b++) {
      auto choose_mat = random_double();
      point3 center(a + 0.9*random_double(), 0.2, b + 0.9*random_double());

      if ((center - vec3(4, 0.2, 0)).length() > 0.9) {
        shared_ptr<material> sphere_material;
        if (choose_mat < 0.8) {
          // diffuse
          auto albedo = color::random() * color::random();
          sphere_material = make_shared<lambertian>(albedo);
          world.add(make_shared<sphere>(center, 0.2, sphere_material));
        } else if (choose_mat < 0.95) {
          // metal
          auto albedo = color::random(0.5, 1);
          auto fuzz = random_double(0, 0.5);
          sphere_material = make_shared<metal>(albedo, fuzz);
          world.add(make_shared<sphere>(center, 0.2, sphere_material));
        } else {
          // glass
          sphere_material = make_shared<dielectric>(1.5);
          world.add(make_shared<sphere>(center, 0.2, sphere_material));
        }
      }
    }
  }

  auto material1 = make_shared<dielectric>(1.5);
  world.add(make_shared<sphere>(point3(0, 1, 0), 1.0, material1));
  auto material2 = make_shared<lambertian>(color(0.4, 0.2, 0.1));
  world.add(make_shared<sphere>(point3(-4, 1, 0), 1.0, material2));
  auto material3 = make_shared<metal>(color(0.7, 0.6, 0.5), 0.0);
  world.add(make_shared<sphere>(point3(4, 1, 0), 1.0, material3));

  return world;
}

int main() {
  ...
  auto world = random_scene();

  point3 lookfrom(13,2,3);
  point3 lookat(0,0,0);
  vec3 vup(0,1,0);
  auto dist_to_focus = 10.0;
  auto aperture = 0.1;
  camera cam(lookfrom, lookat, vup, 20, aspect_ratio, aperture, dist_to_focus);
  ...
}
リスト 1.67 [main.cc] 最後のシーン

次の画像が得られる:

図 1.39:
最後のシーン

ガラス球に影が落ちておらず浮いて見えることに気が付いたかもしれない。これはバグではない ──ガラス球を日常生活で目にすることはあまりないと思うが、実際に見ると変な感じがする。特に曇りの日に見ると、本当に浮かんで見える。ガラス球と大きな球に挟まれる点に達したレイは上にあるガラス球に遮られることなく空に到達できるので、ガラス球の下に影はできない。

次のステップ

これでクールなレイトレーサーの完成だ! 次は何をしようか?

  1. ライト ── シャドウレイを光源に向けて放って陽に影を付けることもできるし、オブジェクトを発光させて陰に影を付けることもできる。オブジェクトを発光させる場合には、発光しているオブジェクトに多くの散乱レイを放ってから重みを減らして調整する処理をすると効率良く計算できる。私は後者のアプローチを気に入っているマイノリティである。
  2. 三角形 ── 多くのクールなモデルは三角形から構成される。モデルの I/O は骨が折れる作業で、ほとんど全員が他人のコードに頼っている。
  3. サーフェステクスチャ ── 壁紙のように画像を張り付ける機能である。実装はとても簡単で、勉強になる。
  4. ソリッドテクスチャ ── Ken Perlin がコードをオンラインに示している。Andrew Kensler のブログには非常にクールな情報がある。
  5. ボリュームレンダリング ── クールな機能だが、ソフトウェアとしてのレンダラのアーキテクチャが試される。ボリュームに hittable のインターフェースを持たせ、密度に応じて交点を確率的に計算するというのが私がよく使うアプローチだ。レンダリングのコードはボリュームが存在していることさえ知る必要がない。
  6. 並列化 ── 同じコードを異なるランダムシードを使って \(N\) 個のコアで一つずつ実行し、生成される \(N\) 個の画像の平均を計算する方法がある。平均の計算では \(N/2\) 個の組から \(N/4\) 個の画像を得る階層的な方法が利用できる。このように並列化を行うと、コアが数千個であってもほぼそのまま動作する。

楽しんで! クールな画像ができたらぜひ私に見せてほしい!

広告