Unity は標準的なシェーダー言語 HLSL を使用しており、一般的な HLSL のデータ型をサポートしています。ただし、Unity はモバイルプラットフォームでのサポートを向上させるために、一部のデータ型を HLSL とは異なる方法で処理します。
シェーダーは、浮動小数点数 (C# などの通常のプログラミング言語では float
と呼ばれます) を使用して計算の大部分を実行します。Unity の HLSL 実装では、スカラー浮動小数点データ型は float
、half
、fixed
です。 これらのデータ型は精度が異なり、その結果、パフォーマンスや消費電力が異なります。また、half3
や float4x4
など、ベクトルや行列に関連するデータ型もいくつかあります。
float
これは最高精度の浮動小数点データ型です。ほとんどのプラットフォームでは、float
値は通常のプログラミング言語と同様に 32 ビットです。
完全な float
精度は通常、ワールド空間の位置やテクスチャ座標、または三角関数や累乗/指数計算のような複雑な関数を含むスカラー計算に有用です。これらの目的で低精度の浮動小数点データ型を使用すると、精度に関連したアーティファクトを発生させる可能性があります。例えばテクスチャー座標の場合、half
には大きなテクスチャの 1 テクセルオフセットを正確に表現するのに十分な精度がありません。
half
これは中精度浮動小数点データ型です。half
値をサポートするプラットフォームでは、通常 16 ビットです。その他のプラットフォームでは float
になります。
half
値は、float
値よりも範囲が狭く精度が低くなります。
半精度は、短いベクトル、方向、オブジェクト空間の位置、ハイダイナミックレンジ (HDR) の色など、高精度を必要としない値のシェーダー性能を向上させるのに便利です。
fixed
これは OpenGL ES 2.0 Graphics API でのみサポートされています。他の API では、サポートされている最低精度 (half
または float
) になります。
これは最も精度の低い固定小数点値で、通常 11 ビットです。fixed
値の範囲は –2.0 から +2.0 で、精度は 1/256 です。
固定精度は、標準色 (一般的に標準テクスチャに保管されます) とそれらの単純な制御に使用されます。
Unity のシェーダーコンパイラーは、HLSL の浮動小数点数のサフィックス を無視します。そのため、浮動小数点数のサフィックスはすべて float
になります。
このコードは、Unity でサフィックス h
の数字が悪影響を及ぼす可能性を示しています。
half3 packedNormal = ...;
half3 normal = packedNormal * 2.0h - 1.0h;
サフィックス h
は無視されるので、シェーダーコンパイラーがこれらのステップを実行するコードを生成します。
1. 中間の normal
値を高精度で計算します (float3
)
2. その中間の値を half3
に変換します。 これはシェーダーの性能を低下させます。
このコードは、計算に half
値しか使わないので、より効率的です。
half3 packedNormal = ...;
half3 normal = packedNormal * half(2.0) - half(1.0);
Unity のシェーダーコンパイラーは、HLSL の浮動小数点数のサフィックス を無視します。そのため、浮動小数点数のサフィックスはすべて float
になります。
このコードは、Unity でサフィックス h
の数字が悪影響を及ぼす可能性を示しています。
half3 packedNormal = ...;
half3 normal = packedNormal * 2.0h - 1.0h;
サフィックス h
は無視されるので、シェーダーコンパイラーがこれらのステップを実行するコードを生成します。
1. 中間の normal
値を高精度で計算します (float3
)
2. その中間の値を half3
に変換します。 これはシェーダーの性能を低下させます。
このコードは、計算に half
値しか使わないので、より効率的です。
half3 packedNormal = ...;
half3 normal = packedNormal * half(2.0) - half(1.0);
整数 (int
データ型) はしばしばループカウンターや配列のインデックスとして使用されます。そのため、通常は、さまざまなプラットフォームで問題なく使用できます。
選択したプラットフォームによっては、GPU が整数型をサポートしない場合があります。例えば、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 コンポーネントを使用して、ベクトルをインデックス化することができます。
float4 myColor = ...
float redValue = myColor.r;
行列型も同様に作成されます。例えば、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;
PC (Windows/Mac/Linux) の GPU は 常に 高精度のため、シェーダーで float
、half
、fixed
どのデータ型を使おうと関係ありません。常に完全な 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 の消費電力が少なくなるため、バッテリー寿命が長くなります。
Unity では、位置とテクスチャ座標以外はすべて半精度で始めることを推奨しています。計算の一部で半精度では不十分な場合のみ、精度を上げてください。
特殊な浮動小数点値のサポートは、実行している GPU ファミリー (主にモバイル) によって異なる場合があります。
Direct3D 10 をサポートするすべての PC の GPU は、明確に指定された IEEE 754 浮動小数点規格をサポートします。つまり、浮動小数点数は、CPU 上の通常のプログラミング言語の場合とまったく同じように動作します。
モバイル GPU のサポートレベルは、わずかに異なります。例えば、ゼロをゼロで除算すると NaN (“数字ではない”) になるモバイルがありますが、無限大、ゼロ、または、その他の特定できない値になるものもあります。ターゲットデバイスでシェーダーをテストして、それらのサポートを確認してください。
GPU には、そのパフォーマンスや能力に関してベンダーによる詳しいガイドがあります。詳細は、それらを参照してください。