Unity-著色器數(shù)據(jù)類型和精度
Unity 中的標(biāo)準(zhǔn)著色器語(yǔ)言為?HLSL,支持一般 HLSL 數(shù)據(jù)類型。但是,Unity 對(duì) HLSL 類型有一些補(bǔ)充,特別是為了在移動(dòng)平臺(tái)上提供更好的支持。
基本數(shù)據(jù)類型
著色器中的大多數(shù)計(jì)算是對(duì)浮點(diǎn)數(shù)(在 C# 等常規(guī)編程語(yǔ)言中為?float
)進(jìn)行的。浮點(diǎn)類型有幾種變體:float
、half
?和?fixed
(以及它們的矢量/矩陣變體,比如?half3
?和?float4x4
)。這些類型的精度不同(因此性能或功耗也不同):
高精度:float
最高精度浮點(diǎn)值;一般是 32 位(就像常規(guī)編程語(yǔ)言中的?float
)。
完整的?float
?精度通常用于世界空間位置、紋理坐標(biāo)或涉及復(fù)雜函數(shù)(如三角函數(shù)或冪/取冪)的標(biāo)量計(jì)算。
中等精度:half
中等精度浮點(diǎn)值;通常為 16 位(范圍為 –60000 至 +60000,精度約為 3 位小數(shù))。
半精度對(duì)于短矢量、方向、對(duì)象空間位置、高動(dòng)態(tài)范圍顏色非常有用。
低精度:fixed
最低精度的定點(diǎn)值。通常是 11 位,范圍從 –2.0 到 +2.0,精度為 1/256。
固定精度對(duì)于常規(guī)顏色(通常存儲(chǔ)在常規(guī)紋理中)以及對(duì)它們執(zhí)行簡(jiǎn)單運(yùn)算非常有用。
整數(shù)數(shù)據(jù)類型
整數(shù)(int
?數(shù)據(jù)類型)通常用作循環(huán)計(jì)數(shù)器或數(shù)組索引。為此,它們通??梢栽诟鞣N平臺(tái)上正常工作。
根據(jù)平臺(tái)的不同,GPU 可能不支持整數(shù)類型。例如,Direct3D 9 和 OpenGL ES 2.0 GPU 僅對(duì)浮點(diǎn)數(shù)據(jù)進(jìn)行運(yùn)算,并且可以使用相當(dāng)復(fù)雜的浮點(diǎn)數(shù)學(xué)指令來模擬簡(jiǎn)單的整數(shù)表達(dá)式(涉及位運(yùn)算或邏輯運(yùn)算)。
Direct3D 11、OpenGL ES 3、Metal 和其他現(xiàn)代平臺(tái)都對(duì)整數(shù)數(shù)據(jù)類型有適當(dāng)?shù)闹С?,因此使用位移位和位屏蔽可以按預(yù)期工作。
復(fù)合矢量/矩陣類型
HLSL 具有從基本類型創(chuàng)建的內(nèi)置矢量和矩陣類型。例如,float3
?是一個(gè) 3D 矢量,具有分量 .x、.y 和 .z,而?half4
?是一個(gè)中等精度 4D 矢量,具有分量 .x、.y、.z 和 .w。或者,可使用 .r、.g、.b 和 .a 分量來對(duì)矢量編制索引,這在處理顏色時(shí)很有用。
矩陣類型以類似的方式構(gòu)建;例如?float4x4
?是一個(gè) 4x4 變換矩陣。請(qǐng)注意,某些平臺(tái)僅支持方形矩陣,最主要的是 OpenGL ES 2.0。
紋理/采樣器類型
通常按照如下方式在 HLSL 代碼中聲明紋理:
對(duì)于移動(dòng)平臺(tái),這些將轉(zhuǎn)換為“低精度采樣器”,即預(yù)期紋理應(yīng)具有低精度數(shù)據(jù)。如果您知道紋理包含 HDR 顏色,則可能需要使用半精度采樣器:
或者,如果紋理包含完整浮點(diǎn)精度數(shù)據(jù)(例如深度紋理),請(qǐng)使用完整精度采樣器:
精度、硬件支持和性能
使用?float
/half
/fixed
?數(shù)據(jù)類型的一個(gè)難題是:PC GPU?始終為高精度。也就是說,對(duì)于所有 PC (Windows/Mac/Linux) GPU,在著色器中編寫?float
、half
?還是?fixed
?數(shù)據(jù)類型都無(wú)關(guān)緊要。這些 GPU 將始終以 32 位浮點(diǎn)精度來計(jì)算所有數(shù)據(jù)。
僅當(dāng)目標(biāo)平臺(tái)是移動(dòng)端 GPU 時(shí),half
?和?fixed
?類型才變得重要,在這種情況下,這些類型主要面臨功耗(有時(shí)候是性能)約束。請(qǐng)記住,要確認(rèn)是否遇到精度/數(shù)值問題,必須在移動(dòng)設(shè)備上測(cè)試著色器。
即使在移動(dòng)端 GPU 上,不同的精度支持也會(huì)因 GPU 產(chǎn)品系列而異。下面概述了個(gè)每個(gè)移動(dòng)端 GPU 產(chǎn)品系列如何處理每個(gè)浮點(diǎn)類型(以用于該產(chǎn)品系列的位數(shù)來表示):

大多數(shù)現(xiàn)代移動(dòng)端 GPU 實(shí)際上只支持 32 位數(shù)字(用于?float
?類型)或 16 位數(shù)字(用于?half
?和?fixed
?類型)。一些較舊的 GPU 對(duì)頂點(diǎn)著色器和片元著色器計(jì)算具有不同的精度。
使用較低的精度通常可以更快,這可能是由于改進(jìn)的 GPU 寄存器分配,或是由于某些低精度數(shù)學(xué)運(yùn)算的特殊“快速路徑”執(zhí)行單元。即使沒有原始性能優(yōu)勢(shì),使用較低的精度通常也會(huì)降低 GPU 的功耗,從而延長(zhǎng)電池續(xù)航時(shí)間。
一般的經(jīng)驗(yàn)法則是全部都從半精度開始(但位置和紋理坐標(biāo)除外)。僅當(dāng)半精度對(duì)于計(jì)算的某些部分不足時(shí),才增加精度。
支持無(wú)窮大、非數(shù)字和其他特殊浮點(diǎn)值
對(duì)特殊浮點(diǎn)值的支持可能會(huì)有所不同,具體取決于運(yùn)行的 GPU 產(chǎn)品系列(主要是移動(dòng)端)。
支持 Direct3D 10 的所有 PC GPU 都支持非常明確的 IEEE 754 浮點(diǎn)標(biāo)準(zhǔn)。這意味著,在 CPU 上,浮點(diǎn)數(shù)的行為與常規(guī)編程語(yǔ)言完全相同。
移動(dòng)端 GPU 的支持程度可能稍有不同。在某些移動(dòng)端 GPU 中,將零除以零可能會(huì)導(dǎo)致 NaN(“非數(shù)字”);在其他移動(dòng)端 GPU 上,它可能會(huì)導(dǎo)致無(wú)窮大、零或任何其他不明值。務(wù)必在目標(biāo)設(shè)備上測(cè)試著色器以檢查著色器是否受支持。
外部 GPU 文檔
GPU 供應(yīng)商會(huì)提供有關(guān)其 GPU 性能和功能的深入指南。請(qǐng)參閱下文以了解詳情:
ARM Mali GPU 最佳實(shí)踐開發(fā)者指南 (ARM Mali GPU Best Practices Developer Guide)
Qualcomm Adreno OpenGL ES 開發(fā)者指南 (Qualcomm Adreno OpenGL ES Developer Guide)
PowerVR 架構(gòu)指南 (PowerVR Architecture Guides)