たべもののつくりかた.

目次/第08章

08Havok

盛り付けは、手で置かない

physics — 落として積むという設計

この章の3行まとめ
  • 皿の上の位置を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);
ウィンナー.js とクッキー.js に共通の設定。単位を cm にすると重力の値まで変わる

実験 — 落として積む(唐揚げの山)

—

断面(横から見た2D)での実験です。摩擦を 0 にすると全部が皿の縁まで流れて平らになり、 1 に近づけると落ちた場所でそのまま止まって、不自然に高い塔ができます。

当たり判定は、見た目のとおりでなくてよい

物理エンジンは、見た目の形をそのまま使うと重すぎます。 そこで、当たり判定だけ簡単な形に置き換えます。クッキーやチョコは凸包 (でっぱりだけを包んだ袋のような形)で十分です。

ところがウィンナーは凸包では駄目でした。弓なりに曲がった胴を凸包で包むと、 内側の窪みが埋まってバナナの内側が板になります。 その状態で隣と重ねると、見た目では触れていないのに不自然に浮く。 ウィンナー.js はカプセルを何個か並べたものを当たり判定にしています。

あえて物理を使わない

たこ焼きは、ほぼ球です。物理で落とすと転がります。転がると、 せっかく上面に掛けたソースが横や下を向きます。これは料理として成立しません。 だから、たこ焼き.js は物理を使いません。代わりに、

  • 重なっている2個を、離れる方向に少しずつ押す(何度もくり返す)
  • 舟皿の底の高さの場に着地させる
  • 傾きは 15°までに制限する

という決定論的な緩和で配置しています。他の料理と違って、 この食べ物は「上下」が意味を持つからです。 同じ考え方は、月見団子(15個を規則正しく積む)や、 お寿司(3貫を板に並べる)でも使われています。

つまずきポイント

物理の結果は毎回変わります。 02章で「同じ種なら同じ結果」を守ってきたのに、 物理を挟んだ瞬間に再現性が消えます(計算の順番が実行ごとに揺れるため)。 だから物理を使うサンプルは、落とす順番・初期位置・初速をすべて種から決めて、 揺れる余地を最小にしています。それでも完全には一致しません。

やってみよう
  1. 摩擦を 0 にして落とし、山ではなく1層になることを確かめる。
  2. 跳ね返りを 0.8 にすると何が起きるか予想してから試す。
  3. 個数を 40 にして、いちばん上の1個がどこで止まるか3回見比べる。
  4. たこ焼き.js で「緩和」または「重なり」を検索し、物理を使わない理由を読む。