目次/第05章
三角形の向きと、面の傾き
winding order / normals — 巻き順と法線
- 3Dモデルの正体は、座標の配列と三角形の番号表の2つだけです。
- 三角形には表と裏があり、頂点を並べる向き(巻き順)で決まります。裏返ると消えます。
- 面がどちらを向いているかの矢印を法線といい、明るさはこれだけで決まります。
04章で作った断面を、実際に立体にします。やることは2つだけです。
点を並べることと、どの3点で三角形を張るかを番号で書くこと。
Babylon.js では前者を positions、後者を indices と呼びます。
// 断面を N 段 × M 分割で回して、格子状に点を並べる for (let i = 0; i < N; i++) { const t = i / (N - 1); for (let j = 0; j <= M; j++) { const a = j / M * TAU; const r = radius(t, a); positions.push(r * Math.cos(a), yAt(t), r * Math.sin(a)); uvs.push(j / M, t); } }
巻き順 — 裏返ると、立体が消える
三角形には表と裏があります。どちらが表かは、3つの頂点を並べた向きで決まります。 外から見て反時計回りなら表。3Dの世界では、裏側の面は描くのを省略します (見えないところを描いても無駄なので)。だから間違えると立体がまるごと消えます。 正確には、内側だけが見えて、風船の内壁を見ているような妙な絵になります。
14本のサンプルは、この間違いを実行時に自分で検出して直します。 作った直後にすべての面の法線を合計し、重心から外へ向いているかを調べる。 向いていなければ番号表を入れ替える。「気をつける」ではなく「測って直す」という方針です。
// 3. Mesh utils : 巻き順の自動判定 // 【対策】1頂点で判定すると、たまたま凹んだ所に当たって全体が裏返る。 // 全頂点ぶんの内積の総和で決める(クッキー.js の修正記録より) let dot = 0; for (let k = 0; k < nv; k++) { dot += nx[k] * (px[k] - cx) + ny[k] * (py[k] - cy) + nz[k] * (pz[k] - cz); } if (dot < 0) flipIndices(indices);
法線 — 明るさは、これだけで決まる
面がどちらを向いているかを表す矢印が法線です。 光の向きとの角度で明るさが決まるので、 形は正しいのに法線が変だと、料理が金属や紙に見えます。
法線には2通りの出し方があります。三角形ごとに1本持つ(フラット)と、 頂点ごとに、その頂点を囲む面の平均を持つ(スムーズ)。 団子はスムーズ、板チョコの角はフラットであってほしい。 料理によって、また同じ料理でも場所によって使い分けます。
実験 — 巻き順と法線を切り替える
「表と裏」では、裏を向いた面が赤くなります。「巻き順を裏返す」を押すと全部赤くなり、
ふつうに描いたときは中身が透けて見えます。
立体はドラッグで回せます(触ると自動回転は止まります。ダブルクリックで戻ります)。
上から覗くと、裏返した面がどこにあるかがよく分かります。
法線を「溶接」する
いくつかの部品をくっつけて1つの料理にすると、つなぎ目に線が入ることがあります。
同じ場所に頂点が2つあり、それぞれが別の法線を持っているからです。
そこで、ごく近い頂点どうしの法線を平均して揃える処理を入れます。これを溶接といいます。
14本すべてに weldNormals という関数が入っているのはそのためです。
分割数を上げれば良くなるわけではありません。 上の実験で分割数を 64 にしても、団子はほとんど変わりません。 逆に細かくしすぎると、法線マップ(06章)で作った細かい凹凸と干渉してモアレます。 クッキー.js には「型押しや格子は 0.3mm しかないので、幾何は低周波だけ、 細かい起伏は法線マップに回す」と書いてあります。
- 「表と裏」に切り替えてから「巻き順を裏返す」を押し、色がどう変わるか見る。
- 分割数を 4 まで下げて、団子が何角形になるか数える。
- 「法線をなめらかにする」を切って、同じ形でも印象がどれだけ変わるか観察する。
- クッキー.js の中で「巻き順」という語を検索し、なぜ実測しているのか読む。