3次元ベジエ曲面をクリックしたとき、その画面座標に対応する曲面上の (u, v) を どう求めるか。「三角形化+ニュートン法」「ベジエクリッピング法」、そして 両者を組み合わせた「ハイブリッド法(クリップ→ニュートン切替)」という 性質の異なる三つのアプローチを、仕組み・精度・実測速度の観点で比較する。
カメラ(視点 E)から画面上の画素 (x, y) を通る視線レイを1本引くと、 レイが曲面 S(u, v) と交わる点はふつう1点か数点に限られる。 求めたいのは、その交点における曲面パラメータ (u, v) である。 ベジエ曲面はビキュービック(各方向3次)の制御点パッチで表され、 評価関数 S(u, v) は4×4個の制御点のバーンスタイン基底による重み付き和になる。
この「レイと曲面の交差点探索」は本質的にはレイトレーシングそのものの部分問題であり、 三角形化法はレンダリング(ラスタライズ)寄りの近似的な解き方、 ベジエクリッピング法はレイトレーシング用に考案された厳密寄りの解き方、 ハイブリッド法はその両者の良いところを繋ぎ合わせた実装、という立場の違いがある。
曲面をあらかじめ N×N のグリッドで細分し、各セルを2枚の三角形として 画面へ投影しておく。クリック点を含む三角形を重心座標でヒットテストし、 三角形の3頂点が持つ (u, v) を重心座標で線形補間して初期値を得る。 この初期値から出発し、画面上の誤差
が 0 になるよう、有限差分で求めたヤコビアンを使ってニュートン法を数回反復する。
Nishita らが1990年にレイトレーシング用に提案した手法。視線レイを 「レイを含む2枚の平面の交線」として表現するのが出発点になる。 レイ方向 d に直交し互いにも直交する法線 n₁, n₂ を選び、レイ原点を o とすると、
という2つの3×3次ベジエ関数(スカラー値)ができる。S が制御点のバーンスタイン基底による 線形結合であることから、g₁, g₂ の制御係数は元の制御点を平面までの符号付き距離へ 射影するだけで直接求まる。レイと曲面の交点はまさに g₁(u,v) = 0 かつ g₂(u,v) = 0 となる (u, v) である。
ベジエ関数の値は制御係数の凸包の内側に収まる(凸包性)。したがって g₁ か g₂ の制御係数が全て同符号なら、そのパッチ内に解は存在しないと 数学的に確定でき、即座に棄却できる。符号が混在する場合のみ、 列・行ごとの係数の最小値・最大値が作る「包絡線(ファットライン)」を用いて u 方向・v 方向の安全な範囲を求め、その範囲でパッチを切り詰める。
収縮が遅い場合(同一パッチ内に複数交点があるなど)は4分割し、 それぞれの子パッチで同じ手続きを再帰的に継続する。範囲の幅が 許容誤差(本アプリでは 0.001)を下回れば収束とみなす。
ベジエクリッピング法の弱点は、範囲を許容誤差まで収縮させる終盤の反復が 線形収束であること。凸包性による確実な足場を得たあとまで、 同じ調子でクリップを続けるのはやや非効率になる。 一方でニュートン法は初期値さえ良ければ2次収束(1反復ごとに有効桁数がほぼ倍増) する。そこで、両者の得意な局面だけを使う。
クリップ側は「解の存在範囲をロバストに絞り込む」役、ニュートン側は 「絞り込んだ範囲を高速に仕上げる」役、と分業させることで、 クリップ単独より反復回数が減り、かつ三角形化法のようなメッシュ生成コストも要らない。
同じクリック位置に対して三手法を切り替えて実行し、 performance.now() で計測した例:
| 手法 | 計算時間 | 三角形化比 |
|---|---|---|
| 三角形化+ニュートン法 | 4.300 ms | 基準(1.0倍) |
| ベジエクリッピング法 | 0.500 ms | 約 8.6倍速い |
| ハイブリッド法 | 0.300 ms | 約 14倍速い |
このティーポットの例では、ベジエクリッピング法は三角形化法よりすでに速く、 ハイブリッド法はさらにその上をいく(三角形化法に対して実測でおよそ10倍以上、 この例では約14倍)。差が生まれる主因は次の2つである。
実際の比率は曲面の形状・パッチ数・クリック位置(レイがどれだけ多くのパッチと 交差するか)によって変動する。本アプリのサイドバーでは同じクリックに対して 手法を切り替えて何度でも実測できるので、形状を変えながら傾向を確かめてみてほしい。
| 観点 | 三角形化+ニュートン法 | ベジエクリッピング法 | ハイブリッド法 |
|---|---|---|---|
| 初期解の求め方 | N×N分割メッシュへの点in三角形判定+重心座標補間 | 制御係数の凸包性による棄却/包絡線クリップ | クリップで絞り込んだ範囲の中心 |
| 終盤の収束速度 | 2次収束(ニュートン法) | 線形収束(クリップのみ) | 2次収束(クリップ→ニュートン切替) |
| 精度の保証 | 局所収束のみ(初期値依存) | 凸包性に基づく厳密な範囲追跡 | クリップの保証+ニュートンの速さ |
| 取りこぼし(偽陰性) | メッシュ分割が粗いと起こりうる | 理論上は起こらない | 理論上は起こらない(前半はクリップと同じ) |
| 前処理コスト | 曲面ごとに固定のメッシュ生成が必ず必要 | パッチ全体を1回判定するだけで大半を即棄却できる | ベジエクリッピング法と同じ |
| 複数交点への対応 | 三角形ごとに独立に検出 | 収束が遅い領域のみ4分割して追跡 | クリップ側の4分割をそのまま利用 |
| 実装の複雑さ | 低い | 中〜高 | 最も高い(両方のコードが必要) |
| 実測(ティーポット例) | 4.300 ms | 0.500 ms | 0.300 ms |
三手法とも最終的に得られる (u, v) の精度は同程度まで詰められるが、 速さの序列はほぼ一貫してハイブリッド法 < ベジエクリッピング法 < 三角形化法 (ハイブリッド法が最速)になる。三角形化法が常に固定コストのメッシュ生成を 背負うのに対し、クリップ系の2手法は凸包性による即時棄却で大半のパッチを 無視できるぶん有利であり、さらにハイブリッド法は終盤の遅い線形収束を 2次収束のニュートン法に置き換えることで、クリップ単独よりも一段速くなる。
実際の計算時間はパッチ数・曲率・クリック位置などに依存するため、 本アプリのサイドバーでは同じクリック位置に対して三手法を切り替えて実行し、 それぞれの計算時間を performance.now() で計測・比較できるようにしてある。 形状やクリック位置を変えながら実測比較してみるのが最も確実である。