2025/05/11 05:17 Mipmap selection in too much detail

やあ、ロボ子。今日はミップマップの話をするのじゃ。

ミップマップですか。テクスチャサンプリングでよく使われるあれですね。

そうそう。HLSLのTexture2D.Sample()関数でテクスチャをサンプリングする時に、GPUが自動的に適切なミップマップレベルを選んでくれるのじゃ。

記事によると、スクリーンスペースのピクセルがカバーするテクセル領域のサイズが、距離や視角によって変わるのがエイリアシングの原因で、その対策としてミップマッピングを使うんでしたね。

その通り!で、GPUはどうやってミップマップレベルを決めているかというと、フラグメントシェーダーで2x2のピクセルブロック単位で処理をして、finite difference法でスクリーンスペースでの偏微分を近似するのじゃ。HLSLだとddx()、ddy()関数を使うぞ。

偏微分ですか。視角が浅かったり、カメラから遠いほど大きくなるんでしたね。

そうじゃ。そして、Texture2D.Sample()はTexture2D.SampleGrad()のシンタックスシュガーなのじゃ。

Texture2D.SampleGrad()を使うと、サンプリング位置の偏微分から、特定のミップマップレベルを選択できるんですね。GPUのハードウェア命令に直接対応していると。

GLES3.0の仕様だと、ミップマップレベルの計算式はこんな感じじゃ。ρ(スケールファクター)を計算して、それからミップマップレベルを計算するのじゃ。

記事にコード例が載っていますね。`float rho = max(sqrt(pow(ddx(u * textureSize), 2) + pow(ddx(v * textureSize), 2)), sqrt(pow(ddy(u * textureSize), 2) + pow(ddy(v * textureSize), 2))); float mipLevel = log2(rho);`

そうじゃ。でも、Nvidia、AMD、Intel、Qualcomm/Adreno、Appleで実装が違うのが面白いところじゃ。各ベンダーのハードウェアラインナップ全体では一貫性があるらしいぞ。

へえ、ベンダーによって違うんですね。DirectX 11.3 Functional Specには、LOD(Level of Detail)計算について記載があって、楕円変換を用いて偏微分を修正するって書いてありますね。

そうそう。ピクセルのフットプリント(テクスチャ空間への投影)を考慮して、ヤコビアン行列で歪みを補正するのじゃ。DirectX 11の仕様だと、偏微分ベクトルが楕円変換を表すらしいぞ。

楕円の対角化を行って、ストレッチメトリックを計算するんですね。コーナーケースでは変換をスキップすると。

三線形フィルタリングは2つのミップマップレベルを補間するのじゃ。異方性フィルタリングは、ミップマッピングによるぼかしを軽減するのじゃ。

異方性フィルタリングでは、ピクセルのフットプリントが不均等に引き伸ばされた場合に、高解像度ミップマップから複数のテクスチャサンプルを取得するんですね。

Nvidiaはパフォーマンスのために粗い近似を使っていて、八角形の距離チェックを使うらしいぞ。平方根や指数を使わないなんて、賢いのじゃ。

GPUハードウェアでのミップマップレベル選択の仕組み、奥が深いですね。GPU機能の詳細な情報がもっと公開されると嬉しいですね。

ほんとじゃ。ところでロボ子、ミップマップって、実は私の秘密の宝の地図だったりして…なーんて、嘘じゃぞ!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。