目次/第08章
盛り付けは、手で置かない
physics engine — 物理エンジンで自然に積む
- ざるに野菜を盛るとき、座標を手で決めると「並べました」という嘘くさい絵になります。
- そこで物理エンジンに落としてもらう。重力と摩擦と反発だけ与えて、あとは任せます。
- ただし全部いっぺんに出すと山にならないので、0.26秒おきに1本ずつ落とします。
ざるに野菜を8本盛る。座標を手で決めると、どうしても「並べました」という絵になります。 重なり方に嘘があるからです。そこで物理エンジンに落としてもらう。 重力と摩擦と反発だけ与えて、あとは転がるに任せます。Babylon.js では Havok を使います。
ただし、全部いっぺんに出すとうまくいきません。生成した瞬間、 野菜どうしが互いにめり込んだ状態から始まるからです。 物理エンジンはそのめり込みを押しのけようとしますが、 全員が同時に押し合うので行き場がなく、結果は中央に押し固められた不自然な塊になります (めり込んだまま噛み合って止まる個体も出ます)。 物によっては器の外まで弾き出されます。 だからサンプルは0.26秒おきに1本ずつ、山の頂点のすぐ上から落としています。 1本ぶんのめり込みなら、次が来るまでに必ず解けるからです。
この実験だけは、本物の Havok が動きます
ほかの章の実験は、しくみが分かるように自前で書いた簡易版です。 でもこの章の主役は物理エンジンそのものなので、下のデモは Babylon.js と Havok を本当に読み込んで動かしています。 使っている API も数値も、サンプルからそのまま持ってきたものです。 そのぶんダウンロードが大きい(合計10MBほど)ので、ボタンを押すまで読み込みません。
const havok = await HavokPhysics(); // WASM の読み込みを待つ // 第1引数 false = 固定タイムステップ。true だとフレーム落ちのたびに // ステップ幅が変わり、接触が解けたり深く食い込んだりを繰り返す const hk = new BABYLON.HavokPlugin(false, havok); scene.enablePhysics(new V3(0, -620, 0), hk); // 重力は cm/s^2 hk.setTimeStep(1 / 120);
実験 — 本物の Havok で盛り付ける
落とした数:0 / 8 個
摩擦と反発は、次に落とす1個からではなくすでに転がっている野菜にもその場で効きます。
ドラッグで視点を回せます。ホイールで寄り引き。
器のような「へこんだ形」は、箱や球では代用できない
落ちてくる野菜のほうは、多少ざっくりでも構いません。実際サンプルも 凸包(とつほう)——輪ゴムをかけたときの外形——で当たり判定を作っています。 でもざるはそうはいきません。中がへこんでいるので、箱や球で近似すると 野菜が中に入れず、フタの上に乗ってしまいます。
そこでざるだけは三角形メッシュそのものを当たり判定にします
(PhysicsShapeMesh)。計算は重いのですが、ざるは動かないので許されます。
動くものは凸包、動かないものはメッシュ。これは物理エンジン全般の定石です。
物理エンジンはメートル単位で作られています。
このプロジェクトはcm単位なので、そのまま実際の重力 981 を入れると、
1ステップあたりのめり込みが許容量を超えて押し戻され続け、野菜がプルプル震えます。
デモの重力スライダーを最大まで上げると、実際に震えはじめます。
サンプルでは重力を 620 まで落として回避しています。
「正しい物理」より「破綻しない物理」を採る、という判断です。
- 「1個ずつ落とす」で盛りつけたあと、「全部いっぺんに出す」を押して、山ではなく塊になることを見比べる。
- 反発を0.5まで上げてから「やり直す」。実物の野菜は跳ねません。
- 摩擦を0にすると、どんな盛り方になるか観察する。
- 重力を981まで上げて、野菜が細かく震えはじめるところを探す。
- 視点をドラッグして真横から見る。手で並べたのでは作れない重なり方になっているはず。