目次/第16章
触れ合うと、潰れる
contact deformation — やわらかい物の積み方
- 団子を真球のまま積むと、発泡スチロールの球に見えます。
- 自重と押し合いで、接するところが平らになる。下の段ほど潰れます。
- 潰した体積の行き先と、接触の縁にできる丸い土手が、やわらかさの正体です。
月見団子は15個を三方に積みます(9 + 4 + 2)。 球を15個並べて終わり、にはなりません。月見団子.js の冒頭にこうあります。
平らにするだけなら簡単です。接触面の側を切り落とせばよい。 ところが、それだけではやせた球になります。餅は非圧縮なので、 押されて減った体積はどこかへ行かなければいけません。 行き先は、押されていない自由な面です。つまり他の方向がその分ふくらむ。
// 方向ごとの半径を smin で丸める(=縁に土手のある柔らかい接触) let r = R; for (const c of contacts) { const d = dot(dir, c.n); if (d > 0) r = smin(r, c.dist / d, R * 0.090); // なめらかな最小値 } // 切り取った球冠の体積ぶんだけ全体を膨らませる(餅は非圧縮) r *= Math.cbrt(1 + volumeLoss / sphereVolume);
実験 — 潰す / 体積を戻す / 土手をつける
3つのスイッチを全部切ると、ただの球の山になります。 1つずつ入れていくと、どれがどれだけ効いているかが分かります。
なめらかな最小値(smin)
接触面を作るには「球の半径」と「接触面までの距離」の小さいほうを取ればよい。
ただし Math.min をそのまま使うと、境目に鋭い角ができます。
実物の団子には角がありません。わずかに丸い土手ができて、そこに細い影の線が入ります。
// 多項式スムーズ最小値。k のぶんだけ、境目が丸くつながる const smin = (a, b, k) => { const h = Math.max(0, k - Math.abs(a - b)) / k; return Math.min(a, b) - h * h * k * 0.25; };
串は、団子の中心を通っていない
花見団子は同じ問題を、別の向きで扱っています。 串の方向に押しつぶされ、隣と接する両端が平らになる。 直径 3.0cm に対して串方向は約 2.4cm、接触面の直径は約 1.2cm。 さらに、
- 串の入口は生地が引き込まれてすり鉢状にへこむ(平らだと刺さって見えない)
- 団子は串の中心に乗っていない。わずかに偏心している
- 隣どうしは「めり込む」のではなく、平らな面が触れて細い影の線ができる
どれも数ミリの話です。ところが、この数ミリを入れるかどうかで、 「色つきの球に棒」か「団子」かが決まります。
潰す方向を1つに決めないでください。 下の段の団子は、下から(台)・横から(隣)・上から(上の段)の3方向に押されています。 「上下だけ潰す」と、上から見たときに真円のままなので嘘が見えます。 月見団子.js は接触を全部集めてから、方向ごとに半径を決めています。
体積を戻しすぎると、風船になります。 係数 0.33 は「戻しすぎない」ための値です。実際の餅は多少水分が逃げるので、 きっちり保存するより少なめのほうが自然に見えます。
- 3つのスイッチを全部切って、球の山に戻してみる。
- 「減った体積を戻す」だけを入れて、シルエットがどう変わるか見る。
- 潰し量を 0.6 にすると、どこから餅でなくなるか探す。
- 月見団子.js で smin を検索し、k の値がいくつになっているか調べる。