URP | Depth 深度
目錄

效果

目的
學(xué)習(xí)深度的原理以及計算過程。
了解觀察空間的概念,ComputeScreenPos函數(shù)和Linear01Depth函數(shù)的使用。
粒子切邊問題。
Eye Depth | 觀察空間
觀察空間看到的物體是什么樣子的?
第一種方法
觀察空間是物體相對于攝像機所在平面的距離,(攝像機的深度是 0 ,物體是w)因為是相對,所以Z是相反的。
我們前計算頂點距離攝像機數(shù)值。

第二種方法
在頂點著色器階段,使用函數(shù)ComputeScreenPos裁剪空間轉(zhuǎn)換成屏幕空間,
0代表觀察空間位置,w代表頂點位置,
擴展
為什么輸出是屏幕空間.w分量,不應(yīng)該是z嗎?
從觀察空間到裁剪空間的矩陣是投影矩陣,但要注意的是,投影矩陣并沒有實現(xiàn)真正的投影,而是將頂點變換到齊次裁剪坐標(biāo),為裁剪做準(zhǔn)備,
經(jīng)過投影矩陣變換后,
(透視相機)透視投影下的頂點齊次坐標(biāo)屏幕空間.w值為**-position.z** 。深度值就儲存到w里了。

計算過程參考大佬方法
3D數(shù)學(xué)-透視投影 - 知乎 (zhihu.com)????
圖形學(xué)基礎(chǔ) - 變換 - 投影 - 知乎 (zhihu.com)
輸出頂點
效果和上面的一樣 ,
因為目前數(shù)值很大所以曝光了。越距離攝像機越遠(yuǎn)數(shù)值越大。

這一步可以理解是獲取頂點在屏幕位置的數(shù)值,那我們下一步獲取深度值。????
獲取深度值
URP管線設(shè)置開啟深度圖
打開渲染管線確認(rèn)是否開啟深度(Depth)

ShaderGraphs 里獲取深度節(jié)點

Shader中獲取深度圖
聲明深度變量
頂點著色器階段---輸入 ?裁剪空間齊次坐標(biāo)轉(zhuǎn)換到屏幕空間的齊次坐標(biāo)
注意:這里是輸入的是裁剪空間位置坐標(biāo)
片元著色器階段—輸出結(jié)果
效果

代碼

問題
問題1 為什么裁剪空間轉(zhuǎn)換成屏幕空間需要在除 scrPos.w 分量?
在頂點著色器階段,我們已經(jīng)使用函數(shù)ComputeScreenPos 把裁剪空間轉(zhuǎn)換成屏幕空間了。
為什么到片元著色器階段還要使用 ?屏幕空間.xy / 屏幕空間.w 分量。
從攝像機空間到裁剪空間的矩陣是投影矩陣,但要注意的是,投影矩陣并沒有實現(xiàn)真正的投影,而是將頂點變換到齊次裁剪坐標(biāo),為裁剪做準(zhǔn)備,
經(jīng)過投影矩陣變換后,
(透視相機)透視投影下的頂點齊次坐標(biāo)屏幕空間.w值為**-position.z** 。深度值就儲存到w里了。
(正交相機) 正交投影的w值為1
我們上一節(jié)護(hù)盾篇介紹到 position.z就是物體的深度值。?

裁剪空間下齊次坐標(biāo),x和y的取值范圍是(-w,w) ?然后 W 分量**(-z)**
屏幕空間下的齊次坐標(biāo),取值范圍是(0-1),W分量 (-z)
最后通過透視除法之后xy的取值范圍就是(0-1)了。
所以 :這個過程通過齊次除法(透視除法)轉(zhuǎn)換成普通坐標(biāo)
問題2 為什么還需要使用Linear01Depth函數(shù)對深度圖處理。
采樣得到的深度值,在透視投影的情況下不是線性的,因為經(jīng)過透視投影和齊次除法后,Zndc和Zview的倒數(shù)是線性關(guān)系,我們采樣得到了非線性的深度值.


判斷物體是否和其它物體相交
實現(xiàn)這個效果我們就需要判斷當(dāng)前物體的深度值與深度圖中對應(yīng)的深度值是否在一定范圍內(nèi),
如果是則判定為相交。
第1步我們在裁剪空間計算出物體的位置信息,
第2步獲取場景深度數(shù)據(jù),物體的像素深度。
第3步 在判斷物體是否和場景中的其他物體相交。
特效中粒子和模型交叉時會出現(xiàn)切邊。就可以使用這樣的方法解決。
默認(rèn)效果,帶有切邊

1. 第一種方法 ?使用裁剪空間計算深度
第一種方法,護(hù)盾使用的方法。
開始計算出物體在屏幕空間的位置信息。
計算空間深度轉(zhuǎn)換成線性
這里使用函數(shù)Linear01Depth 轉(zhuǎn)換到(0-1)
注意 :函數(shù)定義在Common.hlsl里,注意它和build in的同名函數(shù)的參數(shù)不同

在計算模型線性深度
最后計算出物體之間的深度效果
效果

參數(shù)

代碼

2. 第二種 使用屏幕空間獲取深度
使用函數(shù)ComputeScreenPos 裁剪空間信息轉(zhuǎn)換到齊次空間下屏幕空間位置 。
頂點著色器階段
在片元著色器階段
輸出結(jié)果

代碼
ComputeScreenPos | 計算齊次空間下屏幕坐標(biāo)位置
URP內(nèi)置獲取
擴展 ComputeScreenPos ?屏幕齊次坐標(biāo)
透視投影之后透視除法之前的坐標(biāo)空間被稱為裁剪空間,也叫齊次(裁剪)空間
看這個函數(shù)輸入的是一個位置信息,該函數(shù)傳入的是齊次空間下的坐標(biāo),
下面我們進(jìn)行齊次坐標(biāo)推導(dǎo)到屏幕坐標(biāo)
頂點在變換到齊次坐標(biāo)后,其x和y分量的范圍在[-w, w]。
假設(shè)目前屏幕的寬度為width,高度為height,那么屏幕坐標(biāo)的計算方法為:
Unity Shader
這樣變換完的結(jié)果和我們上面計算的結(jié)果一樣。
總結(jié)
ComputeScreenPos 函數(shù)是計算裁剪空間轉(zhuǎn)換到屏幕空間

LinearEyeDepth和Linear01Depth
這是這倆個函數(shù)的對比。
Linear01Depth會返回相機空間中范圍在(0,1]的深度,近平面為Near/Far,遠(yuǎn)平面為1。
LinearEyeDepth會返回相機空間中的深度,近平面為Near,遠(yuǎn)平面為Far。
總結(jié)
這倆個計算深度的方法不同,都是計算物體深度,第二種方法更簡單。
擴展:實現(xiàn)水深度
使用上面2種制作一下水面深度的效果。
第一種,裁剪空間和像素深度
在片元計算器階段 使用裁剪空間和屏幕位置計算頂點位置。
獲取渲染深度
輸入裁剪空間的像素深度
計算倆個物體的深度


第二種 ?自定義函數(shù)求深度
定義ComputeScreenPos函數(shù) ,上面介紹過。
這個函數(shù)是把裁剪空間齊次坐標(biāo)轉(zhuǎn)換到屏幕空間的齊次坐標(biāo),映射到 (0,1)范圍
定義一個函數(shù)獲取全部深度,輸出是float類型,所以輸出單通道。
在定義一個計算倆個物體深度
注意 : ScreenPosition.xy / ScreenPosition.w ? 是在做透視除法,像素除深度
在片元著色器階段輸出

代碼