ひとことで
3 次元の格子の各点に数値(密度や距離)を持たせ、数値がしきい値をまたぐ所に三角形を張って、表面のメッシュを取り出す方法です。格子の立方体 1 つごとに、8 つの角が内側か外側かで 2⁸ = 256 通りのケースに分け、あらかじめ用意した表から「どの辺に頂点を置き、どう三角形をつなぐか」を引きます。値の場さえ作れれば、どんな形でも三角形に変換できます。
ゲームでの使いどころ
- 掘れる・盛れる地形:地形を「高さ」ではなく「3 次元の密度」で持てば、洞窟・トンネル・張り出しも表せる。掘った場所の周りの格子だけを作り直せばよい(ボクセル地形)。
- メタボール・液体:溶け合う球や、粒子の流体の表面を、粒子から作った密度場から毎フレーム取り出す。
- 距離場からのメッシュ化:符号付き距離場で作った形を、物理の当たり判定や通常のレンダリング用のメッシュに変換する。
- 医療・スキャン:CT などの 3 次元画像から臓器の表面を作るのが元々の用途(1987 年、Lorensen と Cline)。
しくみ
格子点の値を 、しきい値を とします。
- ケース番号:立方体の 8 つの角について、(内側)なら 1、そうでなければ 0 とし、8 ビットの数(0〜255)にします。0 と 255 は表面が通らないので何もしません。
- 頂点の位置:内側と外側の角を結ぶ辺の上に頂点を置きます。両端の値 から、ちょうど になる位置を線形補間で求めます。
- 三角形:ケース番号で表(triTable)を引き、辺の番号の 3 つ組を三角形にします。
- 法線:値の場の勾配 が表面に垂直なので、格子点で中心差分を取り、頂点の位置で補間して法線にします。三角形の向きから計算するより、なめらかに見えます。
実装のポイント
- 表は写してくる:256 通りの表は手で作るものではありません。Paul Bourke の表(Three.js の
MarchingCubes.jsにも入っている)をそのまま使います。角と辺の番号の付け方が表と一致しているかだけ注意します。 - 頂点の共有:隣り合う立方体は同じ辺を共有するので、辺ごとに作った頂点を覚えておけば、頂点の数を約 1/6 に減らせ、つなぎ目もきれいに閉じます。
- チャンクに分ける:地形を 32³ 程度の塊(チャンク)に分け、変更のあった塊だけを作り直します。GPU のコンピュートシェーダーで作ることも多いです。
- 外周を閉じる:格子の外側を「外」の値にしておくと、切り口にも面ができて、閉じた塊になります。
つまずきやすい点
- 穴があく(あいまいなケース):元の表には、隣の立方体とのつながり方があいまいなケースがあり、まれに小さな穴があきます。気になる場合は、あいまいさを解決した改良版(Marching Cubes 33 など)や、Dual Contouring のような別の方法を使います。
- とがった角が丸まる:頂点は辺の上にしか置けないので、立方体の角のような鋭い形は面取りされたようになります。
- 細長い三角形:表面が格子の角のすぐ近くを通ると、とても小さい三角形や細長い三角形ができます。気になる場合は平滑化や簡略化で整えます。
デモで試すこと
- 「掘れる地形」で地形をクリックすると、その場所が球の形に削れ、トンネルや穴が作れます。高さマップの地形ではできない横穴ができることを確かめてください。
- 「格子の細かさ」を小さくすると表面がかくかくになり、大きくすると三角形の数と作る時間が増えます。
- 「辺の上で位置を補間する」を切ると、頂点が辺の中点に固定され、表面が階段状になります。補間の大切さがわかります。
- 「1 つのセルを見る」では、黄色の角(内側)と灰色の角(外側)を結ぶ辺の上に赤い頂点が置かれ、三角形が張られる様子を 1 つずつ確かめられます。