縮小サンプリング

mipmapおよびripmap画像作成処理を書いた。


mipmap、ripmapはテクスチャマッピングにおける、縮小サンプリング時の処理だ。
つまり、出力画像のほうがテクスチャ画像より小さい(したがって出力画像の1ピクセルにテクスチャ画像の複数のピクセルが存在する)ときに出力画像にエイリアシングを抑える効果を持つ。
もちろんmipmap、ripmapの画像はただそれだけでは意味がなくて、これをピクセルごとの出力画像vsテクスチャ画像の解像度比率を求めて適切な解像度のピクセルをサンプリングしてあげる必要がある。
出力画像vsテクスチャ画像の解像度比率は出力画像の1ピクセル/テクスチャ画像の1ピクセルである。それぞれ縦横あるからdx/du、dy/dv、dx/du、dy/duとなる。この情報もとに適当な解像度を求めてやる。「適当な」としてるのは本当に適当にということで、解像度比率は4つ求められるのに対し、mipmapならひとつのレベルを、ripmapなら2つのレベルを求めるだけなので当然だ。
縦と横の解像度が同じよう縮小したmipmapに対し縦横別々に縮小したripmapは大きな平面の向こう側など縦と横で縮小率が大きく異なる場合に有効だ。
しかしripmapはメモリの消費率が大きく、また結局出力ピクセルがテクスチャ座標に対し斜めに投影された場合など適切な解像度レベルを求められない。その代わりmipmapを複数回サンプルすることにより、より適切なサンプリングを求めるのを異方向性サンプリングと呼ぶ。
異方向性サンプリングにおいて、サンプル分布に楕円を用いるものをEWAアルゴリズムと呼ぶ(らしい)。
縮小サンプリングにおいて、正確な値を求めたいのであれば範囲総和を用いる。
これは出力座標→テクスチャ座標の変換を行い出力画像の1ピクセルの四角形をテクスチャ座標に投影する。投影された四角形の内部に存在するすべてのテクスチャ画像のピクセルを平均したものをサンプルとする。
範囲総和は遠ければ遠いほど非常にたくさんのテクスチャ画像のピクセルを参照しなくてはならず重たい。
いっぽう投影された四角形を4分木で分割して複数レベルのmipmapを参照することで、範囲総和を高速化することができる。
ほかには範囲総和のサンプル数を固定化することで高速化する手法もある。(準最適化サンプリング 参照:GPU Gems 27.2.2 エイリアシング)。

出力画像vsテクスチャ画像の関係は本来的に1次レイのときにしかありえない。
このため2次レイ以降での縮小サンプリングは非常に困難である。(ビームトレーシングを用いれば、「それなり」にはできるはずだが・・・)
またアルゴリズム的にレイトレースには向いていなく、スキャンライン・Zバッファーなどのラスタライズで求めるほうが素直な解決方法であるようだ。

疑問:
■mipmap、ripmapを求める際に非power of 2な解像度を持つ画像に対してはどう対処するのがいいのだろう?
 案1:power of 2に拡大する:拡大フィルタには何を使えばよいか?
 案2:ラップモードを考慮して仮想的にpower of 2にする
■mipmap、ripmap中のそれぞれのレベルの画像を参照するとき拡大フィルタ(bilinear,bicubic, etc...)は使うべきか否か?

いいわけ:
今回はまだ画像の縮小処理を作っただけで、テクスチャの貼り付けまで行えてない。
理由は縮小サンプリングにはラスタライザが必要となるためだ。
レイトレーサに今回の仕組みを実装することはあまり気持ちのいい仕事ではない。
一次レイのためだけに光線クラスに対し保存する情報を追加するべきではないと考えるからだ。