Unity之Shader在模型上渲染积雪效果
在游戏中有时会用到下雪的场景,这样就需要在模型上产生积雪效果,这个工作如果要美术做贴图的话,这个工作量将是非常的庞大,比如下雪10分钟的积雪程度和下雪30分钟,50分钟肯定不一样,这样一个模型需要美术做好多积雪模型,这样美术会崩溃的,并且这么多贴图放在项目中,会造成资源包原来越大,不利于开发。
这时利用Shader编程来实现积雪效果,通过调整某些设定好的数值改变积雪程度。
下面进入Shader编程
首先在Project面包 Create->Shader,双击打开创建的Shader脚本,编写代码如下
<span style="font-size:14px;">Shader "Custom/BaseDiffuse" {
Properties {
//基本贴图 类型为 2D 默认颜色为white
_MainTex ("Base (RGB)", 2D) = "white" {}
//法线贴图 类型为 2D
_Bump ("Bump", 2D) = "bump" {}
//定义一个滑动条,类型为 Range 取值范围 0 - 1
_Snow ("Snow Level", Range(0, 1)) = 0
// 定义一个颜色,类型为 Color 默认值为 (1, 1, 1, 1)
_SnowColor ("Snow Color", Color) = (1, 1, 1, 1)
//定义一个方向,类型为 Vector 默认值为 (0, 1, 0)
_SnowDirection ("Snow Direction", Vector) = (0, 1, 0)
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf BasicDiffuse
//在CG模块重新声明Properties模块中的变量
sampler2D _MainTex;
sampler2D _Bump;
float _Snow;
float4 _SnowColor;
float4 _SnowDirection;
struct Input { //定义 Input 结构,
float2 uv_MainTex;
float2 uv_Bump;
float3 worldNormal; INTERNAL_DATA //如果SurfaceOutput中设定了Normal值的话,
//通过worldNormal可以获取当前点在世界中的法线值
};
void surf (Input IN, inout SurfaceOutput o) {
// 获取UV贴图的值
half4 c = tex2D (_MainTex, IN.uv_MainTex);
//UnpackNormal是定义在UnityCG.cginc文件中的方法,这个文件中包含了一系列常用的CG变量
//以及方法。UnpackNormal接受一个fixed4的输入,并将其转换为所对应的法线值(fixed3)
o.Normal = UnpackNormal(tex2D(_Bump, IN.uv_Bump));
//首先看这个条件的不等式的左侧,对雪的方向和输入点的世界法线方向进行点积。
//WorldNormalVector通过输入的点和这个点的法线值,来计算它在世界坐标中的方向;
//右侧的lerp函数:当Snow取最小值1时,这个函数将返回1,而Snow取最大值时,返回-1。
//这样我们就可以通过设定Snow的值来控制积雪的阈值,要是积雪等级Snow是0时,不等
//式左侧不可能大于右侧,因此完全没有积雪;相反要是_Snow取最大值1时,由于左侧必定大于-1,
//所以全模型积雪。而随着取中间值的变化,积雪的情况便会有所不同。
if (dot(WorldNormalVector(IN, o.Normal), _SnowDirection.xyz) > lerp(1, -1, _Snow))
{
//达到积雪阀值的位置渲染雪的颜色
o.Albedo = _SnowColor.rgb;
}else
{
//未达到积雪阀值的位置渲染贴图颜色
o.Albedo = c.rgb;
}
o.Alpha = c.a;
}
// Shader中对于方法的名称有着比较严格的约定,想要创建一个光照模型,首先要做的是
//按照规定的规则声明一个光照计算的函数名字,即 Lightig<FunctionName>,
//对于BasicDiffuse方法名,名称要写为下方的LightingBasicDiffuse,光照模型的计算式在surf方法
//的表面颜色之后,根据输入的光照条件对原来的颜色在这种光照下的表现进行计算,最后输出新的
//颜色值给渲染单元完成在屏幕的绘制.
inline float4 LightingBasicDiffuse(SurfaceOutput s, fixed3 lightDir, fixed atten)
{
//s.Normal 光照表面法向量,lightDir 光线方向, atten 光强衰减
// dot(s.Normal, lightDir) 为光照表面的法向量与光线方向的点积
//max( , )返回两个参数中较大的一个
float difLight = max(0, dot(s.Normal, lightDir));
float4 col;
//下面的表达式是计算漫反射的公式
//即 发射率 * 光颜色 * (光照表面的法向量与光线方向的点击) * 光照衰减
//乘以2 是增强颜色值
col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2);
//设置透明度
col.a = s.Alpha;
return col;
}
ENDCG
}
FallBack "Diffuse"
}
</span>
创建材质球,选择材质球的Shader为自己创建的
Custom/BaseDiffuse
然后选择模型相应的基本贴图和发现贴图,如下所示
设置 SnowLevel(下雪强度), Snow Color(雪的颜色),以及 Snow Direction(雪的方向)
效果如下所示
通过修改不同的参数达到不同的效果