实现原理没什么好说的,和世界向上方向的向量做一次点积,超过一定值就打上白色。基于基础系列中的法线纹理,并做了一些小改动。
Shader "Custom/Rock"
{
Properties
{
_Color("Color",Color)=(1,1,1,1)
_MainTex("基础纹理",2D)="white"{}
_NormalTex("法线纹理",2D)="bump"{}
_BumpScale("凹凸缩放",float)=1.0
_SnowLevel("积雪程度",float)=1.0
_SnowColor("积雪颜色",Color)=(1,1,1,1)
_SnowDir("积雪方向",Vector)=(0,1,0)
}
SubShader
{
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _NormalTex;
float4 _NormalTex_ST;
half _BumpScale;
fixed _SnowLevel;
fixed4 _SnowColor;
half4 _SnowDir;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 tangent:TANGENT;
float4 texcoord:TEXCOORD0;
};
struct v2f
{
float4 vertex:SV_POSITION;
//我们需要将切线空间到世界空间的变换矩阵传递到片元着色器
//由于片元着色器最大只支持float4大小的插值寄存器,因此我们将矩阵分成3行4列
//最后一列用于存储世界坐标,实际计算并不会参与
float4 matrix_TangentToObject0:TEXCOORD0;
float4 matrix_TangentToObject1:TEXCOORD1;
float4 matrix_TangentToObject2:TEXCOORD2;
float4 uv:TEXCOORD3;
};
v2f vert(a2v v)
{
v2f o;
o.vertex=UnityObjectToClipPos(v.vertex);
float3 worldPos=UnityObjectToWorldDir(v.vertex);
float3 worldNormal=UnityObjectToWorldNormal(v.normal);
float3 worldTangent=UnityObjectToWorldDir(v.tangent);
//副切线由法线和切线的叉积得到,w用于表示副切线的方向
float3 worldBinormal=cross(worldNormal,worldTangent)*v.tangent.w;
//根据线性代数的知识,我们知道从切线空间到世界空间的变换矩阵由切线空间的三个坐标轴按列构成
//这三个坐标轴必须是在世界坐标下的表示
o.matrix_TangentToObject0=
float4(worldTangent.x,worldBinormal.x,worldNormal.x,worldPos.x);
o.matrix_TangentToObject1=
float4(worldTangent.y,worldBinormal.y,worldNormal.y,worldPos.y);
o.matrix_TangentToObject2=
float4(worldTangent.z,worldBinormal.z,worldNormal.z,worldPos.z);
//o.tangentLightDir=mul(rotation,ObjSpaceLightDir(v.vertex));
//o.tangentViewDir=mul(rotation,ObjSpaceViewDir(v.vertex));
o.uv.xy=TRANSFORM_TEX(v.texcoord,_MainTex);
o.uv.zw=TRANSFORM_TEX(v.texcoord,_NormalTex);
return o;
}
fixed4 frag(v2f i):SV_Target
{
half4 rawNormal=tex2D(_NormalTex,i.uv.zw);
//用于光照法线
half3 tangentNormal=UnpackNormal(rawNormal);
//用于积雪法线
half3 tangentNormal1=tangentNormal;
tangentNormal.xy*=_BumpScale;
tangentNormal.z=sqrt(1.0-
saturate(dot(tangentNormal.xy,tangentNormal.xy)));
tangentNormal1.xy*=_SnowLevel;
tangentNormal1.z=sqrt(1.0-
saturate(dot(tangentNormal1.xy,tangentNormal1.xy)));
half3 worldNormal=normalize(half3(
dot(i.matrix_TangentToObject0.xyz,tangentNormal),
dot(i.matrix_TangentToObject1.xyz,tangentNormal),
dot(i.matrix_TangentToObject2.xyz,tangentNormal)));
half3 worldNormal1=normalize(half3(
dot(i.matrix_TangentToObject0.xyz,tangentNormal1),
dot(i.matrix_TangentToObject1.xyz,tangentNormal1),
dot(i.matrix_TangentToObject2.xyz,tangentNormal1)));
//纹理采样
fixed3 texResult=tex2D(_MainTex,i.uv.xy)*_Color;
fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 diffuse=_LightColor0*texResult
*saturate(dot(normalize(_WorldSpaceLightPos0),worldNormal));
fixed3 color=diffuse+ambient;
//离下雪方向越大,积雪效果约淡
half difference=dot(worldNormal1 , _SnowDir.xyz);//-_SnowArea;
difference=saturate(difference);
color=difference*_SnowColor.rgb+(1-difference)*color;
//difference=saturate(difference);
//边缘颜色渐变
return fixed4(color,1.0);
}
ENDCG
}
}
}
效果仅供参考,实现方式有多种,效果也各不相同
模型原样,素材是网上随便找的:
看有博客说的是全局积雪什么的,用深度纹理什么的,看不懂,感觉Shader也是一个大坑。。。