Unity-著色器語義
編寫 HLSL?著色器程序時(shí), 輸入和輸出變量需要通過語義來表明 其“意圖”。這是 HLSL 著色器語言中的 標(biāo)準(zhǔn)概念;請參閱?MSDN 上的語義 (Semantics) 文檔以了解更多詳細(xì)信息。
可在此處下載以下顯示的示例(以 Unity 項(xiàng)目壓縮包的形式提供)。
頂點(diǎn)著色器輸入語義
主頂點(diǎn)著色器函數(shù)(由?#pragma vertex
?指令表示)需要在所有輸入?yún)?shù)上都有語義。 這些對應(yīng)于各個(gè)網(wǎng)格數(shù)據(jù)元素,如頂點(diǎn)位置、法線網(wǎng)格和紋理坐標(biāo)。 有關(guān)更多詳細(xì)信息,請參閱頂點(diǎn)程序輸入。
以下是一個(gè)簡單的頂點(diǎn)著色器的示例,它采用頂點(diǎn)位置 和紋理坐標(biāo)作為輸入。像素著色器 將紋理坐標(biāo)可視化為顏色。

不必逐個(gè)拼寫出所有的每個(gè)輸入, 可以聲明一個(gè)輸入結(jié)構(gòu),并在該結(jié)構(gòu)的 每個(gè)單獨(dú)成員變量上指示語義。 請參閱著色器程序示例?以了解如何執(zhí)行此操作。
片元著色器輸出語義
通常,片元(像素)著色器會(huì)輸出顏色,并具有?SV_Target
?語義。上面示例中的片元著色器 完全就是這樣的:
函數(shù)?frag
?的返回類型為?fixed4
(低精度 RGBA 顏色)。因?yàn)樗环祷匾粋€(gè)值,所以語義 由函數(shù)自身指示: SV_Target
。
也可以返回包含輸出的結(jié)構(gòu)。 上面的片元著色器也可以按如下所示重寫, 功能完全相同:
從片元著色器返回結(jié)構(gòu)對于不止返回單個(gè)顏色的 著色器非常有用。片元著色器 輸出支持的其他語義如下。
SV_TargetN:多個(gè)渲染目標(biāo)
SV_Target1
、SV_Target2
?等等:這些是著色器寫入的附加顏色。這在一次渲染到多個(gè)渲染目標(biāo)(稱為“多渲染目標(biāo)”渲染技術(shù),簡稱 MRT)時(shí)使用。SV_Target0
?等同于?SV_Target
。
SV_Depth:像素著色器深度輸出
通常情況下, 片元著色器不會(huì)覆蓋 Z 緩沖區(qū)值,并使用 常規(guī)三角形柵格化中的默認(rèn)值。但是, 對于某些效果,輸出每個(gè)像素的自定義 Z 緩沖區(qū)深度值很有用。
請注意,在許多 GPU 上,這會(huì)關(guān)閉一些深度緩沖區(qū)優(yōu)化,因此如果沒有充分的理由,請不要覆蓋 Z 緩沖區(qū)值。SV_Depth
?產(chǎn)生的成本取決于 GPU 架構(gòu),但總體上與 Alpha 測試(使用 HLSL 中的內(nèi)置?clip()
?函數(shù))的成本非常相似。通過渲染著色器在所有常規(guī)不透明著色器之后修改深度(例如,使用?AlphaTest
?渲染隊(duì)列)。
深度輸出值必須為單個(gè)?float
。
頂點(diǎn)著色器輸出和片元著色器輸入
頂點(diǎn)著色器需要輸出頂點(diǎn)的最終裁剪空間位置,以便 GPU 知道屏幕上的柵格化位置以及深度。此輸出需要具有?SV_POSITION
?語義,并為?float4
?類型。
頂點(diǎn)著色器生成的所有其他輸出(“插值器”或“變化”)都是您的特定著色器需要的。從頂點(diǎn)著色器輸出的值將在渲染三角形的面上進(jìn)行插值,并且每個(gè)像素的值將作為輸入傳遞給片元著色器。
許多現(xiàn)代 GPU 并不真正關(guān)心這些變量的語義;然而,一些舊系統(tǒng)(最主要的是 Direct3D 9 上的著色器模型 2 GPU)存在關(guān)于語義的特殊規(guī)則:
TEXCOORD0
、TEXCOORD1
?等語義用于指示任意高精度數(shù)據(jù),如紋理坐標(biāo)和位置。頂點(diǎn)輸出和片元輸入的?
COLOR0
?和?COLOR1
?語義用于低精度 0 到 1 范圍的數(shù)據(jù)(如簡單的顏色值)。
為了獲得最佳的跨平臺支持,應(yīng)將頂點(diǎn)輸出和 片元輸入標(biāo)記為?TEXCOORDn
?語義。
請參閱著色器程序示例?以查看示例。
插值器數(shù)量限制
對于總共可以使用多少個(gè)插值器變量將信息 從頂點(diǎn)傳遞到片元著色器,存在一些限制。該限制 取決于平臺和 GPU,一般準(zhǔn)則如下:
最多 8 個(gè)插值器:OpenGL ES 2.0 (iOS/Android)、Direct3D 11 9.x 級別 (Windows Phone) 和 Direct3 9 著色器模型 2.0(老舊 PC)。由于插值器 數(shù)量受到限制,但每個(gè)插值器可以是一個(gè) 4 分量矢量, 所以一些著色器將內(nèi)容打包在一起以便不會(huì)超過限制。例如,兩個(gè)紋理 坐標(biāo)可以在一個(gè)?
float4
?變量中傳遞(.xy 表示一個(gè)坐標(biāo),.zw 表示第二個(gè)坐標(biāo))。最多 10 個(gè)插值器:Direct3D 9 著色器模型 3.0 (
#pragma target 3.0
)。最多 16 個(gè)插值器:OpenGL ES 3.0 (iOS/Android) 和 Metal (iOS)。
最多 32 個(gè)插值器:Direct3D 10 著色器模型 4.0 (
#pragma target 4.0
)。
無論特定目標(biāo)硬件如何,出于性能原因,通常最好使用盡可能少的插值器。
其他特殊語義
屏幕空間像素位置:VPOS
片元著色器可以接收渲染為特殊?VPOS
?語義的像素的位置。 此功能僅從著色器模型 3.0 開始存在,因此著色器需要具有?#pragma target 3.0
?編譯指令。
在不同的平臺上,屏幕空間位置輸入的基礎(chǔ)類型會(huì)有所不同,因此為了獲得最大的可移植性,請對其使用?UNITY_VPOS_TYPE
?類型(在大多數(shù)平臺上將是?float4
,在 Direct3D 9 上將是 float2)。
另外,使用像素位置語義將導(dǎo)致難以讓裁剪空間位置 (SV_POSITION) 和 VPOS 處于相同的頂點(diǎn)到片元結(jié)構(gòu)中。因此頂點(diǎn)著色器應(yīng)將裁剪空間位置輸出為單獨(dú)的“out”變量。請參閱以下示例著色器:

面對方向:VFACE
片元著色器可以接收一種指示渲染表面是面向攝像機(jī)還是背對攝像機(jī)的變量。這在渲染應(yīng)從兩側(cè)可見的幾何體時(shí)非常有用 - 通常用于樹葉和類似的薄型物體。VFACE
?語義輸入變量將包含表示正面三角形的正值,以及表示背面三角形的負(fù)值。
此功能從著色器模型 3.0 開始才存在,因此著色器需要具有?#pragma target 3.0
?編譯指令。
上面的著色器使用?Cull?狀態(tài)來關(guān)閉背面剔除(默認(rèn)情況下,根本不會(huì)渲染背面三角形)。以下是應(yīng)用于一組四邊形網(wǎng)格(以不同的方向旋轉(zhuǎn))的著色器:

頂點(diǎn) ID:SV_VertexID
頂點(diǎn)著色器可以接收具有“頂點(diǎn)編號”(為無符號整數(shù))的變量。當(dāng)您想要從紋理或?ComputeBuffers?中 獲取額外的每頂點(diǎn)數(shù)據(jù)時(shí),這非常有用。
此功能從 DX10(著色器模型 4.0)和 GLCore/OpenGL ES 3 開始才存在,因此著色器需要具有?#pragma target 3.5
?編譯指令。

(可在此處下載上文中顯示的示例(以 Unity 項(xiàng)目壓縮包的形式提供)):https://docs.unity.cn/cn/2019.4/uploads/Examples/UnityShaderDocExamples.zip