崩壞3角色渲染分析

渲染逆向方法:

Adreno Profiler抓幀, 並且分析其中的OpenGL調用及相關資源(頂點數據、紋理、Shader代碼等)

其中Shader代碼和在Unity裏選中Shader並點擊Compile and show code看到的gles3部分類似, 建議轉換成更易於閱讀的形式

 

卡通着色思路:

光照計算仍然是漫反射+高光反射, 其中漫反射是HalfLambert, 高光反射公式來自於Blinn-Phong模型

比較關鍵的點是, 漫反射部分不是漸變的, 而是分了3, 以實現卡通風格的層次感, 即所謂的梯度漫反射(Ramped Diffuse)

上圖是還原出來的Unity Shader及渲染結果, 下面簡要介紹一下該Shader的實現細節..

 

Main Color:

主紋理, rgb爲基礎顏色, a的作用見下文

 

Bloom Mask:

未使用

 

Light Map:

光照紋理, rgb作用見下文

 

mainColor.a:

主紋理alpha通道, 表示不受光照影響的程度, 1.0時無論是否有光照影響都爲原顏色, 0.0時僅包含光照計算結果,

如身體和頭髮主紋理中, 一些黃色的部分, alpha值較高, 用來保持高亮

從主紋理中分離出來的alpha通道, 見下圖

Avatar_Kiana_C2_Texture_Body_Color_RGB2048_A.pngAvatar_Kiana_C2_Texture_Hair_Color_Common_A.png

以及 輸出-主紋理-A通道.png

 

UsingBloomMask:

材質屬性, 是否使用BloomMask紋理調整不受光照影響的程度, 默認關閉

公式爲 mainColor.a *= tex2D(_BloomMaskTex, i.texcoord5.xy).x

注意: 只能減弱或保持原狀, 因爲紋理採樣結果在0.0~1.0之間

 

UsingDitherAlpha:

材質屬性, 是否應用alpha抖動, 默認關閉

 

FirstShadowMultColor:

材質屬性, 暗面亮度一, xyz分量分別對應主紋理rgb通道, 值越小越暗, 此處爲(0.72941, 0.6, 0.65098)

公式爲fristShadowColor = mainColor.rgb * _FirstShadowMultColor.xyz

 

SecondShadowMultColor:

材質屬性, 暗面亮度二, xyz分量分別對應主紋理rgb通道, 值越小越暗, 此處爲(0.65098, 0.45098, 0.549019)

公式爲secondShadowColor = mainColor.rgb * _SecondShadowMultColor.xyz

 

i.color.rlightMapColor.gLightAreaSecondShadow:

頂點顏色r通道和光照紋理g通道, 兩者乘積rgProduct用來做暗面顏色選擇, 公式如下

diffuseColor = rgProduct >= 0.090000033 ? otherColor : shadowColor

otherColor = ((rgProductFix + i.halfLambert) * 0.5 >= _LightArea) ? mainColor.rgb : fristShadowColor

shadowColor = ((rgProduct + i.halfLambert) * 0.5 >= _SecondShadow) ? fristShadowColor : secondShadowColor

 

其中,

rgProductFixrgProduct經過微調的一個值;

i.halfLambert是半蘭伯特值, 即法線與光線夾角的餘弦值映射到0.0~1.0範圍內, 夾角越小值越接近1, 用於表示漫反射部分的強度;

_LightArea_SecondShadow是材質屬性, 分別爲用於選擇 原顏色和暗面一暗面一和暗面二的閾值;

 

上述公式可理解爲,

如果rgProduct非常小的話, 在暗面一和暗面二中選一個; 否則, 在原顏色和暗面一中選一個,

相當於漫反射率不再是根據法線漸變, 而是分了3(按閾值選擇), 以此實現卡通風格的層次感,

更進一步地, rgProduct非常小的時候, 除非i.halfLambert比較大, 否則選的往往是暗面二

 

下圖1 輸出-明暗分佈.png, 其中不同顏色代表了不同的區域, 綠色和黑色是暗面一和暗面二, 白色和紅色是原顏色和暗面一

下圖2 輸出-頂點R通道×光照紋理G通道.png, 其中比較黑的區域正對應了上圖的綠色和黑色區域

 

Shininess:

材質屬性, 光澤度, Blinn-Phong光照模型中用於計算高光反射的指數, 用於控制高光區域的亮點大小, 值越大亮點半徑越小

 

lightMapColor.b:

光照紋理b通道, 用於使某些區域更容易出現高光, 因爲出現高光的條件是 lightMapColor.b + blinnSpec > 1.0

其中blinnSpec是按照Blinn-Phong光照模型計算出來的高光度, 越大表示高光反射越強,

下圖 ID_118_B.png, 這是頭髮的光照紋理b通道, 比較明顯; 以及 ID_113_B.png 輸出-光照紋理-B通道.png

 

lightMapColor.rLightSpecColorSpecMulti:

lightMapColor.r爲光照紋理r通道, LightSpecColorSpecMulti爲材質屬性, 共同控制當存在高光時高光的顏色,

公式爲 _LightSpecColor.xyz * _SpecMulti * lightMapColor.r

見下圖 ID_113_R.pngID_118_R.png輸出-光照紋理-R通道.png

 

最終產生的高光分佈: (比想象中弱很多)

 

Color:

材質屬性, 用於調整光照計算結果, 只能調的更弱或者保持原狀,

公式爲litColor.xyz = (diffuseColor + specColor) * _Color.xyz;

 

其他輸出圖:

輸出-主紋理-RGB通道.png 輸出-頂點色-RGB通道.png

 

皮膚shader:

與上述shader類似, 但是沒有BloomMask, 增加了ProbToggle用於調節膚色(未見實際使用), 並且mainColor.a不再有上述作用

 

描邊的實現:

將模型在觀察空間中, 按法線往外擴張, 以剔除正面的方式繪製 (Shader聲明的頂點屬性是切線, 但實際提交的數據應該還是法線)

下圖 輸出-膨脹方向.png, 其中紅色表示右下, 綠色表示左上, 黃色表示右上, 黑色表示左下, 注意: 只是大概的方向不是絕對的

最終描邊結果 輸出-最終結果.png, 爲了更明顯, 描邊顏色設置爲了黑色, 遊戲中實際的值爲(0.4117647, 0.3112941, 0.3768184)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章