先看效果,再上代码,最后知识点解释:
{–Xray基本原理就是:ZTest Great产生的作用
描边:法线外拓(把顶点沿着法线方向向外挤)
卡通着色颜色处理:产生色阶,颜色的离散化
轮廓外发光:确定外轮廓线在哪,再发光–}
卡通着色
(1)效果:
描边:
边缘光:
// float lerp(float a, float b, float w) {
// return a(1-w) + b * w;
// }
// 上面是 lerp插值的公式:说白了,也就是一个混合公式,他们俗称插值, 只不过w相当于以第二个参数为源,第一个参数为目标。 直白点,就是把b向a上混合
Shader "Unlit/KaTong"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Diffuse("Diffuse",Color) = (1,1,1,1)
_OutLineSize("Outline",Range(0,0.2))=0.1
_OutLineColor("OutlineColor",Color)=(0,0,0,0)
_Steps("diffuse Color devide to Steps",Range(1,30))=10
_ToonEffectSize("ToonEffectSize",Range(0,1))=0.5
////渐进纹理
//_RampTex("RampTex",2D) = "white"{}
//边缘光
_RimColor("RimColor",Color) =(0,0,0,0)
_RimPower("RimPower",Range(0.00001,100))=1
//Xray 透视
_XRayColor("XRayColor",Color) = (1,1,1,1)
_XRayPower("XrayPower",Range(0.0001,3))=1
}
SubShader
{
Tags { "Queue"="Geometry" "RenderType"="Opaque" }
LOD 100
Pass
{
Tags { "Queue"="Geometry+1000" "RenderType"="Opaque" }
Name "XRay"
Tags{"ForceNoSjadowCasting"="true"}
Blend SrcAlpha One
ZWrite Off
ZTest Greater
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float4 _XRayColor;
float _XRayPower;
struct v2f{
float4 pos : SV_POSITION;
float3 worldViewDir:TEXCOORD0;
float3 worldNormal:NORMAL;
};
v2f vert(appdata_base v){
v2f o;
o.pos = UnityWorldToClipPos(v.vertex);
o.worldViewDir = ObjSpaceViewDir(v.vertex);
o.worldNormal = v.normal;
return o;
}
fixed4 frag(v2f i):SV_TARGET{
float3 worldNormal = normalize(i.worldNormal);
float3 worldViewDir = normalize(i.worldViewDir);
float rim = 1-dot(worldNormal,worldViewDir);
return _XRayColor * pow(rim,1/_XRayPower);
}
ENDCG
}
Pass
{
Name "OutLine"
Cull Front
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float _OutLineSize;
float4 _OutLineColor;
struct v2f{
float4 vertex : SV_POSITION;
};
v2f vert(appdata_base v){
v2f o;
v.vertex += float4(v.normal,0) * _OutLineSize;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_TARGET{
return _OutLineColor;
}
ENDCG
}
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _Diffuse;
float _Steps;
float _ToonEffectSize;
float4 _RimColor;
float _RimPower;
v2f vert(appdata_base v){
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld,v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
}
fixed4 frag(v2f i):SV_TARGET{
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
float4 albedo = tex2D(_MainTex,i.uv);
float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
float3 worldNormal = normalize(i.worldNormal);
//卡通颜色分层 方式1:
float difLight = dot(worldLightDir,worldNormal) * 0.5 + 0.5;
//颜色平滑在【0,1】之间
difLight = smoothstep(0,1,difLight);
// 颜色离散化 分成_Steps层
float toon = floor(difLight * _Steps)/_Steps;
//就是把toon向difLight上混合
difLight = lerp(difLight,toon,_ToonEffectSize);
fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * difLight;
////卡通颜色分层 方式2:
//渐进纹理颜色值
//float difLight = dot(worldLightDir,worldNormal) * 0.5 + 0.5;
//fixed4 rampColor = tex2D(_RampTex, fixed2(difLight,difLight));:
//fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * rampColor.rgb;
//边缘光 首先要确定边缘的位置:worldNormal和 viewDir 垂直时,才是边缘,即:dot(worldNormal,viewDir) = 0
float3 viewDir = UnityWorldSpaceViewDir(i.worldPos);
float rim = 1- dot(worldNormal,viewDir);
float3 rimColor = _RimColor * pow(rim,1/_RimPower);
return fixed4(ambient + diffuse + rimColor,1);
}
ENDCG
}
}
}
用到的知识点:
1.渲染队列:在此shader中共用3个pass,第一个XRay透视 pass的Tags { “Queue”=“Geometry+1000” }是3个当中最后一个渲染
2.深度测试和深度写入(默认ZWrite on):
默认为ZTest LEqual
ZTest Less:深度小于当前缓存则通过
ZTest Greater:深度大于当前缓存则通过
ZTest LEqual:深度小于等于当前缓存则通过
ZTest GEqual:深度大于等于当前缓存则通过
ZTest Equal:深度等于当前缓存则通过
ZTest NotEqual:深度不等于当前缓存则通过
ZTest Always:不论如何都通过
ZTest Off等同于ZTest Always,关闭深度测试等于完全通过。
3.透明度混合:开启混合,并设置混合因子。源颜色(该片元颜色)乘以SrcFactor,目标颜色(已经存在于颜色缓冲的颜色)会乘以DstFactor,然后把两者相加后在存入颜色缓冲区
4.常用函数:
(1)lerp(a,b,w):说白了,也就是一个混合公式,插值, 只不过w相当于以第二个参数为源,第一个参数为目标。 就是把b向a上混合
//函数
float lerp(float a, float b, float w) {
return a(1-w) + b * w;
}
(2)smoothstep(a, b, x)可以用来生成0到1的平滑过渡.
https://blog.csdn.net/u010333737/article/details/828592465
5.其他:
漫反射,dot,pow等基本的就不再说了,多动手多思考!!!!!