【Unity Shader实战】卡通风格的Shader(一)

_Ramp ("Ramp Texture", 2D) = "white" {}sampler2D _Ramp;添加新的指令:#pragma surface surf Toon解释:我们去掉了final函数,将其功能移到了后面的surf函数中。这样允许我们有更多的可变性。上述语句说明我们将使用名称为Toon的光照函数。修改surf函数:void surf (Input IN, inout SurfaceOutput o) {half4 c = tex2D (_MainTex, IN.uv_MainTex);o.Normal = UnpackNormal( tex2D(_Bump, IN.uv_Bump));o.Albedo = (floor(c.rgb * _Tooniness)/_Tooniness);o.Alpha = c.a;}实现Toon光照函数:half4 LightingToon(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten){float difLight = max(0, dot (s.Normal, lightDir));float dif_hLambert = difLight * 0.5 + 0.5;float rimLight = max(0, dot (s.Normal, viewDir));float rim_hLambert = rimLight * 0.5 + 0.5;float3 ramp = tex2D(_Ramp, float2(rim_hLambert, dif_hLambert)).rgb;float4 c;c.rgb = s.Albedo * _LightColor0.rgb * ramp;c.a = s.Alpha;return c;}解释:上述最重要的部分就是如何在ramp中采样,我们使用了两个值:漫反射光照方向和边缘光照方向。max是为了防止明暗突变的区域产生奇怪的现象,0.5的相关操作则是为了改变光照区间,进一步提高整体亮度。具体可参加之前的文章。

完整代码如下:

Shader "Custom/Toon" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_Bump ("Bump", 2D) = "bump" {}_Ramp ("Ramp Texture", 2D) = "white" {}_Tooniness ("Tooniness", Range(0.1,20)) = 4}SubShader {Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM#pragma surface surf Toonsampler2D _MainTex;sampler2D _Bump;sampler2D _Ramp;float _Tooniness;float _Outline;struct Input {float2 uv_MainTex;float2 uv_Bump;};void surf (Input IN, inout SurfaceOutput o) {half4 c = tex2D (_MainTex, IN.uv_MainTex);o.Normal = UnpackNormal( tex2D(_Bump, IN.uv_Bump));o.Albedo = (floor(c.rgb * _Tooniness)/_Tooniness);o.Alpha = c.a;}half4 LightingToon(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten){float difLight = max(0, dot (s.Normal, lightDir));float dif_hLambert = difLight * 0.5 + 0.5;float rimLight = max(0, dot (s.Normal, viewDir));float rim_hLambert = rimLight * 0.5 + 0.5;float3 ramp = tex2D(_Ramp, float2(rim_hLambert, dif_hLambert)).rgb;float4 c;c.rgb = s.Albedo * _LightColor0.rgb * ramp;c.a = s.Alpha;return c;}ENDCG}FallBack "Diffuse"}效果如下:

float _Outline;前面说了,边缘光照需要使用观察方向,因此我们修改Input结构体:struct Input {float2 uv_MainTex;float2 uv_Bump;float3 viewDir;};解释:viewDir也是Unity的内置参数,其他内置参数可在官网找到。我们在surf函数中使用如下方法检测那些边:half edge = saturate(dot (o.Normal, normalize(IN.viewDir)));edge = edge < _Outline ? edge/4 : 1;o.Albedo = (floor(c.rgb * _Tooniness)/_Tooniness) * edge;解释:我们首先得到该像素的法线方向和观察方向的点乘结果。如果该结果小于我们的阈值,我们认为这就是我们要找的那些边缘点,并除以4(一个实验值)来减少它的值得到黑色;否则,让它等于1,即没有任何效果。

整体代码如下:

Shader "Custom/Toon" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_Bump ("Bump", 2D) = "bump" {}_Ramp ("Ramp Texture", 2D) = "white" {}_Tooniness ("Tooniness", Range(0.1,20)) = 4_Outline ("Outline", Range(0,1)) = 0.4}SubShader {Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM#pragma surface surf Toonsampler2D _MainTex;sampler2D _Bump;sampler2D _Ramp;float _Tooniness;float _Outline;struct Input {float2 uv_MainTex;float2 uv_Bump;float3 viewDir;};void surf (Input IN, inout SurfaceOutput o) {half4 c = tex2D (_MainTex, IN.uv_MainTex);o.Normal = UnpackNormal( tex2D(_Bump, IN.uv_Bump));half edge = saturate(dot (o.Normal, normalize(IN.viewDir)));edge = edge < _Outline ? edge/4 : 1;o.Albedo = (floor(c.rgb * _Tooniness)/_Tooniness) * edge;o.Alpha = c.a;}half4 LightingToon(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten){float difLight = max(0, dot (s.Normal, lightDir));float dif_hLambert = difLight * 0.5 + 0.5;float rimLight = max(0, dot (s.Normal, viewDir));float rim_hLambert = rimLight * 0.5 + 0.5;float3 ramp = tex2D(_Ramp, float2(rim_hLambert, dif_hLambert)).rgb;float4 c;c.rgb = s.Albedo * _LightColor0.rgb * ramp;c.a = s.Alpha;return c;}ENDCG}FallBack "Diffuse"}

最后效果如下:

弊端

这是更新的内容。这种方法有一个明显的弊端就是,对于那叫平坦、棱角分明的物体,使用上述描边方法会产生突变等非预期的情况。例如下面的效果:

望着它们,我睡着了。今天已经过去——我生命中所有天中的一天,

【Unity Shader实战】卡通风格的Shader(一)

相关文章:

你感兴趣的文章:

标签云: