貫通(すり抜け)を起こさない衝突判定
— ベジエ曲面と 球 / 三角形・凸多面体 —

1.問題 — なぜすり抜けるのか

衝突判定の多くは、一定間隔の時刻ごとに「いま重なっているか」を調べる方式です。しかし物体が速いと、ある時刻では手前、次の時刻では向こう側にいて、どちらの時刻でも重なりが検出されません。これがすり抜け(トンネリング)です。

下図は、半径 0.15 の球がベジエ曲面(ティーポットの注ぎ口)をかすめる軌跡について、球の中心から曲面までの最短距離を時刻の関数として描いたものです。

0.00.20.40.60.81.00.00.51.01.52.0 時刻 t 距離 球の半径 r = 0.15 灰点=離散時刻での評価点(9分割)。赤帯を飛び越しており衝突を見落とす 赤帯 t∈[0.382, 0.408] 幅0.027
青線=球の中心から曲面までの最短距離、赤破線=球の半径。距離が半径を下回る(=接触している)のは赤帯のわずか幅 0.027 の区間だけで、灰点で示した離散時刻の評価はこれを飛び越している。

接触している時間帯は、この例では全体の 2.7 % しかありません。評価時刻をいくら細かくしても、物体が速くなればいつでも同じ状況が再現します。刻みを細かくする方向では原理的に解決しません。

2.共通する原理 — 凸包性による「保証つきの棄却」

ベジエ曲面 S(u,v) の値は、必ず制御点の凸包に含まれます。したがって、ある領域について「ここには解が存在しない」ことを計算で確定できます

衝突判定に使うときは、これを時間を含めた領域に対して適用します。すなわち「この時間帯・このパラメータ領域では接触が起こり得ない」と確定した箱だけを捨て、確定できない箱を細分していきます。捨てた箱に解が無いことは保証されているので、接触時間がどれほど短くても見落としません。

相手の形状によって、時間の扱い方に2通りの実現法があります。以下ではそれぞれを説明します。

相手の形状時間の扱い条件関数
第3のパラメータ t を追加F(u,v,t) = |S(u,v) − C(t)|² − r²(3変数ベジエ関数)
三角形・凸多面体スイープ体として空間に畳み込む掃引でできる凸多面体の各面による曲面のクリップ

3.球との衝突 — 時刻を第3のパラメータにする

球の中心が時刻の関数 C(t) で動くとき、接触の条件は次式です。

F(u,v,t) = | S(u,v) − C(t) |² − r² = 0   (1)

C(t) をベジエ曲線で表せば、F は3変数のベジエ関数になります。|S − C|² は C について2次なので、t の次数は軌跡の次数の2倍です。

軌跡 C(t)t の次数F の次数 (u×v×t)係数の個数
静止(動かない)06×649
線分(等速直線運動)16×6×2147
自由落下・放物運動26×6×4245
一般の m 次ベジエ曲線m6×6×2m49(2m+1)

係数の構成は軽い計算で済みます。F を展開すると

F = |S(u,v)|² − 2 S(u,v)·C(t) + |C(t)|² − r²   (2)

となり、第2項は変数分離形 f(u,v)·g(t) です。u,v と t は独立な変数なので、各因子を目的次数に上げた係数どうしの積がそのまま3変数の係数になります。第1項は (u,v) だけ、第3項は t だけの関数で、定数 −r² はバーンスタイン基底が1の分割であることから全係数に加えるだけです。

アルゴリズム

  1. 凸包による棄却 箱 (u,v,t) について F の係数を作り、全部が正であればその時間帯・その領域では衝突しないと確定して捨てる。
  2. 交互分割 符号が混在する箱は分割する。uv の4分割と時刻の2分割を交互に行うと3方向が均等に細かくなる。時刻の分割は軌跡のベジエ曲線を de Casteljau で半分にするだけである。
  3. 時刻による枝刈り(分枝限定法) 早い時刻の箱から処理し、すでに接触が確認できた時刻 t* より後に始まる箱は、そこでの衝突が必ず遅いので丸ごと捨てる。
  4. 二分法による精密化 残った箱の時間区間内を走査・二分して接触時刻を必要な精度まで追い込む。接触点はその時刻で球面に達している点、接触法線は球の中心から接触点への向きとして得られる。
落とし穴:枝刈りの基準は「上界」でなければならない
枝刈りに使う t* は、実際に接触を確認した時刻すなわち衝突時刻の上界である必要があります。実装の途中で、末端の箱の下限 t₀ を t* として使ったところ、接触時刻が最大 0.01 ほどずれました。箱の下限は下界にすぎず、その箱の本当の接触はもっと遅いかもしれないため、その間に本当の最早接触を含む箱を捨ててしまうからです。末端の箱の中を実際に調べて「確かに接触している点」を1つ見つけ、その時刻を上界とすることで解決しました。

実行例と検証

A (t=0) B (t=1) 衝突 t = 0.31575 接触 1 点
線分 A→B に沿って動く半径 0.5 の球。衝突時刻で球が止まり、接触点(赤)と接触法線が示される。衝突後の軌跡は破線。

ユタティーポット(32パッチ)に対し、時刻を4000分割し各時刻で全パッチを29×29点に標本化した総当たり計算と比較しました。

軌跡半径本手法総当たり判定ノード時間
(−4.5, 2.6, 0) → (4.5, −0.6, 0)0.50.315750.316000.00025449895 ms
(−5, 0.2, 0) → (5, 0.2, 0)0.30.209040.209250.000214824153 ms
(0, 5, 0) → (0, −5, 0) 真上から0.40.275500.275500.000007760346 ms
(3.2, 4, 0) → (3.2, −3, 0) 注ぎ口0.150.380010.380250.00024172451 ms
(−5, 6, 0) → (5, 6, 0) 頭上を通過0.5衝突なし衝突なし2082 ms

最後の行に注目してください。衝突しない軌跡は 208ノード・2ミリ秒で「絶対に衝突しない」と断定できます。ほとんどのパッチが最初の1回の符号チェックで消えるためで、衝突判定では圧倒的多数を占める「当たらない場合」がもっとも速いという、実用上ありがたい性質になっています。

▶ 実演プログラム 始点・終点・半径をスライダーで動かすと、衝突時刻・接触点・判定ノード数・凸包による棄却率・枝刈り回数がその場で再計算されます。アニメーションでは球が接触の瞬間で停止します。
bezier_sphCollision.html を開く

4.三角形・凸多面体との衝突 — スイープ体を使う

相手が多角形の場合、時刻を変数として追加しなくても済む、より軽い方法があります。鍵は次の事実です。

剛体が並進するときのスイープ体(掃いた領域)は、厳密に凸多面体になる。

三角形と並進ベクトルのミンコフスキー和なので、側面3枚とキャップで囲まれた三角柱がスイープ体そのものです。近似でも外接でもなく、完全に一致します。

掃引方向 d 時刻 a の三角形 時刻 b の三角形 側面 3 枚 並進のスイープ体は 三角形 ⊕ 線分 のミンコフスキー和であり、 厳密に凸多面体になる(近似ではない)
時刻 a から b までに三角形が掃く領域。側面3枚+キャップで囲まれた凸多面体になる。

したがって次が厳密に成り立ちます。

曲面がこの凸多面体と交差する ⇔ 時刻 a から b の間のどこかで接触が起きた

曲面と凸多面体の交差判定は、すでに確立している「凸多面体で曲面をクリップする」処理そのものです。各面について、曲面の制御点の符号付き距離を係数とするベジエ関数を作り、全係数が同符号なら分離を確定、そうでなければ UV 範囲を収縮して反復します。時間を陽に扱うことなく、タイムステップ全体にわたる衝突の有無が判定できます。

速度がどれほど速くても、接触時間がどれほど短くても、この判定が正しければ見落としは起こりません。

接触時刻を求める — 時間方向の再帰

「衝突したか」だけでなく「いつ衝突したか」が必要です。ここで注意すべき点があります。

時刻の特定段階に離散サンプリングを持ち込むと、保証が失われる
当初の実装では、f = 1/4, 2/4, 3/4, 1 の静止三角形で当たり判定を行い、どれも当たらなければ広域判定の誤検出として棄却していました。しかしこれは第1節で述べた離散サンプリングそのもので、接触している時間帯がタイムステップの 1/4 より短いと4点すべてが外れ、本物の衝突が捨てられます。スイープ判定で保証した「見落としなし」が、時刻を求める段階で失われていました。

正しくは、静止判定ではなくスイープ判定で時間区間を二分します。区間 [a,b] のスイープ体が曲面と交差しないなら、その時間帯に接触が無いことは保証されています。したがって次のように進めます。

t = 0 t = 1 判定: 接触あり前半: 接触なし → 棄却後半: 接触あり接触なし → 棄却接触あり接触あり 各段でスイープ体を作って判定する。「接触なし」は凸包性による保証なので、その区間は二度と調べなくてよい
時間区間の再帰。前半が交差すれば最初の接触は前半にあり、後半は調べる必要がない。前半が交差しなければ、その時間帯に接触が無いことが確定する。

常に「最初の接触を含むことが保証された区間」を保ちながら幅を半分ずつ縮められるため、接触時間がどれほど短くても取りこぼしません。新しい数式は一切必要なく、既存のスイープ判定を再帰的に呼ぶだけです。

実装で必要になった2つの手当て

過検出の除去 クリッピングは反復回数や誤差閾値が緩いと「交差あり」側に倒れます。見落としはしませんが過検出はするため、これをそのまま接触として採用すると、実際には当たっていない位置で停止してしまいます。そこで、区間が十分細くなった葉では反復回数を上げて再確認し、過検出と分かればその枝を捨てて後半の区間を調べ直します(バックトラック)。全区間が過検出と判明すれば接触なしとして落下を継続します。

このとき誤差閾値 tol は変えてはいけません。tol は接触の定義そのものなので、小さくすると、かすめる接触を取り逃がして貫通が深くなります。増やすのは反復回数だけにします。

薄いスイープ体の退化 区間が狭まると三角柱が薄くなり、側面を作る3点がほぼ一直線に並んで法線が数値的に定まらなくなります。厚みが誤差閾値を下回った時点で、厚み0の極限である静止三角形の判定へ切り替えることで回避します。

実行例と検証

曲面を細かく標本化した独立の真値と比較しました(速度1.0、tol = 0.02、反復2、1/60秒ステップ)。

進行方向真値(移動距離)旧方式(点サンプリング)本方式
垂直 −Y3.15303.1001(−0.0529)3.1583(+0.0053)
+X 斜め3.49253.4697(−0.0228)3.5000(+0.0075)
−X 斜め3.24053.2334(−0.0071)3.2500(+0.0095)
+Z 斜め3.45603.4057(−0.0503)3.4583(+0.0023)
−Z 斜め3.25803.1465(−0.1115)3.2667(+0.0087)

誤差は 0.02〜0.11 から 0.002〜0.011 へと1桁改善し、すべて許容誤差 tol = 0.02 の範囲内に収まりました。符号にも意味があります。旧方式は誤差が、すなわち接触より手前で止まっていました。過検出をそのまま接触として採用していたためです。本方式は誤差がで、保証区間の上端を採るため確実に接触した側で止まります。物理的にはめり込み方向に倒れないほうが自然です。

1ステップの移動量を増やしていくと差は決定的になります。

1ステップの移動量旧方式本方式旧の計算時間本方式の計算時間
0.017−0.053+0.0050.68 ms1.12 ms
0.333−0.078+0.0030.41 ms2.09 ms
1.000−0.075+0.0110.43 ms1.87 ms
3.333見落とし(すり抜け)+0.18799.7 ms4.5 ms

素直に当たる方向では、スイープ体は平面が4枚あるぶん静止三角形より重く、1〜2 ms 程度かかります。一方、斜め方向では旧方式が過検出のたびに4点走査を無駄打ちして判定回数が383回に膨らんだのに対し、本方式は凸包による棄却が効いて4〜5回で決着し、19.1 ms から 6.3 ms へ短縮しました。極端な高速移動では、旧方式が 99.7 ms を費やしたうえで見落としたのに対し、本方式は 4.5 ms で検出しています。

▶ 実演プログラム 三角形の落下方向・速度・反復回数・誤差閾値を変えながら、スイープ体の可視化、接触時刻の保証区間、UV 範囲を確認できます。
sweep_collision2.html を開く

5.2つの方法の使い分け

スイープ凸多面体3変数 F(u,v,t)
対象並進する多角形・凸多面体球、任意の軌跡・変形・回転
追加の変数不要時刻 t
判定に使う量平面との符号付き距離(線形)ベジエ係数(6×6×2 次など)
スイープ体の扱い厳密に凸(近似なし)
接触時刻時間方向の再帰が必要求解に内蔵
多項式求解不要必要(ただしクリッピングで代替)
計算コスト軽い重い

多角形かつ並進という条件下では、スイープ体方式のほうが明確に優れています。既存の凸多面体クリップをそのまま使え、平面は4枚で済み、多項式求解が不要だからです。曲がった軌跡・回転・変形が必要になった時点で3変数方式へ移る、という整理が自然です。

なお回転が加わると、スイープ体は凸でなくなります。各頂点が弧を描き、弧は弦の外側に膨らむため、2つの姿勢の凸包はスイープ体の一部を取りこぼします。対処は、タイムステップ内の弧の膨らみ(サジッタ)を上から抑えて各平面を外側にオフセットするか、四元数を使って3変数の定式化に移るかのいずれかです。四元数を用いれば回転行列の成分は四元数成分の2次式になるため、有理ベジエ関数として同じ枠組みで扱えます。

6.従来法との比較

(a) 離散時刻での重なり判定

最も広く使われている方式です。実装が容易で高速ですが、第1節で示したとおりすり抜けを原理的に排除できません。刻みを細かくしても、物体が速くなれば同じ状況が再現します。

(b) 保守的前進(conservative advancement)

現在の距離と最大速度から「この時間だけは絶対に衝突しない」安全な時間幅を求めて前進する方式です。見落としは生じませんが、距離計算を繰り返すため接触直前で歩幅が極端に小さくなり、収束が遅くなります。また曲面に対する距離計算そのものが容易ではありません。

(c) 三角形どうしの CCD(3次方程式)

4点が同一平面上に来る条件から、時刻の3次方程式を解く古典的な方法です。この3次式を浮動小数点で解くと、ほぼ平行・ほぼ縮退した配置や接触に近い場合に符号判定を誤り、衝突を見落とすことがあると長く指摘されてきました。布や髪のシミュレーションでは一度の見落としが自己交差を招き、破綻が伝播します。

これに対し、本稿のスイープ体方式は多項式求解を一切使いません。平面との距離という線形量と凸包の符号判定だけで済むため、数値的な壊れ方が根本的に少ない構造です。

(d) 包含に基づく手法(inclusion-based)

近年 CCD の分野で主流になりつつある方式で、時間区間と空間領域の箱に対して関数値の上下限を保証つきで求め、解が無いと確定できた箱を捨てて残りを細分します。これはベジエクリッピング法の凸包による棄却とまったく同じ発想です。CCD の分野はロバスト性を追求した結果、独立に同じ原理へ到達しています。

ただし既存の包含法は区間を二分して細分するのに対し、ベジエクリッピングは制御係数から作る上下限の包絡線によって解が存在し得る範囲まで一気に収縮させます。同じ保証を保ちながら探索量が減ります。実測では、凸包クリップを無効にして単純4分割のみとした場合、輪郭線抽出における判定ノード数が 753 から 4328 へと約5.7倍に増加しました。

(e) ポリゴン近似を前提とすること

既存の CCD 研究は、ほぼすべて点・線分・三角形を対象としており、曲面はポリゴンに分割してから扱うのが前提です。分割を細かくすればポリゴン数が爆発し、粗くすれば実際の曲面より内側で判定することになって、めり込みや浮き、分割由来の偽の稜線による引っかかりが生じます。本稿の方法は曲面のまま扱うため、この問題が原理的に生じません。

手法すり抜け曲面の扱い特徴
離散時刻の重なり判定生じ得る分割が必要最も簡便・高速。速度が上がると破綻
保守的前進なし距離計算が困難接触直前で歩幅が縮み収束が遅い
3次方程式による CCD生じ得る分割が必要退化配置で符号判定を誤る
包含に基づく手法なし分割が必要二分細分のため収縮が遅い
本手法なし曲面のまま凸包性で確実に棄却。多項式求解が不要(多面体の場合)

7.新規性

第1に、衝突判定を「曲面上の条件をベジエ関数の零点問題として解く」という枠組みの一事例として位置づけた点です。断面抽出、輪郭線抽出、球や二次曲面との交線と同じ解法がそのまま適用でき、条件式と次数だけが異なります。

第2に、凸包性による棄却が変数の個数に依存しないことを利用し、2変数の交線抽出と同一の実装で3変数の連続衝突検出が得られることを示した点です。テンソル積バーンスタイン基底は3変数でも非負かつ総和が1であるため、判定は完全に同じ形になります。

第3に、並進するスイープ体が厳密に凸多面体であることを利用し、時刻を変数として導入せずにタイムステップ全体の衝突有無を判定できることを示した点です。多項式求解を回避しているため、既存の三角形 CCD が抱える数値的頑健性の問題が構造的に生じません。

第4に、曲面をポリゴン分割せずに扱える点です。既存の CCD 研究の空白領域であり、CAD データ(NURBS)をそのまま VR や物理シミュレーションで扱う場面に直結します。

包含に基づく手法が近年 CCD 分野の主流になりつつあることを踏まえると、ベジエクリッピング法は1990年の時点で同じ原理を採用していたことになります。「古い手法」ではなく、現在の最良の方針を先取りしていたと位置づけられます。

8.注意点と今後の課題

接触は重根になる

ちょうど接する瞬間、条件関数は符号を変えずに0に接します。したがって「符号の変化」を頼りにする検出では接触を取り逃がします。「F の最小値が0以下になる最小の t」として扱う必要があります。

保証の範囲

棄却が保証つきであることと、最終的に得られる時刻の精度は別問題です。捨てた箱に衝突が無いことは数学的に保証されるため見落としは生じませんが、残った箱の中で時刻を追い込む段階には近似が含まれます。また係数計算は通常の浮動小数点で行っているため、数学的には保証つきでも数値的には証明されていません。係数計算に上下丸めを入れて区間として扱えば、この点も解決できます。

性能

現状は1接触あたり数〜百数十ミリ秒です。ゲームの衝突判定予算は1フレーム全体で数ミリ秒なので開きがあります。ただしこれは最適化の問題で、包含球の階層によるブロードフェーズ(各箱の判定は完全に独立なので SIMD・GPU 並列化に向く)で詰められる性質のものです。

今後の拡張

9.応用分野