Unity-計(jì)算著色器
計(jì)算著色器
計(jì)算著色器是在顯卡上并位于正常渲染管線(xiàn)之外運(yùn)行的程序。它們可用于大規(guī)模并行的 GPGPU 算法,或用于加速游戲渲染的某些部分。為了有效使用它們,通常需要深入了解 GPU 架構(gòu)和并行算法;并了解?DirectCompute、OpenGL Compute、CUDA?或?OpenCL。
Unity 中的計(jì)算著色器與?DirectX?11 DirectCompute 技術(shù)緊密配合。計(jì)算著色器適用的平臺(tái):
Windows 和 Windows 應(yīng)用商店,使用 DirectX 11 或 DirectX 12 圖形 API 和 Shader Model 5.0 GPU
macOS 和 iOS,使用?Metal 圖形?API
Android、Linux 和 Windows 平臺(tái),Vulkan?API
現(xiàn)代?OpenGL?平臺(tái)(Linux 或 Windows 上的 OpenGL 4.3;Android 上的 OpenGL ES 3.1)。請(qǐng)注意,Mac OS X 不支持 OpenGL 4.3
現(xiàn)代游戲主機(jī)(Sony PS4 和 Microsoft Xbox One)
在運(yùn)行時(shí)可使用?SystemInfo.supportsComputeShaders?來(lái)查詢(xún)計(jì)算著色器支持情況。
計(jì)算著色器資源
類(lèi)似于常規(guī)著色器,計(jì)算著色器是項(xiàng)目中的資源文件,文件擴(kuò)展名為?.compute。它們是以 DirectX 11 樣式?HLSL?語(yǔ)言編寫(xiě)的,具有最少數(shù)量的 #pragma 編譯指令來(lái)指示哪些函數(shù)將編譯為計(jì)算著色器內(nèi)核。
下面是計(jì)算著色器文件的基本示例,它使用紅色填充輸出紋理:
// test.compute
# pragma kernel FillWithRed
RWTexture2D<float4> res;
[numthreads(1,1,1)]
void FillWithRed (uint3 dtid : SV_DispatchThreadID) { ? ?
res[dtid.xy] = float4(1,0,0,1);
}
此處的語(yǔ)言是標(biāo)準(zhǔn)?DX11 HLSL,具有附加的?#pragma kernel FillWithRed
?指令。一個(gè)計(jì)算著色器資源文件必須包含至少一個(gè)可以調(diào)用的?compute kernel
,該函數(shù)由?#pragma directive
?指示。文件中可以有更多內(nèi)核;只需添加多個(gè)?#pragma kernel
?行。
使用多個(gè)?#pragma kernel
?行時(shí),請(qǐng)注意在?#pragma kernel
?指令的同一行上不允許?// text
?樣式的注釋?zhuān)绻褂?,?huì)導(dǎo)致編譯錯(cuò)誤。
可選擇性地在?#pragma kernel
?行后面添加要在編譯該內(nèi)核時(shí)定義的多個(gè)預(yù)處理器宏,例如:
# pragma kernel KernelOne SOME_DEFINE DEFINE_WITH_VALUE=1337
# pragma kernel KernelTwo OTHER_DEFINE // ...
調(diào)用計(jì)算著色器
在腳本中,應(yīng)定義 ComputeShader 類(lèi)型的變量并分配對(duì)資源的引用。如此便可使用?ComputeShader.Dispatch?函數(shù)來(lái)調(diào)用它們。請(qǐng)參閱關(guān)于?ComputeShader 類(lèi)的 Unity 文檔以了解更多詳細(xì)信息。
與計(jì)算著色器密切相關(guān)的是?ComputeBuffer?類(lèi),該類(lèi)將定義任意數(shù)據(jù)緩沖區(qū)(在 DX11 術(shù)語(yǔ)中稱(chēng)為“結(jié)構(gòu)化緩沖區(qū)”)。如果已設(shè)置“隨機(jī)訪(fǎng)問(wèn)”標(biāo)志(在 DX11 中稱(chēng)為“無(wú)序訪(fǎng)問(wèn)視圖”),也可從計(jì)算著色器中寫(xiě)入渲染紋理。請(qǐng)參閱?RenderTexture.enableRandomWrite?以了解與此相關(guān)的更多信息。
計(jì)算著色器中的紋理采樣器
紋理和采樣器不是 Unity 中的單獨(dú)對(duì)象,因此要在計(jì)算著色器中使用它們,必須遵循以下 Unity 特定規(guī)則之一:
使用與紋理名稱(chēng)相同的名稱(chēng),以?
sampler
?開(kāi)頭(例如,Texture2D MyTex
;SamplerState samplerMyTex
)。在此情況下,采樣器將初始化為紋理的過(guò)濾/包裹/各向異性 (filter/wrap/aniso) 設(shè)置。使用預(yù)定義采樣器。因此,該名稱(chēng)必須具有?
Linear
?或?Point
(對(duì)于過(guò)濾模式)和?Clamp
?或?Repeat
(包裹模式)。例如,SamplerState MyLinearClampSampler
?會(huì)創(chuàng)建一個(gè)具有線(xiàn)性過(guò)濾模式和鉗制包裹模式的采樣器。
有關(guān)更多信息,請(qǐng)參閱采樣器狀態(tài)文檔。
跨平臺(tái)支持
與常規(guī)著色器一樣,Unity 可將計(jì)算著色器從 HLSL?轉(zhuǎn)換為其他著色器語(yǔ)言。因此,對(duì)于最簡(jiǎn)單的跨平臺(tái)版本,應(yīng)以 HLSL 編寫(xiě)計(jì)算著色器。但是,在執(zhí)行此操作時(shí)需要考慮一些因素。
跨平臺(tái)最佳實(shí)踐
DirectX 11 (DX11) 支持在其他平臺(tái)(如?Metal?或?OpenGL ES)上不支持的許多操作。因此,應(yīng)始終確保著色器在提供更少支持的平臺(tái)(而不是僅在 DX11 上)上具有良好定義的行為。以下是要考慮的一些事項(xiàng):
越界內(nèi)存訪(fǎng)問(wèn)是錯(cuò)誤的。DX11 在讀取時(shí)可能始終返回零,并且在讀取某些寫(xiě)入時(shí)沒(méi)有問(wèn)題,但提供較少支持的平臺(tái)可能會(huì)在執(zhí)行此操作時(shí)導(dǎo)致 GPU 崩潰。密切注意特定于 DX11 的破解問(wèn)題,與線(xiàn)程組大小倍數(shù)不匹配的緩沖區(qū)大小,試圖從緩沖區(qū)的開(kāi)頭或結(jié)尾讀取相鄰的數(shù)據(jù)元素,以及類(lèi)似的不兼容性。
初始化您的資源。新緩沖區(qū)和紋理的內(nèi)容是未定義的。有些平臺(tái)可能會(huì)提供全零,但在其他平臺(tái)上,可能會(huì)有某種內(nèi)容(包括非數(shù)字)。
綁定計(jì)算著色器聲明的所有資源。即使您確定著色器在當(dāng)前狀態(tài)下由于分支而沒(méi)有使用資源,仍必須確保有資源與其綁定。
平臺(tái)特定差異
Metal(適用于 iOS 和 tvOS 平臺(tái))不支持對(duì)紋理的原子操作。Metal 也不支持對(duì)緩沖區(qū)的?
GetDimensions
?查詢(xún)。如果需要,請(qǐng)將緩沖區(qū)大小信息作為常量傳遞給著色器。OpenGL ES?3.1(適用于 Android、iOS、tvOS 平臺(tái))僅保證一次支持 4 個(gè)計(jì)算緩沖區(qū)。實(shí)際的實(shí)現(xiàn)通常支持更多數(shù)量,但在一般情況下,如果為 OpenGL ES 進(jìn)行開(kāi)發(fā),應(yīng)考慮在結(jié)構(gòu)中對(duì)相關(guān)數(shù)據(jù)分組,而不是將每個(gè)數(shù)據(jù)項(xiàng)放在自己的緩沖區(qū)中。
僅限 HLSL 或僅限 GLSL 的計(jì)算著色器
通常情況下會(huì)以?HLSL?編寫(xiě)計(jì)算著色器文件,并自動(dòng)將這些文件編譯或轉(zhuǎn)換到所有需要的平臺(tái)中。但是,可以阻止轉(zhuǎn)換為其他語(yǔ)言(即僅保留 HLSL 平臺(tái))或者手動(dòng)編寫(xiě)?GLSL?計(jì)算代碼。
以下信息僅適用于僅限 HLSL 或僅限 GLSL 的計(jì)算著色器,而不適用于跨平臺(tái)版本。這是因?yàn)榇诵畔⒖赡軐?dǎo)致計(jì)算著色器源代碼被排除在某些平臺(tái)之外。
對(duì)于非 HLSL 平臺(tái),不會(huì)處理?
CGPROGRAM
?和?ENDCG
?關(guān)鍵字包圍的計(jì)算著色器源代碼。GLSLPROGRAM
?和?ENDGLSL
?關(guān)鍵字包圍的計(jì)算著色器源代碼視為 GLSL 源代碼,并逐字發(fā)出。這僅在目標(biāo)平臺(tái)為 OpenGL 或 GLSL 平臺(tái)時(shí)才奏效。還應(yīng)注意,雖然自動(dòng)轉(zhuǎn)換的著色器遵循緩沖區(qū)上的 HLSL 數(shù)據(jù)布局,但是手動(dòng)編寫(xiě)的 GLSL 著色器將遵循 GLSL 布局規(guī)則。