画像の縮小アルゴリズム

DXRubyの公式掲示板で拡大フィルタの話が出たので思い出した話をメモ。

■拡大縮小のアルゴリズム
画像の描画はCPUでやってもGPUでやっても、元の画像をVRAMに転送することで行う。等倍の転送ならそのままになるが、3D描画ではドットバイドットの描画がされることはまず無いので、拡大なり縮小なりをすることになる。
CPUでやる場合、拡大は1ピクセルのテクスチャを複数ピクセルに描きこむような処理をするが、それだとカクカクな絵になってしまうから、隣のピクセルの色と合成するわけだが、この処理には大変時間がかかる。GPUではハードウェアがそのへんをやってくるれるのでシェーダを使う場合でも意識せずに高速処理ができる。HLSLで言うところのTex2D関数はテクスチャの位置を表すのにピクセル座標ではなくfloat型の0.0〜1.0を使うのはそういうことである。
縮小はCPUだとテクスチャの間引きをすることになる。間引いたぶんを足して縮小率をかけてやれば綺麗に合成できるが、これも大変時間がかかる。この処理はGPUでもサポートされていないので、半分までの縮小なら色がブレンドされるが、ぴったり半分に縮小すると綺麗に間引きされてしまう。

■ミップマップ
3D描画をサポートするAPIはミップマップという機能を持っていて、テクスチャを作成した際に1/2の累乗サイズの画像をあらかじめ作成することができる。この画像はきちんとブレンド処理されたものであるので、小さく縮小する場合にもっとも近いサイズの画像を元にして描画するので、できうる限り綺麗な絵を描画することができる。テクスチャを作成するときにミップマップを使うように指定すれば自動的に処理される。ミップマップの欠点はテクスチャが使うVRAMが増えてしまうことと、テクスチャの作成/更新に時間がかかるようになることである。

■DXRubyでは
ミップマップは使っていない。Imageオブジェクトは動的に作成するし更新もされるし、縮小描画がされるかどうかもわからないので、ミップマップをサポートすることによる速度低下を懸念している。
Imageオブジェクトを作るときにオプションで指定できるようにするのも手だ。今後3D描画をサポートすることを考えると、ミップマップテクスチャを使えないのは描画品質面でつらいことになる気がする。
どういうインターフェイスで指定するかが問題なのでちょっと検討することにしよう。