【HLSL ddx / ddy】
在光柵化的時刻,GPUs會在同一時刻並行運行很多Fragment Shader,但是並不是一個pixel一個pixel去執行的,而是將其組織在2x2的一組pixels分塊中,去並行執行。
偏導數就正好是計算的這一塊像素中的變化率。從下圖可以看出來ddx 就是右邊的像素塊的值減去左邊像素塊的值,而ddy就是下面像素塊的值減去上面像素塊的值。其中的x,y代表的是屏幕坐標。
【偏導數的應用】
1、LOD的確定。
大家應該都知道mipmap 的用處,但是可能並不知道mipmap的核心在選擇到底用那一塊mipmap的level時,靠的就是偏導數。屏幕空間的貼圖UV偏導數過大的時候代表貼圖離我們過遠,就會選擇低等級的mipmap。
比如,原圖的LOD=1,次大的LOD=2,依此類推。
在Shader中使用tex2D(tex, uv)的時候相當於在GPU內部展開成下面:
tex2D(sampler2D tex, float4 uv)
{
float lod = CalcLod(ddx(uv), ddy(uv)); uv.w= lod; return tex2Dlod(tex, uv); }
2、計算法線。
如果調用ddx(Pos),和ddy(Pos)這個代表求出相鄰的2個像素塊之間坐標的差值,即下面圖中的紅色和綠色2個矢量,而這2個矢量都在這個三角形的平面上,那么執行 normalize( cross(ddx(pos),ddy(pos)) ) 就求出的面的法線。
但是這里要注意,在HlSL上面,或者Unity上面要寫成normalize( cross(ddy(pos),ddx(pos)) ),不然法線是反向的。這個是由於左右手坐標系引起的。
void surf (Input IN, inout SurfaceOutput o) { o.Albedo = normalize(cross(ddy(IN.worldPos),ddx(IN.worldPos))); }
3、貼圖加強勾邊。
void surf (Input IN, inout SurfaceOutput o) { half4 c = tex2D(_MainTex, IN.uv_MainTex); //c += ddx(c)*2 + ddy(c)*2;這行代碼開啟和關閉的效果 o.Albedo = c.rgb; o.Alpha = c.a; }
左邊是直接顯示圖片,右邊是在圖片上面加上x和y的偏導數。
【fwidth】
This function computes the following: abs(ddx(x)) + abs(ddy(x)).
參考:
1、https://blog.csdn.net/wylionheart/article/details/78026707
2、http://www.aclockworkberry.com/shader-derivative-functions/#footnote_3_1104