表面の上の座標系
一言でいうと
UVは、テクスチャ画像の上の座標で、頂点ごとに付けておけば、ラスタライザーがピクセルごとに補間してくれます。その座標から色を取り出す方式がサンプリングで、拡大するときと縮小するときで、必要な方法が異なります。
なぜ必要なのか
頂点ごとに色を付けると、三角形1つに、色が3つだけです。レンガの模様や文字を表現するには、頂点を模様の分だけ細かく分割する必要がありますが、それは、手に負えません。
テクスチャは、その問題を逆転させます。色を形状から切り離して、別の画像に置き、表面の各地点が、その画像のどこを指すかだけを決めておきます。その「どこ」が、UV座標です。そうすれば、三角形2つの四角形に、いくらでも複雑な絵を貼れます。
どう動くのか
UVは、普通0から1の間に決めて、(0,0)が画像の1つの角、(1,1)が対角線の反対側の角です。どの角が(0,0)かは、APIごとに違います。OpenGLは左下、Direct3Dは左上です。テクスチャが反転して出るバグの半分は、ここから来ます。
範囲を外れたUVをどう扱うかが、ラップモードです。繰り返し(repeat)は、小数部だけを取って、模様を繰り返し、クランプ(clamp)は、端の値を引き伸ばし、ミラー(mirror)は、1回ずつ反転させて貼ります。タイル模様には繰り返しが、絵1枚をそのまま貼るときには、クランプが合っています。
色を取り出す方法は、2つが基本です。このコードブロックの韓国語は、最近傍がテクセル1つを取り、双線形が隣り合うテクセル4つを縦横の比率で混ぜるという意味で、幅と高さはプレースホルダーです。
최근접(nearest) i = floor(u * 폭), j = floor(v * 높이) 자리의 텍셀 하나
쌍선형(bilinear) 이웃한 텍셀 네 개를 가로세로 비율로 섞는다
双線形で重要なのは、テクセルの中心が、(i+0.5)/幅にあるという点です。この半マスを抜かすと、絵が半テクセルだけずれます。そのため、座標をu * 폭 - 0.5に移してから(プレースホルダーは、幅です)、整数部と小数部に分けます。
透視補正補間は、テクスチャでとくに重要です。画面座標で求めた重心座標で、UVをそのまま混ぜると、遠近が入った面で、模様がゆがみます。画面で均等に分けた間隔が、3次元空間では均等ではないからです。正しい方法は、u/w、v/w、1/wを補間してから、前の2つを、後ろの1つで割ることです。
iw = Σ bary_k * (1 / w_k)
u = Σ bary_k * (u_k / w_k) / iw
初期のコンソールゲームで、床の模様が波打っていたのは、この補正をしていなかったからです。今は、ハードウェアが自動で行ってくれますが、なぜ必要なのかは、知っておく価値があります。
縮小は、また別の問題です。1つのピクセルが、テクセル数十個を覆うと、そのうちの1つだけを選んでも、元の模様を代表できません。カメラが少し動いただけでも、選ぶテクセルが変わって、画面がちらつきます。解決法が、ミップマップです。テクスチャを、先に半分ずつ縮めて、連なりとして作っておき、ピクセルが覆うテクセルの数に合う段階を選んで使います。メモリを3分の1余計に使う代わりに、ちらつきが消え、小さく描くときは、むしろキャッシュのヒット率が上がって、速くなります。
異方性フィルタリングは、ミップマップの限界を補います。ミップマップは、1つのピクセルが、縦横に同じようにテクセルを覆うと仮定しますが、床のように、斜めに見える面では、一方向にだけ長く覆います。そのとき、ミップの段階を長いほうに合わせると、短いほうが、必要以上にぼやけます。そのため、ゲームのグラフィックス設定にある異方性フィルタリングは、長いほうの方向に、サンプルを複数取って、そのぼやけを戻すものです。遠くへ伸びる道路がくっきりするのが、このオプションの効果です。
テクスチャが、メモリにどう置かれるかも、性能に影響します。画面の隣のピクセルは、たいてい、テクスチャの隣のテクセルを読みますが、行優先でそのまま置くと、縦に隣り合うテクセルが、メモリで遠く離れます。そのため、GPUは、テクスチャを、小さな四角形のブロック単位に並べ替えて保存します。これをスウィズル、またはタイルドレイアウトと呼び、テクスチャのアップロードが、単純なコピーより遅い理由の1つです。
現場での姿
タイル模様の境界に、細い線が見える問題が、よくあります。繰り返しモードで、双線形のサンプリングが、画像の右端と左端を混ぜるからですが、これは、実は、繰り返しモードが意図したとおりに動作したのです。その代わり、クランプモードを使うと、反対側の端を混ぜません。
もう1つは、アトラスのにじみです。複数の絵を1枚にまとめておき、UVで切り出して使う方式ですが、ミップマップの低い段階では、隣の絵の色が混ざり込んできます。絵の間に余白を置くか、ミップの段階を制限する必要があります。
最後に、UVを誰が決めるのかを、押さえておきます。頂点のUVは、モデリングの段階で、人やツールが決めます。3次元の表面を、2次元の平面に広げる作業なので、切る線をどこに置くかと、ゆがみをどこに寄せるかを、決める必要があります。この作業を、UV展開と呼び、失敗すると、模様が伸びたり、継ぎ目が目立ったりします。シェーダー側では、すでに決まったUVを受け取って使うだけですが、模様がおかしいとき、原因がシェーダーではなく、モデルにある可能性があることは、知っておくほうが良いです。
次のラボですること
チェッカー模様のテクスチャを作り、最近傍と双線形のサンプリングを、それぞれ実装します。次に、遠近が入った四角形に模様を貼って、補正していないものと、補正したものを並べて見て、差分の画像を取り出します。最後に、細かく揺れる模様で、ミップマップの1段階を作って、ちらつきが消えることを、数字で確認します。