關(guān)于本系列
這是Unity3D Shader入門指南系列的第二篇旗唁,本系列面向的對(duì)象是新接觸Shader開(kāi)發(fā)的Unity3D使用者,因?yàn)槲冶旧碜约阂彩荢hader初學(xué)者瘸爽,因此可能會(huì)存在錯(cuò)誤或者疏漏描函,如果您在Shader開(kāi)發(fā)上有所心得季二,很歡迎并懇請(qǐng)您指出文中紕漏,我會(huì)盡快改正拒啰。在之前的開(kāi)篇中介紹了一些Shader的基本知識(shí)驯绎,包括ShaderLab的基本結(jié)構(gòu)和語(yǔ)法,以及簡(jiǎn)單逐句地講解了一個(gè)基本的shader谋旦。在具有這些基礎(chǔ)知識(shí)后剩失,閱讀簡(jiǎn)單的shader應(yīng)該不會(huì)有太大問(wèn)題,在繼續(xù)教程之前簡(jiǎn)單閱讀一下Unity的Surface Shader Example册着,以檢驗(yàn)?zāi)欠裾莆樟松弦还?jié)的內(nèi)容拴孤。如果您對(duì)閱讀大部分示例Shader并沒(méi)有太大問(wèn)題,可以正確地指出Shader的結(jié)構(gòu)指蚜,聲明和使用的話乞巧,就說(shuō)明您已經(jīng)準(zhǔn)備好繼續(xù)閱讀本節(jié)的內(nèi)容了。
法線貼圖(Normal Mapping)
法線貼圖是凸凹貼圖(Bump mapping)的一種常見(jiàn)應(yīng)用摊鸡,簡(jiǎn)單說(shuō)就是在不增加模型多邊形數(shù)量的前提下绽媒,通過(guò)渲染暗部和亮部的不同顏色深度,來(lái)為原來(lái)的貼圖和模型增加視覺(jué)細(xì)節(jié)和真實(shí)效果免猾。簡(jiǎn)單原理是在普通的貼圖的基礎(chǔ)上是辕,再另外提供一張對(duì)應(yīng)原來(lái)貼圖的,可以表示渲染濃淡的貼圖猎提。通過(guò)將這張附加的表示表面凸凹的貼圖的因素于實(shí)際的原貼圖進(jìn)行運(yùn)算后获三,可以得到新的細(xì)節(jié)更加豐富富有立體感的渲染效果。在本節(jié)中,我們將首先實(shí)現(xiàn)一個(gè)法線貼圖的Shader疙教,然后對(duì)Unity Shader的光照模型進(jìn)行一些討論棺聊,并實(shí)現(xiàn)一個(gè)自定義的光照模型。最后再通過(guò)更改shader模擬一個(gè)石頭上的積雪效果贞谓,并對(duì)模型頂點(diǎn)進(jìn)行一些修改使積雪效果看起來(lái)比較真實(shí)限佩。在本節(jié)結(jié)束的時(shí)候,我們就會(huì)有一個(gè)比較強(qiáng)大的可以滿足一些真實(shí)開(kāi)發(fā)工作時(shí)可用的shader了裸弦,而且更重要的是祟同,我們將會(huì)掌握它是如何被創(chuàng)造出來(lái)的。
關(guān)于法線貼圖的效果圖理疙,可以對(duì)比看看下面晕城。模型面數(shù)為500,左側(cè)只使用了簡(jiǎn)單的Diffuse著色窖贤,右側(cè)使用了法線貼圖砖顷。比較兩張圖片不難發(fā)現(xiàn),使用了法線貼圖的石頭在暗部和亮部都有著更好的表現(xiàn)主之。整體來(lái)說(shuō)择吊,凸凹感比Diffuse的結(jié)果增強(qiáng)許多,石頭看起來(lái)更真實(shí)也更具有質(zhì)感槽奕。
![image](https://onevcat.com/assets/images/2013/shader-tutorial2-compare.jpg)
本節(jié)中需要用到的上面的素材可以在這里下載几睛,其中包括上面的石塊的模型,一張貼圖以及對(duì)應(yīng)的法線貼圖粤攒。將下載的package導(dǎo)入到工程中所森,并新建一個(gè)material,使用簡(jiǎn)單的Diffuse的Shader(比如上一節(jié)我們實(shí)現(xiàn)的)夯接,再加上一個(gè)合適的平行光光源焕济,就可以得到我們左圖的效果。另外盔几,本節(jié)以及以后都會(huì)涉及到一些Unity內(nèi)建的Shader的內(nèi)容晴弃,比如一些標(biāo)準(zhǔn)常用函數(shù)和常量定義等,相關(guān)內(nèi)容可以在Unity的內(nèi)建Shader中找到逊拍,內(nèi)建Shader可以在Unity下載頁(yè)面的版本右側(cè)找到上鞠。
接下來(lái)我們實(shí)現(xiàn)法線貼圖。在實(shí)現(xiàn)之前芯丧,我們先簡(jiǎn)單地稍微多了解一些法線貼圖的基本知識(shí)芍阎。大多數(shù)法線圖一般都和下面的圖類似,是一張以藍(lán)紫色為主的圖缨恒。這張法線圖其實(shí)是一張RGB貼圖谴咸,其中紅轮听,綠,藍(lán)三個(gè)通道分別表示由高度圖轉(zhuǎn)換而來(lái)的該點(diǎn)的法線指向:Nx岭佳、Ny血巍、Nz。在其中絕大部分點(diǎn)的法線都指向z方向驼唱,因此圖更偏向于藍(lán)色藻茂。在shader進(jìn)行處理時(shí)驹暑,我們將光照與該點(diǎn)的法線值進(jìn)行點(diǎn)積后即可得到在該光線下應(yīng)有的明暗特性玫恳,再將其應(yīng)用到原圖上,即可反應(yīng)在一定光照環(huán)境下物體的凹凸關(guān)系了优俘。關(guān)于法向貼圖的更多信息京办,可以參考wiki上的相關(guān)條目。
![一張典型的法線圖](https://onevcat.com/assets/images/2013/shader-tutorial2-normal.jpg)
回到正題帆焕,我們現(xiàn)在考慮的主要是Shader入門惭婿,而不是圖像學(xué)的原理。再上一節(jié)我們寫的Shader的基礎(chǔ)上稍微做一些修改叶雹,就可以得到適應(yīng)并完成法線貼圖渲染的新Shader财饥。新加入的部分進(jìn)行了編號(hào)并在之后進(jìn)行說(shuō)明。
Shader "Custom/Normal Mapping"
{ Properties { _MainTex ("Base (RGB)", 2D) = "white" {}
//1 _Bump ("Bump", 2D) = "bump" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex; //2 sampler2D _Bump;
struct Input {
float2 uv_MainTex; //3 float2 uv_Bump;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
//4 o.Normal = UnpackNormal(tex2D(_Bump, IN.uv_Bump);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
聲明并加入一個(gè)顯示名稱為Bump
的貼圖折晦,用于放置法線圖
為了能夠在CG程序中使用這張貼圖钥星,必須加入一個(gè)sample,希望你還記得~
獲取Bump的uv信息作為輸入
從法線圖中提取法線信息满着,并將其賦予相應(yīng)點(diǎn)的輸出的Normal屬性谦炒。UnpackNormal
是定義在UnityCG.cginc文件中的方法,這個(gè)文件中包含了一系列常用的CG變量以及方法风喇。UnpackNormal
接受一個(gè)fixed4的輸入宁改,并將其轉(zhuǎn)換為所對(duì)應(yīng)的法線值(fixed3)。在解包得到這個(gè)值之后魂莫,將其賦給輸出的Normal还蹲,就可以參與到光線運(yùn)算中完成接下來(lái)的渲染工作了。
現(xiàn)在保存并且編譯這個(gè)Shader耙考,創(chuàng)建新的material并使用這個(gè)shader谜喊,將石頭的材質(zhì)貼圖和法線圖分別拖放到Base和Bump里,再將其應(yīng)用到石頭模型上琳骡,應(yīng)該就可以看到右側(cè)圖的效果了锅论。
光照模型
在我們之前的看到的Shader中(其實(shí)也就上一節(jié)的基本diffuse和這里的normal mapping),都只使用了Lambert的光照模型(#pragma surface surf Lambert)楣号,這是一個(gè)很經(jīng)典的漫反射模型最易,光強(qiáng)與入射光的方向和反射點(diǎn)處表面法向夾角的余弦成正比怒坯。關(guān)于Lambert和漫反射的一些詳細(xì)的計(jì)算和推論,可以參看wiki(Lambert藻懒,漫反射)或者其他地方的介紹剔猿。一句話的簡(jiǎn)單解釋就是一個(gè)點(diǎn)的反射光強(qiáng)是和該點(diǎn)的法線向量和入射光向量和強(qiáng)度和夾角有關(guān)系的,其結(jié)果就是這兩個(gè)向量的點(diǎn)積嬉荆。既然已經(jīng)知道了光照計(jì)算的原理归敬,我們先來(lái)看看如何實(shí)現(xiàn)一個(gè)自己的光照模型吧。
在剛才的Shader上進(jìn)行如下修改鄙早。
首先將原來(lái)的#pragma
行改為這樣
#pragma surface surf CustomDiffuse
然后在SubShader塊中添加如下代碼
inline float4 LightingCustomDiffuse (SurfaceOutput s, fixed3 lightDir, fixed atten) { float difLight = max(0, dot (s.Normal, lightDir));
float4 col; col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2);
col.a = s.Alpha;
return col;
}
最后保存汪茧,回到Unity。Shader將編譯限番,如果一切正常舱污,你將不會(huì)看到新的shader和之前的在材質(zhì)表現(xiàn)上有任何不同。但是事實(shí)上我們現(xiàn)在的shader已經(jīng)與Unity內(nèi)建的diffuse光照模型撇清了關(guān)系弥虐,而在使用我們自己設(shè)定的光照模型了扩灯。
喵的,這些代碼都干了些什么霜瘪!相信你一定會(huì)有這樣的疑惑...沒(méi)問(wèn)題珠插,沒(méi)有疑惑的話那就不叫初學(xué)了,還是一行行講來(lái)颖对。首先正像我們上一篇所說(shuō)捻撑,#pragma
語(yǔ)句在這里聲明了接下來(lái)的Shader的類型,計(jì)算調(diào)用的方法名惜互,以及指定光照模型布讹。在之前我們一直指定Lambert為光照模型,而現(xiàn)在我們將其換為了CustomDiffuse训堆。
接下來(lái)添加的代碼是計(jì)算光照的實(shí)現(xiàn)描验。shader中對(duì)于方法的名稱有著比較嚴(yán)格的約定,想要?jiǎng)?chuàng)建一個(gè)光照模型坑鱼,首先要做的是按照規(guī)則聲明一個(gè)光照計(jì)算的函數(shù)名字膘流,即Lighting<Your Chosen Name>
。對(duì)于我們的光照模型CustomDiffuse鲁沥,其計(jì)算函數(shù)的名稱自然就是LightingCustomDiffuse
了呼股。光照模型的計(jì)算是在surf方法的表面顏色之后,根據(jù)輸入的光照條件來(lái)對(duì)原來(lái)的顏色在這種光照下的表現(xiàn)進(jìn)行計(jì)算画恰,最后輸出新的顏色值給渲染單元完成在屏幕的繪制彭谁。
也許你已經(jīng)猜到了,我們之前用的Lambert光照模型是不是也有一個(gè)名字叫LightingLambert的光照計(jì)算函數(shù)呢允扇?Bingo缠局。在Unity的內(nèi)建Shader中则奥,有一個(gè)Lighting.cginc文件,里面就包含了LightingLambert的實(shí)現(xiàn)狭园。也許你也注意到了读处,我們所實(shí)現(xiàn)的LightingCustomDiffuse的內(nèi)容現(xiàn)在和Unity內(nèi)建中的LightingLambert是完全一樣的,這也就是使用新的shader的原來(lái)視覺(jué)上沒(méi)有區(qū)別的原因唱矛,因?yàn)閷?shí)現(xiàn)確實(shí)是完全一樣的罚舱。
首先來(lái)看輸入量,SurfaceOutput s
這個(gè)就是經(jīng)過(guò)表面計(jì)算函數(shù)surf處理后的輸出绎谦,我們講對(duì)其上的點(diǎn)根據(jù)光線進(jìn)行處理管闷,fixed3 lightDir
是光線的方向,fixed atten
表示光衰減的系數(shù)燥滑。在計(jì)算光照的代碼中渐北,我們先將輸入的s的法線值(在Normal mapping中的話這個(gè)值已經(jīng)是法線圖中的對(duì)應(yīng)量了)和輸入光線進(jìn)行點(diǎn)積(dot函數(shù)是CG中內(nèi)置的數(shù)學(xué)函數(shù),希望你還記得铭拧,可以參考這里)。點(diǎn)積的結(jié)果在-1至1之間恃锉,這個(gè)值越大表示法線與光線間夾角越小搀菩,這個(gè)點(diǎn)也就應(yīng)該越亮。之后使用max來(lái)將這個(gè)系數(shù)結(jié)果限制在0到1之間破托,是為了避免負(fù)數(shù)情況的存在而導(dǎo)致最終計(jì)算的顏色變?yōu)樨?fù)數(shù)肪跋,輸出一團(tuán)黑,一般來(lái)說(shuō)這是我們不愿意看到的土砂。接下來(lái)我們將surf輸出的顏色與光線的顏色_LightColor0.rgb
(由Unity根據(jù)場(chǎng)景中的光源得到的州既,它在Lighting.cginc中有聲明)進(jìn)行乘積,然后再與剛才計(jì)算的光強(qiáng)系數(shù)和輸入的衰減系數(shù)相乘萝映,最后得到在這個(gè)光線下的顏色輸出(關(guān)于difLight * atten * 2中為什么有個(gè)乘2吴叶,這是一個(gè)歷史遺留問(wèn)題,主要是為了進(jìn)行一些光強(qiáng)補(bǔ)償序臂,可以參見(jiàn)這里的討論)蚌卤。
在了解了基本實(shí)現(xiàn)方式之后,我們可以看看做一些修改玩玩兒奥秆。最簡(jiǎn)單的比如將這個(gè)Lambert模型改亮一些逊彭,比如換成Half Lambert模型。Half Lambert是由Valve創(chuàng)造的可以使物體在低光線條件下增亮的技術(shù)构订,最早被用于半條命(Half Life)中以避免在低光下物體的走形侮叮。簡(jiǎn)單說(shuō)就是把光強(qiáng)系數(shù)先取一半,然后在加0.5悼瘾,代碼如下:
inline float4 LightingCustomDiffuse (SurfaceOutput s, fixed3 lightDir, fixed atten) { float difLight = dot (s.Normal, lightDir);
float hLambert = difLight * 0.5 + 0.5;
float4 col;
col.rgb = s.Albedo * _LightColor0.rgb * (hLambert * atten * 2);
col.a = s.Alpha;
return col;
}
這樣一來(lái)囊榜,原來(lái)光強(qiáng)0的點(diǎn)谷异,現(xiàn)在對(duì)應(yīng)的值變?yōu)榱?.5,而原來(lái)是1的地方現(xiàn)在將保持為1锦聊。也就是說(shuō)模型貼圖的暗部被增強(qiáng)變亮了歹嘹,而亮部基本保持和原來(lái)一樣,防止過(guò)曝孔庭。使用Half Lambert前后的效果圖如下尺上,注意最右側(cè)石頭下方的陰影處細(xì)節(jié)更加明顯了,而這一切都只是視覺(jué)效果的改變圆到,不涉及任何貼圖和模型的變化怎抛。
![Half Lambert下發(fā)現(xiàn)貼圖的表現(xiàn)](https://onevcat.com/assets/images/2013/shader-toturial-hl.jpg)
表面貼圖的追加效果
OK,對(duì)于光線和自定義光照模型的討論暫時(shí)到此為止芽淡,因?yàn)槿绻归_(kāi)的話這將會(huì)一個(gè)龐大的圖形學(xué)和經(jīng)典光學(xué)的話題了马绝。我們回到Shader,并且一起實(shí)現(xiàn)一些激動(dòng)人心的效果吧挣菲。比如富稻,在你的游戲場(chǎng)景中有一幕是雪地場(chǎng)景,而你希望做一些石頭上白雪皚皚的覆蓋效果白胀,應(yīng)該怎么辦呢椭赋?難道讓你可愛(ài)的3D設(shè)計(jì)師再去出一套覆雪的貼圖然后使用新的貼圖?當(dāng)然不或杠,不是不能哪怔,而是不該。因?yàn)樾碌馁N圖不僅會(huì)增大項(xiàng)目的資源包體積向抢,更會(huì)增大之后修改和維護(hù)的難度认境,想想要是有好多石頭需要實(shí)現(xiàn)同樣的覆雪效果,或者是要隨著游戲時(shí)間堆積的雪逐漸變多的話挟鸠,你應(yīng)該怎么辦叉信?難道讓設(shè)計(jì)師再把所有的石頭貼圖都蓋上雪,然后再按照雪的厚度出5套不同的貼圖么兄猩?相信我茉盏,他們會(huì)瘋的。
于是枢冤,我們考慮用Shader來(lái)完成這件工作吧鸠姨!先考慮下我們需要什么,積雪效果的話淹真,我們需要積雪等級(jí)(用來(lái)表示積雪量)讶迁,雪的顏色,以及積雪的方向核蘸∥∨矗基本思路和實(shí)現(xiàn)自定義光照模型類似啸驯,通過(guò)計(jì)算原圖的點(diǎn)在世界坐標(biāo)中的法線方向與積雪方向的點(diǎn)積,如果大于設(shè)定的積雪等級(jí)的閾值的話則表示這個(gè)方向與積雪方向是一致的祟峦,其上是可以積雪的罚斗,顯示雪的顏色,否則使用原貼圖的顏色宅楞。廢話不再多說(shuō)针姿,上代碼,在上面的Shader的基礎(chǔ)上厌衙,更改Properties里的內(nèi)容為
Properties { _MainTex ("Base (RGB)", 2D) = "white" {}
_Bump ("Bump", 2D) = "bump" {}
_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)
}
沒(méi)有太多值得說(shuō)的距淫,唯一要提一下的是_SnowDirection設(shè)定的默認(rèn)值為(0,1,0),這表示我們希望雪是垂直落下的婶希。對(duì)應(yīng)地榕暇,在CG程序中對(duì)這些變量進(jìn)行聲明:
sampler2D _MainTex;sampler2D _Bump;
float _Snow;
float4 _SnowColor;
float4 _SnowDirection;
接下來(lái)改變Input的內(nèi)容:
struct Input {
float2 uv_MainTex;
float2 uv_Bump;
float3 worldNormal;
INTERNAL_DATA
};
相對(duì)于上面的Shader輸入來(lái)說(shuō),加入了一個(gè)float3 worldNormal; INTERNAL_DATA
喻杈,如果SurfaceOutput中設(shè)定了Normal值的話彤枢,通過(guò)worldNormal可以獲取當(dāng)前點(diǎn)在世界中的法線值。詳細(xì)的解說(shuō)可以參見(jiàn)Unity的Shader文檔奕塑。接下來(lái)可以改變surf函數(shù)堂污,實(shí)裝積雪效果了。
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Normal = UnpackNormal(tex2D(_Bump, IN.uv_Bump));
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;
}
和上面相比龄砰,加入了一個(gè)if…else…的判斷。首先看這個(gè)條件的不等式的左側(cè)讨衣,我們對(duì)雪的方向和和輸入點(diǎn)的世界法線方向進(jìn)行點(diǎn)積换棚。WorldNormalVector
通過(guò)輸入的點(diǎn)及這個(gè)點(diǎn)的法線值,來(lái)計(jì)算它在世界坐標(biāo)中的方向反镇;右側(cè)的lerp函數(shù)相信只要對(duì)插值有概念的同學(xué)都不難理解:當(dāng)Snow取最小值0時(shí)固蚤,這個(gè)函數(shù)將返回1,而Snow取最大值時(shí)歹茶,返回-1夕玩。這樣我們就可以通過(guò)設(shè)定_Snow的值來(lái)控制積雪的閾值,要是積雪等級(jí)Snow是0時(shí)惊豺,不等式左側(cè)不可能大于右側(cè)燎孟,因此完全沒(méi)有積雪;相反要是Snow取最大值1時(shí)尸昧,由于左側(cè)必定大于-1揩页,所以全模型積雪。而隨著取中間值的變化烹俗,積雪的情況便會(huì)有所不同爆侣。
應(yīng)用這個(gè)Shader萍程,并且適當(dāng)?shù)卣{(diào)節(jié)一下積雪等級(jí)和顏色,可以得到如下右邊的效果兔仰。
![添加了積雪效果的Shader](https://onevcat.com/assets/images/2013/shader-tutorial2-snow.jpg)
更改頂點(diǎn)模型
到現(xiàn)在位置茫负,我們還僅指是在原貼圖上進(jìn)行操作,不管是用法線圖使模型看起來(lái)凸凹有致乎赴,還是加上積雪忍法,所有的計(jì)算和顏色的輸出都只是“障眼法”,并沒(méi)有對(duì)模型有任何實(shí)質(zhì)的改動(dòng)无虚。但是對(duì)于積雪效果來(lái)說(shuō)缔赠,實(shí)際上積雪是附加到石頭上面,而不應(yīng)當(dāng)簡(jiǎn)單替換掉原來(lái)的顏色友题。但是具體實(shí)施起來(lái)嗤堰,最簡(jiǎn)單的辦法還是直接替換顏色,但是我們可以稍微變更一下模型度宦,使原來(lái)的模型在積雪的方向稍微變大一些踢匣,這樣來(lái)達(dá)到一種雪是附加到石頭上的效果。
我們繼續(xù)修改之前的Shader戈抄,首先我們需要告訴surface shadow我們要改變模型的頂點(diǎn)离唬。首先將#param行改為
#pragma surface surf CustomDiffuse vertex:vert
這告訴Shader我們想要改變模型頂點(diǎn),并且我們會(huì)寫一個(gè)叫做vert
的函數(shù)來(lái)改變頂點(diǎn)划鸽。接下來(lái)我們?cè)偬砑右粋€(gè)參數(shù)输莺,在Properties中聲明一個(gè)_SnowDepth
變量,表示積雪的厚度裸诽,當(dāng)然我們也需要在CG段中進(jìn)行聲明:
//In Properties{…}_SnowDepth ("Snow Depth", Range(0,0.3)) = 0.1
//In CG declarefloat _SnowDepth;
接下來(lái)實(shí)現(xiàn)vert方法嫂用,和之前積雪的運(yùn)算其實(shí)比較類似,判斷點(diǎn)積大小來(lái)決定是否需要擴(kuò)大模型以及確定模型擴(kuò)大的方向丈冬。在CG段中加入以下vert方法
void vert (inout appdata_full v) {
float4 sn = mul(transpose(_Object2World) , _SnowDirection);
if(dot(v.normal, sn.xyz) >= lerp(1,-1, (_Snow * 2) / 3)) {
v.vertex.xyz += (sn.xyz + v.normal) * _SnowDepth * _Snow;
}
}
和surf的原理差不多嘱函,系統(tǒng)會(huì)輸入一個(gè)當(dāng)前的頂點(diǎn)的值,我們根據(jù)需要計(jì)算并填上新的值作為返回即可埂蕊。上面第一行中使用transpose
方法輸出原矩陣的轉(zhuǎn)置矩陣往弓,在這里_Object2World是Unity ShaderLab的內(nèi)建值,它表示將當(dāng)前模型轉(zhuǎn)換到世界坐標(biāo)中的矩陣蓄氧,將其與積雪方向做矩陣乘積得到積雪方向在物體的世界空間中的投影(把積雪方向轉(zhuǎn)換到世界坐標(biāo)中)函似。之后我們計(jì)算了這個(gè)世界坐標(biāo)中實(shí)際的積雪方向和當(dāng)前點(diǎn)的法線值的點(diǎn)積,并將結(jié)果與使用積雪等級(jí)的2/3進(jìn)行比較lerp后的閾值比較匀们。這樣缴淋,當(dāng)前點(diǎn)如果和積雪方向一致,并且積雪較為完整的話,將改變?cè)擖c(diǎn)的模型頂點(diǎn)高度重抖。
加入模型更改前后的效果對(duì)比如下圖露氮,加入模型調(diào)整的右圖表現(xiàn)要更為豐滿真實(shí)。
![image](https://onevcat.com/assets/images/2013/shader-tutorial2-snow-vert.jpg)