unity粒子系统粒子范围_粒子系统模块–常见问题

unity粒子系统粒子范围_粒子系统模块–常见问题

unity粒子系统粒子范围

从Unity 5.3开始,您可以对粒子系统的模块进行完全脚本访问。 我们注意到这些新的脚本功能可能会有些混乱。 为什么我们以非常规的方式使用结构? (Starting with Unity 5.3, you have full scripting access to the particle system’s modules. We noticed these new scripting features can be a bit confusing. Why do we use structs in an unconventional manner?)

In this blog post, we will answer some of your questions, take a little peek behind the scenes and explain some of our plans to make the process more intuitive in the future.

在此博客文章中,我们将回答您的一些问题,在后台进行一些窥视,并解释一些使将来的过程更加直观的计划。

访问模块 (Accessing Modules)

一个例子 (An example)

Here is a typical example in which we modify the rate property from the Emission module.

这是一个典型示例,其中我们从“排放”模块修改了rate属性。

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);
}
}
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 ) ;
}
}

To anyone familiar with .NET, you may notice that we grab the struct and set its value, but never assign it back to the particle system. How can the particle system ever know about this change, what kind of magic is this!?

对于熟悉.NET的任何人,您可能会注意到我们抓取了该结构并设置了它的值,但从未将其分配回粒子系统。 粒子系统怎么会知道这种变化,这是什么魔术!

这只是一个界面 (It’s just an interface)

Particle System modules in Unity are entirely contained within the C++ side of the engine. When a call is made to a particle system or one of its modules, it simply calls down to the C++ side. Internally, particle system modules are properties of a particle system. They are not independent and we never swap the owners or share them between systems. So whilst it’s possible in script to grab a module and pass it around in script, that module will always belong to the same system.

Unity中的粒子系统模块完全包含在引擎的C ++端。 当调用粒子系统或其模块之一时,它仅调用C ++端。 在内部,粒子系统模块是粒子系统的属性。 它们不是独立的,我们绝不交换所有者或在系统之间共享它们。 因此,尽管可以在脚本中获取模块并在脚本中传递它,但该模块将始终属于同一系统。

To help clarify this, let’s take a look at the previous example in detail. When the system receives a request for the emission module, the engine creates a new EmissionModule struct and passes the owning particle system as its one and only parameter. We do this because the particle system is required in order to access the modules properties.

为了澄清这一点,让我们详细看一下前面的示例。 当系统收到对发射模块的请求时,引擎将创建一个新的EmissionModule结构,并将拥有的粒子系统作为其唯一参数传递。 我们这样做是因为需要粒子系统才能访问模块属性。

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
public sealed class ParticleSystem : Component
{
.....
public EmissionModule emission { get { return new EmissionModule(this); } }
....
}
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);
}
}
......
}
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
public sealed class ParticleSystem : Component
{
. . . . .
public EmissionModule emission { get { return new EmissionModule ( this ) ; } }
. . . .
}
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 ) ;
}
}
. . . . . .
}

When we set the rate, the variable m_ParticleSystem is used to access the module and set it directly. Therefore we never need to reassign the module to the particle system, because it is always part of it and any changes are applied immediately. So all a module does is call into the system that owns it, the module struct itself is just an interface into the particle systems internals. Internally, the modules store their respective properties and they also hold state based information, which is why it is not possible for modules to be shared or assigned to different particle systems. If you do want to copy properties from one system to another, it is advised that you only copy the relevant values and not the entire class, as this results in less data being passed between the C++ side and the C# side.

当我们设置速率时,变量m_ParticleSystem用于访问模块并直接进行设置。 因此,我们永远不需要将模块分配给粒子系统,因为它始终是粒子系统的一部分,并且所有更改都将立即应用。 因此,模块所做的只是调用拥有它的系统,模块结构本身只是粒子系统内部的接口。 在内部,模块存储它们各自的属性,并且它们还保存基于状态的信息,这就是为什么模块无法共享或分配给不同的粒子系统的原因。 如果确实要将属性从一个系统复制到另一个系统,建议您仅复制相关值,而不要复制整个类,因为这样会减少在C ++端和C#端之间传递的数据。

MinMaxCurve (The MinMaxCurve)

A significant number of module properties are driven by our MinMaxCurve class. It is used to describe a change of a value with time. There are 4 possible modes supported; here is a brief guide on how to use each when scripting.

我们的MinMaxCurve类驱动大量的模块属性。 它用于描述值随时间的变化。 支持4种可能的模式。 这是有关在编写脚本时如何使用它们的简要指南。

不变 (Constant)

By far the simplest mode, constant just uses a single constant value. This value will not change over time. If you wanted to drive a property via script, then setting the scalar would be one way to do this.

到目前为止,最简单的模式是,常量仅使用一个常量值。 该值不会随时间变化。 如果要通过脚本驱动属性,则设置标量将是执行此操作的一种方法。

In script, we would access the constant like this:

在脚本中,我们将这样访问常量:

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);
}
}
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

在两个常数之间随机

This mode generates a random value between two constants. Internally, we store the two constants as a key in the min and max curves respectively. We get our value by performing a lerp between the 2 values using a normalised random parameter as our lerp amount.This means that we are almost doing the same amount of work as the random between two curves mode.

此模式在两个常量之间生成一个随机值。 在内部,我们将两个常数分别存储为最小和最大曲线中的一个键。 通过使用归一化随机参数作为lerp量在两个值之间执行lerp来获得值,这意味着我们所做的工作量几乎与两条曲线模式之间的随机数相同。

This is how we would access the two constants of a module:

这就是我们访问模块的两个常量的方式:

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);
}
}
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)

In this mode, the value of the property will change based on querying a curve. When using curves from the MinMaxCurve in script there are some caveats. Firstly, if you try to read the curve property when it is in one of the Curve modes, then the you’ll get the following error message: “Reading particle curves from script is unsupported unless they are in constant mode”. Due to the way the curves are compressed in the engine, it is not possible to get the MinMaxCurve unless it is using one of the 2 constant modes.We know this isn’t great, read on our plans to improve it. The reason for this is that internally, we don’t actually just store an AnimationCurve, but select one of two paths. If the curve is simple (no more than 3 keys with one at each end), then we use an optimized polynomial curve, which provides improved performance. We then fallback to using the standard non-optimized curve if it is more complex. In the Inspector, an unoptimized curve will have a small icon at the bottom right which will offer to optimize the curve for you.

在这种模式下,属性的值将根据查询曲线而改变。 在脚本中使用MinMaxCurve中的曲线时,有一些警告。 首先,如果您尝试在其中一种“曲线”模式下读取“ curve”属性,则会收到以下错误消息: “不支持从脚本读取粒子曲线,除非它们处于恒定模式”。 由于引擎中曲线的压缩方式不同,除非使用2种恒定模式之一,否则无法获得MinMaxCurve。我们知道这不好,请阅读我们的改进计划。 原因是在内部,我们实际上不只是存储AnimationCurve,而是选择两个路径之一。 如果曲线很简单(两端不超过3个关键点,每个关键点不超过3个关键点),那么我们将使用优化的多项式曲线来改善性能。 然后,如果更为复杂,我们便退回到使用标准非优化曲线。 在检查器中,未优化的曲线将在右下角带有一个小图标,该图标将为您优化曲线。

优化曲线 (An optimized curve)

未优化的曲线 (An unoptimized curve)

While it may not be possible to get the curve from a module in script, it is possible to work around this by storing your own curve and applying this to the module when required, like this:

尽管可能无法从脚本中的模块获取曲线,但可以通过存储自己的曲线并将其应用到模块中来解决此问题,如下所示:

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);
}
}
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 ) ;
}
}

在2条曲线之间随机。 (Random between 2 curves.)

This mode generates random values from in between the min and a max curves, using time to determine where on the x axis to sample. The shaded area represents the potential values. This mode is similar to the curve mode in that it is not possible to access the curves from script and that we also use optimized polynomial curves(when possible). In order to benefit from this, both curves must be optimizable, that is contain no more than 3 keys and have one at each end. Like in curve mode, it is possible to tell if the curves are optimized by examining the bottom right of the editor window.

此模式从最小曲线和最大曲线之间的中间值生成随机值,并使用时间确定在x轴上的哪个位置进行采样。 阴影区域代表电位值。 此模式与曲线模式相似,因为无法从脚本访问曲线,并且在可能的情况下也使用优化的多项式曲线。 为了从中受益,两条曲线都必须是可优化的,即最多包含3个关键点,并且两端各有一个。 像在曲线模式下一样,可以通过检查编辑器窗口的右下角来判断曲线是否已优化。

This example is very similar to the curve, however, we now also set the minimum curve as well.

这个示例与曲线非常相似,但是,我们现在也设置了最小曲线。

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);
}
}
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 ) ;
}
}

性能 (Performance)

We did some simple performance comparisons to see how these different modes compare. These samples were taken before our recent SIMD optimizations, which should provide a significant performance boost. In our specific test scene, we got these results:

我们做了一些简单的性能比较,以了解这些不同模式的比较。 这些样本是在我们最近的SIMD优化之前进行的,这可以显着提高性能。 在我们特定的测试场景中,我们得到了以下结果:

减轻痛苦 (Easing the pain)

从MinMaxCurve类读取曲线 (Reading curves from the MinMaxCurve class)

We know that you really ought to be able to read particle system curves from script, regardless of what mode they are in. We are actively working on removing this limitation, so you can read/modify all those lovely curves in your scripts. Its also currently not possible to query the curve to check if the mode is using a curve, without an error being thrown. That’s also going to be fixed!

我们知道您确实应该能够从脚本中读取粒子系统曲线,而不管它们处于哪种模式。我们正在积极努力消除此限制,因此您可以在脚本中读取/修改所有这些可爱的曲线。 当前也无法查询曲线以检查模式是否正在使用曲线,而不会引发错误。 这也将得到解决!

将模块从结构更改为类 (Changing modules from structs to classes)

We are currently prototyping a change to move all the structs to classes. Functionally they will behave the same, however by using a reference type, it should be clearer that the module belongs to a system. It will also allow for setting/getting values without having to hold a temporary variable. However, this will mean we allocate them once in the constructor, which will generate garbage, but only at initialization time.

我们当前正在对更改进行原型设计,以将所有结构移至类。 从功能上讲,它们的行为相同,但是通过使用引用类型,应该更清楚模块属于系统。 它还将允许设置/获取值,而不必保留临时变量。 但是,这将意味着我们在构造函数中分配它们一次,这将生成垃圾,但仅在初始化时产生。

For example:

例如:

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

最后 (Finally)

We hope this post has been of some use to you, please head over to this forum post to grab the examples and comment/discuss. We will also add this information over to our documentation.

我们希望这篇文章对您有所帮助,请转到此论坛文章以获取示例和评论/讨论。 我们还将把这些信息添加到我们的文档中。

翻译自: https://blogs.unity3d.com/2016/04/20/particle-system-modules-faq/

unity粒子系统粒子范围