Version: 2022.3
言語: 日本語
ビルトインのシェーダー変数
サンプラー状態の利用

シェーダーのデータ型と精度

Unity は標準的なシェーダー言語 HLSL を使用しており、一般的な HLSL のデータ型をサポートしています。ただし、Unity はモバイルプラットフォームでのサポートを向上させるために、一部のデータ型を HLSL とは異なる方法で処理します。

基本的なデータ型

シェーダーは、浮動小数点数 (C# などの通常のプログラミング言語では float と呼ばれます) を使用して計算の大部分を実行します。Unity の HLSL 実装では、スカラー浮動小数点データ型は floathalffixed です。 これらのデータ型は精度が異なり、その結果、パフォーマンスや消費電力が異なります。また、half3float4x4 など、ベクトルや行列に関連するデータ型もいくつかあります。

高精度: 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 は 常に 高精度のため、シェーダーで floathalffixed どのデータ型を使おうと関係ありません。常に完全な 32 ビット浮動小数点精度ですべてを計算します。

halffixed 型は、モバイルの 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 ビット数 (halffixed 型の両方に使用) のいずれかしかサポートしていません。一部の古い GPU では、頂点シェーダーとフラグメントシェーダーの計算で精度が異なります。

低精度を使用すると高速になることがよくあります。それは、GPU レジスターの割り当てが改善されたため、または特定の低精度数学演算用の特別な “高速パス” 実行ユニットによるためです。直接のパフォーマンス上の利点がない場合でも、低い精度を使用すると GPU の消費電力が少なくなるため、バッテリー寿命が長くなります。

Unity では、位置とテクスチャ座標以外はすべて半精度で始めることを推奨しています。計算の一部で半精度では不十分な場合のみ、精度を上げてください。

無限、NaN、他の特別な浮動小数点値の適用

特殊な浮動小数点値のサポートは、実行している GPU ファミリー (主にモバイル) によって異なる場合があります。

Direct3D 10 をサポートするすべての PC の GPU は、明確に指定された IEEE 754 浮動小数点規格をサポートします。つまり、浮動小数点数は、CPU 上の通常のプログラミング言語の場合とまったく同じように動作します。

モバイル GPU のサポートレベルは、わずかに異なります。例えば、ゼロをゼロで除算すると NaN (“数字ではない”) になるモバイルがありますが、無限大、ゼロ、または、その他の特定できない値になるものもあります。ターゲットデバイスでシェーダーをテストして、それらのサポートを確認してください。

外部 GPU ドキュメント

GPU には、そのパフォーマンスや能力に関してベンダーによる詳しいガイドがあります。詳細は、それらを参照してください。

その他の参考資料

ビルトインのシェーダー変数
サンプラー状態の利用