粒子系統模組Particle System Modules - FAQ

Unity 5.3開始,開發者可以透過腳本來存取粒子系統中所有的模組了。我們了解這些新的腳本特性可能會讓大家困惑,為什麼要用非常規的方式來使用結構?本文中你會找到一些答案。

存取模組(Accessing Modules)


範例:
這是一個典型的修改Emission Module中的速率的範例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using UnityEngine;
public class AccessingAParticleSystemModule : MonoBehaviour
{
   // Use this for initialization
   void Start ()
   {
     // Get the emission module.
     var forceModule = GetComponent<ParticleSystem>().forceOverLifetime;
     // Enable it and set a value
     forceModule.enabled = true ;
     forceModule.x = new ParticleSystem.MinMaxCurve(15.0f);
   }
}
如果你熟悉.NET,你會注意到我們抓了結構體並且設了它的值,但沒有將值貼回粒子系統中。那麼粒子系統是如何知道這個改變呢?怎麼辦到的?


只是一個介面


Unity中的粒子系統完全包含在引擎的C++部分中。當呼叫粒子系統或者其中的一個模組時,會直接呼叫C++端。
在內部,粒子系統模組(Particle system modules)只是粒子系統中一個屬性。他們並非獨立,且無法在系統間改變模組所有權或共用模組。所以雖然可以在腳本中抓取一個模組並傳遞,但模組永遠只會屬於同一個系統。

為了便於理解,讓我們看一下例子
當系統接收到一個對emission module的請求時,引擎會新建一個EmissionModule結構並且作為唯一的參數傳遞給它的擁有者。這麼做是因為存取模組的屬性必需要有粒子系統在上層。

1
2
3
4
5
6
7
8
public sealed class ParticleSystem : Component
{
.....
   public EmissionModule emission { get { return new EmissionModule( this ); } }
....
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public partial struct EmissionModule
{
   private ParticleSystem m_ParticleSystem; // Direct access to the particle system that owns this module.
   EmissionModule(ParticleSystem particleSystem)
   {
     m_ParticleSystem = particleSystem;
   }
   public MinMaxCurve rate
   {
     set
     {
       // In here we call down to the c++ side and perform what amounts to this:
       m_ParticleSystem->GetEmissionModule()->SetRate(value);
     }
   }
......
}
當我們設定速率時,變數m_ParticleSystem用來存取這個模組並直接設定速率值。因此我們完全不需要重新賦予值到粒子系統中,因為它永遠是粒子系統的一部分,任何改變都會立即生效。所以模組做的只是呼叫擁有它的粒子系統,模組結構體本身只是一個進入粒子系統內部的接口。

在內部,模組存儲他們各自的屬性並保留狀態資訊,這就是為何無法在不同的粒子系統中共用模組。
如果你想將屬性從一個系統拷貝到另外一個,建議只拷貝相對應的值而不要拷貝整個類別,這樣就可以讓C++和C#之間拷貝的資料盡可能的少。

The MinMaxCurve


有很多模組的屬性都是由MinMaxCurve類別來驅動的。用來描述隨時間的變化的值,支援4種模式。以下是如何在腳本中使用它們的指南。

Constant


這是最簡單的模式,Constant只使用單一的值。這個值不會隨著時間改變而改變。如果你想要透過腳本改變一個值,改變這個值是一種方法。 

在腳本中存取Constant的程式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using UnityEngine;
public class MinMaxCurveConstantMode : MonoBehaviour
{
   ParticleSystem myParticleSystem;
   ParticleSystem.EmissionModule emissionModule;
   void Start()
   {
     // Get the system and the emission module.
     myParticleSystem = GetComponent<ParticleSystem>();
     emissionModule = myParticleSystem.emission;
     GetValue();
     SetValue();
   }
   void GetValue()
   {
     print( "The constant value is " + emissionModule.rate.constantMax);
   }
   void SetValue()
   {
     emissionModule.rate = new ParticleSystem.MinMaxCurve(10.0f);
   }
}

Random between two constants 


這個模式在兩個值之間產生一個亂數。在內部我們會將這兩個值作為關鍵分別存到最小和最大的曲線中。我們透過在兩個值之間進行線性插值計算來獲取新值,它使用一個標準劃的亂數作為插值量。這取樣方式和Random between two curves幾乎相同。

如何存取模組兩個constant的範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using UnityEngine;
public class ParticleModuleExamples : MonoBehaviour
{
   ParticleSystem myParticleSystem;
   ParticleSystem.EmissionModule emissionModule;
   void Start()
   {
     // Get the system and the emission module.
     myParticleSystem = GetComponent<ParticleSystem>();
     emissionModule = myParticleSystem.emission;
     GetRandomConstantValues();
     SetRandomConstantValues();
   }
   void GetRandomConstantValues()
   {
     print( string .Format( "The constant values are: min {0} max {1}." , emissionModule.rate.constantMin, emissionModule.rate.constantMax));
   }
   void SetRandomConstantValues()
   {
     // Assign the curve to the emission module
     emissionModule.rate = new ParticleSystem.MinMaxCurve(0.0f, 1.0f);
   }
}

Curve


在這個模式中,屬性值會透過對一個曲線的查詢來改變,使用腳本中MinMaxCurve的曲線時有一些注意事項。
首先,如果試著在一個Curve模式下讀取曲線值時會得到如下的錯誤:“Reading particle curves from script is unsupported unless they are in constant mode”。
由於曲線在引擎中是壓縮的狀態無法存取到MinMaxCurve,除非使用兩個constant模式之一,我們正著手計畫改進這點。主要原因是系統內部我們沒有實際保存一個AnimationCurve而是從兩個路徑中選擇一個。如果曲線很簡單(不超過三個key並在每個端點都有一個)。那麼我們會用一個性能較好的優化曲線。如果曲線很複雜我們會回頭使用未優化的曲線。在Inspector視窗中,未優化的曲線會在右下顯示一個小圖示讓你手動優化這個曲線。

優化的曲線

 

未優化的曲線

 
雖然不能用腳本從模組中存取曲線,但可以先存一個自己的曲線然後在需要的時候貼到到模組中,像這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using UnityEngine;
public class MinMaxCurveCurveMode : MonoBehaviour
{
   ParticleSystem myParticleSystem;
   ParticleSystem.EmissionModule emissionModule;
   // We can "scale" the curve with this value. It gets multiplied by the curve.
   public float scalar = 1.0f;
   AnimationCurve ourCurve;
   void Start()
   {
     // Get the system and the emission module.
     myParticleSystem = GetComponent<ParticleSystem>();
     emissionModule = myParticleSystem.emission;
     // A simple linear curve.
     ourCurve = new AnimationCurve();
     ourCurve.AddKey(0.0f, 0.0f);
     ourCurve.AddKey(1.0f, 1.0f);
     // Apply the curve
     emissionModule.rate = new ParticleSystem.MinMaxCurve(scalar, ourCurve);
     // In 5 seconds we will modify the curve.
     Invoke( "ModifyCurve" , 5.0f);
   }
   void ModifyCurve()
   {
     // Add a key to the current curve.
     ourCurve.AddKey(0.5f, 0.0f);
    // Apply the changed curve
    emissionModule.rate = new ParticleSystem.MinMaxCurve(scalar, ourCurve);
   }
}


Random between 2 curves


這個模式從最小和最大曲線之間產生一個亂數,它用時間來決定在X軸上採樣的位置。陰影區表示可能的值。這個模式和曲線模式類似,不能在腳本中存取曲線也會幫你優化曲線(在允許情況下)。想要用這個模式看到效果,兩條曲線都必須被優化,也就是說和曲線模式一樣每條曲線不超過三個key並在每個端點各有一個key,你可以透過inspector視窗檢查右下角來確定曲線是否被優化。



下面的範例和Curve曲線模式很相似,只不過現在多設定了最小曲線。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using UnityEngine;
public class MinMaxCurveRandom2CurvesMode : MonoBehaviour
{
   ParticleSystem myParticleSystem;
   ParticleSystem.EmissionModule emissionModule;
   AnimationCurve ourCurveMin;
   AnimationCurve ourCurveMax;
   // We can "scale" the curves with this value. It gets multiplied by the curves.
   public float scalar = 1.0f;
   void Start()
   {
     // Get the system and the emission module.
     myParticleSystem = GetComponent<ParticleSystem>();
     emissionModule = myParticleSystem.emission;
     // A horizontal straight line at value 1
     ourCurveMin = new AnimationCurve();
     ourCurveMin.AddKey(0.0f, 1.0f);
     ourCurveMin.AddKey(1.0f, 1.0f);
     // A horizontal straight line at value 0.5
     ourCurveMax = new AnimationCurve();
     ourCurveMax.AddKey(0.0f, 0.5f);
     ourCurveMax.AddKey(1.0f, 0.5f);
     // Apply the curves
     emissionModule.rate = new ParticleSystem.MinMaxCurve(scalar, ourCurveMin, ourCurveMax);
     // In 5 seconds we will modify the curve.
     Invoke( "ModifyCurve" , 5.0f);
   }
   void ModifyCurve()
   {
     // Create a "pinch" point.
     ourCurveMin.AddKey(0.5f, 0.7f);
     ourCurveMax.AddKey(0.5f, 0.6f);
     // Apply the changed curve
     emissionModule.rate = new ParticleSystem.MinMaxCurve(scalar, ourCurveMin, ourCurveMax);
   }
}

效能


我們做了一些簡單的效能比對來看看這些模式之間的差異。這些樣本都是在我們的SIMD優化前獲取的,SIMD優化能讓效能明顯提升。在特定測試場景結果如下:


解除你的苦痛


從MinMaxCurve中讀取曲線


或許你想要從腳本中讀取粒子系統曲線,不管何種模式。我們正努力讓這個功能實現,讓你可以在腳本中存取這些可愛的曲線。還有,現在無法檢查出是否模組正在用曲線。這也正在改進中!

將模組從Struct轉換為Class


我們現在正著手將所有的結構轉換到類別的工作。從功能上他們的行為是一樣的,但是類別是參考類型,這會更加明確模組從屬一個系統。同樣也可以在不保持一個臨時變數的情況下設定/獲取值。但是這就代表在構造時就會分配記憶體,在初始化時會產生GC。
例如:

1
2
3
4
5
6
var em = ps.emission;
em.enabled = true ;
// Could be written as
ps.emission.enabled = true ;


結尾


希望本文講解能幫到你,可以到這裡參與討論。文中提到的粒子模組資訊也會加到Unity說明文件中。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值