Shader "Unlit/卡通场景shader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Diffuse("Color",Color) = (1,1,1,1) // 漫反射
_Outline("",Range(0,1)) = 0.1 // 描边参数
_OutlineColor("OutlineColor",Color) = (0,0,0,0) // 描边颜色
_Steps("Steps",Range(1,30)) = 1 // 颜色分阶参数
_ToonEffect("ToonEffect",Range(0,1)) = 0.5 // 卡通影响
_BumpMap("Normal Map",2D) = "bump" {} // 法线贴图
_BumpScale("Bump Scale",float) = 1 // 法线贴图影响度
_SnowDir("SnowDir",Vector) = (0,1,0) // 雪方向
_SnowColor("SnowColor",Color) = (0,0,0,0) // 雪颜色
//_SnowLevel("SnowLevel",Range(0,1)) = 0.5 // 雪厚度 想要全局设置时这里需要注释掉,不然无法控制数值变化
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
UsePass "Unlit/shader018/Outline" // 用shader018的Outline Pass通道,要保证变量数、名一致
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile __ SNOW_ON // 单个宏 shader的变种 __代表只需要一个 默认都是关闭的,想开启去代码中开
#include "Lighting.cginc"
#include "UnityCG.cginc"
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
fixed3 worldNormal : TEXCOORD1; // 世界法线向量,计算漫反射 需要世界光向量和世界法线向量点乘
float3 worldLightDir : TEXCOORD2;
float3 worldViewDir : TEXCOORD3;
float3 worldBinormal : TEXCOORD4;
fixed2 tangentUv : TEXCOORD5;
float3x3 rotationTanToWorld : TEXCOORD6;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Diffuse;
float _Steps;
float _ToonEffect;
sampler2D _BumpMap;
float4 _BumpMap_ST;
float _BumpScale;
float3 _SnowDir;
float4 _SnowColor;
float _SnowLevel;
v2f vert (appdata_tan v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.tangentUv = TRANSFORM_TEX(v.texcoord, _BumpMap); // 法线贴图uv
o.worldNormal = UnityObjectToWorldNormal(v.normal); // 法线从模型变换到世界坐标 法线是向量所以fixed3 为世界光向量和世界法线向量点乘计算漫反射做准备 所以要计算世界法线向量
o.worldLightDir = WorldSpaceLightDir(v.vertex); // 世界光向量 漫反射世界光向量和世界法线向量点乘
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; // 顶点信息从模型转到世界坐标系
o.worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos)); // 世界视角方向
TANGENT_SPACE_ROTATION;
o.worldBinormal = binormal; // 副切线向量
o.rotationTanToWorld = rotation;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// 法线贴图
fixed4 packedNormal = tex2D(_BumpMap, i.tangentUv); // 法线贴图采样
// 法线贴图要设置为normal map
fixed3 tangentNormal = UnpackNormal(packedNormal); // 解压缩法线贴图 unity会自动搞到【0,1】范围内 z值也算好了 解压出的是法线贴图的切线空间法线
tangentNormal.xy = tangentNormal.xy * _BumpScale; // 解压都做好了,乘上法线贴图控制参数让他可调整即可
float3 tangentWorldNormal = normalize(mul(i.rotationTanToWorld , tangentNormal)); // 切线空间法线转换到世界坐标系
// 光照模型
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; // 环境光
fixed4 albedo = tex2D(_MainTex, i.uv); // 图片采样
float difLight = max(0, dot(i.worldLightDir, tangentWorldNormal)) * 0.5 + 0.5; // max不让这个值小于零 *0.5+0.5半兰伯特光照模型 这是漫反射光的值 参数为世界光方向和转过来的法线贴图世界法线来让他有纹理感
// 卡通颜色
difLight = smoothstep(0, 1, difLight); // 颜色平滑在【0,1】之间
// 颜色离散化
float toon = floor(difLight * _Steps) / _Steps; // floor参数向下取整 目的:分几块
difLight = lerp(difLight, toon, _ToonEffect); // lerp前两个值插值,第三个是权值 光照模型
fixed4 color = fixed4(ambient + _LightColor0.rgb * difLight * albedo * _Diffuse.rgb, 1); // 计算返回值
// 雪
#if SNOW_ON // 对应的宏区间
if (dot(tangentWorldNormal, _SnowDir) > lerp(1, -1, _SnowLevel)) { //lerp给定权重在两个向量之间执行线性内插
color.rgb = _SnowColor.rgb;
}else{
color = color;
}
#endif
return color;
}
ENDCG
}
}
}