之前的預(yù)備知識能讓我們掌握shader的基本用法搏明,并且寫出一些簡單的shader鼠锈。這次我們通過積雪效果來更進(jìn)一步的了解shader是如何結(jié)合數(shù)學(xué)闪檬,實(shí)現(xiàn)效果星著。
另外注意,關(guān)注有強(qiáng)烈光照需求的shader才使用surface shader粗悯,否則使用VF shader就可虚循。
Shader "Custom/SnowEffect" { //定義shader的路徑
Properties{
_MainTex("Albedo (RGB)", 2D) = "white" {} //要使用的紋理
//定義了默認(rèn)值為“bump”的2D類型的紋理_Bump,初始值為空样傍。
_Bump("Bump",2D) = "bump"{}
_Snow("Snow Level",Range(0,1)) = 0
_SnowColor("Snow Color",Color) = (1,1,1,1)
_SnowDirection("Snow Direction",Vector) = (0,1,0) //默認(rèn)水平方向横缔,值為1,而不是-1
_SnowDepth("Snow Depth",Range(0,0.3)) = 0.1 //積雪厚度
}
SubShader{
//在腳本中可以通過判斷rendertype來做一些處理衫哥,比如shader替換茎刚、shader關(guān)閉
//參考: https://blog.csdn.net/nnsword/article/details/17840439 類型
// https://blog.csdn.net/zmafly/article/details/51141011 作用
// http://lib.csdn.net/article/unity3d/44793 解析
Tags { "RenderType" = "Opaque" }
CGPROGRAM //shader的正文
//聲明surface shader 函數(shù)名,光照類型撤逢,使用的頂點(diǎn)函數(shù)(自定頂點(diǎn)函數(shù)名為vert)
#pragma surface surf Lambert vertex:vert
//添加對PROPERTIES的引用
sampler2D _MainTex;
sampler2D _Bump;
float _Snow;
float4 _SnowColor;
float4 _SnowDirection;
float _SnowDepth;
struct Input {
float2 uv_MainTex;
//添加一個(gè)變量float2 uv_Bump來獲得_Bump紋理的uv坐標(biāo)膛锭。
float2 uv_Bump;
//獲取世界坐標(biāo)下的法向值
float3 worldNormal;
INTERNAL_DATA
};
void surf(Input IN, inout SurfaceOutput o) {
//tex2D對紋理進(jìn)行采樣
half4 c = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
//tex2D根據(jù)輸入?yún)?shù)的類型,獲取對應(yīng)含義的值蚊荣,此處從_Bump紋理中提取法向信息
//UnpackNormal函數(shù)的作用就是將tex2D函數(shù)獲取到的fixed4類型值轉(zhuǎn)換成fixed3類型的值
o.Normal = UnpackNormal(tex2D(_Bump, IN.uv_Bump));
//得到世界坐標(biāo)系下的真正法向量(而非凹凸貼圖產(chǎn)生的法向量初狰,要做一個(gè)凹凸貼圖法向值到世界坐標(biāo)系法向值的轉(zhuǎn)化)和雪落
//下相反方向的點(diǎn)乘結(jié)果,即兩者余弦值互例,并和_Snow(積雪程度)比較
if (dot(WorldNormalVector(IN, o.Normal), _SnowDirection.xyz) > lerp(1, -1, _Snow))
{
/*
我們知道奢入,余弦值是-1和1之間的一個(gè)數(shù),越接近于1媳叨,說明該點(diǎn)法向與雪落下相反方向越一致腥光,當(dāng)為-1時(shí),說明兩者方向相反糊秆。
此處我們可以看出_Snow參數(shù)只是一個(gè)插值項(xiàng)柴我,當(dāng)上述夾角余弦值大于
lerp(1,-1,_Snow)=1-2*_Snow時(shí),即表示此處積雪覆蓋扩然,所以此值越大
多講一點(diǎn)艘儒,lerp的第三個(gè)參數(shù)是一個(gè)(0,1)之間的比例因子夫偶,代表所處前兩個(gè)參數(shù)范圍的位置
注意為了符合正常的自然現(xiàn)象界睁,我們_Snow一般只取0~0.5,因?yàn)榇笥?.5時(shí)兵拢,插值的結(jié)果將小于0翻斟,會造成雪好像穿過了巖石,落到了巖石的后面说铃。這個(gè)道理和光照的道理一樣访惜,物體背面是見不到陽光的嘹履。
*/
//積雪程度程度越大。此時(shí)給覆蓋積雪的區(qū)域填充雪的顏色
o.Albedo = _SnowColor.rgb;
}
else //否則表示未覆蓋
{
o.Albedo = c.rgb;
}
o.Alpha = 1;
}
//自定義頂點(diǎn)函數(shù)
/*
參數(shù)appdata_full v债热,參數(shù)的類型為appdata_full(Unity內(nèi)置類型)砾嫉,該類型包含了紋理坐標(biāo),法向量窒篱,頂點(diǎn)位置焕刮,以及切線信息
*/
void vert(inout appdata_full v)
{
//將_SnowDirection從世界坐標(biāo)系轉(zhuǎn)換到模型的局部坐標(biāo)系下
/*
將_SnowDirection乘以Unity內(nèi)置矩陣 – UNITY_MATRIX_IT_MV
(IT表示Inverse Transpose逆轉(zhuǎn)置矩陣,MV表示 ModelView矩陣墙杯,該矩陣表示是ModelView的逆轉(zhuǎn)置矩陣)配并。
現(xiàn)在我們得到了該頂點(diǎn)的法向量。
_Snow*2/3高镐,這表示只有那些更接近雪落下方向的區(qū)域才會增加雪的厚度溉旋,更符合自然現(xiàn)象。
而這些通過測試的區(qū)域嫉髓,沿著(sn.xyz+v.normal)方向進(jìn)行加厚观腊,也就是將其頂點(diǎn)沿此方向伸展一定距離。
注意到增厚的程度取決于_SnowDepth和_Snow岩喷,而增厚的方向是由物體法向和雪落的方向綜合作用的恕沫,這也符合自然現(xiàn)象。
*/
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;
}
ENDCG
}
FallBack "Diffuse" //shader失敗時(shí)回滾
}
調(diào)節(jié)箭頭所指落雪方向可以改變落雪效果