Unity のスタンダードシェーダー言語は HLSL で、一般的な HLSL データ型がサポートされています。 ただし、Unity では、特にモバイルプラットフォームでより良いサポートを提供するために、HLSL 型にいくらか追加があります。
シェーダーの計算の大半は浮動小数点 (C# などの標準的なプログラミング言語では float
にあたります) で行われています。浮動小数点には、float
、half
、fixed
などのいくつかの型があります (ベクトル/行列のバリアントである half3
や `float4x4 などと同様です) 。これらの型では精度 (および、精度の違いから生じるパフォーマンスや電力消費) が異なります。
float
float は最高精度の浮動小数点値で、通常のプログラミング言語の float
と同じように一般な 32 ビットです。
フルfloat
の精度は、一般に、ワールド空間位置、テクスチャ座標、または三角法や累乗/べき乗などの複雑な関数を含むスカラー計算に使用されます。
half
half は中精度の浮動小数点値で、一般に 16 ビットです (–60000 から +60000 の範囲で、小数点以下約 3 桁)。
half は、ショートベクトル、方向、オブジェクト空間位置、HDR カラー に使用されます。
fixed
fixed は低精度で、固定小数点数です。一般的に 11 ビットで、–2.0 から +2.0 の範囲で、1/256 精度です。
fixed 精度は、標準カラー (一般的に標準テクスチャに保管されるので) とそれらの単純な制御に使用されます。
整数 (int
データ型) はしばしばループカウンターや配列のインデックスとして使用されます。そのため、通常は、さまざまなプラットフォームで問題なく使用できます。
プラットフォームによっては、整数型がGPU にサポートされていないことがあります。例えば、Direct3D 9 と OpenGL ES 2.0 GPU は、浮動小数点データ上でのみ作動します。そのため、シンプルに見える整数表現 (ビットやロジカルオペレーションに関する) は、ある程度複雑な浮動小数点の数式を使用してエミュレーションされていることがあります。
Direct3D 11、OpenGL ES 3、Metal やその他の現段階で使用されている多くのプラットフォームでは、整数のデータ型は適切にサポートされています。そのため、ビットシフトやビットマスクを使用しても、想定通り作動します。
HLSL には、基本の型から作成されたビルトインのベクトル型と行列型があります。例えば、float3
は .x、.y、.z コンポーネントを含む 3D ベクトルです。また、half4
は、中精度の 4D ベクトル (.x、.y、.z、.w コンポーネントを含む) です。あるいは、カラーを使用するときに有用な .r、.g、.b、.a コンポーネントを使用して、ベクトルをインデックス化することができます。
行列型も同様に作成されます。例えば、float4x4
は 4x4 変換行列です。プラットフォームによっては、OpenGL ES 2.0 でよく知られているように正方行列だけしかサポートしないものもあるので注意してください。
多くの場合、HLSL コードではテクスチャを以下のように宣言します。
sampler2D _MainTex;
samplerCUBE _Cubemap;
モバイルプラットフォームでは、これらは “低精度サンプラー” に変換されます。つまり、テクスチャには低精度のデータが含まれることが期待されます。 Unity プロジェクト全体のデフォルトのサンプラー精度は、Player Settings の Shader precision model ドロップダウンで変更することができます。 テクスチャに HDR カラーが含まれることが分かっている場合は、半精度サンプラーを使用するとよいでしょう。
sampler2D_half _MainTex;
samplerCUBE_half _Cubemap;
または、テクスチャがフルの float 精度のデータを含む場合 (例えば 深度テクスチャ)、最高精度を使用します。
sampler2D_float _MainTex;
samplerCUBE_float _Cubemap;
float
/half
/fixed
データ型を使用する上での厄介な問題の 1 つは、PC の GPU は 常に 高精度であるということです。つまり、すべての PC の (Windows/Mac/Linux) GPU にとって、シェーダーで float
、half
、fixed
の中のどのデータ型を使用するかは重要ではありません。PC の GPU は常にフルの 32 ビット浮動小数点精度ですべてを計算します。
half
と fixed
型は、モバイルの GPU をターゲットとする場合にのみ意味があります。これらのタイプは主に電力 (および、場合によってはパフォーマンス) の制約のために存在します。そのため、精度/数値の問題があるかどうか確認するためには、モバイルでシェーダをテストする必要があります。
モバイルの GPU であっても、GPU ファミリーによって精度のサポートにさまざまな違いがあります。以下は、各モバイル GPU ファミリーが各浮動小数点型を処理する方法の概要です (消費されるビット数で表示)。
GPU グループ | float | half | fixed |
---|---|---|---|
PowerVR Series 6/7 | 32 | 16 | |
PowerVR SGX 5xx | 32 | 16 | 11 |
Qualcomm Adreno 4xx/3xx | 32 | 16 | |
Qualcomm Adreno 2xx | 32 (頂点)、24 (フラグメント) | ||
ARM Mali T6xx/7xx | 32 | 16 | |
ARM Mali 400/450 | 32 (頂点)、16 (フラグメント) | ||
NVIDIA X1 | 32 | 16 | |
NVIDIA K1 | 32 | ||
NVIDIA Tegra 3/4 | 32 | 16 |
最近良く使われるモバイルのほとんどの GPU は、実際には 32 ビット数 (float
型に使用) または 16 ビット数 (half
と fixed
型の両方に使用) のいずれかしかサポートしていません。一部の古い GPU では、頂点シェーダーとフラグメントシェーダーの計算で精度が異なります。
低精度を使用すると高速になることがよくあります。それは、GPU レジスターの割り当てが改善されたため、または特定の低精度数学演算用の特別な “高速パス” 実行ユニットによるためです。直接のパフォーマンス上の利点がない場合でも、低い精度を使用すると GPU の消費電力が少なくなるため、バッテリー寿命が長くなります。
一般的に推奨される使用法は、位置とテクスチャ座標を除くすべてに half (中精度) を使用します。計算で精度にいくらか不十分な個所がある場合にのみ、精度を上げます。
計算に使用される精度が異なる GPU グループ (ほとんどモバイル) によって異なるように、特別な浮動小数点値のサポートも異なります。
Direct3D 10 をサポートするすべての PC の GPU は、非常にうまく指定された IEEE 754 浮動小数点規格をサポートします。つまり、浮動小数点数は、CPU 上の通常のプログラミング言語の場合とまったく同じように動作します。
モバイル GPU のサポートレベルは、わずかに異なります。例えば、ゼロをゼロで除算すると NaN (“数字ではない”) になるモバイルがありますが、無限大、ゼロ、または、その他の特定できない値になるものもあります。ターゲットデバイスでシェーダーをテストして、それらのサポートを確認してください。
GPU には、そのパフォーマンスや能力に関してベンダーによる詳しいガイドがあります。詳細は、それらを参照してください。