您當前的位置:首頁 > 攝影

關於unity shader中偏導重建法向量

作者:由 大丘丘 發表于 攝影時間:2022-01-23

非本人原創,只是用做知識分享,望各位大佬不喜勿噴。

話不多說,直接進入正題:

首先複習一下偏導數,這個應該是比較基礎的概念。設定一個函式為

z =f(x,y)

,當y在y0方向上不動,我們對x方向上假設在x0出有增量

\Delta x

,我們就能輕易的求出點

(x_{0},y_{0})

出的增長斜率

\lim_{x \rightarrow 0}\frac{f(x_{0} + \Delta x, y_{0}) - f(x_{0}, y_{0})}{\Delta x}

,這個過程就是關於

z =f(x,y)

函式在點

(x_{0},y_{0})

關於x求偏導數。

同樣在y方向上也可以求

z =f(x,y)

(x_{0},y_{0})

點關於y的偏導數。

那麼瞭解這一點對於我們計算法線有什麼關係?我們首先來了解一下gpu裡面的情況,如下圖所示:

關於unity shader中偏導重建法向量

由於在gpu裡面計算畫素的時候不是一個畫素一個畫素的算,而是把畫素組織成2 * 2的pixels分塊上去做並行處理。如果我們對我們的畫素做偏導,就相當於去求這個畫素某個數值上的變化率。這裡的話我補充一下,就是導數的本質就是在某個點

(x0,y0)

上做

(x0 + \Delta x,y0)

相對於前者的斜率,同時在硬體上就表示為相鄰畫素的相減,也就是近似無限小,兩者之間有著不可言喻的緣分。

當我們分別對x或者y求偏導的時候,其方向也不一樣。

我們再考慮一下我們求法線的方法,切線Tangent和副切線BisTangent做叉乘。既然要求法線我們就需要獲取到我們的切線和副切線。切線和副切線有些同學可能認為這不就是與一個面或者一個點相切的兩條線麼。但其實我們可以用另外一種定義去定義我們的切線和副切線:

切線和副切線是頂點座標變化不同方向上的變化斜率。

怎麼理解,這裡的話我用我一個群裡的大佬的圖來給大家詳細解釋:

關於unity shader中偏導重建法向量

三維座標,二維梯度

在3D座標空間中。我們可以把頂點座標的變化看成是一個函式,對x做偏導就是求頂點變化函式在點

(x_{0},y_{0},z_{0})

關於x方向上的斜率,也就是切線,在y方向上道理相同。所以在unity shader中,我們對x或者y求偏導就能得到其切線和副切線,然後我們就可以叉乘來計算我們的發現了,注意計算完畢後一定要加個normalize來歸一化。

程式碼異常簡單,就一行:

float3 normal = normalize(cross(ddy(Pos),ddx(Pos)));

當然偏導數在unity shader裡面還有很多其他有意思的用法,包括我們熟知的mipmap等等,我這裡把連結給大家貼出來,大家感興趣的可以一起學習進步。

Unity shader 中ddx/ddy偏導數的原理和簡單應用

另外還有一篇關於uv的文章寫的非常好,也推薦一波:

謎之裙襬:切線空間(Tangent Space)完全解析

另外還有一個地方關於矩陣正交化,這裡我也附上一個地址:

線性代數系列(十一)——正交矩陣和正交化_Thincor的部落格-CSDN部落格_矩陣正交化

更新2022年1月24日

在學SDF的時候我又看到了一種比較有意思的寫法,不過這種演算法主要是用在SDF上的。

我們假設用SDF來表達物體的表面,設定一個半徑為1球心座標為(0,0,0)球,用

x^{2} + y^{2} + z^{2} = 1

來表示,如果想求得一個畫素點的法線,可以用下面這個定理來求得(不過這種寫法一般是SDF才會用到):

關於unity shader中偏導重建法向量

由上述公式,我們可以寫出下面的程式碼:

float3 getSDFNormal(float3 pos){

float dx = (f(pos + float(0。001, 0。0, 0。0)) - f(pos))/0。001;

float dy = (f(pos + float(0。0, 0。001, 0。0)) - f(pos))/0。001;

float dz = (f(pos + float(0。0, 0。0, 0。001)) - f(pos))/0。001;

return normalize(float3(dx,dy,dz));

}

float f(float3 pos){

return sqrt(pow(pos。x - 0。0, 2) + pow(pos。y - 0。0, 2) + pos(pos。z - 0。0, 2)) - 1;

}

標簽: 切線  POS  float  畫素  001