Unity shader学习之卡通渲染,轮廓线

效果如下(头部无轮廓):

原理:使用2个pass来渲染。

第一个pass中,使用轮廓线颜色渲染整个背面,并在视角空间下把模型顶点沿着法线方法向外扩张一段距离,来让轮廓线可见,公式为:

viewPos += viewNormal * _Outline;

注意:如果直接使用顶点法线进行扩展,对于一些内凹的模型,就可能发生背面面片遮挡正面面片的情况。为了尽可能防止出现这样的情况,在扩张背面顶点之前,我们首先对顶点法线的z分量进行处理,使它们等于一个定值,然后把法线归一化后再对顶点进行扩张。这样的好处在于,扩展后的背面更加扁平化,从而降低了遮挡正面面片的可能性。代码如下:

viewNormal.z = -0.5;

viewNormal = normalize(viewNormal);

viewPos += viewNormal * _Outline;

第二个pass中,正常渲染物体。

参考shader代码如下:

  1 Shader "America/Character/America-Diffuse-AlphaTest-Face"
  2 {
  3     Properties
  4     {
  5         _Color ("Main Color", Color) = (1,1,1,1)
  6         _MainTex ("Base (RGB)", 2D) = "white" {}
  7         _NormalMap("Normal Map", 2D) = "bump" {}
  8 
  9         _DiffuseRate ("Diffuse Rate", float) = 2
 10         _Ramp ("Toon Ramp (RGB)", 2D) = "gray" {}
 11         _RampRate ("Ramp Rate", float) = 1
 12 
 13         _OverlyingColor("Overlying Color", Color) = (0.5, 0.5, 0.5, 1)
 14 
 15     }
 16 
 17     SubShader
 18     {
 19         Tags 
 20         {
 21             "RenderType" = "Transparent"
 22             "IgnoreProjector" = "True"
 23             "Queue" = "Transparent+100"
 24         }
 25         LOD 200
 26         
 27         
 28         Pass
 29         {
 30             NAME "OUTLINE"
 31 
 32             Cull Front
 33 
 34             CGPROGRAM
 35             #pragma vertex vert
 36             #pragma fragment frag
 37 
 38             struct appdata
 39             {
 40                 float4 vertex : POSITION;
 41                 float4 normal : NORMAL;
 42             };
 43 
 44             struct v2f
 45             {
 46                 float4 pos : SV_POSITION;
 47             };
 48 
 49             v2f vert(appdata v)
 50             {
 51                 v2f o;
 52 
 53                 float4 viewPos = mul(UNITY_MATRIX_MV, v.vertex);
 54                 float4 viewNormal = mul(UNITY_MATRIX_IT_MV, v.normal);
 55 
 56                 viewNormal.z = -0.5;
 57                 o.pos = mul(UNITY_MATRIX_P, viewPos + normalize(viewNormal) * 0.01);
 58 
 59                 return o;
 60             };
 61 
 62             float4 frag(v2f i) : SV_TARGET
 63             {
 64                 return float4(0, 0, 0, 1);
 65             };
 66 
 67             ENDCG
 68         }
 69 
 70         Pass
 71         {
 72             Tags
 73             {
 74                 "LightMode" = "ForwardBase"
 75             }
 76             Cull Off
 77 
 78             CGPROGRAM
 79             #pragma vertex vert
 80             #pragma fragment frag
 81             #pragma multi_compile_fwdbase
 82 
 83             #include "UnityCG.cginc"
 84             #include "AutoLight.cginc"
 85             #include "Lighting.cginc"
 86 
 87             #include "../AmericaCG.cginc"
 88 
 89             fixed4 _Color;
 90             sampler2D _MainTex;
 91             sampler2D _NormalMap;
 92             float _DiffuseRate;
 93             sampler2D _Ramp;
 94             float _RampRate;
 95             fixed4 _OverlyingColor;
 96 
 97             struct appdata
 98             {
 99                 float4 vertex : POSITION;
100                 float2 uv : TEXCOORD0;
101                 float3 normal : NORMAL;
102                 float4 tangent : TANGENT;
103             };
104 
105             struct v2f
106             {
107                 float4 pos : SV_POSITION;
108                 float2 uv : TEXCOORD0;
109                 float4 T2W1 : TEXCOORD1;
110                 float4 T2W2 : TEXCOORD2;
111                 float4 T2W3 : TEXCOORD3;
112             };
113 
114             v2f vert(appdata v)
115             {
116                 v2f o;
117                 o.pos = UnityObjectToClipPos(v.vertex);
118                 o.uv = v.uv;
119                 
120                 float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
121                 float3 worldNormal = UnityObjectToWorldNormal(v.normal);
122                 float3 binormal = cross(normalize(worldNormal), normalize(worldTangent)) * v.tangent.w;
123                 float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
124                 o.T2W1 = float4(worldTangent.x, binormal.x, worldNormal.x, worldPos.x);
125                 o.T2W2 = float4(worldTangent.y, binormal.y, worldNormal.y, worldPos.y);
126                 o.T2W3 = float4(worldTangent.z, binormal.z, worldNormal.z, worldPos.z);
127                 return o;
128             }
129 
130             fixed4 frag(v2f i) : SV_TARGET
131             {
132                 float3 worldPos = float3(i.T2W1.w, i.T2W2.w, i.T2W3.w);
133                 float3 worldLight = normalize(UnityWorldSpaceLightDir(worldPos));
134                 //float3 worldView = normalize(UnityWorldSpaceViewDir(worldPos));
135                 float3 tangentNormal = UnpackNormal(tex2D(_NormalMap, i.uv));
136                 float3x3 tanToWorld = float3x3(i.T2W1.xyz, i.T2W2.xyz, i.T2W3.xyz);
137                 float3 worldNormal = mul(tanToWorld, tangentNormal);
138                 
139                 fixed4 albedo = tex2D(_MainTex, i.uv) * _Color;
140                 fixed3 diffuse = CalcDiffuse(albedo, worldLight, worldNormal, _Ramp, _RampRate);
141                 
142                 fixed4 col = fixed4(diffuse * _DiffuseRate, albedo.a);
143                 col.rgb = Overlay(col, _OverlyingColor);
144 
145                 return col;
146             }
147 
148             ENDCG
149         }
150 
151     } 
152 
153     Fallback "Diffuse"
154 }

转载请注明出处:https://www.cnblogs.com/jietian331/p/13633051.html

原文地址:https://www.cnblogs.com/jietian331/p/13633051.html