The standard Shader language in Unity is HLSL, and general HLSL data types are supported. However, Unity has some additions to the HLSL types, particularly for better support on mobile platforms.
着色器中的大多数计算是对浮点数(在 C# 等常规编程语言中为 float
)进行的。浮点类型有几种变体:float
、half
和 fixed
(以及它们的矢量/矩阵变体,比如 half3
和 float4x4
)。这些类型的精度不同(因此性能或功耗也不同):
float
最高精度浮点值;一般是 32 位(就像常规编程语言中的 float
)。
Full float
precision is generally used for world space positions,
texture coordinates, or scalar computations involving complex functions such as trigonometry or power/exponentiation.
half
中等精度浮点值;通常为 16 位(范围为 –60000 至 +60000,精度约为 3 位小数)。
半精度对于短矢量、方向、对象空间位置、高动态范围颜色非常有用。
fixed
最低精度的定点值。通常是 11 位,范围从 –2.0 到 +2.0,精度为 1/256。
固定精度对于常规颜色(通常存储在常规纹理中)以及对它们执行简单运算非常有用。
整数(int
数据类型)通常用作循环计数器或数组索引。为此,它们通常可以在各种平台上正常工作。
根据平台的不同,GPU 可能不支持整数类型。例如,Direct3D 9 和 OpenGL ES 2.0 GPU 仅对浮点数据进行运算,并且可以使用相当复杂的浮点数学指令来模拟简单的整数表达式(涉及位运算或逻辑运算)。
Direct3D 11、OpenGL ES 3、Metal 和其他现代平台都对整数数据类型有适当的支持,因此使用位移位和位屏蔽可以按预期工作。
HLSL 具有从基本类型创建的内置矢量和矩阵类型。例如,float3
是一个 3D 矢量,具有分量 .x、.y 和 .z,而 half4
是一个中等精度 4D 矢量,具有分量 .x、.y、.z 和 .w。或者,可使用 .r、.g、.b 和 .a 分量来对矢量编制索引,这在处理颜色时很有用。
矩阵类型以类似的方式构建;例如 float4x4
是一个 4x4 变换矩阵。请注意,某些平台仅支持方形矩阵,最主要的是 OpenGL ES 2.0。
通常按照如下方式在 HLSL 代码中声明纹理:
sampler2D _MainTex;
samplerCUBE _Cubemap;
For mobile platforms, these translate into “low precision samplers”, i.e. the textures are expected to have low precision data in them. If you know your texture contains HDR colors, you might want to use half precision sampler:
sampler2D_half _MainTex;
samplerCUBE_half _Cubemap;
Or if your texture contains full float precision data (e.g. depth texture), use a full precision sampler:
sampler2D_float _MainTex;
samplerCUBE_float _Cubemap;
One complication of float
/half
/fixed
data type usage is that PC GPUs are always high precision. That is, for all the
PC (Windows/Mac/Linux) GPUs, it does not matter
whether you write float
, half
or fixed
data types in your shaders.
They always compute everything in full 32-bit floating point
precision.
The half
and fixed
types only become relevant when
targeting mobile GPUs, where these types primarily exist for
power (and sometimes performance) constraints. Keep in
mind that you need to test your shaders on mobile to see
whether or not you are running into precision/numerical issues.
Even on mobile GPUs, the different precision support varies between GPU families. Here’s an overview of how each mobile GPU family treats each floating point type (indicated by the number of bits used for it):
GPU 产品系列 | 浮点精度 | 半精度 | 固定精度 |
---|---|---|---|
PowerVR 系列 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 |
Most modern mobile GPUs actually only support
either 32-bit numbers (used for float
type) or 16-bit numbers
(used for both half
and fixed
types). Some older GPUs have different precisions for vertex shader and fragment shader computations.
Using lower precision can often be faster, either due to improved GPU register allocation, or due to special “fast path” execution units for certain lower-precision math operations. Even when there’s no raw performance advantage, using lower precision often uses less power on the GPU, leading to better battery life.
一般的经验法则是全部都从半精度开始(但位置和纹理坐标除外)。仅当半精度对于计算的某些部分不足时,才增加精度。
对特殊浮点值的支持可能会有所不同,具体取决于运行的 GPU 产品系列(主要是移动端)。
All PC GPUs that support Direct3D 10 support very well-specified IEEE 754 floating point standard. This means that float numbers behave exactly like they do in regular programming languages on the CPU.
Mobile GPUs can have slightly different levels of support. On some, dividing zero by zero might result in a NaN (“not a number”); on others it might result in infinity, zero or any other unspecified value. Make sure to test your shaders on the target device to check they are supported.
GPU vendors have in-depth guides about the performance and capabilities of their GPUs. See these for details: