您好,登錄后才能下訂單哦!
這篇文章主要介紹Unity Shader如何實現基于光照圖的簡易晝夜變化,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
可能有的朋友發現問題了,哎呀,怎么影子木有變化.....是的,變不了,因為我們這是基于烘焙過得光照圖做的變化,所以,陰影是固定的。如果我們有實時光,就不是這個教程所涉及的了,直接調整方向光就可以了。
這個方案最早是基于我以前做的一個MMO項目,在幾年前,實時光并不現實(現在對于很多項目來說也不現實),光線幾乎都是由烘焙后的光照圖來決定。但是我們在做一些劇情動畫時,又需要一些晝夜變化,通常這些變化還是很快速的。譬如,劇情中寫道“就這么,一夜過去了.....”,如果這時候能加一個快速變化的光照系統,還是很有畫面感的,對吧?然后,就有了這個暴力簡陋版晝夜系統。
為什么說它暴力簡陋版呢?因為它真的很暴力,我們最終想到的性能最優辦法,就是直接修改所有材質的顏色,當然最終如果實現出好的效果的話,還是需要很多方面考量的,這里只提供一個簡單的解題思路。
修改材質的顏色,總不能讓我們寫代碼去挨個遍歷場景中所有的材質來修改顏色吧,累死了,而且一想就知道性能堪憂。好在Unity為我們提供了一個便利的修改方法,就是全局修改shader屬性。我們來看看官方的這個API,修改全局shader顏色的,(Shader.SetGlobalColor)。
用起來很簡單,這個API可以直接的修改場景里所有叫這個名字的屬性,前提是這個屬性沒有被暴露在編輯器里,也就是說你只能在Pass通道里聲明它,如果你在屬性塊里聲明了它,對不起,這個API無效,它會優先使用屬性塊里定義的參數。
熟悉了這個API,接下來就簡單了,我們只需要在每一個需要變化的shader里,加入一個天光的顏色屬性,直接乘上去就行了,最后再全局修改這個顏色。看看下面的shader重點代碼,多出來的代碼,用手指頭都能數的過來。
//這里就是需要修改的全局顏色---天光顏色
fixed4 _SkyColor;
void surf (Input IN, inout SurfaceOutputStandard o) {
// 直接乘上去就好了
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color*_SkyColor;
好,還沒完,重點是我們需要用一個腳本來控制修改這個顏色。
這里我寫了四個時段的顏色,分別是,早晨,中午,下午,晚上(事實上如果不計較細節,早晨和中午可以合并)。并把這四個顏色暴露出來,供場景人員修改。還有一個一整天循環一次所需要的時間,單位為秒。
接下來就是在代碼里去推進時間了,下面是代碼,還是比較簡單的,每一行我都寫了詳細注釋,但我代碼寫的并不好,請諒解。
public class DayAndNightManager : MonoBehaviour
{
public float oneDayTime = 10; //一整天循環一次的時間,這里默認的十秒
public Color morningColor = Color.white; //早晨顏色
public Color noonColor = Color.white; //中午顏色
public Color afterNoonColor = Color.white; //傍晚顏色
public Color nightColor = Color.white; //晚上顏色
private Color[] colors;//所用的所有時間段的顏色
private Color currentColor;//當前顏色
private float dayTimer; //時間
// Use this for initialization
void Start () {
//把所有時段的顏色收集起來,這里多了一個,是因為整個是一個循環,結束的時候要回到凌晨時段,所以最后一個顏色是早晨的顏色
colors = new Color[5];
colors[0] = morningColor;
colors[1] = noonColor;
colors[2] = afterNoonColor;
colors[3] = nightColor;
colors[4] = morningColor;
//初始化
Shader.SetGlobalColor("_SkyColor",Color.white);
currentColor = morningColor;
dayTimer = 0;
}
// Update is called once per frame
void Update()
{
//時間開始推進,乘以4是因為我們有四個時段,這樣再乘以后面的一整天時間才是準確的。
dayTimer += Time.deltaTime*4/oneDayTime;
//一個循環結束了,重新開始
if (dayTimer >= (float)colors.Length - 1)
{
dayTimer = 0;
}
//采樣兩個顏色,第一個是即將過去的時間顏色,第二個是即將到來的時間顏色,我們通過兩個數學方法向下和向上取整。
Color color01 = colors[Mathf.FloorToInt(dayTimer)];
Color color02 = colors[Mathf.CeilToInt(dayTimer)];
//兩個顏色的占比,我們通過取時間的小數部分,就可以了。
float weight = dayTimer - Mathf.FloorToInt(dayTimer);
//利用權重來對顏色進行融合
currentColor = Color.Lerp(color01, color02, weight);
//修改全局顏色,_SkyColor已經寫到所有的shader里了
Shader.SetGlobalColor("_SkyColor", currentColor);
//修改全局時間,這個主要是控制天空盒的貼圖融合
Shader.SetGlobalFloat("_DayAndNightChange", dayTimer);
}
代碼的最后一行是修改天空盒的貼圖融合,是的,光變了,天空盒怎么能不變,所以我用了四張天空盒的貼圖來做過度,聽著內存有點吃緊是吧?如果想節約的話,可以用一張貼圖來做顏色變化就可以了,但是效果可能沒有這樣好一點,美術同學可以把四張圖都給你畫的很美吆。
至于天空盒的shader,也很簡單,我使用了一個float屬性來融合四張貼圖,重點代碼如下。
//重點是這個變量,通過全局修改這個變量的參數來對四個時段的貼圖采樣,并融合。
//這個變量的范圍與腳本的時間一致,都是0-4循環,最后一個時段與第一個一樣,都是凌晨
float _DayAndNightChange;
half4 frag (v2f i) : SV_Target
{
//基本就是一些融合算法,先利用時間來算出每個貼圖的顏色占比,然后統一加到一起。
//這只是計算了天空盒的一面,后面的Pass算法相同
half4 col01 = skybox_frag(i,_Tex01, _Tex01_HDR)*(saturate(1- _DayAndNightChange));
half4 col02 = (skybox_frag(i,_Tex02, _Tex02_HDR)*(saturate(2- _DayAndNightChange)))-(skybox_frag(i,_Tex02, _Tex02_HDR)*(saturate(1- _DayAndNightChange)));
half4 col03 = (skybox_frag(i,_Tex03, _Tex03_HDR)*(saturate(3- _DayAndNightChange)))-(skybox_frag(i,_Tex03, _Tex03_HDR)*(saturate(2- _DayAndNightChange)));
half4 col04 = (skybox_frag(i,_Tex04, _Tex04_HDR)*(saturate(4- _DayAndNightChange)))-(skybox_frag(i,_Tex04, _Tex04_HDR)*(saturate(3- _DayAndNightChange)));
half4 col05 = skybox_frag(i,_Tex01, _Tex01_HDR)*(saturate(_DayAndNightChange -3));
half4 c = col01 +col02+col03+col04+col05;
return c;
}
代碼有些冗余,有很大的修改空間........但是這樣看著比較清楚,其實就是利用_DayAndNightChange這個屬性對每張貼圖進行采樣,然后融合。
好,這里我只是實現了一個簡易版的效果,如果想在項目中使用,并實現好的效果,還有很多需要考慮的,譬如,全局修改霧的顏色,還有晚上開啟一些燈光效果,火把效果,還可以寫一個方法,用于跳轉到某個時間。還有如果這種屬性多了的話,最好重新修改一下編輯窗口,否則美術同學看著會很亂。
至于性能方面,這種系統還是很好控制的,個人推薦時間的變化不要像我寫的這樣每幀一次,可以控制一下,譬如0.1s一次。
上面這個簡單工程我也附在這里,如果有什么不對的地方,望指正。
對了,這個工程在打開的時候可能場景是黑的,運行一次就好了。原因是,全局修改的變量,也就是那個_SkyColor,在沒有賦值的時候,是黑色的。后期這個東西可能需要改一下,
以上是“Unity Shader如何實現基于光照圖的簡易晝夜變化”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。