日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

新版“峡谷第一美”妲己尾巴毛发制作分享

發布時間:2024/9/3 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 新版“峡谷第一美”妲己尾巴毛发制作分享 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

關于作者:梁家斌,騰訊互動娛樂天美工作室群高級游戲美術師。
?


之前有很多人來詢問新版妲己寶寶
毛茸茸的尾巴 做法,
先謝謝大家對這個毛發效果的認可,
我在這里就簡單的分享一下,
毛發的實現思路和制作方法。

毛絨材質在生活中出現的頻率非常高,
但是在各種游戲中,
我們卻很少看到這種材質效果的良好表現,
原因在于它們的制作與渲染成本都太高了。
所以, 實時毛發渲染
是業內最為期待的次世代特效之一。

我們先看看這些材質的特征:
?

[ 毛茸茸的衣服 ]

[ 可愛的毛絨玩具 ]

[ 毛茸茸的動物 ]


他們有著柔軟的豐富的外輪廓、
柔和的光影、溫暖,
這種材質表現一直是女孩子所喜愛的。
?

[ 微觀的毛發,其實可以理解為一根根的圓柱體,越細毛發的質感越柔軟 ]

[ 無數細小的圓柱體拼合在一起,就形成了我們看到的皮毛效果 ]


因為毛發復雜性與龐大的計算量
(每根毛發產生的陰影遮擋),
所以在毛發渲染方面,
基本一直都是離線渲染的專利。
?

[ MAYA毛發渲染 ]

[ 迪士尼《瘋狂動物城》毛發渲染 ]


直到最近,
GPU處理能力才達到實時計算毛發的標準,
當然那也是針對PC平臺而言,
我們手機暫時還望塵莫及。
?

[ Square Enix 夜光引擎的毛發 ]

[ 插片-毛發制作 ]


我們一般游戲的毛發渲染,
都是將毛發紋理放到模型面片上面,
用AlphaBlend或者AlphaTest剔除鏤空區。

但這兩者也都無法盡善盡美:
-AlphaBlend沒有深度會有模型穿插問題。
-AlphaTest有頂點深度但邊緣鋸齒感嚴重,
需要在SSAA下面才不會有明顯的鋸齒。
-兩者結合使用效果比較好,
但會帶來更高的性能消耗。

所以至今為止,
游戲上面都很難做到滿意的毛發表現,
尤其是手游,
往往我們只能從設計層面去規避這些問題。
?



要制作一個東西,
我們必須抓住它的特點。
那么毛發有哪些特征呢?
我稍微歸納了一下:

通透性-次表面散射:
毛發是非常的細小的,
光線很容易就可以穿透它的表面,
尤其是淺色毛發,
顏色越深吸收光線的能力越強,
所以深色發毛的透光性相對較低。
?

[ 不同顏色的毛發通透性差異 ]

[ 逆光下的深色頭發與淺色頭發 ]


這也是為啥很多女孩子
比較喜歡染發、燙發的原因之一。
因為淺色比黑色的毛發,
在逆光下的效果要漂亮很多。
燙發可以使頭發蓬松,
讓更多的光線穿透與反彈,
這樣整體的層次感會變得很豐富。

復雜的遮蔽性:
毛發又非常的密集,
毛發相互之間的陰影遮擋造成毛發。
密集的地方光線也很難繼續滲透進去,
就形成了發根到發梢的陰影漸變。
?

[ 毛發的Occlusion ]


特殊的高光-各項異性高光:
頭發的表面并不是光滑的,
上面有一層被稱之為毛鱗片的結構,
產生的高光散射性很高,
很多人造毛很難做到這一點。
這也是為啥很多廉價的假發的質感
讓人一眼就看出來不真實的原因。
?

[ 顯微鏡下的頭發 ]


上面我們說了頭發,
是排列在一起的一個個細小圓柱體。
很多人不理解為什么
我們要把頭發的高光叫做各項異性高光,
我用一張圖簡單說明下。
?

[ 各項異性高光的產生 ]


我們這里提到的所謂各向異性高光,
其實是我們沒辦法真的將頭發
用一個個圓柱體來渲染,
而使用一種基于觀察近似的算法模擬結果。

而動物的短毛皮比人類頭發更加復雜,
可以大致分為兩類,
一種是表層的長毛(被毛),
另一種是內層的絨毛(更加細小、彎曲)。

絲綢同理但更加復雜,
不同的絲本身質感就不一樣,
加上不同針織結構,
如紗、綺、絹、錦、羅、綢、緞等10多類,
造成絲綢效果最終質感有很大的差異性,
有興趣可以深入了解不同絲綢的微觀結構。
?



說了這么多。
在手機游戲里怎么實現這些效果呢?
?


用頂點細分來制作不現實,
這么大量的毛發,
又是移動端平臺,
機器的計算性能達不到要求。

而用大量面片插片的方式,
會占用大量3D美術的人力成本,
盡管效果是很好,
相對效果來說也不太劃算。

最后選擇了美術制作上最簡單的
多pass渲染的方案。
因為這套方案在美術資源制作上,
基本上和普通角色資源沒有差別,
唯一的限制就是skin多邊形數量上的限制。

而且這套方案在PC端游上已經比較成熟,
比如《劍靈》。
多pass的方法局限性也很大,
不過我們可以拆分開來研究和優化。

layer實現方式
?

[ 多pass的實現方式 ]


根據模型使用層 (layer) 來渲染毛發長度,
在 Unity Shader 中,
每一個 Pass 即表示一層。
當渲染每一層時,
使用法線將頂點位置擠出模型表面 。
Pass及使用的層數越多渲染效果越好,
當然開銷也越大。
這種做法如果想要很好的表現,
就需要大量的pass。
如何用少量的pass實現更好的效果,
后面我們再一步步解決。
?

  • float3 aNormal = (v.normal.xyz);
  • aNormal.xyz += FUR_OFFSET;
  • float3 n = aNormal * FUR_OFFSET * (FUR_OFFSET * saturate( v.color.a )); //頂點色alpha通道控制毛發擴展范圍
  • 復制代碼


    然后將Noise貼圖根據layer做衰減,
    來當做alpha值。
    ?

    [ Noise貼圖 ]

  • _UVoffset ("UV偏移:XY=UV偏移;ZW=UV擾動", Vector) = (0, 0, 0.2, 0.2)
  • 復制代碼


    一定加入基于layer層高度的UV偏移。
    ? 沒有UV偏移效果的毛怎么看都會像刺猬。
    ? 記得對毛發做UV偏移的時候,
    ? ?Diffuse貼圖的UV也要跟著一起計算哦。
    ?

  • <p>float2 uvoffset= _UVoffset.xy??* FUR_OFFSET;</p><p>uvoffset *=??0.1 ; //尺寸太大不好調整 縮小精度。</p><p>float2 uv1= TRANSFORM_TEX(v.texcoord.xy, _MainTex ) + uvoffset * (float2(1,1)/_SubTexUV.xy);</p><p>float2 uv2= TRANSFORM_TEX(v.texcoord.xy, _MainTex )*_SubTexUV.xy? ?+ uvoffset;</p><p>o.uv = float4(uv1,uv2);</p>
  • 復制代碼
  • <p>half3 NoiseTex = tex2D(_SubTex, i.uv.zw).rgb;</p><p>half Noise = NoiseTex.r;</p><p>color.rgb = lerp(_Color,_BaseColor,FUR_OFFSET) ;</p><p>color.a = saturate(Noise-FUR_OFFSET) ;</p><p>return color;</p>
  • 復制代碼


    也可以加入風力、重力等頂點控制項。
    根據不同性能的機器來選擇是否開啟。
    ?

    [ 默認:頂點重力:UV偏移 ]

    [ Noise混合 ]


    也可以將多層Noise
    混合到一起來做一些不同的毛發,
    將他們分別放到R、G、B不同的通道里,
    可以減少貼圖量。
    ?


    缺點:
    ? 這樣大家能看出來,
    ??多pass的制作方式,
    ??無法制作頭發這樣的長毛,
    ??只能制作較短的毛發。
    ??不過我們這次的目標也是制作短毛,
    ??所以長毛與頭發可以先拋開。

    ? 要有比較好的效果,
    ??就需要非常多的pass來進行計算,
    ??這也是我們不希望的。
    ??因為移動平臺對大量Overdraw這樣的
    ??像素級處理是非常大的一筆開銷。
    ?

    [ layer30 : layer10 ]


    layer的層數是越少效率越高的,
    在低layer上得到更好效果是我們的目標。
    我將控制半透明毛發的曲線做了一些優化,
    勉強可以在低layer上面達到多layer的效果。
    ?

    [ 對Alpha的衰減曲線做調整 ]

    [ layer30 : layer10 : 擬合曲線后的layer10 ]


    優化Layer數量

    一般的做法:

  • alpha = Noise -FUR_OFFSET;
  • 復制代碼


    優化后:同時加入了可控的變量。

  • alpha = (Noise*2-(FUR_OFFSET *FUR_OFFSET +(FUR_OFFSET*FurMask*5)))*_tming ;
  • 復制代碼


    燈光

    到現在為止,
    在外形上基本接近了我們想要的毛發效果。
    我們還需要將毛發的渲染特征也加上去。
    這里用3個部分來實現:
    環境光、輪廓光、太陽光

    環境光:
    環境光可以是一個單色,
    也可以是一個微弱的頂底漸變,
    或者球協光照(提取Hdir貼圖低頻數據)。
    ?

    [ 這里可以根據手機游戲賬號轉讓平臺不同項目的需求來定義 ]


    這里以簡單的頂底顏色為例:
    ?

  • <p>float3 normal = normalize(mul(UNITY_MATRIX_MV, float4(v.normal,0)).xyz);</p><p>half3 SH = saturate(normal.y *0.25+0.35) ;</p>
  • 復制代碼

    [ 無環境光遮,與真實效果差異很大 ]


    前面講了毛發的特點之一
    就是環境光遮蔽與自陰影,
    缺少了環境光遮蔽的效果只能打20分。
    環境光遮蔽形成的散射是帶有顏色的,
    會根據物體的顏色不同產生不同顏色。
    我很懶,就沒將顏色與環境光遮蔽
    之間的關系公式寫進去,
    直接開放一個顏色手動設置反彈的顏色。
    (也能節約一些計算不是~)
    ?

  • <p>half Occlusion =FUR_OFFSET*FUR_OFFSET; //伽馬轉線性最精簡版</p><p>Occlusion +=0.04 ;</p><p>half3 SHL = lerp (_OcclusionColor*SH,SH,Occlusion) ;</p>
  • 復制代碼

    [ 無環境光遮 vs 加上環境光遮蔽 ]


    但要記住固有色越淺,
    反彈光就越強,
    Visibility的影響就越弱;
    反之顏色越深,
    反彈光就越弱,
    Visibility的影響就越強;
    簡單的說就是:
    物體的顏色越淺,AO顏色越淺;
    反之顏色越深,AO顏色越深。

    輪廓光:
    輪廓光其實也是環境光的一部分。
    這里單獨給輪廓光計算,
    也只是彌補環境反光的不足,
    同時加一些可控項,
    也可以調出一些特殊的不一樣的效果。
    ?

    [ 毛發輪廓光 ]


    同時也和上面的一樣,
    物體的顏色越淺,
    輪廓光穿透率越強;
    反之顏色越深,
    輪廓光穿透率越弱。

    這里也一定要加入環境光遮蔽的遮擋,
    因為毛發的透光性,
    邊緣稀疏的部分光線穿透率更高。
    同時模擬了在環境光下次表面散射效果。
    ?

    [ Fresnel :Fresnel+Visilibity ]


    差異性在低多邊形下會更加明顯。
    ?

  • <p>half Occlusion =FUR_OFFSET*FUR_OFFSET; //伽馬轉線性最精簡版</p><p>Occlusion +=0.04 ;</p><p>half Fresnel = 1-max(0,dot(N,V));//pow (1-max(0,dot(N,V)),2.2);</p><p>half RimLight =Fresnel * Occlusion; //AO的深度剔除 很重要</p><p>RimLight *=RimLight; //fresnel~pow簡化版</p><p>RimLight *=_FresnelLV *SH; //加上環境光因數</p><p>? ?SHL +=RimLight;//與環境光結合</p>
  • 復制代碼

    [ 模型線框:Occlusion平方:Occlusion4四次方 ]


    將Occlusion的計算
    放到RimLight平方的前面,
    是因為模型的多邊形數量低,
    輪廓會比較明顯。
    將Occlusion4次方,
    能更好的減弱低多邊形的影響。
    因為我們用于毛發材質的模型面數,
    是非常非常低的,
    如果模型面數相對高一些的模型,
    可以放到后面。
    ?

    [ 環境光最終渲染結果 ]


    太陽光:
    我們平常說的太陽光,
    其實可以把它看成是平行光。
    太陽其實是個點光源,
    不過因為它過于龐大,
    光線到地球上面的夾角非常非常小,
    再到我們的可視物體的時候,
    就完全可以忽略掉了。
    ?

    [ 太陽為什么是平行光 ]


    我們就取最簡單的公式。
    ?

  • <p>half3 lightDir = -_SGameShadowParams.xyz; //外部傳入的燈光方向</p><p>half NoL =dot(lightDir,normal);</p><p>half DirLight =NoL * _FurDirLightExposure*_DirLightColor;</p>
  • 復制代碼

    [ 正測光:背光 ]


    普通光照模型這樣計算沒有問題,
    但完全沒有毛發的特性:
    缺少太陽光在邊緣的穿透性,
    也沒有逆光下的毛發次表面散射效果。
    缺少每根毛產生的復雜的陰影表現。
    ?

    [ 陰影與光線邊緣的穿透 ]


    用一個最簡單的擬合就可以得到這個效果。
    主要利用了NdotL(-1~1)的特性。
    ?

  • <p>_LightFilter("平行光毛發穿透",??Range(-0.5,0.5)) = 0.0</p><p>half3 lightDir = -_SGameShadowParams.xyz;</p><p>half NoL =dot(lightDir,normal);</p><p>half DirLight= saturate (NoL+_LightFilter+ FUR_OFFSET ) ;</p><p>DirLight *=_FurDirLightExposure*_DirLightColor;</p>
  • 復制代碼

    [ 正測光:背光 ]


    最后將所有光照合并到一起:
    ?

    [ 佩奇陪你過大年 ]


    ? 為了節省性能,
    ??所有燈光與顏色計算全部在頂點空間完成;
    ? 像素空間只用來計算貼圖采樣;
    ? 很多需要貼圖一起計算顏色值的地方
    ??都優化省略掉了,比較遺憾。
    ? 所有顏色計算都是在線性空間進行的
    ??所以最后要轉換到伽馬空間,
    ??這一步也可以去掉,
    ??也可以再加上簡單的tommping,
    ??讓畫面顏色變得更好。

    高光 - Anisotropic(各項異性)
    ?


    前面講毛發特性的時候,
    對各項異性高光做了個簡單的介紹。
    ?

    [ Anisotropic(各項異性) ]


    學術上Anisotropic(各項異性)的解釋:

    ? 某些材質上有一些微觀上有方向的細絲,
    ??這些細絲在宏觀角度來看是不易察覺的,
    ??典型的有光盤的背面或者是頭發。
    ? strand based anisotropy是
    ??對上述光照情形的一種建模。
    (http://www.bluevoid.com/opengl/sig00/advanced00/notes/node159.html)

    一些Anisotropic表現的例子:
    ?

    [ 《崩壞3》 ]

    [ 《愛麗絲驚魂記:瘋狂再臨 (Alice: Madness Returns)》 ]


    各向異性制作的各種具體實現方式
    我就不一一細說了:
    ?

    [ 沿著法線方向去偏移切線 ]

  • <p>float3 TShift(float3 tangent,float3 normal,float shift)</p><p>? ?? ?? ???{</p><p>? ?? ?? ?? ?? ?return normalize(tangent + shift * normal);</p><p>? ?? ?? ???}</p>
  • 復制代碼

    [ Anisotropic高光 ]

  • <p>float StrandSpecular(fixed3 T,fixed3 V,fixed3 L,fixed exponent)</p><p>? ?{</p><p>? ?? ? float3 H = normalize(L+V);</p><p>? ?? ? float dotTH = dot(T,H);</p><p>? ?? ? float sinTH = sqrt(1- dotTH * dotTH);</p><p>? ?? ? float dirAtten = smoothstep(-1,0,dotTH);? ? </p><p>? ?? ? return dirAtten*pow(sinTH,exponent);</p><p>? ?}</p>
  • 復制代碼


    用抖動忒圖來彌補頭發細節。
    ?

    [ 抖動貼圖制作頭發高光細節 ]


    頭發比較特殊
    觀察頭發的高光會發現,
    其中一層高光是有顏色的,
    另外一層高光是沒有顏色的,
    且兩層高光的相互錯開一點點。
    ?

    [ 觀察頭發高光 ]

    [ 頭發雙層高光公式 ]


    我們根據公式在VS里計算出高光效果。
    這時候會發現高光效果會很粗糙,
    簡直有點不堪入目。
    ?

    [ 頂點 VS 逐像素 ]


    一步一步來優化。

    ? 依然使用上面已經使用老套的方法,
    ??用FUR_OFFSET做高光的遮蔽后,
    ??因為VS渲染精度方面過低的問題緩解了,
    ??但效果方面依然不是太好。

    fixed SPec1 =StrandSpecular (T1,V,L,_specExp.x)*FUR_OFFSET;
    ?

    [ 高光加入FUR_OFFSET對比 ]


    ? 因為毛束是一個個細小的單個圓柱體,
    ??它的高光也并不是一個平面連續的表現。
    ??我想了很多方法來彌補毛發體積與細節。
    ??最終下面的結果相對來說,
    ??得出的結果是目前得出的最好的。
    ??大家猜一下——下面這張圖是怎么得到的?
    ?

    [ color = Alpha平方 ]


    其實這就是我們目前的alpha當做色彩輸出的結果。

    ? 越靠近透明的區域越黑,中間區域偏亮。
    ? 它剛好能達到我們高光缺少的細節部分的要求。

    我就用它來當做單根毛發邊緣體積的遮擋。
    得到的結果很不錯。
    同時這個也替代了抖動貼圖。
    ?

  • color.rgb +=i.Specular??* (Noise*Noise);
  • 復制代碼

    [ 加入Noise遮罩,代替抖動貼圖方案 ]


    加入低頻與高頻2層高光后的效果更加自然。
    ?

    [ 雙層高光效果 ]

  • <p><span style="background-color: rgb(255, 255, 255);">f</span>ixed3 T1 = normalize(_specExp.z*normalWorld+binormalWorld);</p><p>fixed3 T2 = normalize(_specExp.w*normalWorld+binormalWorld);</p><p>fixed SPec1 =StrandSpecular (T1,V,L,_specExp.x) *FUR_OFFSET;</p><p>fixed SPec2 =StrandSpecular (T2,V,L,_specExp.y) *FUR_OFFSET;</p><p>o.Specular??= SPec1*_SPColor1??+ SPec2*_SPColor2;</p>
  • 復制代碼


    高光部分我測試了很多方案,
    目前效果只能說還能湊合著用,
    因為都是在VS進行的計算,
    效率上面應該還行。


    第一次寫分享,
    羅里吧嗦的寫了一大堆。
    效果方面肯定還有非常大的優化空間。
    歡迎大家一起討論和指正。

    一些個人遇到的問題:

    ? 毛發UV控制部分我加入了flowmap,
    ??但是FlowTex的繪制太困難,
    ??而且也不直觀。
    ??可以做個工具實時直觀看到flowmap
    ??在毛發上面的繪制效果。
    ??甚至可以直接在unity繪制到模型頂點色
    ??XY2個值上面控制毛發方向。

    ? 多模型重疊的時候還是有深度穿插。
    ??分享一個16年的國外視頻,
    ??用了另一種方案來控制毛發長度與方向。

    ·END·

    總結

    以上是生活随笔為你收集整理的新版“峡谷第一美”妲己尾巴毛发制作分享的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。