1. 程式人生 > >Unity3D 5 官方教程:粒子系統 How-Tos

Unity3D 5 官方教程:粒子系統 How-Tos

這部分解釋瞭如何實現粒子系統的普遍型別。文件中所有的程式碼,你都可以免費使用於任何目的。

一個簡單的爆炸

你可以用一個粒子系統來創造出一個逼真的爆炸,但動態效果在一開始可能看起來會更混亂。精髓之處在於,一個爆炸只是粒子群的向外爆發;但你可以做一些調整,讓它看起來更真實。
一個正在開發的爆炸

粒子的時間線

一個簡單的爆炸,產生一個向所有方向飛速擴散的球形火焰。初始的爆發擁有大量能量,因此非常熾熱(即,明亮),並極快地移動。能量會迅速消散,讓火焰的擴散減緩並冷卻(即,變得不如原來那樣明亮)。最後,隨著所有能量燃燒殆盡,火焰停止,很快完全消失。
一個爆炸粒子通常只有短暫的生命期,你可以改動一些生命期的設定來模擬這一效果。粒子在開始應非常快地離開爆炸中心,但隨著遠離,它的速度應大幅降低。同時,顏色應從一開始為明亮的,之後變暗,最後褪色到透明。最後,在粒子的生命期內降低它的尺寸,會形成火焰隨著燃料耗盡而分散的效果。

實現

從預設的粒子系統物件開始(選單:GameObect->Create General->Particle System),進入Shape模組,設定發射器的形狀為一個小的球體,比如半徑為0.5個單位。標準資源庫中的粒子包含了一個名為Fire Add 的材質,很適合用於爆炸(選單:Assets->Import Package->Particles)。你可以將用於粒子系統的材質設定為使用Renderer模組。隨著Renderer開啟,你應同時關閉Cast Shadows(製造陰影)和Recieve Shadows(接受陰影),因為爆炸火焰應該是發出光而非接收光。
這一步,這粒子系統看起來像有許多小的火球被從一箇中心點扔出來。爆炸當然應該同時產生大量粒子的爆發。在Emission模組,你可以設定Rate值為0,並在時間點0處新增單個粒子的Burst。爆發的粒子數量依賴於你所希望的爆炸強度,但50個粒子是個不錯的開始。隨著爆發設定完成,這個爆炸比之前像多了,但它相當地慢,並且火焰看起來耽擱很久。在Particle System模組中(與遊戲物件會有相同的名字,例如“Explosion”),設定系統中粒子的Duration和Start Lifetime為兩秒。
你也可以使用Size Voer Lifetime模組來創造“火焰耗盡燃料”的效果。將尺寸曲線設定為使用“ramp down”(即,尺寸從100%開始,降低至0)。為了讓火焰黯淡、褪色,啟用 Color Over Lifetime模組,並設定梯度從左邊的白色開始,到右邊的黑色結束。由於Fire Add材質使用附加的著色器來渲染,顏色屬性的黯淡也控制了粒子的透明度;火焰的透明度會變得完全透明,隨著顏色褪至黑。並且,當一個粒子被繪製在另一個之上時,附帶的材質允許粒子的亮度“相加”。這進一步加強了在爆炸起始所有粒子相互間都很接近時,那刺眼奪目的效果。
按照現在的情況,爆炸正在成型,但它看著像是在外太空發生的。粒子在褪色之前,以不變的速度向外逸散,移動相當長的距離。如果你的遊戲設定是在太空中,這大概是你想要的準確效果。然而,在大氣層內發生的爆炸會被周圍的空氣所減速並抑制。開啟Limit Velocity Over Lifetime模組,設定Speed為3.0,Dampen fraction 為0.4;你應該會看到爆炸隨著程序而減少強度。
最後要注意的是,隨著粒子從爆炸中心離開,它們個體的形狀變得更容易辨認。特別地,相同尺寸、相同旋轉的粒子讓這個情況更明顯,相同的影象被重複用於每個粒子。避免這一情況的一個簡單辦法,是在粒子生成時,對尺寸和旋轉進行隨機的變動。在Particle System模組中檢視器的頂部,點選Start Size和Start Rotation屬性的右向小箭頭,都設定為Between Two Constants(在兩個常數間隨機)。對於尺寸,設定值在0.5到1.5,來產生一些變化,而沒有出現太多巨大或微小粒子的風險。現在應該會看到,粒子影象的重複現象少多了。

用法

在測試時,將Looping屬性開啟,有助於重複地觀看爆炸;但在最終的遊戲裡,應該將它關掉,讓爆炸僅發生一次。當爆炸是為有爆炸可能的物件(比如油箱)而設計時,可能希望將粒子系統元件新增到物件上,並讓Play On Awake屬性關閉。之後可以在指令碼中於必要之時啟動爆炸。
void Explode() {
var exp = GetComponent();
exp.Play();
Destroy(gameObject, exp.duration);
}
在其它情況下,爆炸發生在撞擊產生的位置。如果爆炸來自於一個物體(例如,一顆手榴彈)那麼你可以在一個延時之後、或當它碰撞到目標後,呼叫上方所示的Explode函式。

// Grenade explodes after a time delay.
public float fuseTime;

void Start() {
    Invoke("Explode", fuseTime);
}

// Grenade explodes on impact.
void OnCollisionEnter(Collision coll) {
    Explode();
}

對於遊戲裡不被實際表現的物體(例如,一個運動速度太快而無法被看到的拋射體)所產生的爆炸,可以僅僅在合適的位置例項化一個爆炸。可以從例如光線照射的結果,來決定(爆炸)接觸點(從而在接觸點例項化爆炸)。

// On the explosion object.
    void Start() {
        var exp = GetComponent<ParticleSystem>();
        exp.Play();
        Destroy(gameObject, exp.duration);
    }

// Possible projectile script.
public GameObject explosionPrefab;

void Update() {
    RaycastHit hit;

    if (Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hit)) {
        Instantiate (explosionPrefab, hit.point, Quaternion.identity);
    }
}

更深入的想法

這裡開發的爆炸很基礎,但可以修改它的很多部分,來達到在遊戲中所希望看到的實際效果。
你使用的粒子影象將對玩家如何“閱讀”爆炸產生很大的影響。小型的粒子多,那麼分散可見的火星一邊燃燒一邊逸散。不會完全分散開的更大粒子更像是個被毀壞的油箱產生的火球。尤其是,將需要一併改變部分屬性來完成效果。例如,火球會堅挺更久,並且在它消失前會擴張得更少;而一個猛烈的爆炸會將燃燒的部分撒佈到相當遠的距離外。
這裡有一些屬性用隨機值設定,但其它大量屬性有“在兩個常數/曲線之間隨機”的選項,可以使用這些來增加各種各樣的變化。改變尺寸和旋轉來避免明顯的粒子雷同效果;考慮在Start Delay、Start Speed 屬性增加一些隨機。少量的變化有助於加強爆炸的效果顯得更“自然”及難以預料,而不是有控制的機械過程。更大量的變化導致一個“髒(dirty)”爆炸。例如,改變Start Delay將產生一個不猛烈但更慢的爆炸,可能是因為車輛裡的油箱是被分別點燃的。

車的尾氣

轎車和許多其它型別的車輛在將燃料轉化為動力時,會排除尾氣。可以用粒子系統來增加一個排氣為車輛增加漂亮的最後一筆。
An exhaust generated by a particle system

粒子的時間線

尾氣從排氣管飛快地出現,但隨後接觸空氣後迅速減緩。隨著緩慢,尾氣擴散,變得模糊,很快消散在空氣中。由於尾氣是熱的,在它經過周圍的冷空氣時,也有輕微的上升。
尾氣粒子初始時,直徑不應大過排氣管;但在短暫的生命期裡可以在尺寸上有合理的增長。通常初始時有一些透明,隨著與空氣混合褪至完全透明。考慮到動態性,粒子會被非常快地發射,但之後迅速減緩,並且輕微地上升。

實現

在Shape模組,選擇圓錐形狀並將Angle屬性設定為0;這裡的“圓錐”將實際上作為一個圓柱形的排氣管。排氣管的半徑理應取決於車輛的尺寸,但通常可以通過匹配場景視角中的車輛模型來設定(例如,一個轎車模型的背後通常會有一個你可以匹配尺寸的排氣管)。關於你選擇的屬性設定,半徑實際上決定了相當多,比如粒子的大小和發射速率。處於本例的目標,我們假設車輛是個小轎車,在Unity世界座標下的標準尺寸為1米,排氣管的半徑則是0.05或者說是5釐米。
對煙霧粒子,一個適合的影象是在標準資源庫中提供的Smoke4材質。如果尚未擁有,從選單中的Assets->Import Package->Particles匯入。然後,轉至粒子系統的Renderer模組,設定材質屬性為Smoke4。
預設的5秒生命期通常對於車輛尾氣來說太長了,所以應當開啟粒子系統模組(與遊戲物件有相同的名字,例如,“Exhaust”)並設定Start Lifetime為2.5秒。同樣也在這個模組裡,設定Simulation Space to World和Gravity Modifier 為小的負值,比如-0.1。使用世界模擬空間能讓煙霧垂懸在它產生的地方,哪怕車輛在移動。負的重力影響引起煙霧粒子上升,彷彿他們是由熱氣組成的。一個很棒的額外效果是使用Start Rotation旁邊的選單箭頭,選擇在兩個常數間隨機的選項。分別設定兩個值為0和360,煙霧粒子在被髮射時會隨機地旋轉。許多一致對齊的粒子存在容易被察覺,減損本應是隨機、無定型的煙跡。
在這一步,煙霧粒子開始看起來真實可信,預設的發射速率創造了引擎間歇性燃燒的“噗噗”效果。然而,煙霧還沒有向外翻滾和消散。開啟Color Over Lifetime模組,點選頂部在右邊的梯度停止(這控制了顏色的“alpha”值透明度)。設定alpha值為0,可以看到煙霧粒子在場景中褪至無形。取決於引擎有多清潔,可能也希望降低開始時梯度的alpha值,黯淡的煙代表著髒、低效率的燃燒。
在褪至透明的同時,煙也應該隨著逸散而在尺寸上增加,可以在Size Over Lifetime模組中很容易地創造出這個效果。開啟這個模組,選擇曲線,滑動曲線塊到左邊,使粒子以完整尺寸的部分值開始。你選擇的實際值取決於排氣管的尺寸,但比排氣管尺寸稍大一點點的值,會產生很棒的氣體逸散效果。(用排氣管的尺寸作為粒子的起始,意味著氣體被排氣管限制而保持形狀,可是,氣體當然沒有既定的形狀 呀 !)使用粒子系統在場景檢視中的模擬來得到煙霧好的視覺效果。如果煙沒有散播到你希望的足夠遠那種效果,可以在在粒子系統模組中增加Start Size。
最後,煙霧應當隨著它散播而減速。讓這發生的簡單辦法是Force Over Lifetime模組。開啟這個模組,設定Space選項為本地,力的Z方向分量設定為一個負的值,標明粒子被這個力推向後方(系統沿著物體本地空間的Z軸正方向發射粒子)。大約為-0.75的值會表現得很好,如果其他引數也如之前建議那樣的設定。

使用

可以將這個尾氣粒子系統放在車輛物件的一個子物體下。對於簡單的遊戲,可以開啟 Play On Awake和Looping屬性,讓系統執行起來。然而在大多數情況下,隨著車輛移動,可能希望至少改變發射率。這首先是為了可靠性(即,引擎工作更賣力時,產生更多的煙),不過這也有助於阻止煙霧粒子隨著車輛移動而分散。一輛飛速移動的車,而發射率太慢,將會產生明顯的煙霧“噴出”效果,這相當不真實。
可以從指令碼中輕鬆地改變發射率。如果在指令碼中有個代表引擎轉數或者車速的變數,可以簡單地用一個常數乘以這個值,將結果賦予粒子系統的EmissionRate屬性。
// C#

using UnityEngine;
using System.Collections;

public class PartScriptTestCS : MonoBehaviour {

    public float engineRevs;
    public float exhaustRate;

    ParticleSystem exhaust;


    void Start () {
        exhaust = GetComponent<ParticleSystem>();
    }


    void Update () {
        exhaust.emissionRate = engineRevs * exhaustRate;
    }

}



// JS

var engineRevs: float;
var exhaustRate: float;

var exhaust: ParticleSystem;


function Start() {
    exhaust = GetComponent.<ParticleSystem>();
}


function Update () {
    exhaust.emissionRate = engineRevs * exhaustRate;
}

更深入的想法

基本方案已然建立了一個逼真的車輛尾氣。但你可能注意到了,你修改引數時,引擎的“特點”改變了。一個缺少調教、燃燒率低的引擎會不完全地燃燒燃料,導致濃密、黑漆漆的煙霧,在空氣中揮之不去。這完美地契合了老舊農場拖拉機,但絕不適合高效能運動跑車。對於一個“清潔”的引擎,應當對生命期、不透明性和尺寸的上升,使用小的數值。對於一個“髒”的引擎,應當增加這些值,試試使用Emission模組的Bursts屬性來產生引擎噼裡啪啦的效果。