アーキテクチャ

このガイドでは 1 フレームが geometry3d のパッケージを通る流れを追い、各責務がどこにあり、なぜそうなのかを説明します。詳細と導出は各パッケージのページにあります。

階層

Luna-Flow/linear-algebra  (Vector[Double], Matrix[Double])
        │
      core        meshes, transforms, normals, visibility, Lambert
        │
      view        camera, projection, perspective-correct depth, lens model
        │
    frontend      scene → DrawList; shadow map; LumaBuffer; exposure; flow; timelines
        │
   ┌────┼──────────────┐
backend/tui   backend/canvas   backend/gsap
   │              │                │
  demo       demo_canvas       demo_gsap

各パッケージは自分より上にあるパッケージだけをインポートします。core、view、frontend は文字、色、DOM、オペレーティングシステムについて何も知らず、各バックエンドは互いを知らず、時計、環境変数、ファイル、ページ要素に触れるのはデモだけです。

1 フレームの流れ

  1. モデル。 frontend は各 SceneObject の Transform3 をそのメッシュ(core)に適用し、ワールド空間の頂点を得ます。
  2. 影。 ワールド空間のシーンを平行光源から 128 × 128 の正射影の深度マップに描画します。
  3. ビュー。 Camera3 のビュー変換(view)で頂点をカメラ空間に写します。xx が右、yy が上、zz が前です。
  4. 投影。 PerspectiveProjection で頂点をビューポートに投影します。xs=W/2+sx/zx_s = W/2 + s x/z、ys=H/2−sy/zy_s = H/2 - s y/z で、zz を深度として残します。
  5. カリングとシェーディング。 視点の方を向いた各面についてランバート項を計算し、シャドウマップが照らされていると判定した面の割合でそれを減衰させ、その輝度を持つ 2 つの DrawTriangle を出力します。
  6. バックエンド。 バックエンドが DrawList を出力に変えます。
    • backend/tui は yy を terminal_y_scale で圧縮し、三角形ごとにランプの文字を選び、深度バッファを使って FrameBuffer にラスタライズします。
    • backend/canvas はフロントエンドの LumaBuffer にラスタライズし、同じ濃淡のランをキャンバスに塗ります。
    • backend/gsap は三角形を遠いものから近いものへ並べ、SVG ポリゴンを書き出します。
  7. 表示。 デモがフレームを出力するか、ブラウザに描くか、.tui3d シーケンスに保存します。

境界が描画リストである理由

3 つのバックエンドが必要とするものは同じです。各三角形が画面のどこにあり、どれだけ遠く、どれだけ明るいかです。それより前はすべてデバイスに依存しない幾何で、フロントエンドで一度だけ計算されます。それより後はすべてデバイス側の判断です。ほかの案は frontend の設計で検討しています。

バックエンドの間で異なる判断は遮蔽だけです。TUI と Canvas のバックエンドは同じ深度バッファの規則を使い、正確です。SVG には深度バッファがないので、GSAP バックエンドはペインターズアルゴリズムによる並べ替えを使います。これは単一の凸物体では正確で、それ以外では近似です(GSAP の設計)。

パッケージをまたぐ規約

  • 座標。 ワールド空間とカメラ空間は Direct3D の左手系の規約に従います。既定のカメラでは +x+x が右、+y+y が上、+z+z が視聴者から遠ざかる向きです。画面の yy は下に向かって増えます。面は (b−a)×(c−a)(b - a) \times (c - a) が外側を向くように巡回します。
  • 光の方向。 Light はシーンから光源へ向かう単位ベクトルを格納します。
  • 深度。 投影後の深度はどこでもカメラ空間の zz で、小さいほど近くにあります。空のピクセルの深度は 103010^{30} です。
  • 許容誤差。 @core.DEPTH_EPSILON = 10−910^{-9} が、すべてのパッケージで退化した法線、同次除算、面積 0 の三角形、深度テストの同点を判定します。
  • 寛容なコンストラクタ。 コンストラクタは無効なサイズや個数を失敗させずに既定値で置き換えます。ライブラリには Result を返したり例外を送出したりするものはありません。
  • 読み取り専用のレコード。 公開構造体は pub struct です。呼び出し側はすべてのフィールドを読めますが、値はコンストラクタでしか作れません。

このリポジトリにないもの

ニア平面によるクリッピング、シーングラフ、マテリアルやテクスチャ、スムーズシェーディング、アセットの読み込み、物理、空間インデックスはありません。リポジトリの規約は、それらが実装されるまでドキュメントで説明しないよう求めています。