修正半透明頭發(fā)的渲染異常

修正半透明頭發(fā)的渲染異常

這兩天在整理 小甜甜 的捏臉系統(tǒng)圈盔,順帶把前項目 半透明頭發(fā)渲染異常的bug 修正了,效果如下:

screenshot1.png

其實悄雅,前項目的頭發(fā)工作良好驱敲,只是有一點 半透明渲染順序 的小瑕疵,但正如前文 一個自陰影的Bug 所提到的:我在遷移shader的時候因為偷懶宽闲,把頭發(fā)改成了 Surface Shader众眨,從而帶來了一些新的問題。


問題一:關(guān)于Surface Shader的alpha指令

首先容诬,我犯了第一個錯誤娩梨,改 Surface Shader 的過程中,我漏掉了 alpha 指令的設(shè)置览徒,shader變成了 實體渲染狈定,表現(xiàn)如下:

screenshot2.png

關(guān)于 Surface Shader的alpha指令,可以參考Unity幫助文檔:

alpha or alpha:auto - Will pick fade-transparency (same as alpha:fade) for simple lighting functions, and premultiplied transparency (same as alpha:premul) for physically based lighting functions.

alpha:blend - Enable alpha blending.

alpha:fade - Enable traditional fade-transparency.

alpha:premul - Enable premultiplied alpha transparency.

雖然我指定了 Queue = TransparentBlend SrcAlpha OneMinusSrcAlpha习蓬,但因為沒設(shè)置 alpha纽什,Unity最終生成的代碼給我加了這么一句:

UNITY_OPAQUE_ALPHA(c.a);

UNITY_OPAQUE_ALPHA定義如下:

#define UNITY_OPAQUE_ALPHA(outputAlpha) outputAlpha = 1.0

這里認(rèn)為是 實體渲染,強(qiáng)制的把a(bǔ)lpha設(shè)置為 1 了友雳。

修正這個問題很簡單稿湿,加上 alpha 指令的設(shè)置即可:

#pragma surface surf BGHair fullforwardshadows addshadow vertex:vert alpha

問題二:半透明的渲染順序

加上 alpha 后,頭發(fā)通透了好多押赊,但是新的問題來了饺藤,當(dāng) 頭發(fā)的半透明部分相互交錯 時,渲染表現(xiàn)錯誤:

screenshot3.png

因為是半透明渲染流礁,Surface Shader生成的代碼開啟了 深度測試涕俗,關(guān)閉了 深度緩沖寫入,當(dāng) 半透部分相互交錯 時神帅,前后關(guān)系難以保證再姑。

這是半透材質(zhì)經(jīng)常遇到的問題,我們可以把頭發(fā)模型拆成 實體半透 兩部分找御,先渲染 實體部分元镀,再渲染 半透部分绍填,在實體的基礎(chǔ)上做Alpha混合,從而盡可能避免半透交錯的機(jī)會栖疑。

不過當(dāng)初做這個頭發(fā)的時候讨永,并沒有拆分模型,做法也很簡單:開啟 深度緩沖寫入遇革,讓頭發(fā)的半透明部分僅局限于 發(fā)尾卿闹,由于半透區(qū)域很小,一般情況下很難穿幫萝快,不過某些角度下細(xì)看還是會有問題锻霎。

比如下圖紅圈標(biāo)注的部位,后面的頭發(fā)因為 深度測試 沒通過揪漩,導(dǎo)致前面的頭發(fā)直接和背景混合旋恼,引發(fā)了表現(xiàn)錯誤。

screenshot4.png

此外氢拥,因為遷移到了 Surface Shader蚌铜,我發(fā)現(xiàn)如果打開了 alpha 指令,無論我是否指定 ZWrite On嫩海,Unity給我生成的代碼始終是 ZWrite Off 的。


解決方式一:用AlphaTest代替AlphaBlend

如果這里我們用 AlphaTest 來取代 AlphaBlend 囚痴,效果會如何呢叁怪?

作為測試,簡單的加一句 clip深滚,并且關(guān)閉 alpha 指令:

clip(mainColor.a - 0.6);

效果如下:

screenshot5.png

渲染正確了奕谭,只是發(fā)尾太硬,用美術(shù)的話說:不夠透氣痴荐。


解決方式二:加一個Pass

方式一 不夠完美血柳,不過我們可以用它做一個 額外的Pass,類似拆分模型后的 實體部分渲染生兆,渲染完畢再做之前的 半透明渲染难捌。

代碼如下:

Pass
{
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
    #include "UnityCG.cginc"

    sampler2D _MainTex;
    float4 _MainTex_ST;

    half4 _Color;
    half4 _Color2;

    half _Color2Offset;

    struct appdata            
    {
        float3 pos : POSITION;    
        float3 uv0 : TEXCOORD0;   
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };
 
    struct v2f 
    {
        UNITY_POSITION(pos);
        float4 uv0 : TEXCOORD0;
        UNITY_VERTEX_OUTPUT_STEREO
    };
 
    v2f vert (appdata IN)
    {
        v2f o;
        UNITY_SETUP_INSTANCE_ID(IN);
        UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);

        o.pos = UnityObjectToClipPos(IN.pos);
        o.uv0.xy = TRANSFORM_TEX(IN.uv0, _MainTex);

        return o;
    }
 
    half4 frag(v2f IN) : SV_Target
    {
        half4 mainColor = tex2D( _MainTex, IN.uv0.xy );

        clip(mainColor.a - 0.999);

        half3 hairColor = _Color.rgb * mainColor.r;
        half mixStrength = saturate(mainColor.g + _Color2Offset);
        hairColor = lerp(hairColor, _Color2.rgb, mixStrength);

        return half4(hairColor, 1);
    }
    ENDCG          
}

代碼很簡單,最主要的就是下面這句:

clip(mainColor.a - 0.999);

這里把原來的半透部分盡可能的裁剪掉鸦难,只保留實體的輪廓根吁,如下:

screenshot6.png

在這個基礎(chǔ)之上,再做一次半透明渲染即可合蔽。


局限

采用 方式二 后击敌,原先 發(fā)尾 部分因為 半透重疊 引發(fā)的 渲染瑕疵 也可以更大程度的緩解了,如下圖:

screenshot7.png

此外拴事,需要注意的是沃斤,這里能良好工作圣蝎,頭發(fā)的半透部分僅局限于 發(fā)尾 也是一個重要因素。

最后換個臉妝再來一張:

screenshot8.png

個人主頁

本文的個人主頁鏈接:https://baddogzz.github.io/2019/12/24/Fix-Hair-Transparent/

好了衡瓶,拜拜捅彻。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鞍陨,隨后出現(xiàn)的幾起案子步淹,更是在濱河造成了極大的恐慌,老刑警劉巖诚撵,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缭裆,死亡現(xiàn)場離奇詭異,居然都是意外死亡寿烟,警方通過查閱死者的電腦和手機(jī)澈驼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來筛武,“玉大人缝其,你說我怎么就攤上這事∨橇” “怎么了内边?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長待锈。 經(jīng)常有香客問我漠其,道長,這世上最難降的妖魔是什么竿音? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任和屎,我火速辦了婚禮,結(jié)果婚禮上春瞬,老公的妹妹穿的比我還像新娘柴信。我一直安慰自己,他們只是感情好宽气,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布随常。 她就那樣靜靜地躺著,像睡著了一般抹竹。 火紅的嫁衣襯著肌膚如雪线罕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天窃判,我揣著相機(jī)與錄音钞楼,去河邊找鬼。 笑死袄琳,一個胖子當(dāng)著我的面吹牛询件,可吹牛的內(nèi)容都是我干的燃乍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼宛琅,長吁一口氣:“原來是場噩夢啊……” “哼刻蟹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嘿辟,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤舆瘪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后红伦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體英古,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年昙读,在試婚紗的時候發(fā)現(xiàn)自己被綠了召调。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡蛮浑,死狀恐怖唠叛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沮稚,我是刑警寧澤艺沼,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站壮虫,受9級特大地震影響澳厢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜囚似,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望线得。 院中可真熱鬧饶唤,春花似錦、人聲如沸贯钩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽角雷。三九已至祸穷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間勺三,已是汗流浹背雷滚。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留吗坚,地道東北人祈远。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓呆万,卻偏偏與公主長得像,于是被迫代替她去往敵國和親车份。 傳聞我的和親對象是個殘疾皇子谋减,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容