最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Unity-平臺(tái)特定的渲染差異

2021-04-17 13:49 作者:unity_某某師_高錦錦  | 我要投稿

Unity 在如下各種圖形庫(kù)平臺(tái)上運(yùn)行:Open GL、Direct3D、Metal?和游戲主機(jī)。在某些情況下,平臺(tái)與著色器語(yǔ)言語(yǔ)義之間的圖形渲染行為方式存在差異。大多數(shù)情況下,Unity Editor 會(huì)隱藏這些差異,但在某些情況下,Editor 無(wú)法為您執(zhí)行此操作。在這些情況下,您需要確保消除平臺(tái)之間的差異。下面列出了這些情況以及發(fā)生這些情況時(shí)需要采取的操作。

渲染紋理坐標(biāo)

垂直紋理坐標(biāo)約定在兩種類(lèi)型的平臺(tái)之間有所不同,分別是 Direct3D 類(lèi)和 OpenGL 類(lèi)平臺(tái)。

  • Direct3D 類(lèi):頂部坐標(biāo)為 0 并向下增加。此類(lèi)型適用于 Direct3D、Metal 和游戲主機(jī)。

  • OpenGL 類(lèi):底部坐標(biāo)為 0 并向上增加。此類(lèi)適用于 OpenGL 和 OpenGL ES。

除了渲染到渲染紋理的情況下,這種差異不會(huì)對(duì)您的項(xiàng)目產(chǎn)生任何影響。在 Direct3D 類(lèi)平臺(tái)上渲染到紋理時(shí),Unity 會(huì)在內(nèi)部上下翻轉(zhuǎn)渲染。這樣就會(huì)使坐標(biāo)約定在平臺(tái)之間匹配,并以 OpenGL 類(lèi)平臺(tái)約定作為標(biāo)準(zhǔn)。

在著色器中,有兩種常見(jiàn)情況需要您采取操作確保不同的坐標(biāo)約定不會(huì)在項(xiàng)目中產(chǎn)生問(wèn)題,這兩種情況就是圖像效果和 UV 空間中的渲染。

圖像效果

使用圖像效果和抗鋸齒時(shí),系統(tǒng)不會(huì)翻轉(zhuǎn)為圖像效果生成的源紋理來(lái)匹配 OpenGL 類(lèi)平臺(tái)約定。在這種情況下,Unity 渲染到屏幕以獲得抗鋸齒效果,然后將渲染解析為渲染紋理,以便通過(guò)圖像效果進(jìn)行進(jìn)一步處理。

如果您的圖像效果是一次處理一個(gè)渲染紋理的簡(jiǎn)單圖像效果,則?Graphics.Blit?會(huì)處理不一致的坐標(biāo)。但是,如果您在圖像效果中一起處理多個(gè)渲染紋理,則在 Direct3D 類(lèi)平臺(tái)中以及在您使用抗鋸齒時(shí),渲染紋理很可能以不同的垂直方向出現(xiàn)。要標(biāo)準(zhǔn)化坐標(biāo),必須在頂點(diǎn)著色器中手動(dòng)上下“翻轉(zhuǎn)”屏幕紋理,使其與 OpenGL 類(lèi)坐標(biāo)標(biāo)準(zhǔn)匹配。

以下代碼示例演示了如何執(zhí)行此操作:

// 翻轉(zhuǎn)紋理的采樣:
// 主紋理的 // 紋理像素大小將具有負(fù) Y。
# if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0) ? ? ? 
 ?uv.y = 1-uv.y; # endif

請(qǐng)參閱 Unity 的著色器替換示例項(xiàng)目中的邊緣檢測(cè)場(chǎng)景(請(qǐng)參閱?Unity 學(xué)習(xí)資源),了解與此相關(guān)的更詳細(xì)示例。此項(xiàng)目中的邊緣檢測(cè)同時(shí)使用屏幕紋理和攝像機(jī)的深度+法線紋理。

GrabPass?也出現(xiàn)了類(lèi)似的情況。生成的渲染紋理實(shí)際上可能不會(huì)在 Direct3D 類(lèi)(非 OpenGL 類(lèi))平臺(tái)上進(jìn)行上下翻轉(zhuǎn)。如果著色器代碼對(duì) GrabPass 紋理進(jìn)行采樣,請(qǐng)使用?UnityCG include?文件中的?ComputeGrabScreenPos?函數(shù)。

在 UV 空間中渲染

在紋理坐標(biāo) (UV) 空間中渲染特殊效果或工具時(shí),您可能需要調(diào)整著色器,以便在 Direct3D 類(lèi)和 OpenGL 類(lèi)系統(tǒng)之間進(jìn)行一致渲染。您還可能需要在渲染到屏幕和渲染到紋理之間進(jìn)行渲染調(diào)整。為進(jìn)行此類(lèi)調(diào)整,應(yīng)上下翻轉(zhuǎn) Direct3D 類(lèi)投影,使其坐標(biāo)與 OpenGL 類(lèi)投影坐標(biāo)相匹配。

內(nèi)置變量?ProjectionParams.x?包含值?+1?或?–1-1?表示投影已上下翻轉(zhuǎn)以匹配 OpenGL 類(lèi)投影坐標(biāo),而?+1?表示尚未翻轉(zhuǎn)。 您可以在著色器中檢查此值,然后執(zhí)行不同的操作。下面的示例將檢查是否已翻轉(zhuǎn)投影,如果已翻轉(zhuǎn),則再次進(jìn)行翻轉(zhuǎn),然后返回 UV 坐標(biāo)以便匹配。

float4 vert(float2 uv : TEXCOORD0) : SV_POSITION 
{ ?
 ?float4 pos; ? 
 ?pos.xy = uv; ? 
 ?// 此示例使用上下翻轉(zhuǎn)的投影進(jìn)行渲染, ? 
 ?// 因此也翻轉(zhuǎn)垂直 UV 坐標(biāo) ? 
 ?if (_ProjectionParams.x < 0) ? ?
 ? ?pos.y = 1 - pos.y; ?
 ?pos.z = 0; ? 
 ?pos.w = 1; ?
 ?return pos; 
}

裁剪空間坐標(biāo)

與紋理坐標(biāo)類(lèi)似,裁剪空間坐標(biāo)(也稱為投影后空間坐標(biāo))在 Direct3D 類(lèi)和 OpenGL 類(lèi)平臺(tái)之間有所不同:

  • Direct3D 類(lèi):裁剪空間深度從近平面的 +1.0 到遠(yuǎn)平面的 0.0。此類(lèi)型適用于 Direct3D、Metal 和游戲主機(jī)。

  • OpenGL 類(lèi):裁剪空間深度從近平面的 –1.0 到遠(yuǎn)平面的 +1.0。此類(lèi)適用于 OpenGL 和 OpenGL ES。

在著色器代碼內(nèi),可使用內(nèi)置宏?UNITY_NEAR_CLIP_VALUE?來(lái)獲取基于平臺(tái)的近平面值。

在腳本代碼內(nèi),使用?GL.GetGPUProjectionMatrix?將 Unity 的坐標(biāo)系(遵循 OpenGL 類(lèi)約定)轉(zhuǎn)換為 Direct3D 類(lèi)坐標(biāo)(如果這是平臺(tái)所期望的)。

著色器計(jì)算的精度

要避免精度問(wèn)題,請(qǐng)確保在目標(biāo)平臺(tái)上測(cè)試著色器。移動(dòng)設(shè)備和 PC 中的 GPU 在處理浮點(diǎn)類(lèi)型方面有所不同。PC GPU 將所有浮點(diǎn)類(lèi)型(浮點(diǎn)精度、半精度和固定精度)視為相同;PC GPU 使用完整 32 位精度進(jìn)行所有計(jì)算,而許多移動(dòng)設(shè)備 GPU 并不是這樣做。

有關(guān)詳細(xì)信息,請(qǐng)參閱數(shù)據(jù)類(lèi)型和精度的文檔。

著色器中的 const 聲明

const?的使用在 Microsoft HSL(請(qǐng)參閱?msdn.microsoft.com)和 OpenGL 的 GLSL(請(qǐng)參閱?Wikipedia)著色器語(yǔ)言之間有所不同。

  • Microsoft 的 HLSL?const?與 C# 和 C++ 中的含義大致相同:聲明的變量在其作用域內(nèi)是只讀的,但可按任何方式初始化。

  • OpenGL 的 GLSL?const?表示變量實(shí)際上是編譯時(shí)常量,因此必須使用編譯時(shí)約束(文字值或其他對(duì)于?const?的計(jì)算)進(jìn)行初始化。

最好是遵循 OpenGL 的 GLSL 語(yǔ)義,并且只有當(dāng)變量真正不變時(shí)才將變量聲明為?const。避免使用其他一些可變值初始化?const?變量(例如,作為函數(shù)中的局部變量)。這一原則也適用于 Microsoft 的 HLSL,因此以這種方式使用?const?可以避免在某些平臺(tái)上混淆錯(cuò)誤。

著色器使用的語(yǔ)義

要讓著色器在所有平臺(tái)上運(yùn)行,一些著色器值應(yīng)該使用以下語(yǔ)義:

  • __頂點(diǎn)著色器輸出(裁剪空間)位置__:SV_POSITION。有時(shí),著色器使用 POSITION 語(yǔ)義來(lái)使著色器在所有平臺(tái)上運(yùn)行。請(qǐng)注意,這不適用于 Sony PS4 或有曲面細(xì)分的情況。

  • __片元著色器輸出顏色__:SV_Target。有時(shí),著色器使用?COLOR?或?COLOR0?來(lái)使著色器在所有平臺(tái)上運(yùn)行。請(qǐng)注意,這不適用于 Sony PS4。

將網(wǎng)格渲染為點(diǎn)時(shí),從頂點(diǎn)著色器輸出?PSIZE?語(yǔ)義(例如,將其設(shè)置為 1)。某些平臺(tái)(如 OpenGL ES 或 Metal)在未從著色器寫(xiě)入點(diǎn)大小時(shí)會(huì)將點(diǎn)大小視為“未定義”。

有關(guān)更多詳細(xì)信息,請(qǐng)參閱有關(guān)著色器語(yǔ)義的文檔。

Direct3D 著色器編譯器語(yǔ)法

Direct3D 平臺(tái)使用 Microsoft 的?HLSL 著色器編譯器。對(duì)于各種細(xì)微的著色器錯(cuò)誤,HLSL 編譯器比其他編譯器更嚴(yán)格。例如,它不接受未正確初始化的函數(shù)輸出值。

使用此編譯器時(shí),您可能遇到的最常見(jiàn)情況是:

  • 具有?out?參數(shù)的表面著色器頂點(diǎn)修改器。按如下方式初始化輸出:

 void vert (inout appdata_full v, out Input o) ?
{ ? ? 
 ?**UNITY_INITIALIZE_OUTPUT(Input,o);** ? 
 ? ?// ... ? ? 
}
  • 部分初始化的值。例如,函數(shù)返回?float4,但代碼只設(shè)置它的?.xyz?值。如果只需要三個(gè)值,請(qǐng)?jiān)O(shè)置所有值或更改為?float3。

  • 在頂點(diǎn)著色器中使用?tex2D。這是無(wú)效的,因?yàn)轫旤c(diǎn)著色器中不存在 UV 導(dǎo)數(shù)。這種情況下,您需要采樣顯式 Mip 級(jí)別;例如,使用?tex2Dlod?(tex, float4(uv,0,0))。此外,還需要添加?#pragma target 3.0,因?yàn)?tex2Dlod?是著色器模型 3.0 的功能。

著色器中的 DirectX 11 (DX11) HLSL 語(yǔ)法

表面著色器編譯管線的某些部分不能理解特定于 DirectX 11 的 HLSL(Microsoft 的著色器語(yǔ)言)語(yǔ)法。

如果您正在使用 HLSL 功能(比如?StructuredBuffers、RWTextures?和其他非 DirectX 9 語(yǔ)法),請(qǐng)將它們包裹在 DirectX X11 專用的預(yù)處理器宏中,如下例所示。

# ifdef SHADER_API_D3D11 
// DirectX11 專用代碼,例如 
StructuredBuffer

使用著色器幀緩沖提取

一些 GPU(最明顯的是 iOS 上基于 PowerVR 的 GPU)允許您通過(guò)提供當(dāng)前片元顏色作為片元著色器的輸入來(lái)進(jìn)行某種可編程混合(請(qǐng)參閱?khronos.org?上的?EXT_shader_framebuffer_fetch)。

可在 Unity 中編寫(xiě)使用幀緩沖提取功能的著色器。要執(zhí)行此操作,請(qǐng)?jiān)谑褂?HLSL(Microsoft 的著色語(yǔ)言,請(qǐng)參閱?msdn.microsoft.com)或 Cg(Nvidia 的著色語(yǔ)言,請(qǐng)參閱?nvidia.co.uk)編寫(xiě)片元著色器時(shí)使用?inout?顏色參數(shù)。

以下示例采用的是 Cg 語(yǔ)言。

CGPROGRAM 
// 只為可能支持該功能的平臺(tái)(目前是 gles、gles3 和 metal) 
// 編譯著色器 
# pragma only_renderers framebufferfetch 
void frag (v2f i, inout half4 ocol : SV_Target) { ? 
 ?// ocol 可以被讀?。ó?dāng)前幀緩沖區(qū)顏色) ?
 ?// 并且可以被寫(xiě)入(將顏色更改為該顏色) ?
 ?// ... 
} ? 
ENDCG

著色器中的深度 (Z) 方向

深度 (Z) 方向在不同的著色器平臺(tái)上不同。

DirectX 11、DirectX 12、PS4、Xbox One、Metal:反轉(zhuǎn)方向

  • 深度 (Z) 緩沖區(qū)在近平面處為 1.0,在遠(yuǎn)平面處減小到 0.0。

  • 裁剪空間范圍是 [near,0](表示近平面處的近平面距離,在遠(yuǎn)平面處減小到 0.0)。

其他平臺(tái):傳統(tǒng)方向

  • 深度 (Z) 緩沖區(qū)值在近平面處為 0.0,在遠(yuǎn)平面處為 1.0。

  • 裁剪空間取決于具體平臺(tái):

    • 在 Direct3D 類(lèi)平臺(tái)上,范圍是 [0,far](表示在近平面處為 0.0,在遠(yuǎn)平面處增加到遠(yuǎn)平面距離)。

    • 在 OpenGL 類(lèi)平臺(tái)上,范圍是 [-near,far](表示在近平面處為負(fù)的近平面距離,在遠(yuǎn)平面處增加到遠(yuǎn)平面距離)。

請(qǐng)注意,使反轉(zhuǎn)方向深度 (Z) 與浮點(diǎn)深度緩沖區(qū)相結(jié)合,可顯著提高相對(duì)于傳統(tǒng)方向的深度緩沖區(qū)精度。這樣做的優(yōu)點(diǎn)是降低 Z 坐標(biāo)的沖突并改善陰影,特別是在使用小的近平面和大的遠(yuǎn)平面時(shí)。

因此,在使用深度 (Z) 發(fā)生反轉(zhuǎn)的平臺(tái)上的著色器時(shí):

  • 定義了 UNITY_REVERSED_Z。

  • _CameraDepth?紋理的紋理范圍是 1(近平面)到 0(遠(yuǎn)平面)。

  • 裁剪空間范圍是“near”(近平面)到 0(遠(yuǎn)平面)。

但是,以下宏和函數(shù)會(huì)自動(dòng)計(jì)算出深度 (Z) 方向的任何差異:

  • Linear01Depth(float z)

  • LinearEyeDepth(float z)

  • UNITY_CALC_FOG_FACTOR(coord)

提取深度緩沖區(qū)

如果要手動(dòng)提取深度 (Z) 緩沖區(qū)值,則可能需要檢查緩沖區(qū)方向。以下是執(zhí)行此操作的示例:

float z = tex2D(_CameraDepthTexture, uv); 
# if defined(UNITY_REVERSED_Z) ? 
z = 1.0f - z; 
# endif

使用裁剪空間

如果要手動(dòng)使用裁剪空間 (Z) 深度,則可能還需要使用以下宏來(lái)抽象化平臺(tái)差異:

float clipSpaceRange01 = UNITY_Z_0_FAR_FROM_CLIPSPACE(rawClipSpace);

注意:此宏不會(huì)改變 OpenGL 或 OpenGL ES 平臺(tái)上的裁剪空間,因此在這些平臺(tái)上,此宏返回“-near”1(近平面)到 far(遠(yuǎn)平面)之間的值。

投影矩陣

如果處于深度 (Z) 發(fā)生反轉(zhuǎn)的平臺(tái)上,則?GL.GetGPUProjectionMatrix()?返回一個(gè)還原了 z 的矩陣。 但是,如果要手動(dòng)從投影矩陣中進(jìn)行合成(例如,對(duì)于自定義陰影或深度渲染),您需要通過(guò)腳本按需自行還原深度 (Z) 方向。

以下是執(zhí)行此操作的示例:

var shadowProjection = Matrix4x4.Ortho(...);
//陰影攝像機(jī)投影矩陣 
var shadowViewMat = ... ? ? 
//陰影攝像機(jī)視圖矩陣 
var shadowSpaceMatrix = ... 
//從裁剪空間到陰影貼圖紋理空間 ? ? 
//當(dāng)引擎通過(guò)攝像機(jī)投影計(jì)算設(shè)備投影矩陣時(shí), 
//"m_shadowCamera.projectionMatrix"被隱式反轉(zhuǎn) 
m_shadowCamera.projectionMatrix = shadowProjection; 
//"shadowProjection"在連接到"m_shadowMatrix"之前被手動(dòng)翻轉(zhuǎn), 
//因?yàn)樗灰暈橹鞯钠渌仃嚒?
 if(SystemInfo.usesReversedZBuffer) { ? ?
 ?shadowProjection[2, 0] = -shadowProjection[2, 0]; ? ?
 ?shadowProjection[2, 1] = -shadowProjection[2, 1]; ? 
 ?shadowProjection[2, 2] = -shadowProjection[2, 2]; ?
 ?shadowProjection[2, 3] = -shadowProjection[2, 3]; 
} ? ?
m_shadowMatrix = shadowSpaceMatrix * shadowProjection * shadowViewMat;

深度 (Z) 偏差

Unity 自動(dòng)處理深度 (Z) 偏差,以確保其與 Unity 的深度 (Z) 方向匹配。但是,如果要使用本機(jī)代碼渲染插件,則需要在 C 或 C++ 代碼中消除(反轉(zhuǎn))深度 (Z) 偏差。

深度 (Z) 方向檢查工具

  • 使用?SystemInfo.usesReversedZBuffer?可確認(rèn)所在平臺(tái)是否使用反轉(zhuǎn)深度 (Z)。


Unity-平臺(tái)特定的渲染差異的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
凤阳县| 汉源县| 静乐县| 凤翔县| 盐池县| 庆元县| 丰镇市| 通州区| 霍城县| 延吉市| 连南| 涪陵区| 莆田市| 普格县| 监利县| 吉水县| 安国市| 蒙山县| 武宁县| 迁西县| 合山市| 柳河县| 洛南县| 浦城县| 元朗区| 无为县| 太白县| 清涧县| 虎林市| 黑龙江省| 平乐县| 呼和浩特市| 海宁市| 万源市| 隆化县| 瑞昌市| 江源县| 赤峰市| 玉环县| 应城市| 仁怀市|