Skip to content
Copied!
published on 2026-04-05

1. raytracing_demos の構成

このページでは,Ray Tracingプロジェクト固有のWASM構成を扱います。VitePress一般のWASM読み込み制約(fetch + Blob URL など)は雑想ノートを参照してください。

ワークスペースの cargo-doc はここで見られます。

ワークスペース全体像

master/wasm/raytracing は Cargo ワークスペースで,以下の構成になっています。

master/wasm/raytracing/
├── Cargo.toml                    # ワークスペース定義
├── build.sh                      # wasm-pack ビルドスクリプト
├── common/                       # 共通ライブラリ(wasm-bindgen 非依存)
│   └── src/
│       ├── lib.rs
│       ├── vec3.rs               # Vec3, Color, Point3, 各種関数
│       ├── ray.rs                # Ray
│       ├── hittable.rs           # HitRecord, Hittable トレイト
│       ├── hittable_list.rs      # HittableList
│       ├── sphere.rs             # Sphere
│       ├── material.rs           # Material トレイト, Lambertian, Metal, Dielectric
│       ├── camera.rs             # Camera
│       └── utils.rs              # 乱数, 数学定数
├── r102-gradient/                # 1.2章
├── r103-vec3/                    # 1.3章
│   ⋮  (各章クレート)
├── r113-final-scene-hq/          # 1.13章(高品質版)
└── raytracing-demos/             # WASM エクスポート傘クレート(cdylib)
    └── src/
        └── lib.rs

3層の依存関係は以下のとおりです。

common (rlib)  ←  r1XX-* (rlib)  ←  raytracing-demos (cdylib)  →  WASM

VitePress から直接呼ばれるのは raytracing-demos がエクスポートする関数群のみです。

Cargo ワークスペースの設定

Cargo.toml(ワークスペース直下)は共通依存のバージョンを一元管理します。

toml
[workspace]
members = [
    "common",
    "r102-gradient",
    # ... 各章クレート ...
    "raytracing-demos",
]
resolver = "2"

[workspace.dependencies]
common       = { path = "common" }
wasm-bindgen = "0.2"

[workspace.dependencies] に記載した依存は,各クレートの Cargo.toml から { workspace = true } で参照できます。章クレートが common のバージョンを個別管理しなくて済むのはこのためです。

3層構成

common:共通ライブラリ

common は純粋な Rust ライブラリで,wasm-bindgen に依存しません。

toml
# common/Cargo.toml
[package]
name    = "common"
version = "0.1.0"
edition = "2024"

[dependencies]
# wasm-bindgen はない

lib.rs がすべてのモジュールをクレート外へ再エクスポートします。

rust
// common/src/lib.rs(抜粋)
pub mod vec3;
pub use vec3::{
    Color, Point3, Vec3, dot, cross, reflect, refract, unit_vector,
    write_color, write_color_gamma, random_in_unit_sphere, /* ... */
};
pub mod ray;          pub use ray::Ray;
pub mod hittable;     pub use hittable::{HitRecord, Hittable};
pub mod sphere;       pub use sphere::Sphere;
pub mod material;     pub use material::{Material, Lambertian, Metal, Dielectric};
pub mod hittable_list; pub use hittable_list::HittableList;
pub mod camera;       pub use camera::Camera;
pub mod utils;        pub use utils::{INFINITY, PI, degrees_to_radians, random_double, /* ... */};

章クレート(r1XX-*)

各章のデモを実装するクレートです。命名規則は次のとおりです。

r + 週番号 + 章番号2桁 + - + 説明

例: r102-gradient, r106-sphere-normals, r109-metal-fuzz
  • 先頭に r がついているのは,Cargo はクレート名の数値始まりを禁止しているため,raytracing っぽい接頭辞をつけた
  • 同じ章に複数のデモがある場合は説明部分を変える(例:r108-diffuse, r108-lambertian, r108-hemisphere
  • 第2週(Ray Tracing: The Next Week)は r2XX-*,第3週は r3XX-* と同じ規則で続く

章クレートは common だけに依存し,wasm-bindgen を持ちません。

toml
# r109-metal/Cargo.toml(例)
[package]
name    = "r109-metal"
version = "0.1.0"
edition = "2024"

[dependencies]
common = { workspace = true }

各クレートは公開 API として pub fn render_image() -> String をただひとつ持ちます。

rust
// r102-gradient/src/lib.rs(例)
pub fn render_image() -> String {
    let mut output = String::new();
    output.push_str("P3\n256 256\n255\n");
    for j in 0..256 {
        for i in 0..256 {
            // R, G, B 値を計算して書き込む
            output.push_str(&format!("{} {} {}\n", ir, ig, ib));
        }
    }
    output
}

wasm-bindgen への依存がないため,cargo test で通常の Rust テストとして動作確認できます。

raytracing-demos:傘クレート

全章クレートを束ねて WASM バイナリとして出力するクレートです。

toml
# raytracing-demos/Cargo.toml
[lib]
crate-type = ["cdylib"]       # WASM(.wasm)として出力するために必要

[dependencies]
r102-gradient = { version = "*", path = "../r102-gradient" }
# ... 全章クレート ...
r113-final-scene-hq = { version = "*", path = "../r113-final-scene-hq" }
wasm-bindgen.workspace = true

lib.rs では各章クレートの render_image()#[wasm_bindgen] でラップするだけです。

rust
// raytracing-demos/src/lib.rs(抜粋)
use wasm_bindgen::prelude::*;

// 1.2: Gradient
#[wasm_bindgen] pub fn render_gradient()  -> String { r102_gradient::render_image() }

// 1.4: Ray, Camera, Background
#[wasm_bindgen] pub fn render_sky()       -> String { r104_ray_camera_background::render_image() }

// 1.5: Rendering a Sphere
#[wasm_bindgen] pub fn render_sphere()    -> String { r105_sphere::render_image() }

// ...

// 1.13: Final Scene (high quality)
#[wasm_bindgen] pub fn render_final_scene_hq() -> String { r113_final_scene_hq::render_image() }

この設計により,各章のレンダリングロジックは wasm-bindgen なしにテストでき,エクスポート宣言だけが raytracing-demos に集約されます。

新しいデモを追加する手順

新しい章が増えたとき(原典 v4 の追加章,第2週の章など)の手順は常に同じです。

1. 章クレートを作成する

bash
# master/wasm/raytracing/ 内で実行
cargo new --lib r114-new-chapter

r114-new-chapter/Cargo.tomledition = "2024" と,必要なら common = { workspace = true } を追加します。src/lib.rspub fn render_image() -> String { … } を実装します。

2. ワークスペース Cargo.tomlmembers に追加する

toml
[workspace]
members = [
    # ...
    "r114-new-chapter",      # ← 追加
    "raytracing-demos",
]

3. raytracing-demos/Cargo.toml[dependencies] に追加する

toml
r114-new-chapter = { version = "*", path = "../r114-new-chapter" }

4. raytracing-demos/src/lib.rs にエクスポートを追加する

rust
#[wasm_bindgen]
pub fn render_new_chapter() -> String {
    r114_new_chapter::render_image()
}

以上です。あとは build.sh を実行すれば,新しい関数が含まれた WASM バイナリが生成されます。第2週(r2XX-*)以降でも手順は変わりません。

ビルド

bash
# master/wasm/raytracing/ 内で実行
bash build.sh

内部では次のコマンドが実行されます。

bash
wasm-pack build --target web raytracing-demos \
  --out-dir <repo>/docs/public/wasm/raytracing_demos --release

--target web で ES Modules 形式(raytracing_demos.js + raytracing_demos_bg.wasm)が出力されます。--release を外すとデバッグビルドになりますが,レイトレーシングのような計算負荷の高い処理では速度が大幅に落ちます。

PPM 文字列を返す理由

各デモ関数が String で PPM(P3)を返す設計にしているのは,以下の理由によります。

  • 原典の学習手順(C++ のターミナル文字列出力を Rust で段階的に再実装する流れ)に沿える
  • WebAssembly 境界をまたいだデータ受け渡しが単純になる
  • デバッグ時にヘッダー(P3 / 幅 高さ / 255)を目視確認しやすい

VitePress 側の受け取り

VitePress では PPMRenderer コンポーネントが次を担当します。

  1. raytracing_demos.jsfetch + Blob URL 方式で読み込み,WASM を初期化
  2. 目的のエクスポート関数(例:render_gradient)を呼び出す
  3. 返ってきた PPM 文字列をパースして canvas へ描画

canvas サイズは PPM ヘッダーから先に取得し,Vue のリアクティブ更新が完了してから描画します。順序を誤ると描画後に canvas がリセットされるためです(詳細はPPMRenderer の実装を参照)。

配置場所

build.shwasm-pack の出力先を docs/public/wasm/raytracing_demos/ に指定しています。生成された raytracing_demos.js / raytracing_demos_bg.wasm はここへ自動的に配置されます。