目次/第09章
部品を作って、たくさん並べる
instancing / scattering — 実体としてのトッピング
- 青のり・かつお節・砂糖粒・ごま。絵に描くと消えます。実体として置く必要があります。
- 同じ部品を何百個も置くときはインスタンスを使い、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);
実験 — トッピングを撒いて、重なりをほぐす
「格子に並べる」は、重なりがゼロなのに一目で嘘と分かります。 乱数で撒いてから少しだけほぐす、が実物に近い落としどころです。
重なりをほぐす
乱数で撒くと、必ず何枚かが同じ場所に重なります。重なった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 も必ず併せて変える」を規約にしました。
同じ部品を何百個も並べる章なので、いちばん踏みやすい落とし穴です。
- 枚数を 260 にして、ほぐす回数 0 と 10 を見比べる。
- 「格子に並べる」に切り替え、なぜ嘘に見えるのか1行で書く。
- ほぐす回数を 30 にして、格子とどれくらい似てくるか観察する。
- たこ焼き.js で「青のり」を検索し、何枚撒いているか調べる。