たべもののつくりかた.

目次/第16章

16Contact

触れ合うと、潰れる

contact deformation — やわらかい物の積み方

この章の3行まとめ
  • 団子を真球のまま積むと、発泡スチロールの球に見えます。
  • 自重と押し合いで、接するところが平らになる。下の段ほど潰れます。
  • 潰した体積の行き先と、接触の縁にできる丸い土手が、やわらかさの正体です。

月見団子は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);
月見団子.js。smin(多項式スムーズ最小値)が「丸い土手」を作る

実験 — 潰す / 体積を戻す / 土手をつける

—

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;
};
この1行が、硬い球とやわらかい餅を分ける

串は、団子の中心を通っていない

花見団子は同じ問題を、別の向きで扱っています。 串の方向に押しつぶされ、隣と接する両端が平らになる。 直径 3.0cm に対して串方向は約 2.4cm、接触面の直径は約 1.2cm。 さらに、

  • 串の入口は生地が引き込まれてすり鉢状にへこむ(平らだと刺さって見えない)
  • 団子は串の中心に乗っていない。わずかに偏心している
  • 隣どうしは「めり込む」のではなく、平らな面が触れて細い影の線ができる

どれも数ミリの話です。ところが、この数ミリを入れるかどうかで、 「色つきの球に棒」か「団子」かが決まります。

つまずきポイント

潰す方向を1つに決めないでください。 下の段の団子は、下から(台)・横から(隣)・上から(上の段)の3方向に押されています。 「上下だけ潰す」と、上から見たときに真円のままなので嘘が見えます。 月見団子.js は接触を全部集めてから、方向ごとに半径を決めています。

体積を戻しすぎると、風船になります。 係数 0.33 は「戻しすぎない」ための値です。実際の餅は多少水分が逃げるので、 きっちり保存するより少なめのほうが自然に見えます。

やってみよう
  1. 3つのスイッチを全部切って、球の山に戻してみる。
  2. 「減った体積を戻す」だけを入れて、シルエットがどう変わるか見る。
  3. 潰し量を 0.6 にすると、どこから餅でなくなるか探す。
  4. 月見団子.js で smin を検索し、k の値がいくつになっているか調べる。