テクスチャマッピングとフィルタリング
拡大でボケ、縮小でチラつくテクスチャの品質問題を、UV座標・ミップマップ・異方性フィルタの原理から理解し、破綻しない設定を選べるようになります。
- 1.テクスチャは UV 座標でサンプリングし、隣接テクセルを重み付け平均するバイリニアで拡大時のブロックノイズを抑える。
- 2.縮小時は1ピクセルに多数のテクセルが落ちてエイリアシングが起きるため、事前縮小したミップマップを LOD で選び、境目はトライリニアで補間する。
- 3.斜め視のミップマップ過剰ボケは、ピクセルの投影が細長い異方性を複数サンプルで積分する異方性フィルタで解消する。
テクスチャマッピングが解く問題
ポリゴンの表面に画像(テクスチャ)を貼り付けて、少ない頂点で豊かな見た目を得るのがテクスチャマッピングです。各頂点にはテクスチャ上の位置を指す UV 座標(テクスチャ座標)が付与され、多くは 0.0〜1.0 に正規化されます。ラスタライザはこの UV を三角形内部でパースペクティブ補正しながら補間し、ピクセルごとのサンプリング位置を決めます。GPU の役割分担は ハードウェア部品 のグラフィックス項も参照してください。
問題は「テクスチャの解像度」と「画面に映る大きさ」がまず一致しない点にあります。近づけばテクセル(テクスチャの1画素)が画面上で引き伸ばされ(マグニフィケーション)、遠ざかれば1つの画面ピクセルに多数のテクセルが詰め込まれます(ミニフィケーション)。この2つはまったく別の破綻の仕方をするため、対策も分けて考える必要があります。
最近傍とバイリニア ── 拡大時の補間
サンプリングの最も素朴な方法は 最近傍(nearest / point) です。UV を最寄りのテクセル中心に丸めて1点だけ読むため高速ですが、拡大するとテクセルが四角いブロックとして見えます(ドット絵をわざと出したい場合を除き好まれません)。
そこで バイリニアフィルタリング を使います。サンプリング点を囲む2×2のテクセルを読み、UV の小数部を重みにして双一次補間します。
バイリニア補間(1ピクセル分):
u, v から周囲4テクセルの座標を求める:
u0 = floor(u - 0.5), u1 = u0 + 1
v0 = floor(v - 0.5), v1 = v0 + 1
fu = frac(u - 0.5), fv = frac(v - 0.5) // 小数部が重み
横方向に2回、縦方向に1回、線形補間:
top = lerp( tex(u0,v0), tex(u1,v0), fu )
bot = lerp( tex(u0,v1), tex(u1,v1), fu )
out = lerp( top, bot, fv )
4テクセルの加重平均になるため、拡大しても輪郭が滑らかにつながります。GPU のテクスチャユニットはこの2×2フェッチと補間を専用ハードウェアで1サイクル級に実行するため、実務上バイリニアは事実上の既定と考えてよいでしょう。
ミニフィケーションとエイリアシング
厄介なのは縮小側です。1つの画面ピクセルがテクスチャ上では広い領域(多数のテクセル)に対応するのに、バイリニアは2×2しか読みません。つまり ピクセルが覆うべき情報のごく一部しかサンプリングしていない ことになります。
これは信号処理でいうアンダーサンプリングそのもので、ナイキスト周波数を超える細かい模様が低い周波数の偽パターンとして現れます。これが エイリアシング です。市松模様の床が遠方でザワザワと蠢いたり、カメラやオブジェクトが動くたびに模様がチラチラと明滅する(テクスチャクローリング)のは典型的な症状です。本来1ピクセルの色は「そのピクセルが覆うテクセル領域の平均」であるべきなのに、点サンプリングでは平均が取れていないことが原因です。
1つの画面ピクセルはテクスチャ上で有限の面積(フットプリント)を占めます。正しい色はその面積内のテクセルを積分平均した値です。実行時に毎フレーム広い領域を積分するのは高コストなので、後述のミップマップで「あらかじめ平均済みの縮小画像」を用意しておき、必要な縮小率に近いものを1〜2枚読むだけで近似します。
ミップマップと LOD 選択
ミップマップ は、元テクスチャを1/2ずつ縮小した画像の階層(ピラミッド)を事前生成したものです。各段(ミップレベル)は下位段を2×2平均などでフィルタして作るため、すでに帯域制限(ローパス)済みです。レベル0が原寸、レベル1が縦横1/2、と続きます。追加メモリは元の約1/3(1/4 + 1/16 + … の等比和)で済みます。
実行時は縮小率に応じて どのレベルを読むか(LOD: Level of Detail) を選びます。指標は「画面上で1ピクセル動いたとき UV がどれだけ動くか」、すなわちテクスチャ座標の画面微分です。
LOD の計算(等方の場合):
ピクセル間のUV変化(テクセル単位)を求める:
dx = ( du/dsx, dv/dsx ) // 画面x方向へ1px進めたときのUV差
dy = ( du/dsy, dv/dsy ) // 画面y方向へ1px進めたときのUV差
ρ = max( length(dx), length(dy) ) // 1pxが覆うテクセル距離
LOD = log2( ρ )
例: ρ = 4(1ピクセルが4テクセルぶん覆う)なら LOD = 2 を選ぶ
GPU はピクセルを2×2の クアッド 単位で処理し、隣接ピクセル間の UV 差分を取ることで du/dsx などの微分を自動で得ます。シェーダ内で分岐によりクアッドが割れると微分が乱れ、LOD が不正確になり得る点は実装上の注意点です。
トライリニアと異方性フィルタリング
LOD は連続値になりますが、ミップレベルは整数段しかありません。単純に近い段へ丸めると、床などで LOD がレベル1からレベル2へ切り替わる境界に くっきりした帯(ミップバンド) が見えてしまいます。
これを消すのが トライリニアフィルタリング です。隣り合う2つのミップレベルそれぞれでバイリニア補間し(合計8テクセル)、LOD の小数部を重みにして2枚の結果をさらに線形補間します。バイリニアが「面内2次元」の補間なのに対し、トライリニアは「レベル方向」も足した3次元の補間になります。段の切り替わりが連続化され、帯が消えます。
| 方式 | 1ピクセルの読み取り | 主な用途と弱点 |
|---|---|---|
| 最近傍 | 1テクセル | 最速。拡大でブロック、縮小でチラつく |
| バイリニア | 2×2 = 4テクセル | 拡大は滑らか。単独ではミップ帯が出る |
| トライリニア | 2レベル×4 = 8テクセル | ミップ帯を除去。斜め視では過剰にボケる |
| 異方性 | 複数点を細長く積分 | 斜め・奥行き方向の鮮鋭度を維持。コスト大 |
トライリニアにも弱点があります。LOD は縦横の微分の 最大値 で決めるため、床を浅い角度で見るような場面では、視線に沿う方向だけテクセルが強く圧縮され、直交方向はさほど圧縮されていない、という 異方的 な状況が生じます。最大値に合わせて粗いミップを選ぶと、圧縮の弱い方向まで巻き添えでボケてしまうのです。
異方性フィルタリング(AF) はこれを解決します。ピクセルのフットプリントは正方形ではなく、投影によって細長い平行四辺形になります。AF はその長軸に沿って複数のサンプル点を並べ、各点でトライリニア相当のサンプリングを行って積分します。設定の「16x」は最大16サンプルまで長軸方向に取れることを意味し、圧縮の強い方向の情報を細かく拾いつつ、直交方向はボケさせません。異方比(長軸÷短軸)が大きいほどサンプル数を増やします。
AF のサンプル数はハードウェアが異方比に応じて動的に決めます。ほぼ正対している面では異方比が1に近く、16x設定でも実サンプルは少なく済むため、遠景を多用しないシーンでは体感コストは意外に小さいことが多いです。一方、地平線まで続く地面など高異方比の面が画面を覆うと帯域を食い切るので、性能計測は「最悪ケースのカメラ角度」で行うのが鉄則です。
ラップモードと境界の扱い
UV が 0〜1 の範囲を外れたとき、どのテクセルを返すかを決めるのが ラップモード(アドレッシングモード) です。
- リピート(wrap): 小数部だけを使い、テクスチャを敷き詰める。タイル状の床や壁に使う。
- クランプ(clamp to edge): 範囲外を端のテクセルに固定。スカイボックスや UI で継ぎ目を出したくないときに使う。
- ミラー(mirror): 1周ごとに反転して敷き詰める。継ぎ目が目立ちにくい。
- ボーダー: 範囲外を指定した縁色で返す。
バイリニアは境界のテクセルと反対側の端のテクセルを混ぜてしまうことがあります。リピートでは反対端が本来つながる色なので問題になりにくい一方、アトラス(複数画像を1枚にまとめたテクスチャ)では隣のタイルの色を拾って縁がにじむ「テクスチャブリード」が起きます。対策はタイル間に余白(ガター)を設け、境界テクセルを外側へ数ピクセル複製しておくことです。ミップレベルが上がるほど混ざる範囲が広がるので、上位ミップほど余白が効きます。
まとめ
- テクスチャは UV 座標でサンプリング し、拡大時は周囲2×2を加重平均する バイリニア でブロックノイズを抑える。
- 縮小時は1ピクセルに多数テクセルが落ちて エイリアシング が起きる。正解は「フットプリント内の平均」で、これを事前計算したのが ミップマップ。
- どのミップを読むかは UV の画面微分から LOD として求め、レベル境界の帯は トライリニア(8テクセル+レベル間補間)で連続化する。
- 斜め視の過剰ボケは、細長いフットプリントを長軸方向に複数サンプルで積分する 異方性フィルタリング で解消する。
- ラップモード は範囲外 UV の扱いを決め、アトラス利用時はガターで テクスチャブリード を防ぐのが実務上の定石。
グラフィックス Article
テクスチャマッピングとフィルタリングを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
グラフィックス
比較で見る軸
難易度: advanced / カテゴリ: グラフィックス / タグ数: 6
導入後に効く点
縮小時は1ピクセルに多数のテクセルが落ちてエイリアシングが起きるため、事前縮小したミップマップを LOD で選び、境目はトライリニアで補間する。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- グラフィックス
- タグ数
- 6
判断チェックリスト
- 自社の用途が「グラフィックス / テクスチャ」に近いか確認する。
- 強みである「テクスチャは UV 座標でサンプリングし、隣接テクセルを重み付け平均するバイリニアで拡大時のブロックノイズを抑える。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。