目次/第08章
盛り付けは、手で置かない
physics — 落として積むという設計
- 皿の上の位置を1個ずつ手で書くと、必ず「並べた」ように見えます。
- そこで上から落として、重力と摩擦に任せます。物理エンジンは Havok。
- ただし14本のうち何本かは、あえて物理を使いません。転がってはいけない料理があるからです。
唐揚げを皿に山盛りにしたい。座標を手で書くと、どうやっても不自然になります。 隙間が均等すぎるか、めり込むか、どちらかです。実物の山は、 落ちたものが下のものに引っかかって、たまたまそこで止まった結果できています。
だから、そのとおりにします。皿を置いて、重力を設定して、上から1個ずつ落とす。 あとは物理エンジンが勝手に積んでくれます。書くのは「何を、どこから、どんな向きで落とすか」だけです。
// 8. Scene / 物理(クッキー.js) const hk = await HavokPhysics(); scene.enablePhysics(new V3(0, -620, 0), new BABYLON.HavokPlugin(true, hk)); // 【対策】単位が cm なので重力は 981 相当。ただし Havok の接触許容量は // 絶対値で決まっているため、実重力だと震える。620 で安定域に入る new BABYLON.PhysicsAggregate(cookie, BABYLON.PhysicsShapeType.CONVEX_HULL, { mass: 6, friction: 0.55, restitution: 0.04 }, scene);
実験 — 落として積む(唐揚げの山)
断面(横から見た2D)での実験です。摩擦を 0 にすると全部が皿の縁まで流れて平らになり、 1 に近づけると落ちた場所でそのまま止まって、不自然に高い塔ができます。
当たり判定は、見た目のとおりでなくてよい
物理エンジンは、見た目の形をそのまま使うと重すぎます。 そこで、当たり判定だけ簡単な形に置き換えます。クッキーやチョコは凸包 (でっぱりだけを包んだ袋のような形)で十分です。
ところがウィンナーは凸包では駄目でした。弓なりに曲がった胴を凸包で包むと、 内側の窪みが埋まってバナナの内側が板になります。 その状態で隣と重ねると、見た目では触れていないのに不自然に浮く。 ウィンナー.js はカプセルを何個か並べたものを当たり判定にしています。
あえて物理を使わない
たこ焼きは、ほぼ球です。物理で落とすと転がります。転がると、 せっかく上面に掛けたソースが横や下を向きます。これは料理として成立しません。 だから、たこ焼き.js は物理を使いません。代わりに、
- 重なっている2個を、離れる方向に少しずつ押す(何度もくり返す)
- 舟皿の底の高さの場に着地させる
- 傾きは 15°までに制限する
という決定論的な緩和で配置しています。他の料理と違って、 この食べ物は「上下」が意味を持つからです。 同じ考え方は、月見団子(15個を規則正しく積む)や、 お寿司(3貫を板に並べる)でも使われています。
物理の結果は毎回変わります。 02章で「同じ種なら同じ結果」を守ってきたのに、 物理を挟んだ瞬間に再現性が消えます(計算の順番が実行ごとに揺れるため)。 だから物理を使うサンプルは、落とす順番・初期位置・初速をすべて種から決めて、 揺れる余地を最小にしています。それでも完全には一致しません。
- 摩擦を 0 にして落とし、山ではなく1層になることを確かめる。
- 跳ね返りを 0.8 にすると何が起きるか予想してから試す。
- 個数を 40 にして、いちばん上の1個がどこで止まるか3回見比べる。
- たこ焼き.js で「緩和」または「重なり」を検索し、物理を使わない理由を読む。