2の累乗以外は死ね

UV座標(ググれ)をそれぞれ0.0〜2.0にして256x64の板ポリゴンに縦横2回ずつ貼りつけた結果がこちら。


これが元画像(160x64)


…えっ?
よく見た結果、160x64の元画像のうち、128x32の部分を抜き出したものになっています。0.0〜1.0をはみ出したUV座標によって繰り返しているので、テクスチャ全体が見えているはずです。ちなみにD3DXCreateTextureFromFileEx関数でMipLevel(ミップマップ(ググれ)の階層数)を1にしてやると、きちんと(?)256(右の部分に透過色を追加)x64を半分にしたものが4つ見えます。
ミップマップは縮小状態を先に用意しておくのが目的であり、画像としての情報が変わってしまうのはまずいでしょう。なんでミップレベルまでいじろうと思ったのかは謎ですが、もはやいじる場所がなくなるほどわけわかめだったのでしょう。


Q.なんでこうなるの?
A.画像ファイルのサイズが2の累乗じゃないから。
いろいろとだめなんですよ2の累乗じゃないと。ビデオカードってのは普通2の累乗のサイズのテクスチャしか作れないんです。これに合わせないと今回みたいな原因不明のわけのわからん現象が…。
160が切りのいい数字だと思ってるんでしょうかねこれ。4*10だから?10ってなんぞや。


なんだか死兆星点灯カットインの画像がぼやけてると指摘をいただきまして、まあ原因はD3DXCreateTextureFromFileで画像をロードする時に横幅が160→256に切り上げられ、デフォルト指定のD3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHERで拡大され(ここで256x64目いっぱいに広げられたテクスチャに)、それを160x64の板ポリゴンに貼りつけたのでここでまたテクスチャフィルタでスケーリングが行われ、まあ2回もスケーリングしたらぼやけますよね(いやうまくぼけてる方がフィルタがうまく効いてるってことかも)。
ということでロード関数をD3DXCreateTextureFromFileExに切り替え、大量のパラメータが必要なもののD3DX_FILTER_NONEで拡大をやめさせ、右側に透明な黒が入るようにしました。2の累乗でないテクスチャが生成できてしまう環境だとやばいことになるのでサイズも256x64を指定。2Dゲームだとミップマップなんていらないよね…。完全にメモリの無駄だと思われるのでMipLevelsには1を指定。で、テクスチャに貼ってみるとなぜか128x32の部分の謎の抜き出しですよ。ほんとによくわからないけどなぜか解決しました。もう嫌。2の累乗なら全く問題にならなかったんだろうけど同じ色で透過があったりなかったりの謎のデータで編集不能。いや、無理してでも変換プログラムを書いた方が早かったかもしれぬ…。


2の累乗以外は死ね。


あ、ちなみに非想天則で良く見るキャラ絵のまわりに変なゴミが見える現象ですが、テクスチャの繰り返し処理のせいです。テクスチャラッピングといいます。まあデフォルトでD3DTADDRESS_WRAP(普通の繰り返し)なんですよね。これのせいで例えば左側に右端のドットが見えてしまったりするわけです。2DゲームならD3DTADDRESS_BORDERが安定でしょう。周りを設定色(デフォルトは透明な黒)で塗りつぶします。

dev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
dev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);

UVの縦横両方に設定してください。ちなみになんかお空の周りにゴミが見えるのは多分あのマント(私の勝手な憶測によるとステンシルバッファ(ググれ)による)がよくわからないけどはみ出しちゃってるんだと思う。


ちなみに、同じような原理で1枚の画像の1部分をUV座標で抜き出すと、ゴミが見えることが多々あります。実際、北斗七星ゲージの表示でその指摘を受けました。
対処法

  • 1枚の画像に複数の要素を入れるのをやめる。全部1画像。
  • 周りに十分な大きさの空白を入れる。

ドット絵師にとっては涙目な仕様が多い時代なのかもしれませんが、我慢してください。ビットブリット(ビットのそのままの転送)ではなく、テクスチャマッピングの時代なのです。テクスチャマッピングは基本的に3Dゲームの地面を表現するものだとイメージしておいてください。ミップマップとかも含めて。仕方ないね。回転拡大縮小アルファブレンドがガンガンにできるっていう悪いことばかりでもないけどね。