テクスチャマッピング — 画像を面に貼る技術

ポリゴン数を増やさずに表面の模様や細部を表現する切り札がテクスチャ。画像のどこを貼るかを指すUV座標、画素とテクセルのずれを埋める補間、縮小時のちらつきを抑えるミップマップ、遠近感を保つパースペクティブ補正 — 「貼るだけ」に見えて奥が深いしくみを、動かして学びます。

1. UV座標 — 頂点に貼られた「画像上の住所」

テクスチャ画像上の位置は、横方向 u・縦方向 v の 0〜1 の割合で表します。3Dモデルの各頂点にこのUV座標を持たせておくと、ラスタライズの際に面の内部のUVが補間で求まり、画素ごとに「画像のどこの色を持ってくるか」が決まります。テクスチャの1画素は、画面の画素(ピクセル)と区別してテクセルと呼びます。

UV空間と3Dの面の対応 — 色つきの点は同じUVを指す
左がテクスチャ(UV空間)、右がそれを貼った3Dの面。面がどう回転しても、色つきの点の対応(=UV座標)は変わりません。なお v 軸の向き(上か下か)はAPIで流儀が異なります(OpenGLは左下原点、DirectXは左上原点)。
POINT — UVは「割合」の座標 UVはピクセル数ではなく 0〜1 の割合。だからテクスチャの解像度を差し替えてもUVはそのまま使える。0〜1 の外側をどう扱うか(繰り返し=リピート、端を引き伸ばす=クランプ等)は「ラップモード」として別途指定する。

2. 拡大 — テクセルの「間」の色をどう作るか

物体に近づくと、1つのテクセルが画面上の多数の画素を覆います(拡大)。画素のUVが指す着地点は、たいていテクセル中心から半端な位置。そこで色の作り方が2通りあります。

8×8 テクスチャの拡大 — 最近傍 vs 双線形
拡大率を上げるほど差がはっきりします。グラデーションは双線形の圧勝ですが、ドット絵はあえて最近傍で描くのが正解(カクカクしたエッジが持ち味)。拡大は失われた情報を作れないので、双線形でも「ぼける」ことは避けられません。
c = (1−s)(1−t)·c00 + s(1−t)·c10 + (1−s)t·c01 + st·c11 双線形補間。s, t は着地点の小数部分(0〜1)、c00〜c11 は周囲4テクセルの色

3. 縮小 — エイリアシングとミップマップ

遠くの面では逆に、1画素が何十・何百ものテクセルを覆います(縮小)。1点だけサンプリングすると覆ったテクセルの大半を無視することになり、静止画ではモアレ模様、動くと激しいちらつきが出ます。これはサンプリング不足による折り返し(エイリアシング)で、音声のサンプリングで見たのと同じ原理です。

本来は画素が覆う範囲の平均色を取るべきですが、画素ごとに何百テクセルも足すのは高価。そこであらかじめ 1/2 ずつ縮小した画像のピラミッド=ミップマップを作っておき、縮小率に合った段から読みます。

縮小の破綻とミップマップ — 距離を変えて比較
左は原寸テクスチャを1点サンプルで縮小 — 本来ほぼ無地に見えるはずの距離でモアレ模様が浮きます。右はミップマップの適切な段(λ)から読むので落ち着いた色に。「近い段のみ」にして距離を動かすと段の切り替わりがパッと見えます(ポッピング)— 隣り合う2段を混ぜるトライリニアで解消されます。
注意 — 危険なのは拡大より縮小 縮小時の1点サンプリングは情報の大半を捨てる。一度サンプリングで壊れた模様は後から直せない(音声のエイリアシングと同じ)。だからGPUは縮小側にこそミップマップという事前対策を用意している。
λ = log2(1画素が覆うテクセルの幅) λ = 0 ならレベル0(原寸)、λ = 3 ならレベル3(1/8 サイズ)を使う。小数部分は2段のブレンド(トライリニア)に使う
POINT — 追加メモリはたったの 1/3 ミップマップ全段のメモリは 1/4 + 1/16 + 1/64 + … = 元画像の 1/3 しか増えない。この安さで縮小時の画質と速度(キャッシュ効率)が同時に手に入るため、3Dテクスチャリングでは標準装備になっている。

4. 遠近感と補間 — パースペクティブ補正

透視投影では、奥のものほど画面上で圧縮されます。ところがスクリーン上でUVをそのまま線形補間(アフィン補間)すると、この圧縮が無視され、テクスチャが均等な速さで進んでしまいます。結果、床のチェッカーは奥行き感を失い、三角形の分割線に沿って模様が折れ曲がります。

正しくは、スクリーン上で線形に補間してよいのは u/w と 1/w(w は透視除算前の奥行き)。画素ごとにこの2つを補間し、最後に割り算して u を復元します。これがパースペクティブ補正です。

アフィン補間の歪み — 奥に傾いた床のチェッカーで比較
同じ台形(奥に傾いた床)に同じチェッカーを貼っています。左のアフィン補間では市松の行の高さが均等になって遠近感が消え、水色の三角形分割線で模様が折れ曲がります。オレンジの帯はテクスチャの v = 0.5 の線 — 補正ありでは正しく奥寄りに置かれます。奥行きの比を 1 にすると(傾きなし)両者は一致します。
u = (u/w の線形補間)÷(1/w の線形補間) スクリーン上で線形に補間してよいのは u/w と 1/w。画素ごとに割り算して u を復元する
注意 — 初代PlayStationのテクスチャの揺れ 初代PlayStationのGPUはこの補正を持たず、アフィン補間で描いていた。そのため床や壁のテクスチャが歪み、視点が動くとぐにゃぐにゃ揺れて見えた。当時の開発者はポリゴンを細かく分割して歪みを目立たなくしていた。現代のGPUはすべての属性を自動でパースペクティブ補正する。

5. まとめ

一歩先へ — 異方性フィルタリング 床を浅い角度で見ると、1画素が覆う範囲は正方形ではなく細長い楕円になる。等方的なミップマップは楕円の長い方に合わせて段を選ぶしかなく、遠くの床が余計にぼける。異方性フィルタリング(AF)は楕円の長軸に沿って複数のサンプルを取り、浅い角度でもくっきり感を保つ。ゲームの設定画面にある「異方性 ×16」はこのサンプル数のことだ。