204 lines
5.3 KiB
Markdown
204 lines
5.3 KiB
Markdown
## ToonShader
|
||
书中案例使用了2个Pass来实现效果。
|
||
|
||
### OutlinePass
|
||
模型外面边
|
||
```
|
||
Pass {
|
||
NAME "OUTLINE"
|
||
|
||
Cull Front
|
||
|
||
CGPROGRAM
|
||
|
||
#pragma vertex vert
|
||
#pragma fragment frag
|
||
|
||
#include "UnityCG.cginc"
|
||
|
||
float _Outline;
|
||
fixed4 _OutlineColor;
|
||
|
||
struct a2v {
|
||
float4 vertex : POSITION;
|
||
float3 normal : NORMAL;
|
||
};
|
||
|
||
struct v2f {
|
||
float4 pos : SV_POSITION;
|
||
};
|
||
|
||
v2f vert (a2v v) {
|
||
v2f o;
|
||
|
||
float4 pos = mul(UNITY_MATRIX_MV, v.vertex);
|
||
//IT_MV rotates normals from object to eye space
|
||
float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
|
||
normal.z = -0.5;
|
||
pos = pos + float4(normalize(normal), 0) * _Outline;
|
||
o.pos = mul(UNITY_MATRIX_P, pos);
|
||
|
||
return o;
|
||
}
|
||
|
||
float4 frag(v2f i) : SV_Target {
|
||
return float4(_OutlineColor.rgb, 1);
|
||
}
|
||
|
||
ENDCG
|
||
}
|
||
```
|
||
|
||
### ToonShader
|
||
颜色计算:
|
||
`Ramp颜色=tex2D(_Ramp, float2(dot(worldNormal, worldLightDir))).rgb`
|
||
`diffuse=贴图颜色*指定颜色*灯光颜色*(Ramp贴图)`
|
||
|
||
```
|
||
fixed4 c = tex2D (_MainTex, i.uv);
|
||
fixed3 albedo = c.rgb * _Color.rgb;
|
||
|
||
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
|
||
|
||
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
|
||
|
||
fixed diff = ;
|
||
diff = (diff * 0.5 + 0.5) * atten;
|
||
|
||
fixed3 diffuse = _LightColor0.rgb * albedo * tex2D(_Ramp, float2(diff, diff)).rgb;
|
||
```
|
||
|
||
高光计算:
|
||
使用fwidth与smooth主要是用于抗锯齿。https://blog.csdn.net/candycat1992/article/details/44673819
|
||
|
||
```
|
||
fixed spec = dot(worldNormal, worldHalfDir);
|
||
fixed w = fwidth(spec) * 2.0;
|
||
fixed3 specular = _Specular.rgb * lerp(0, 1, smoothstep(-w, w, spec + _SpecularScale - 1)) * step(0.0001, _SpecularScale);
|
||
```
|
||
|
||
Pass代码
|
||
```
|
||
Pass {
|
||
Tags { "LightMode"="ForwardBase" }
|
||
|
||
Cull Back
|
||
|
||
CGPROGRAM
|
||
|
||
#pragma vertex vert
|
||
#pragma fragment frag
|
||
|
||
#pragma multi_compile_fwdbase
|
||
|
||
#include "UnityCG.cginc"
|
||
#include "Lighting.cginc"
|
||
#include "AutoLight.cginc"
|
||
#include "UnityShaderVariables.cginc"
|
||
|
||
fixed4 _Color;
|
||
sampler2D _MainTex;
|
||
float4 _MainTex_ST;
|
||
sampler2D _Ramp;
|
||
fixed4 _Specular;
|
||
fixed _SpecularScale;
|
||
|
||
struct a2v {
|
||
float4 vertex : POSITION;
|
||
float3 normal : NORMAL;
|
||
float4 texcoord : TEXCOORD0;
|
||
float4 tangent : TANGENT;
|
||
};
|
||
|
||
struct v2f {
|
||
float4 pos : POSITION;
|
||
float2 uv : TEXCOORD0;
|
||
float3 worldNormal : TEXCOORD1;
|
||
float3 worldPos : TEXCOORD2;
|
||
SHADOW_COORDS(3)
|
||
};
|
||
|
||
v2f vert (a2v v) {
|
||
v2f o;
|
||
|
||
o.pos = mul( UNITY_MATRIX_MVP, v.vertex);
|
||
o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
|
||
o.worldNormal = UnityObjectToWorldNormal(v.normal);
|
||
o.worldPos = mul(_Object2World, v.vertex).xyz;
|
||
|
||
TRANSFER_SHADOW(o);
|
||
|
||
return o;
|
||
}
|
||
|
||
float4 frag(v2f i) : SV_Target {
|
||
fixed3 worldNormal = normalize(i.worldNormal);
|
||
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
|
||
fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
|
||
fixed3 worldHalfDir = normalize(worldLightDir + worldViewDir);
|
||
|
||
fixed4 c = tex2D (_MainTex, i.uv);
|
||
fixed3 albedo = c.rgb * _Color.rgb;
|
||
|
||
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
|
||
|
||
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
|
||
|
||
fixed diff = dot(worldNormal, worldLightDir);
|
||
diff = (diff * 0.5 + 0.5) * atten;
|
||
|
||
fixed3 diffuse = _LightColor0.rgb * albedo * tex2D(_Ramp, float2(diff, diff)).rgb;
|
||
|
||
fixed spec = dot(worldNormal, worldHalfDir);
|
||
fixed w = fwidth(spec) * 2.0;
|
||
fixed3 specular = _Specular.rgb * lerp(0, 1, smoothstep(-w, w, spec + _SpecularScale - 1)) * step(0.0001, _SpecularScale);
|
||
|
||
return fixed4(ambient + diffuse + specular, 1.0);
|
||
}
|
||
|
||
ENDCG
|
||
}
|
||
```
|
||
|
||
### 素描风格
|
||
通过`hatchFactor=max(0,dot(worldLightDir,worldNormal))*7`获取因子。之后计算各个图层的混合因子:
|
||
```
|
||
if (hatchFactor > 6.0) {
|
||
// Pure white, do nothing
|
||
} else if (hatchFactor > 5.0) {
|
||
o.hatchWeights0.x = hatchFactor - 5.0;
|
||
} else if (hatchFactor > 4.0) {
|
||
o.hatchWeights0.x = hatchFactor - 4.0;
|
||
o.hatchWeights0.y = 1.0 - o.hatchWeights0.x;
|
||
} else if (hatchFactor > 3.0) {
|
||
o.hatchWeights0.y = hatchFactor - 3.0;
|
||
o.hatchWeights0.z = 1.0 - o.hatchWeights0.y;
|
||
} else if (hatchFactor > 2.0) {
|
||
o.hatchWeights0.z = hatchFactor - 2.0;
|
||
o.hatchWeights1.x = 1.0 - o.hatchWeights0.z;
|
||
} else if (hatchFactor > 1.0) {
|
||
o.hatchWeights1.x = hatchFactor - 1.0;
|
||
o.hatchWeights1.y = 1.0 - o.hatchWeights1.x;
|
||
} else {
|
||
o.hatchWeights1.y = hatchFactor;
|
||
o.hatchWeights1.z = 1.0 - o.hatchWeights1.y;
|
||
}
|
||
|
||
```
|
||
之后在片元着色器中将因子与6张素描贴图的采样结果相乘以及计算白色区域光照,最后相加:
|
||
```
|
||
fixed4 hatchTex0 = tex2D(_Hatch0, i.uv) * i.hatchWeights0.x;
|
||
fixed4 hatchTex1 = tex2D(_Hatch1, i.uv) * i.hatchWeights0.y;
|
||
fixed4 hatchTex2 = tex2D(_Hatch2, i.uv) * i.hatchWeights0.z;
|
||
fixed4 hatchTex3 = tex2D(_Hatch3, i.uv) * i.hatchWeights1.x;
|
||
fixed4 hatchTex4 = tex2D(_Hatch4, i.uv) * i.hatchWeights1.y;
|
||
fixed4 hatchTex5 = tex2D(_Hatch5, i.uv) * i.hatchWeights1.z;
|
||
fixed4 whiteColor = fixed4(1, 1, 1, 1) * (1 - i.hatchWeights0.x - i.hatchWeights0.y - i.hatchWeights0.z -
|
||
i.hatchWeights1.x - i.hatchWeights1.y - i.hatchWeights1.z);
|
||
|
||
fixed4 hatchColor = hatchTex0 + hatchTex1 + hatchTex2 + hatchTex3 + hatchTex4 + hatchTex5 + whiteColor;
|
||
|
||
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
|
||
|
||
return fixed4(hatchColor.rgb * _Color.rgb * atten, 1.0);
|
||
``` |