潤稿 - 阿祥 - 阿祥的開發日常
Twin Souls: Path of the Shadows是一款遊戲性相當完善,且卡通渲染效果相當優異的手機遊戲,本文由 Unity 大中華區技術經理Marek Marchlewicz(馬瑞),為大家分享一篇如何透過修改 Unity 的渲染管道來實現與Twin Souls: Path of the Shadows一樣的卡通渲染效果。
卡通渲染是一種非真實感的渲染方法,一般也稱作 Cel-Shading 或 Toon Shading,透過將平滑陰影變化轉換成擁有明顯邊界,讓畫面呈現出手繪般的效果。
上圖中,由左至右分別是 Diffuse、Cel Shading 以及擁有三個臨界值的 Cel Shading。在通常情況下一個像素所接收到的光源強度是光源方向與法線方向之間的點積(NdotL)。將這個光源強度經由四捨五入調整,或是透過不同“臨界值”的取樣後,就會呈現出不同的卡通渲染效果。在最簡單的卡通渲染效果中,如果點積大於零,則像素會呈現高光,反之如果點積小於零,則像素會被設定成陰影。
卡通渲染效果有許多不同的實現方式,而這次我們會針對渲染路徑(Renderring Path)來完成不同的實現方法。渲染路徑可以在攝影機的 Inspector 面板中設定。下面我們會介紹如何透過正向渲染與延遲渲染路徑來實現卡通渲染效果。
如果你的場景並不是多光源場景,正向渲染(Forward Rendering)是一個不錯的選擇。因為在這種模式下,渲染引擎會遍歷所有光源的頂點及像素,在多光源場景裡可能會帶來較大的負荷。但是,若是你的場景中只有少數或甚至一個光源,這種遍歷方式就不會造成負擔。具體實現時,可以創建一個表面著色器(Surface Shader),並透過自定義的光照模型,來實現如何在正向渲染中完成卡通渲染效果。
經由 “LightingCelShadingForward” 的運算,可以計算出 NdotL,並且透過 NdotL 來完成卡通渲染效果。此外,還可以使用簡單的方法來避免 “if else” 的使用。可行的方法為:
NdotL = 1 + clamp(floor(NdotL), -1, 0);
若是需要模糊邊緣則可以使用:
NdotL = smoothstep(0, 0.025f, NdotL);
與正向渲染相比較下,延遲渲染(Deferred Rendering)的優點是在多光源的場景中可以得到較優異的性能表現。當使用延遲渲染時,引擎會先遍歷場景中的每個光源,並且將光源與場景的幾何信息儲存在緩衝區中。
此外為了重複利用 Unity 的新功能以及強大的 Standard Shader,我們這次使用的方法運用了新的 Unity 延遲渲染運作流程。而這種做法從最初的解決方案發布以來,Unity 對此又進行了許多更新,所以需要完成下列步驟:
取代為:
half nl = CustomLambertTerm(normal, light.dir);
修改為:
修改成:
在完成上述的所有步驟後,我們的 “Internal-DefferredShading.shader” 就大功告成了!接著我們就可以在 Edit > ProjectSettings > Graphhics > Defferred 中選擇我們修改後的 “Internal-DeferredShading.shader” 著色器。
最後,確保攝影機的渲染路徑切換成正確的延遲渲染後,可以注意到我們在標準著色器(Standard Shader)的基礎上完成了卡通渲染效果,如下圖所示。
許多卡通風格的遊戲中,都會對物體進行外輪廓的繪製,這種方式會讓畫面呈現出漫畫一般的視覺效果,而這種外輪廓效果當然也有許多不同的實現方式。可以透過在著色器中檢查法線方向與視角方向的點積,或是使用 Two Pass 來做兩次渲染,當然也可以在後製效果中實現。最簡單的應用方案是在攝影機中添加 Edge Detection 效果:
最後完成的效果如下。
在本文中,我們參考了《Twin Souls: The Path of Shadows》中的卡通渲染效果,最後在幾乎沒有使用其他添加資源的前提下,透過修改 Unity 的渲染管道來加以實現卡通風格渲染,完成了類似的畫面呈現,如下圖所示。
這種透過使用延遲渲染所完成的卡通渲染效果技術相當有用,因為它並不會替換整個光照模型,而只是針對現有模型做特殊的陰影處理,可以在幾乎沒有額外性能開銷的情況下保留 Unity的 PBR(Physically-Based Rendering)技術並完成卡通渲染效果。
Twin Souls: Path of the Shadows是一款遊戲性相當完善,且卡通渲染效果相當優異的手機遊戲,本文由 Unity 大中華區技術經理Marek Marchlewicz(馬瑞),為大家分享一篇如何透過修改 Unity 的渲染管道來實現與Twin Souls: Path of the Shadows一樣的卡通渲染效果。
卡通渲染原理
卡通渲染是一種非真實感的渲染方法,一般也稱作 Cel-Shading 或 Toon Shading,透過將平滑陰影變化轉換成擁有明顯邊界,讓畫面呈現出手繪般的效果。
實現方法
卡通渲染效果有許多不同的實現方式,而這次我們會針對渲染路徑(Renderring Path)來完成不同的實現方法。渲染路徑可以在攝影機的 Inspector 面板中設定。下面我們會介紹如何透過正向渲染與延遲渲染路徑來實現卡通渲染效果。
正向渲染(Forward Rendering)
如果你的場景並不是多光源場景,正向渲染(Forward Rendering)是一個不錯的選擇。因為在這種模式下,渲染引擎會遍歷所有光源的頂點及像素,在多光源場景裡可能會帶來較大的負荷。但是,若是你的場景中只有少數或甚至一個光源,這種遍歷方式就不會造成負擔。具體實現時,可以創建一個表面著色器(Surface Shader),並透過自定義的光照模型,來實現如何在正向渲染中完成卡通渲染效果。
Shader "Custom/CelShadingForward"}
{
Properties
{
_Color("Color", Color) = (1, 1, 1, 1)
_MainTex("Albedo (RGB)", 2D) = "white" {}
}
SubShader
{
Tags
{
"RenderType" = "Opaque"
}
LOD 200
CGPROGRAM
#pragma surface surf CelShadingForward
#pragma target 3.0
half4 LightingCelShadingForward(SurfaceOutput s, half3 lightDir, half atten)
{
half NdotL = dot(s.Normal, lightDir);
if (NdotL <= 0.0)
NdotL = 0;
else
NdotL = 1;
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2);
c.a = s.Alpha;
return c;
}
sampler2D _MainTex;
fixed4 _Color;
struct Input
{
float2 uv_MainTex;
};
void surf(Input IN, inout SurfaceOutput o)
{
// Albedo comes from a texture tinted by color
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
經由 “LightingCelShadingForward” 的運算,可以計算出 NdotL,並且透過 NdotL 來完成卡通渲染效果。此外,還可以使用簡單的方法來避免 “if else” 的使用。可行的方法為:
NdotL = 1 + clamp(floor(NdotL), -1, 0);
若是需要模糊邊緣則可以使用:
NdotL = smoothstep(0, 0.025f, NdotL);
延遲渲染(Deferred Rendering)
與正向渲染相比較下,延遲渲染(Deferred Rendering)的優點是在多光源的場景中可以得到較優異的性能表現。當使用延遲渲染時,引擎會先遍歷場景中的每個光源,並且將光源與場景的幾何信息儲存在緩衝區中。
此外為了重複利用 Unity 的新功能以及強大的 Standard Shader,我們這次使用的方法運用了新的 Unity 延遲渲染運作流程。而這種做法從最初的解決方案發布以來,Unity 對此又進行了許多更新,所以需要完成下列步驟:
- 從 Unity 官網下載 Built-In Shader。
- 將下載文件進行解壓縮,在 “DefaultResourcesExtra” 資料夾中找到 “Internal-DeferredShading.shader”,並複製到專案中的 “Resources” 資料夾
- 在解壓縮文件中的 “CGIncludes” 資料夾裡找到 “UnityDeferredLibrary.cginc” 以及 “UnityStandardBRDF.cginc”,並將這些檔案複製到轉案中的 “Recourses” 資料夾
- 將 “UnityDeferredLibrary.cginc” 重新命名為 “UnityDeprecatedEx.cginc”,並新增下列方法:
inline half CustomDotClamped ( half3 a, half3 b )
{
#if (SHADER_TARGET < 30)
return saturate(dot(a,b));
#else
return max(0.0h, dot(a,b));
#endif
}
inline half CustomLambertTerm ( half3 normal, half3 lightDir )
{
return smoothstep(0.0,0.05f, CustomDotClamped (normal, lightDir));
}
- 將 “UnityStandardBRDF.cginc” 重新命名為 “UnityStandardBRDFCustom.cginc”,複製 BRDF1_Unity_PBS 方法,重命名為 BRDF_CUSTOM_Unity_PBS 方法,並將下列代碼取代:
取代為:
half nl = CustomLambertTerm(normal, light.dir);
- 在 “Internal-DeferredShading.shader” 中,修改匯入的 CG 庫名稱 :
#include "UnityDeferredLibrary.cginc"
#include "UnityStandardBRDF.cginc"
修改為:
#include "UnityDeprecatedEx.cginc"
#include "UnityStandardBRDFCustom.cginc"
- 在 “Internal-DeferredShading.shader” 中,刪除 UnityPBSLighting.cginc。
- 將 “Internal-DeferredShading.shader” 的 UNITY_BRDF_PBS 方法修改成 UNITY_CUSTOM_BRDF_PBS 方法
half4 res = BRDF_Unity_PBS (......);
修改成:
half4 res = BRDF_CUSTOM_Unity_PBS (......);
在完成上述的所有步驟後,我們的 “Internal-DefferredShading.shader” 就大功告成了!接著我們就可以在 Edit > ProjectSettings > Graphhics > Defferred 中選擇我們修改後的 “Internal-DeferredShading.shader” 著色器。
最後,確保攝影機的渲染路徑切換成正確的延遲渲染後,可以注意到我們在標準著色器(Standard Shader)的基礎上完成了卡通渲染效果,如下圖所示。
外輪廓(Toon outline)
許多卡通風格的遊戲中,都會對物體進行外輪廓的繪製,這種方式會讓畫面呈現出漫畫一般的視覺效果,而這種外輪廓效果當然也有許多不同的實現方式。可以透過在著色器中檢查法線方向與視角方向的點積,或是使用 Two Pass 來做兩次渲染,當然也可以在後製效果中實現。最簡單的應用方案是在攝影機中添加 Edge Detection 效果:
- 點擊 Assets > Import Package > Effects,導入 Standard Assets Effect
- 選擇場景中的攝影機,並且在檢視面板(Inspector)中點擊 Add Component > Image Effect > Edge Detection > Edge Detection
最後完成的效果如下。
最終效果
在本文中,我們參考了《Twin Souls: The Path of Shadows》中的卡通渲染效果,最後在幾乎沒有使用其他添加資源的前提下,透過修改 Unity 的渲染管道來加以實現卡通風格渲染,完成了類似的畫面呈現,如下圖所示。
總結
這種透過使用延遲渲染所完成的卡通渲染效果技術相當有用,因為它並不會替換整個光照模型,而只是針對現有模型做特殊的陰影處理,可以在幾乎沒有額外性能開銷的情況下保留 Unity的 PBR(Physically-Based Rendering)技術並完成卡通渲染效果。
沒有留言:
張貼留言