目次/第06章
模様も、その場で描く
procedural texture — UV とテクスチャ生成
- 立体の表面と画像を対応づける座標を UV といいます。u が横、v が縦。
- このプロジェクトは画像を1枚も読み込まず、1ピクセルずつ計算して描いています。
- 描くのは色(アルベド)だけではありません。光り方と凹凸も別の画像として描きます。
立体ができたら、表面に模様を貼ります。そのために、
立体の表面のどの点が画像のどの点に対応するかを決めておきます。これが UV です。
回転体なら簡単で、u は一周した角度、v は下から上への位置にすればよい。
05章で uvs.push(j / M, t) と書いていたのがそれです。
次に画像を用意します。ふつうは写真を読み込みますが、このプロジェクトは
RawTexture という「生の数値の配列」を作って、
1ピクセルずつ色を計算して詰めます。トーストの焼き色なら、
その位置のノイズを見て、焼けていれば茶色、焼けていなければ白、というふうに。
// 5. TextureLab : 焼き色を1ピクセルずつ描く(トースト.js の考え方) const data = new Uint8Array(S * S * 4); for (let y = 0; y < S; y++) for (let x = 0; x < S; x++) { const u = x / S, v = y / S; const n = fbm(u * 6, v * 6, 21, 5); // 焼きムラ const heat = clamp(bake * 1.4 + (n - 0.5) * 0.6, 0, 1); const c = heat < 0.5 ? mix3(CRUMB, CBR1, heat * 2) : mix3(CBR1, CBR3, heat * 2 - 1); const i = (y * S + x) * 4; data[i] = c[0] * 255; data[i+1] = c[1] * 255; data[i+2] = c[2] * 255; data[i+3] = 255; }
1枚では足りない。3枚要る
色の画像(アルベド)だけを貼っても、まだ紙に印刷したように見えます。 同じトーストでも、白いところはざらついて光を散らし、焦げたところは少し光る。 その差を伝えるのが2枚目の ORM です。 R に陰り(AO)、G に粗さ(Roughness)、B に金属度(Metallic)を詰めた1枚の画像で、 3つの情報を3つの色チャンネルに同居させています。
3枚目が法線マップ。細かい凹凸を、頂点を増やさずに表現します。 本当は平らなのに、法線だけを傾けて「でこぼこしている」と光に嘘をつく。 トーストの気泡の縁も、クッキーの型押しも、これでやっています。
実験 — 3枚の画像を描き分ける
左が焼いている画像そのもの、右がそれを貼った結果。 「粗さ」の画像は、白いほどざらざら(光らない)という意味です。
継ぎ目をなくす
筒に模様を巻くと、一周して戻ったところで模様がぶつかります。 03章で出てきた「u 方向に折り返すノイズ」はこのためのものです。 さらに、05章で分割の列を M+1 本にしていたのも同じ理由で、 u=0 の頂点と u=1 の頂点を別々に持たせないと、継ぎ目の面で模様が逆走します。
法線マップの上下の符号は、環境によって逆です。
高さの画像から法線を作るとき、縦方向の差を (hd - hu) と書くか
(hu - hd) と書くかで、凸が凹に化けます。
Babylon.js は V が下向きなので前者。14本のうち5本のコメントに、
この符号を間違えて直した記録が残っています。
1mm の粒は、テクスチャでは描けません。 たこ焼きの青のりを緑の点として描くと、遠くから見たときミップマップで溶けて 「緑がかった靄」になります。たこ焼き.js が青のりを板ポリゴンの実体として置いているのは、 それが理由です(→ 09章)。
- 焼き加減を 0 から 1 まで動かし、3枚の画像がそれぞれどう変わるか見比べる。
- 「粗さ」だけを見て、焦げた部分と白い部分のどちらが明るいか確かめ、その理由を考える。
- 「立体に貼ってみる」を切り、画像だけを見たときに何の模様か分かるか試す。
- トースト.js の TextureLab を開き、1枚のテクスチャに何色が混ぜられているか数える。