如果代码中有什么不清楚请查看以下基础知识
Shader基础知识
unity3d 中 七种坐标知识详解
卡通渲染
卡通渲染通常包括描边和阴影分段,当前这个写的不好,等有时间完善后更新。
Shader "Custom/Cartoon" {
Properties{
//主贴图
_MainTex("MainTex",2D) = "white"{}
//主颜色
_Color("Color",Color) = (1,1,1,1)
//漫反射色调纹理
_RampTex("Ramp",2D) = "white"{}
//描边宽度
_Outline("Outline",Range(0,1)) = 0.1
//描边颜色
_OutlineColor("OutlineColor",Color) = (0,0,0,1)
//高光反射颜色
_Specular("SpecularColor",Color) = (1,1,1,1)
//高光阈值
_SpecularScale("Specular Scale",Range(0,0.1)) = 0.01
}
SubShader{
//该段pass 的作用是描边
Pass{
NAME "OUTLINE"
Cull Front
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//定义与unity通信的变量
fixed _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);
//UNITY_MATRIX_MV的逆转置矩阵,用于将法线从模型空间变换到观察空间,也可以用于得到UNITY_MATRIX_MV的逆矩阵
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;
}
fixed4 frag(v2f i) :SV_Target{
return fixed4(_OutlineColor.rgb,1);
}
ENDCG
}
//该段作用时上色
Pass{
Tags{"LightMode" = "ForwardBase"}
//裁剪后方
Cull Back
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "Lighting.cginc"
#include "UnityCG.cginc"
#include "AutoLight.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
sampler2D _RampTex;
fixed4 _Specular;
fixed _SpecularScale;
//应用到顶点着色器的数据
struct a2v {
//顶点位置,法线与贴图
float4 vertex:POSITION;
float3 normal:NORMAL;
float2 texcoord:TEXCOORD0;
};
//顶点到片段着色器的数据
struct v2f {
//顶点信息、uv信息、世界坐标法线信息和世界坐标信息。
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
float3 worldPos:TEXCOORD2;
SHADOW_COORDS(3)
};
//顶点着色器正文
v2f vert(a2v v) {
v2f o;
//将模型坐标转换为裁剪坐标
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
TRANSFER_SHADOW(o);
return o;
}
//片段着色器 指定输出为SV_Target
fixed4 frag(v2f i) :SV_Target{
//获取模型在世界空间的法线向量 计算与输入向量方向相同的单位向量
fixed3 worldNormal = normalize(i.worldNormal);
//仅用于向前渲染中,输入一个世界空间中的顶点位置, 返回世界空间中从该点到光源的光照方向。没有被归一化
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
//输入一个世界空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向
fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
//计算与输入向量方向相同的单位向量
fixed3 worldHalf = 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(_RampTex,float2(diff,diff)).rgb;
fixed spec = dot(worldNormal,worldHalf);
fixed w = fwidth(spec)*2.0;
fixed3 specular = _Specular.rgb*lerp(0,1,smoothstep(-w,w,spec + _SpecularScale - 1))*step(0.0001,_SpecularScale);
//最后添加的step(0.0001,_SpecularScale);是为了控制当Specular为0时,不出现高光效果
return fixed4(ambient + diffuse + specular,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
//这里的回调需要注意包含能够处理阴影的特殊Pass
}