対象者
2Dのスプライト描画に悩まされていて、本質を知りたい人向けです。
正しく解説されている記事を見つけられなかったので、執筆に至りました。
原因
- 描画位置がずれている。
- カメラの位置がずれている。
※DirectX, OpenGL, Unity, UEどれも原因は一緒
補足
- ゲームエンジンやライブラリの不具合ではない。
- 補間方法の指定は関係ない。
- 1ピクセル大きく描画しても解決している訳ではない。
- テクスチャ周辺を透明ピクセルで埋めても解決はしていない。
どうしたらいいの?
描画位置とカメラの位置をずれないようにする。
なんでずれるの?
作り手が気づいてない&本質を理解できておらず発生しています。
解説
ディスプレイはピクセルという単位で描かれています。
大切なことなので、もう一度いいます。ディスプレイはピクセル単位です。
ピクセルを扱う座標は整数です。
もう一度いいますね。ピクセルは整数です。
次に大切なことを言います。ゲームエンジン/ライブラリは浮動小数で座標を扱います。
もう一度いいますね。ゲームエンジン/ライブラリは浮動小数です。
3x3背景の中に2x2のスプライトを中心に描画するとこうなります。
これはピクセル領域から「はみ出ている」ので描画できません!
んじゃどうなるの?
パターン1 切り捨て
スプライトを並べた時に隙間が出来たり、欠けたりする原因はこれ
パターン2 混ざる
UVのサンプリングに影響を与えて隣の色が出たり、変な色になる原因はこれ。
本質はこれのどちらかです。
小数の具合に応じて、切り捨てられたり混じったり変化します。
なので、動かしてから隙間が出たりする訳です。
どうしたらいいの?
ピクセルでぴったり表示できる座標にする。
これだけです…本当にこれだけ…
偶数ピクセル数の画像を描画するときは、描画位置を整数化つまりintキャストを実施して+0.5もしくは-0.5を行えばよいです。※どちらにずらすかはお好みで
奇数ピクセルの画像を描画するときは、描画位置の整数化が必要になります。
当然のことですが、幅/高さが偶数・偶奇か判定して、それぞれ計算しなければなりません。
同様にカメラの位置もずれてはいけません。こちらも気をつけましょう。
カメラの位置に応じて偶数時・奇数時の計算式が逆になりますのでご注意ください。
※整数か0.5刻みかによって違う
参考(Unity)
正常系
ピクセルぴったりにすると補間方法の違いも影響を受けていません。
正確には補間されていますが、計算結果が同じ値になります。
(高速化の観点ではニアレストネイバーの方がよいです)
異常系(GameObjectを正常に表示できない位置にずらす)
色が混じっていることが分かりますね。
補間方法が効いており、真ん中の部分がバイリニアだと隣の色が混じっています。
一見するとニアレストネイバー(Unityではポイント)が綺麗に見えるため
解決すると勘違いされる部分です。
スライスするとバイリニアは隣の色を拾って問題になることが分かりやすいですね。
内側1ピクセルスライスしたらよいとか、1ピクセル大きくすればよい、もしくは空ければよいと言われる部分です。
位置を変えれば、ニアレストネイバーでも隣の色を拾うので、何の解決にもなっていません。
異常系(カメラを正常に表示できない位置にずらす)
オブジェクトの位置が正常でも、カメラの位置がずれてると台無しです。
同様の問題が発生します。