たべもののつくりかた.

目次/第09章

09Parts

部品を作って、たくさん並べる

instancing / scattering — 実体としてのトッピング

この章の3行まとめ
  • 青のり・かつお節・砂糖粒・ごま。絵に描くと消えます。実体として置く必要があります。
  • 同じ部品を何百個も置くときはインスタンスを使い、1個ぶんの形を使い回します。
  • 置いたあとに重なりをほぐす。均等に並べると、ふりかけたようには見えません。

たこ焼きの上に青のりをかけます。テクスチャに緑の点を描けばよさそうですが、 これは失敗します。1mm の粒は、少し離れるとミップマップ(縮小版の画像)で溶けて 緑がかった靄になります。粉を「ふりかけた」ように見せられるのは、実体のかけらだけです。

そこで、板ポリゴン(四角い板を1枚)を青のりの形に切り抜いて、何百枚も撒きます。 同じことを、かつお節(薄く曲がった板)、砂糖粒(小さな多面体)、 ごま、チョコチップ(小さな円錐)でもやっています。

インスタンス — 形は1個ぶんだけ作る

500枚の板を1枚ずつ作ると、頂点の配列も500個ぶん要ります。 そこで、形は1個だけ作り、位置・向き・大きさ・色だけを500個ぶん持つ。 これがインスタンスです。GPU 側は「同じ形を、行列を差し替えながら500回描く」だけになります。

// 1枚だけ作って、あとは行列で配る
const flake = makeFlakeMesh(scene);
flake.thinInstanceSetBuffer("matrix", matrices, 16);
// 個体ごとの色は、頂点色ではなくインスタンスの色として渡す
flake.thinInstanceSetBuffer("color", colors, 4);
ご飯.js は約1400粒の米をこの方法で置いている(→ 15章)

実験 — トッピングを撒いて、重なりをほぐす

—

「格子に並べる」は、重なりがゼロなのに一目で嘘と分かります。 乱数で撒いてから少しだけほぐす、が実物に近い落としどころです。

重なりをほぐす

乱数で撒くと、必ず何枚かが同じ場所に重なります。重なった2枚は、 光の当たり方が同じになるので1枚の濃い染みに見えます。 そこで、近すぎる組を見つけて、離れる方向に少しずつ動かす操作を何回かくり返します。

ここで大事なのはやりすぎないことです。ほぐしきると格子になり、 「ふりかけた」ではなく「並べた」に戻ってしまいます。 上の実験でほぐす回数を 30 まで上げると、それが見えます。

粒を、模様ではなく実体で作る判断

どこまでを実体で作り、どこからをテクスチャで済ませるか。 14本のサンプルは、だいたい次の基準で分けています。

大きさやり方例
数 mm 以上実体のメッシュ。シルエットに出る米粒・チョコチップ・レモン・大根おろし
1〜3mm板ポリゴン(かけら)。輪郭は要るが厚みは要らない青のり・かつお節・大葉
1mm 未満法線マップとアルベド。凹凸だけ嘘をつく衣の粒立ち・砂糖の細粒・す(気泡)の底
つまずきポイント

板ポリゴンは、裏から見ると消えます。 片面しか描かない設定のままだと、撒いたかけらの半分が見えなくなります。 両面描画(backFaceCulling = false)にするか、 裏返っているものを作るときに向きを揃えます。

影を落とす対象に入れると、一気に重くなります。 500枚のかけら全部に影を計算させる必要はありません。 大きいものだけ影を持たせ、小さいかけらは外します。

同じ名前で何個も作ると、あとで自分が困ります。 ウィンナー4本を全部 "wiener" という名前で作っていたことがありました。 画面は正しく出るので気づきません。ところが Playground の Inspector で3本目をクリックすると、2本目が選ばれます。 Babylon.js は new BABYLON.Mesh(name) のときに id にも同じ値を入れるので、名前が同じなら id まで同じになり、 Inspector が id で引き当てるときに取り違えるためです。

厄介なのは、名前だけ直しても直らないことです。 あとから mesh.name を変えても id は元のまま残ります。 14本のサンプルは「name を変えたら id も必ず併せて変える」を規約にしました。 同じ部品を何百個も並べる章なので、いちばん踏みやすい落とし穴です。

やってみよう
  1. 枚数を 260 にして、ほぐす回数 0 と 10 を見比べる。
  2. 「格子に並べる」に切り替え、なぜ嘘に見えるのか1行で書く。
  3. ほぐす回数を 30 にして、格子とどれくらい似てくるか観察する。
  4. たこ焼き.js で「青のり」を検索し、何枚撒いているか調べる。