【Unity】【シェーダ】小数点の精度と型の使い分けについて(float / half / fixedの話)

シェーダで小数点を使う時には、float、half、fixedの3つの型が使えます。
この記事ではこれらの違いと使い分けについて簡単にまとめます。
必要な知識のみ。深入りはしません(できません)。

そもそもなぜ3種類も使うのか?

GPUで計算するとき、より精度の低い型を使えばよりパフォーマンスが出るし、消費電力が抑えられます。
GPUでは単純な計算を大量に並列処理するので、この効果はより顕著なものとなります。
そのためシェーダでは可能な限り低い精度の型を使って計算をするというわけです。

サイズと範囲と精度の違い

まずサイズについては下記のような違いがあります。

  • fixed: 11bit
  • half: 16bit
  • float: 32bit

また、扱える範囲と精度は次のように異なります。
使う際に意識しなければならないのは精度なので、そういう意味でサイズよりも重要です。

  • fixed: 範囲は-2〜2、1/256の精度しかない
  • half: 範囲は-60000から+60000、小数点以下は3桁まで
  • float: 範囲は大きく精度は高い(一般的なfloat)

ざっくりですが、これだけわかれば大体のケースでは問題は起こりません。

実際どのように使い分ければいいのか?

上記の知識が得られたところで、シェーダを書きながらいちいち精度を考えていられません。
Unityのマニュアルにも書いてありますが、基本的には下記のルールに従って使い分ければOKです。

  1. ワールド座標、UV座標を取り扱う場合はfloatを使う
  2. その他は全部half
  3. 例外的に、テクスチャをサンプリングしてその後加工しない場合はfixedを使う
  4. 上記のルールで問題が起こったら一つ上の精度の型を使う

PCとモバイルの違い

精度の問題は、PCとモバイル端末で見え方が違うことで判明することが多いです。
これは、PCではhalfとかfixedとか書いてもすべてfloatとして扱われるためです。

これに対してモバイルのGPUではパフォーマンスがシビアなので、上記のように型が分けられています。
ただしモバイルでも仕様はまちまちな部分があり、特にfixedをhalfと同じものとして取り扱うGPUは少なくないようです。

この辺りを調べだすとややこしいですが、前節の使い分けのルールに従っていれば特に意識しなくていいことであるとは思います。

halfで小さい値を使うときにはアンダーフローに注意

halfを使う上で意識しないと問題が起こるケースとして、アンダーフローによる端末依存バグがあります。
これについては別記事にまとめましたのでこちらも合わせてご覧ください。

light11.hatenadiary.com

関連

light11.hatenadiary.com

参考

docs.unity3d.com

docs.unity3d.com

GPUの浮動小数点精度の話 - Qiita