Spine在Unity中半透明重疊問題優化


 

 

如圖,在2D游戲中常使用到spine動畫,比如人物動態立繪

為了與UI場景結合,使用SkeletonGraphic模式

而在部分情形下,需要spine動畫(與界面一起)淡入或淡出

此時spine表現效果不佳,會出現透視效果

如圖所示

 

 

可以明顯看出,各骨骼蒙皮出現了透視疊加的視覺效果

原本應被腿部遮擋的服飾也透視了出來

那么如何解決這個問題呢?

 

目前看來效果最好的方式是使用RenderTexture把100%alpha的spine渲染到一張紋理上

再對紋理設置alpha實現半透效果

 

此外我也嘗試了通過shader實現類似效果

現記錄如下

 

1.雙通道使用深度寫入

在馮樂樂的書中有一個shader可實現3D半透明物體的渲染Chapter8-AlphaBlendZWrite.shader

然而在我們這里並不適用

因為spine貼圖中的各個頂點深度都是一致的

 

 

 

 

這里ZSpacing默認是0

若手動修改其值可以改變各頂點的Z值

進而可使用深度寫入/深度測試

但spine的表現會受到較大影響,不可取

 

 

 

2.雙通道使用模板測試

這個方式相對更接近我們的目標(雖然比起RenderTexture效果遜色)

思路如下

spine渲染各個骨骼按從底部到頂部的順序,最高層級的骨骼最后渲染

因此若只渲染最高層級的像素,即不會存在透視

 

首先第一個pass輸出一個空顏色rgba0,0,0,0

注:若輸出的顏色不為空,該顏色很可能會顯示出來,雙通道先后輸出的顏色受混合模式決策后進入幀緩沖區

並對模板值操作,使通過alpha測試的部分模板值+1

Stencil
{
    Ref 0 // 參考值0(並未使用)
    Comp Always // 比較函數,總是通過
    Pass IncrSat // 比較通過后的模板操作,模板值加一
    ReadMask [_StencilReadMask]
    WriteMask [_StencilWriteMask]
}

 

然后第二個pass對spine圖像正常采樣

並使用一套不同的模板邏輯

Stencil
{
    Ref 1 // 參考值1
    Comp Equal // 比較函數,僅當參考值等於模板值時通過
    Pass Keep // 比較通過后,不改變模板值
    Fail DecrSat // 比較失敗時,模板值減一
    ReadMask [_StencilReadMask]
    WriteMask [_StencilWriteMask]
}

 

注:雙通道時可以指定不同的Stencil寫在Pass內

 

這里詳細說明一下核心邏輯

比如當一個像素點包含了衣服和手臂兩個重復的骨骼時

且在正常疊加順序時是衣服被手臂遮擋

當渲染時,首先屏幕空間的模板值被清零(對應每個像素點模板值均清零)

通道1

按順序先后渲染衣服/手臂(注:衣服手臂均在同一張spine圖集內,所以是一批的,順序是spine導出時就決定確定的)

該像素點進行兩次模板檢測,均通過(Comp Always),模板值變為2(Pass IncrSat)

通道2

仍是按順序先后渲染衣服/手臂

而此次模板參數決定了,前n-1次模板測試都會失敗,且失敗后模板值-1

直到最后一次,也就渲染最上層手臂時,模板值已經減到了1,與Ref參考值相等,通過模板測試

所以只會渲染手臂對應的部分

 

效果如下

該效果與我們期望的差距很大

到底發生了什么呢?

通過模板的確只渲染了最上層的骨骼蒙皮

但問題是最上層的骨骼蒙皮往往是方形區域伴隨較大塊透明區域

而我們在模板測試中,並未區別區里透明區域與非透明區域

理想情況應該是,對於一個像素點,僅當骨骼蒙皮與其有重疊且重疊部分非透明時才修改其模板值

於是我們對通道1做以下修改

 

fixed4 frag1 (VertexOutput IN) : SV_Target

{

// 對spine貼圖采樣得到rgba顏色 部分代碼省略

// 注意clip丟棄掉的部分(接近透明的像素)不會寫入(修改)模板值

#ifdef UNITY_UI_ALPHACLIP

clip (color.a - 0.01);

#endif

return half4(0.0, 0.0, 0.0, 0.0);

}

 

修改后表現如下

可以看出在人物右腿后的披風完全沒有透視了

但此時還存在兩個問題

 

1.骨骼蒙皮之間的邊緣處出現透視,漏出了底色

邊緣判定時若只渲染最上層骨骼,很可能其邊緣處alpha很小

本應透入下方骨骼,但卻因為現有的機制,直接透出了底色

 

2.模板計算問題

當疊加層數較多時,還會存在模板計算的問題

假設某點處疊有5層骨骼

自下而上

第五層 非透明

第四層 全透明

第三層 非透明

第二層 全透明

第一層 非透明

經過pass1后模板值變成3

顯然我們希望的是只渲染第一層

但在pass2處理時,第五/第四兩層模板檢測失敗后,模板值已經變成了1

而由於Pass Keep的設定,因此后面的第三/第二/第一層均可通過模板檢測

若僅通過第二/第一層尚無影響,因為第二層是全透明的

但第三層通過的話必然會繼續引發透視的問題

 

另外,肯定還會想到混合模式

如果混合模式使用Blend One Zero

一定程度上可以丟棄掉底層像素只保留最上層

與我們模板測試所實現的方案非常相似

區別在於,混合模式下完全拋棄了背景

spine半透后只能透出黑色而模板的方式可以透出背景圖

其次就是部分區域不能正常展示

比如眼睛這里,因為眼球基礎上還有一層類似妝的接近透明的層,於是眼球被完全丟棄了

 

 

參考文獻:枚舉值對照表

Comp [_StencilComp] 為什么是浮點數? - 知乎

https://docs.unity.cn/cn/current/Manual/SL-Stencil.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM