練習專案 六 Back facing描邊法

2021-10-20 14:46:03 字數 2842 閱讀 5824

描邊,在**渲染中是乙個非常重要的主題。目前比較流行的描邊方法有兩種:一種是基於後處理的描邊,這種方式相對不容易定製,適用於對複雜場景的描邊;一種是過程式描邊,通過兩次繪製,一次繪製本體,一次繪製描邊。

本文主要介紹第二種描邊方式,在《guilty gear xrd》中稱其為back facing法。

基本思路是通過兩次繪製,一次繪製本體,一次繪製描邊。

這裡就有個問題,兩次繪製的順序怎麼處理呢?

經過試驗可以發現,兩種順序可以得到相同的結果。

在urp中,如果沒有設定lightmode,那麼urp預設使用srpdefaultunlit。所以,可以將繪製本體pass的lightmode設為srpdefaultunlit,而將繪製描邊pass的lightmode設為universalforward。這樣,就可以實現先繪製本體,再繪製描邊的功能了。主要的**如下:

varyings vert(attributes input)

此時,可以得到如下的結果:

檢視frame debugger,可以發現,確實是先繪製本體,再繪製描邊。

上面的步驟,得到了乙個基本的描邊效果。但是當物體遠離相機時,可以發現,描邊會變細。我們希望得到的,是描邊寬度不隨物體距離相機遠近而變化的效果。

這裡就需要多提乙個知識點。物體變換到投影空間後,x、y代表投影空間下的橫縱座標,z代表投影空間下的深度,w等於-z,w用於後面的齊次除法。我們希望得到的,是在螢幕上顯示固定寬度的描邊,那麼頂點向外延伸的距離就應該是ndc空間下的固定距離,而不是投影空間下的固定距離。於是,在投影空間下計算向外延伸的距離的時候,乘上w的值,這樣,在之後的齊次除法中會將座標值除以w,得到的就是不會隨距離相機遠近不同的描邊寬度了。**如下:

output.vertex = transformobjecttohclip(input.positionos.xyz);

float3 normal = transformobjecttoworldnormal(input.normalos);

float2 offset = transformworldtohclipdir(normal).xy;

output.vertex.xy += offset * output.vertex.w * _outline;

上面兩個部分,得到的都是寬度一致的描邊。但是,當試著對得到的offset進行歸一化時,就會出現下面這種問題。**如下:

這是因為,觀察空間變換到投影空間xy會非等比縮放,所以正常的法線在投影空間就是非歸一化的。在投影空間下,output.vertex.xy未歸一化,如果法線offset歸一化了,最後計算得到的偏移值在xy方向上的拉伸程度就會不同。所以,這裡不需要對offset歸一化。

當然,也可以對offset歸一化後,再根據螢幕的寬高比計算出乙個係數,將offset.y乘以這個係數,得到乙個新的法線,這樣也可以解決上面的問題。

output.vertex = transformobjecttohclip(input.positionos.xyz);

float3 normal = transformobjecttoworldnormal(input.normalos);

float2 offset = normalize(transformworldtohclipdir(normal).xy);

//將近裁剪面右上角位置的頂點變換到觀察空間

float4 nearupperright = mul(unity_camerainvprojection, float4(1, 1, unity_near_clip_value, _projectionparams.y));

//求得螢幕寬高比

float aspect = abs(nearupperright.x / nearupperright.y);

offset.y *= aspect;

output.vertex.xy += offset * output.vertex.w * _outline;

當然,這種方式相對上一種方式有點麻煩,只是提供一種思路。

完整**

在《罪惡裝備-xrd》的分享中,也提到了在**渲染中,其他的一些提公升描邊質量的方法。比如,使用頂點色儲存描邊粗細、顏色等,可以更加精細地控制描邊。最近在實際的工作中,也遇到一種提公升描邊效果的方式:根據頂點距離相機的距離,計算出乙個引數,在代表描邊寬度的漸變貼圖中取樣,這樣,可以定製各種不同距離的描邊寬度。

C 小練習(六)

程式設計將乙個二維陣列元素變換為逆向存放,即按元素在記憶體中的物理排列位置,第乙個元素變成倒數第乙個元素,第二個元素變成倒數第二個元素,依此類推。例如,原始二維陣列為,逆向存放後變為。試建立乙個類revarr,完成上述工作。具體要求如下 1 私有資料成員 int a m n 初始化時存放原始二維陣列...

筆試題練習(六)

1,輸入n,列印 n n螺旋矩陣 比如 n 3,列印 n 4,列印 1 2 3 4 109 8 7 author phinecos since 2005 05 27 public class test inti 上 for i n m i m i 右for i n m 1 i1 i 下 for i ...

演算法筆記練習(六)

相關操作 for int i 0 i iterator it vt.begin it vt.end it 操作 for set itaretor it st.begin it st.end it 獲取長度 st.size 清空容器 st.clear 操作連線 str str1 str2 通過字典序比...