Unity Shader 学习笔记 (五) 积雪效果Shader

Unity Shader 学习笔记 (五) 积雪效果Shader

简单的积雪效果

Shader "Custom/jixue xiaoguo " {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		//法线贴图
		_Bump ("Bump", 2D) = "bump" {}
		//表示覆盖在岩石上雪的数量,范围从0~1
        _Snow ("Snow Level", Range(0,1)) = 0.1
		//积雪颜色  默认白色
		_SnowColor ("Snow Color", Color) = (1.0,1.0,1.0,1.0)
		//积雪方向
		_SnowDirection ("Snow Direction", Vector) = (0,1,0)
		//积雪厚度
    	_SnowDepth ("Snow Depth", Range(0,0.3)) = 0.1
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		
		#pragma surface surf Lambert

		//获取属性的具体值
		sampler2D _MainTex;
		sampler2D _Bump;
		float _Snow;
		float4 _SnowColor;
		float4 _SnowDirection;
		float _SnowDepth;

		//输入
		struct Input {
			float2 uv_MainTex;
			float2 uv_Bump;
        	float3 worldNormal;
        	INTERNAL_DATA
		};

		//输出
		void surf (Input IN, inout SurfaceOutput o) {

			 //该像素的真实颜色值
    		half4 c = tex2D (_MainTex, IN.uv_MainTex);
 
    		//从凹凸贴图中得到该像素的法向量
    		o.Normal = UnpackNormal (tex2D (_Bump, IN.uv_Bump));
 
    		//得到世界坐标系下的真正法向量(而非凹凸贴图产生的法向量,要做一个切空间到世界坐标系的转化)和雪落
    		//下相反方向的点乘结果,即两者余弦值,并和_Snow(积雪程度)比较
    		if(dot(WorldNormalVector(IN, o.Normal), _SnowDirection.xyz)>lerp(1,-1,_Snow))
        		//此处我们可以看出_Snow参数只是一个插值项,当上述夹角余弦值大于
        		//lerp(1,-1,_Snow)=1-2*_Snow时,即表示此处积雪覆盖,所以此值越大,
        		//积雪程度程度越大。此时给覆盖积雪的区域填充雪的颜色
        		o.Albedo = _SnowColor.rgb;
    		else
        		//否则使用物体原先颜色,表示未覆盖积雪 
        		o.Albedo = c.rgb;
    		o.Alpha = 1;
		}
		ENDCG
	} 
	FallBack "Diffuse"
}


效果图

Unity Shader 学习笔记 (五) 积雪效果Shader_第1张图片


我们对雪的方向和和输入点的世界法线方向进行点积。WorldNormalVector通过输入的点及这个点的法线值,来计算它在世界坐标中的方向;右侧的lerp函数:当Snow取最小值0时,这个函数将返回1,而Snow取最大值时,返回-1。这样我们就可以通过设定Snow的值来控制积雪的阈值,要是积雪等级Snow是0时,不等式左侧不可能大于右侧,因此完全没有积雪;相反要是_Snow取最大值1时,由于左侧必定大于-1,所以全模型积雪。而随着取中间值的变化,积雪的情况便会有所不同。

更加真实的积雪

Shader "Custom/Realistic Snow (2)" {
    Properties {
	//岩石贴图
        _MainTex ("Base (RGB)", 2D) = "white" {}
	//法线贴图
        _Bump ("Bump", 2D) = "bump" {}
	//表示覆盖在岩石上雪的数量,范围从0~1
        _Snow ("Snow Level", Range(0,1) ) = 0
	//积雪颜色  默认白色
        _SnowColor ("Snow Color", Color) = (1.0,1.0,1.0,1.0)
	//积雪方向
        _SnowDirection ("Snow Direction", Vector) = (0,1,0)
	//积雪厚度
        _SnowDepth ("Snow Depth", Range(0,0.2)) = 0.1
	//湿润度,如果该值越大,则混色中积雪颜色所占比例越低,这表明积雪越湿润,则雪的颜色越少,都化成水了
        _Wetness ("Wetness", Range(0, 0.5)) = 0.3
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
 
        CGPROGRAM
        #pragma surface surf Lambert vertex:vert

	//获取属性的具体值
        sampler2D _MainTex;
        sampler2D _Bump;
        float _Snow;
        float4 _SnowColor;
        float4 _SnowDirection;
        float _SnowDepth;
        float _Wetness;
 
	//输入结构体
        struct Input {
	    //获取岩石贴图的uv坐标
            float2 uv_MainTex;
	    //获取法线贴图的uv坐标
            float2 uv_Bump;
	    //如果SurfaceOutput中设定了Normal值的话,通过worldNormal可以获取当前点在世界中的法线值
            float3 worldNormal;INTERNAL_DATA
        };
	
	//顶点着色程序入口

         void vert (inout appdata_full v) 
	 {
             //将_SnowDirection转化到模型局部坐标系下
             float4 sn = mul(UNITY_MATRIX_IT_MV, _SnowDirection);
 
             if(dot(v.normal, sn.xyz) >= lerp(1,-1, (_Snow*2)/3))
             {
                  v.vertex.xyz += (sn.xyz + v.normal) * _SnowDepth * _Snow;
             }
          }
	
        void surf (Input IN, inout SurfaceOutput o) {
            half4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Normal = UnpackNormal (tex2D (_Bump, IN.uv_Bump));

	    //WorldNormalVector通过输入的点及这个点的法线值,来计算它在世界坐标中的方向
	    //然后用输入点在世界坐标中的方向和 积雪的方向 做点积运算  并减去 _Snow插值
            half difference = dot(WorldNormalVector(IN, o.Normal), _SnowDirection.xyz) - lerp(1,-1,_Snow);

	    //saturate(x)函数  如果 x 小于 0 ,返回 0 ;如果 x 大于 1 ,返回 1 ;否则,返回 x
            difference = saturate(difference / _Wetness);
		
	    //对光源的反射率。
            o.Albedo = difference*_SnowColor.rgb + (1-difference) *c;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

效果图:

Unity Shader 学习笔记 (五) 积雪效果Shader_第2张图片




你可能感兴趣的:(Unity Shader 学习笔记 (五) 积雪效果Shader)