1 日月 SunAndMoon
晝夜的話肯定少不了太陽(yáng)和月亮,太陽(yáng)和月亮實(shí)現(xiàn)的道理是一樣的,只不過(guò)是月亮比太陽(yáng)多了一個(gè)需要控制月牙程度(or添加貼圖)的細(xì)節(jié)~
1.1 Sun
太陽(yáng)的話很簡(jiǎn)單,直接在shader里實(shí)現(xiàn)一個(gè)太陽(yáng)跟隨平行光旋轉(zhuǎn)而旋轉(zhuǎn)的樣子就行。實(shí)現(xiàn)這個(gè)效果需要用到Unity內(nèi)置變量_WorldSpaceLightPos0獲取當(dāng)前平行光的方向,不要被這個(gè)參數(shù)名字“l(fā)ightPos”迷惑了,它實(shí)際上就是一個(gè)歸一化的vector(w=0)。接著用Unity內(nèi)置的distance函數(shù)計(jì)算當(dāng)前uv坐標(biāo)(i.uv.xyz)到上面那個(gè)的距離。
如何理解這個(gè)“距離”呢?——我們?cè)賮?lái)復(fù)習(xí)一遍圖形學(xué)基礎(chǔ)吧:學(xué)習(xí)齊次坐標(biāo)時(shí)講到“點(diǎn)與向量的區(qū)別”時(shí),例如vector(a, b, c, 0)和point(a, b, c, 1),我們可以把vector看作這個(gè)point挪向無(wú)窮遠(yuǎn)處位置。行,那么我們?cè)賮?lái)看看這個(gè)distance計(jì)算出來(lái)的結(jié)果的幾何意義是不是就十分簡(jiǎn)單了——uv坐標(biāo)越靠近,代表離這個(gè)無(wú)窮遠(yuǎn)處的點(diǎn)越近,于是結(jié)果越小。
- 我們需要的是一個(gè)實(shí)心圓(模擬“日月”),如果只將distance的結(jié)果與_SunColor相乘并作為片元著色器的結(jié)果輸出,主要代碼及效果如下:
float sun = distance(i.uv.xyz, _WorldSpaceLightPos0);
...
fixed4 col = sun * _SunColor;
- 場(chǎng)景中越靠近遠(yuǎn)處的“太陽(yáng)”位置越黑,想要實(shí)現(xiàn)一個(gè)實(shí)心圓就很簡(jiǎn)單了,補(bǔ)充后代碼及效果如下:
float sun = distance(i.uv.xyz, _WorldSpaceLightPos0);
float sunDis = 1 - sun / _sunRadius;
...
fixed4 col = sunDis * _SunColor;
?為了實(shí)現(xiàn)控制最大化,加入了_sunRadius參數(shù)以控制“太陽(yáng)”的大小,選擇除法的原因也很簡(jiǎn)單——太陽(yáng)越大意味著白色部分越大,意味著disatance()函數(shù)計(jì)算結(jié)果的權(quán)重更加分散,所以是除法。
- 到了這一步你會(huì)發(fā)現(xiàn),上圖還是缺點(diǎn)什么!
【第一】邊界有些模糊,我們想實(shí)現(xiàn)的效果是輪廓明顯的“日月”,這是因?yàn)?strong>邊界的sunDis數(shù)值不夠大,導(dǎo)致_sunColor相乘混合的顏色“淡”。如何處理?——簡(jiǎn)單,直接乘上個(gè)合適的倍數(shù)就行!
【第二】原有的網(wǎng)格不見(jiàn)了,給人一種黑色“籠罩”整個(gè)天空盒的錯(cuò)覺(jué)??吹竭@里你似乎會(huì)覺(jué)得疑惑:“網(wǎng)格不見(jiàn)了”啥意思?我來(lái)舉個(gè)例子,下面是我將sunDis值分別設(shè)置為1,0,-1的效果:
2和3看似都是黑色,其實(shí)還是有差別的,他會(huì)掩蓋網(wǎng)格。而且這個(gè)sunDis系數(shù)最后是跟類型為Color的_SunColor變量相乘,參考光照計(jì)算模型,這里理應(yīng)將該系數(shù)也限制在(0, 1),這里用saturate()就行!
考慮了以上兩點(diǎn)后最終的代碼:
float sun = distance(i.uv.xyz, _WorldSpaceLightPos0);
float sunDis = saturate((1 - sun / _sunRadius) * 50);
...
fixed4 col = sunDis * _SunColor;
最終效果:
1.2 Moon?
太陽(yáng)做完了,到了月亮部分,它倆一個(gè)在光的正方向(太陽(yáng))一個(gè)在反方向(月亮),這個(gè)不難理解吧!所以,關(guān)于跟隨平行光方向的部分,設(shè)置跟Sun一樣,只是多了一個(gè)負(fù)號(hào)。
這里我計(jì)劃實(shí)現(xiàn)兩種月亮的方法,一種是貼上一個(gè)真實(shí)的月亮圖片,另一個(gè)是做一個(gè)簡(jiǎn)單的可以控制的月牙形狀。
第一種:月牙
另外,由于月亮是有月牙的~就用兩個(gè)圓相減的形式做出月牙的效果,相減效果采用給uv.x一個(gè)偏移值_CrescentOffset的方法實(shí)現(xiàn)的。同樣,這里也需要注意只要涉及相減的需要給數(shù)值規(guī)范到(0, 1)才能確保效果的正確。
下面是月亮部分的代碼:
//2.Add Moon
float moon = distance(i.uv.xyz, -_WorldSpaceLightPos0);
float moonDis = saturate((1 - moon / _MoonRadius) * 50);
float crescent = distance(float3(i.uv.x + _CrescentOffset, i.uv.yz), -_WorldSpaceLightPos0);
float crescentDis = saturate((1 - crescent / _MoonRadius) * 50);
moonDis = saturate(moonDis - crescentDis);
fixed4 moonN = moonDis * _MoonColor;
最終效果:
第二種:月亮貼圖
貼圖主要問(wèn)題是解決UV坐標(biāo)系變換問(wèn)題,因?yàn)槿绻^續(xù)用原始的改變光照方向后月亮貼圖會(huì)變形的問(wèn)題,我們希望每個(gè)角度貼圖形狀都是圓圓的(參考日常生活中每個(gè)角度的月亮都是圓圓的),那么我們就需要一個(gè)建立一個(gè)4x4的坐標(biāo)系變換矩陣去實(shí)現(xiàn)。
問(wèn)題又來(lái)了:Unity自帶的變換矩陣unity_WorldToLight對(duì)于平行光是行不通的,只適用于point/spot/烘焙光,所以這里我們需要自己腳本實(shí)現(xiàn)變換矩陣。這里我們不難想到shadowmap里也需要求得光源空間的變換矩陣,可以參考我記錄的GAMES202作業(yè)1中CalcLightMVP()的實(shí)現(xiàn)過(guò)程去寫出這個(gè)變換矩陣,還可以跟著這一篇用Unity實(shí)現(xiàn)Shadow Map的博客實(shí)現(xiàn)這個(gè)變換矩陣,道理都是相通的。
更方便的還可以用Unity自帶的transform的worldToLocalMatrix獲得當(dāng)前對(duì)象的世界空間到local空間的變換矩陣,給場(chǎng)景中的平行光一個(gè)子Camera再獲取一下這個(gè)變換矩陣就行(后面會(huì)補(bǔ)充完整腳本內(nèi)容和shader部分的內(nèi)容,這里就先放一個(gè)效果)。
效果如下,加上了一點(diǎn)后面會(huì)做的漸變天空效果:
2 天空主體色?Gradient Sky
1.0版本
完成了日月交替的部分只能說(shuō)才實(shí)現(xiàn)了一小部分,而且天空很單調(diào),為了實(shí)現(xiàn)更加酷炫的效果,加點(diǎn)漸變天空顏色。說(shuō)起漸變,要用上lerp()了!分別給白天天空和晚上天空賦予顏色——基于UV坐標(biāo)的y?軸值來(lái)做天空顏色的漸變,記住還是需要saturate()!最后根據(jù)uv坐標(biāo)(i.uv.y)判斷何時(shí)晝夜交替。
// 3.gradient sky
fixed3 gradientDay = lerp(_DayBottomColor, _DayTopColor, saturate(i.uv.y));
fixed3 gradientNight = lerp(_NightBottomColor, _NightTopColor, saturate(i.uv.y));
fixed3 gradientSky = lerp(gradientNight, gradientDay, saturate(_WorldSpaceLightPos0.y));
2.0版本
上面的漸變天空簡(jiǎn)單的lerp做的,很枯燥。參考程序化天空盒實(shí)現(xiàn)晝夜變換,我們也來(lái)這位大佬的構(gòu)思思路,做一次分析(畢竟是作品集,所有過(guò)程自己實(shí)現(xiàn)一遍最好啦?。蔡炜兆兓瘹w納了出來(lái):
參考他提出的思路,地平線漸變用worldPos.y控制,但天空的主體顏色用光方的z和y共同控制,關(guān)于天空主體色我的理解:
(糾正一下,感覺(jué)早晨不是supper blue而是一種偏綠色的藍(lán)色?顏色可以自行調(diào)整的)
即從早晨開(kāi)始,早晨(非常藍(lán))-->中午(正常藍(lán))-->傍晚(紫色)-->深夜(深藍(lán)色),其中,y控制著白天和晚上,z控制白天三種顏色變換、晚上三種顏色交替
白天:
上述思路對(duì)應(yīng)的理解代碼為,
// 早午過(guò)渡
col = lerp(morningCol, noonCol, smoothstep(0,0.5,z));
// 再把上面的當(dāng)作午的,進(jìn)行午傍晚過(guò)渡
lerp(col, nightfallCol, smoothstep(0.5,1,z));
同理晚上:
// 早晚過(guò)渡
col = lerp(morningCol, nightCol, smoothstep(0,0.5,z));
// 再把上面的當(dāng)作晚的,進(jìn)行晚和傍晚的過(guò)渡
lerp(col, nightfallCol, smoothstep(0.5,1,z));
再優(yōu)化一下:我想要清晨和傍晚的顏色持續(xù)的少一點(diǎn),白天的天藍(lán)色維持的久一點(diǎn),這樣就需要更改參數(shù),索性直接多給兩個(gè)參數(shù),來(lái)調(diào)節(jié)一天內(nèi)清晨和傍晚的持續(xù)時(shí)間,最終關(guān)于天空顏色早晚變化的參數(shù)如下:
3 地平線漸變
跟參考文章不太一樣的是,我把漸變天空分為兩個(gè)部分:半天空漸變色+范圍變化的Bloom,雖然這樣比較麻煩(疊加了三層orz),但原神有些畫面它就是三種顏色疊加的效果,例如下圖傍晚的天空:

索性直接拆成三塊做。?
3.1 半天空漸變
半天空漸變色有4種顏色,4個(gè)顏色變化的時(shí)間剛好跟天空主題漸變色對(duì)應(yīng),
1 晚上:深藍(lán)色+淡色地平線
早晨:淺藍(lán)色+淡色地平線
中午:天藍(lán)色+淺藍(lán)地平線
傍晚:紫色+淡黃色地平線
由于這個(gè)是跟主色疊加,是不是應(yīng)該在天空主體漸變的基礎(chǔ)上修改,達(dá)到天空主色漸變的感覺(jué):
好,說(shuō)做就做,以早晨為例,還需要能控制漸變程度等,最后的參數(shù)如下:
整個(gè)天空顏色很接近了(斗膽),現(xiàn)在就差地平線附近的Bloom。
3.2 范圍變化的Bloom
(做了一下午了,起來(lái)活動(dòng)一下繼續(xù),orz,,)
再繼續(xù)觀察:
早->午:紅色(?。?->黃色(大)-->白色(?。?/p>
傍晚->晚上:黃色(大)-->橙黃色(超大)-->黃色(小)
(補(bǔ)充:既然節(jié)點(diǎn)4Mie散射開(kāi)始,那我們把大部分白色的Bloom都交給Mie散射,假設(shè)整個(gè)發(fā)光到節(jié)點(diǎn)4就宣告結(jié)束。)?
【空缺了一部分思路,這里做得比較著急沒(méi)有記錄,放個(gè)對(duì)比圖吧之后補(bǔ)充】
日出日落配上天空顏色變化:
emmm配色什么的感覺(jué)挺臟的,然后bloom那里需要給參數(shù)調(diào)整的,做的時(shí)候隨便選的,先繼續(xù)進(jìn)行下面的步驟,最后再優(yōu)化。?
接下來(lái)是加上云、和星空銀河,放在下一篇文章吧。
我上面實(shí)現(xiàn)漸變天空選擇的顏色還是照抄參考里的配色。但是!我認(rèn)為一個(gè)優(yōu)秀的天空盒,配色一定是要有講究的!配色的實(shí)現(xiàn)方法打算參考這篇文章里提到的將配色數(shù)據(jù)做成數(shù)組形式,像動(dòng)畫關(guān)鍵幀那樣呈現(xiàn)出來(lái)的方法。
3 大氣散射
做的時(shí)候沒(méi)有記錄過(guò)程,作品搞完后會(huì)回來(lái)補(bǔ)上。
參考
這里是我搜刮遍了各種網(wǎng)站找到的實(shí)現(xiàn)動(dòng)態(tài)天空盒的文章,自己在做的過(guò)程中也參考了很多,這里羅列出來(lái)希望對(duì)看到這篇文章的你有所幫助:
風(fēng)格化的動(dòng)態(tài)天空球 – WalkingFat
Unity日夜循環(huán)天空球(Procedural Skybox) - 知乎
Making a Stylized Skybox Shader
Unity 卡通渲染 程序化天空盒 - 知乎
【unity URP】晝夜循環(huán)天空球 - 知乎文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-799814.html
程序化天空盒實(shí)現(xiàn)晝夜變換 - 知乎 (zhihu.com)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-799814.html
到了這里,關(guān)于【程序化天空盒】過(guò)程記錄01:日月 天空漸變 大氣散射的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!