Search Unity

What is the Unity 5.3 equivalent of the old ParticleSystem.emissionRate

Discussion in 'General Graphics' started by BenHymers, Dec 10, 2015.

  1. BenHymers

    BenHymers

    Joined:
    Dec 16, 2014
    Posts:
    25
    In 5.3, ParticleSystem.emissionRate is deprecated in favour of ParticleSystem.emission, but the docs don't mention what part of emission... I see a mode which can be set to 'constant', and a constantMin and constantMax on MinMaxCurve... do I need to set this mode, and set min and max to be the same value, to get the old behaviour of setting emissionRate to one value?
     
  2. namanam

    namanam

    Joined:
    Jul 27, 2013
    Posts:
    5
    +1 , emissionRate property is deprecated. Use emission.rate instead. but HOW.
     
    Malbers likes this.
  3. Mahdi-Jeddi

    Mahdi-Jeddi

    Joined:
    Dec 21, 2012
    Posts:
    27
    +1. The problem is that all of the properties are either struct which cannot be edited inline or readonly! :(
     
  4. fffMalzbier

    fffMalzbier

    Joined:
    Jun 14, 2011
    Posts:
    2,869
  5. rodcarvalho

    rodcarvalho

    Joined:
    Mar 18, 2013
    Posts:
    2
    Still don't know to get rate value for example. When I'm going set rate value I have to use: new ParticleSystem.MinMaxCurve(0); everytime I want to change rate value :(
     
  6. Potaski

    Potaski

    Joined:
    Aug 21, 2013
    Posts:
    52
    The values in the module can not be set. e.g. GetComponent<ParticleSystem>().emission.rate = new ParticleSystem.MinMaxCurve(100); doesn't work.

    Edit: Can be set when assign the module to a local variable, it works but kind of a pain.
     
    Last edited: Dec 14, 2015
  7. fffMalzbier

    fffMalzbier

    Joined:
    Jun 14, 2011
    Posts:
    2,869
    That the way unity apparently want us to do it.
    Just get a copy of the struct and modify it , unity has it linked in the backend and will update the data back to the particle system without you needing to write all the data back what could be very slow if you would like to do that every frame.
     
    Last edited: Feb 15, 2016
    Psyco92 likes this.
  8. Mahdi-Jeddi

    Mahdi-Jeddi

    Joined:
    Dec 21, 2012
    Posts:
    27
    This is just so much work! ;)

    var em = Particle.emission;
    var rate = new ParticleSystem.MinMaxCurve();
    rate.constantMax = emissionRate;
    em.rate = rate;
     
  9. BenHymers

    BenHymers

    Joined:
    Dec 16, 2014
    Posts:
    25
    Hmm, bit of a faff, but that'll work - thanks! Unity people: this is the kind of thing that would be helpful in the docs when you deprecate things.

    I set the constantMin too, just in case.
     
  10. Razieln64

    Razieln64

    Joined:
    May 3, 2008
    Posts:
    129
    Looks like it's time to code some extension methods to make things simpler...

    Code (csharp):
    1. public static class ParticleSystemExtension
    2. {
    3.     public static void EnableEmission(this ParticleSystem particleSystem, bool enabled)
    4.     {
    5.         var emission = particleSystem.emission;
    6.         emission.enabled = enabled;
    7.     }
    8.  
    9.     public static float GetEmissionRate(this ParticleSystem particleSystem)
    10.     {
    11.         return particleSystem.emission.rate.constantMax;
    12.     }
    13.  
    14.     public static void SetEmissionRate(this ParticleSystem particleSystem, float emissionRate)
    15.     {
    16.         var emission = particleSystem.emission;
    17.         var rate = emission.rate;
    18.         rate.constantMax = emissionRate;
    19.         emission.rate = rate;
    20.     }
    21. }
     
  11. ysalmi

    ysalmi

    Joined:
    Jan 25, 2013
    Posts:
    19
    Thanks for the script, this really saves some time.
     
  12. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    615
    Thanks for the extension script.
     
  13. Futurerobot

    Futurerobot

    Joined:
    Jul 13, 2011
    Posts:
    179
    Hm I'm not sure I understand. The EmissionModule is (titled as) a struct ( value-type ), but I can reference it and then use it to edit values? Does the struct store a reference back to the particlesystem? Does this also work if I make a new EmissionModule and assign it to a particlesystem?
     
    landon912 likes this.
  14. landon912

    landon912

    Joined:
    Nov 8, 2011
    Posts:
    1,572
    What black magic is going on here?
     
    Sabrido likes this.
  15. Thelo

    Thelo

    Joined:
    Sep 13, 2009
    Posts:
    98
    I would also like an explanation. As a read-only struct (not a class), it would seem to be actually impossible to modify the EmissionModule of a ParticleSystem?

    In particular, when doing:
    Code (csharp):
    1. var myEmission = particleSystem.emission;
    in C#, the variable myEmission there is a copy of the particleSystem's emission, not a reference! And therefore, any changes to this myEmission variable would not affect the particleSystem at all?

    And yet, modifying this copy is what the ParticleSystem.Emission docs shows as an example. So... what's going on here?

    Edit: I see a Unity dev offhandedly said in another thread that yes, modifying the copied struct is the intended thing to do, even though it doesn't make much intuitive sense. I would like to highlight how opaque this behavior is to developers.
     
    Last edited: Feb 20, 2016
    landon912 and alexandresk like this.
  16. alexandresk

    alexandresk

    Joined:
    Jul 11, 2013
    Posts:
    51
    Why god why?????????

    Thelo link explain. A little.

    SO in my case, to dynamic change emission ( and always enable it )

    Code (CSharp):
    1.  
    2. public ParticleSystem turbina1;
    3.  private ParticleSystem.EmissionModule EmissionTurbina1;
    4.  
    5.     void Start () {
    6.         EmissionTurbina1 = turbina1.emission;
    7.     }
    8.  
    9.  
    10.     void Update () {
    11.  
    12.         EmissionTurbina1.enabled = true;
    13.         EmissionTurbina1.rate = new ParticleSystem.MinMaxCurve(some_number);
    14.  
    15.     }
     
    Last edited: Feb 20, 2016
  17. landon912

    landon912

    Joined:
    Nov 8, 2011
    Posts:
    1,572
    Yes, I'm interested in how they even got this working and secondly, why the hell are we going against everything OOP and C# every said?
     
  18. Futurerobot

    Futurerobot

    Joined:
    Jul 13, 2011
    Posts:
    179
    Could it somehow be talking to the c++ layer where structs are reference type? Would be nice to know.
     
  19. landon912

    landon912

    Joined:
    Nov 8, 2011
    Posts:
    1,572
    Well it is running in C++ but it also has to be communicating through a C# layer. So they're converting a C# struct into a C++ struct(reference)? Not sure why though.
     
  20. alvola

    alvola

    Joined:
    Sep 14, 2015
    Posts:
    1
    How I can change the rate value in Update? :(
     
  21. Futurerobot

    Futurerobot

    Joined:
    Jul 13, 2011
    Posts:
    179
    @landon91235 : I was just guessing, I'm intrigued :D

    @alvola : pretty much like alexandresk said above, drop your particle system into the MyParticleSystem, then change myRate.
    1. public ParticleSystem myParticleSystem;
    2. private ParticleSystem.EmissionModule myEmissionModule;
    3. public float myRate;

    4. void Start ()
    5. {
    6. myEmissionModule = myParticleSystem.emission;
    7. }
    8. void Update ()
    9. {
    10. myEmissionModule.rate = new ParticleSystem.MinMaxCurve(myRate);
    11. }
     
    Dev.Gameon and samana1407 like this.
  22. SpacePilot1000

    SpacePilot1000

    Joined:
    Dec 23, 2013
    Posts:
    7
    This is very handy, thank you!
     
  23. Zaflis

    Zaflis

    Joined:
    May 26, 2014
    Posts:
    432
    Just a note:
    ps.emission.enabled = false; // Can't do, Property or indexer `UnityEngine.ParticleSystem.emission' cannot be assigned to (it is read only)

    But indeed it only works when all these are done
    Code (CSharp):
    1.   private ParticleSystem ps;
    2.   private ParticleSystem.EmissionModule em;
    3. ...
    4.         ps = GetComponent<ParticleSystem>();
    5.         em = ps.emission;
    6. ...
    7.         em.enabled = false;
     
  24. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,228
    Hey all,

    It seems like you have this all pretty much figured out, but I thought I'd comment on it.

    Firstly, some docs are here:
    http://docs.unity3d.com/ScriptReference/ParticleSystem-emission.html

    And here's an example of setting a curve:
    http://docs.unity3d.com/ScriptReference/ParticleSystem-rotationBySpeed.html

    The MinMaxCurve has constructors for setting a single constant value, as well as the other curve types. So you don't need to set constantMax (etc) directly.

    And secondly, how does it work? You're correct that's it's both opaque and unintuitive. When you set properties on those local variables, you are actually talking directly to the native code, which is why it works but seems like it shouldn't. We took this approach because it avoids any Garbage Collection being required, and it's efficient.

    And finally, we are actively looking at making this more intuitive, because we agree with your concerns. Namely, we are looking at changing the structs to classes, so you can write more intuitive C# code, whilst still not generating garbage. We are also adding new properties to let you get/set the constant value, so you won't have to bother at all with the MinMaxCurve if you only want to use single constant values. This work is targeting Unity 5.5 and beyond though, so you may be stuck with the current implementation for a little bit longer..!

    I hope this helps explain things a little bit :)
     
    Last edited: Apr 12, 2016
    Beguiled, Thelo and karl_jones like this.
  25. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,301
    I just found this post after banging my head for an hour trying to figure out what was going on. I'd say this goes beyond "unintuitive" and into "weird hack of base programming semantics that makes no sense". A local struct is supposed to be a local struct; why does it actually morph into a weird class pointer back to its original reference? I don't think efficiency is a good enough reason to do something this fundamentally weird, especially when there is no documentation on how to do it. Just showing an example where you assign it to a local variable isn't going to make it clear without a big note saying "You have to actually assign it to a local variable, which will then act as a non-local variable and actually change the original, because reasons." Unless people are setting emission.rate ten thousand times per frame in their Update loops I don't really see why this is necessary.
     
    lsdrambo likes this.
  26. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    3,573
    Take a look a this for further info http://blogs.unity3d.com/2016/04/20/particle-system-modules-faq/
     
    Aldo-V likes this.
  27. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,301
    I don't see why you guys cared about "generating garbage" in this particular case. Emission would have just been a class object within an existing class (ParticleSystem) which already generates garbage regardless. Once you're creating a new object, it having member objects doesn't really matter. When people say they want to minimize garbage generation, they're usually talking about function calls that unexpectedly create something on the heap in the background, or objects that unexpectedly generate garbage constantly during an Update loop or something. Having a class within a class does not fall into that category; that's just normal C#. When you create a ParticleSystem, it would create its contained Emission and then when the PS gets GC'd, it would GC its contained objects as well; that's just normal. Changing it to a struct doesn't really have any advantage. In many cases where people worry about GC (like in an Update loop) it's actually much worse: having a normal "Emission" object that's a class within your PS would just require normal allocation when the PS is allocated, but turning it into a struct accessor like you guys did means that a lot of people will put the required local variable in the update loop code, so you're constantly creating a new Emission struct on the stack every frame, which is less performant than just having a single one on the heap that gets referenced.
     
  28. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    6,457
    So, how the hell do I get CURRENT emission rate with the new api? MinMax curve does not return it... and I don't need the curve. I need currently used value.
     
  29. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,228
    In 5.3, something like:

    Code (CSharp):
    1. var em = ps.emission;
    2. float rate = em.rate.constantMax;
    Should do the trick.
    This is being improved for 5.4+, where you will be able to say:

    Code (CSharp):
    1. var em = ps.emission;
    2. float rate = em.rate.constant;
     
    fffMalzbier likes this.
  30. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    6,457
    That doesn't seem to be correct, according to documentation.

    Documentation says that curve has multiple modes, and with that in mind constantMin/constantMax will have effect only in some of them.

    I'd need to get current emission rate for the point at which curve is currently located. Constant max simply returns upper bound, not emission rate, and appears to be only doing that when the curve in "use constant" mode.

    So, how do I extract current "cursor position" of a particle system within the curve? The particle system obviously samples data from specific point of the curve. How do I know from which one?
     
  31. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,228
    Apologies - I misunderstood your question. Unfortunately that isn't supported in 5.3, but 5.4 adds new Evaluate methods to the MinMaxCurve and MinMaxGradient, to allow you to do this:

    Code (CSharp):
    1. var em = ps.emission;
    2. float time = (ps.time / ps.duration); // when evaluating curves, the time value is normalized into the 0-1 range
    3. float value = em.rate.Evaluate(time);
     
    karl_jones likes this.
  32. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,228
    That code does not cause that error.
    What does the rest of your code look like? Mainly regarding where you got myEmissionModule from. It should look something like this:

    Code (CSharp):
    1. var myEmissionModule = particleSystem.emission;
    2. myEmissionModule.rate = newParticleSystem.MinMaxCurve(myRate);
     
  33. mkgame

    mkgame

    Joined:
    Feb 24, 2014
    Posts:
    583
    Hello,

    I'm using Uity 5.3.3 and I would like to ask you how the performace of this call is compared to the old one. The new one with "new ParticleSystem.MinMaxCurve(value);" creates a new class, so it allocates memory and then the garbage collector has to free the memory. I guess, a lot of us know the overhead of the garbage collector. This happens then for every frame, when the code changes dinamically the emission rate (e.g. foam particle for a boat, which depends of current speed).

    I would then use the old deprecated way, because the new one is inefficient and will be changed in 5.4 again, or in 5.5. Is this approach correct?

    I'm working in a small high tech company, where we decided to follow the gerrit/git workflow. In this workflow such thing would be filtered out, because at least an another developer has to check the changes before it can be commited. Without a test case the commit won't be applied (+ we have a lot of regression tests). It looks like you suffer from the same issue we did. E.g: compatibility issue, making the same mistakes again, dependency issues and so on.
     
  34. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,228
    It's a struct, so there should be no GC.
    Are you seeing allocations?
     
    Last edited: Aug 23, 2016
  35. IronLionZion

    IronLionZion

    Joined:
    Dec 15, 2015
    Posts:
    74
    Weird indeed. Don't know why the devs would add and EmissionModule.Get/SetBursts(), but not a Get/SetRate(), seeing that ParticleSystem.emission is read only. Well, like Kettlewell said, we'll have to wait until 5.5 for that. Anyway, thanks Razieln64 for the code snippet, even though I'm not sure why it works.
     
  36. richardzzzarnold

    richardzzzarnold

    Joined:
    Aug 2, 2012
    Posts:
    72
    How is this an improvement ?

    All i want to do is dynamically adjust my particle emission rate and now that process is a goddam incomprehensible
    nightmare to implement.
     
  37. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    3,573
  38. Razieln64

    Razieln64

    Joined:
    May 3, 2008
    Posts:
    129
    You can also use a multiplier so set the emission rate in the new 5.5 release. I find it works better that way when curves are used instead of constant values.
     
    richardkettlewell and karl_jones like this.
  39. Xhnathius

    Xhnathius

    Joined:
    Feb 2, 2017
    Posts:
    2
    I would need help with that

    void Start()
    {


    foreach (ParticleSystem i in m_VelocityShootParticles)
    {

    i.particleSystem.emissionRate = m_ShootSpeed;
    }

    }


    void Update()
    {
    if (Input.GetButton("Fire1"))
    {
    //ShootFX.SetActive(true);
    ShootNow();

    foreach (ParticleSystem i in m_VelocityShootParticles)
    {
    i.particleSystem.enableEmission = true;
    }

    foreach (ParticleSystem i in m_OtherParticles)
    {
    i.particleSystem.enableEmission = true;
    }

    }
    else
    {
    //ShootFX.SetActive(false);

    foreach (ParticleSystem i in m_VelocityShootParticles)
    {
    i.particleSystem.enableEmission = false;
    }


    foreach (ParticleSystem i in m_OtherParticles)
    {
    i.particleSystem.enableEmission = false;
    }
    }
    }


    evrything whats with Emission is wrong ..
     
    Last edited: Feb 2, 2017
  40. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,228
    The console window should be providing you with warnings for each use of the obsolete API, with recommendations of what to change, in each specific case.

    You can also see this page for a complete example of using the new emission API:
    https://docs.unity3d.com/ScriptReference/ParticleSystem-emission.html

    You should be able to see in the link how to enable the module (emissionEnabled replacement) and how to set the emission rate (emissionRate replacement)
     
    Xhnathius and karl_jones like this.
  41. Xhnathius

    Xhnathius

    Joined:
    Feb 2, 2017
    Posts:
    2
    thank you !! :D
     
    richardkettlewell likes this.
  42. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    6,457
    I just had to waste some time again figuring out how the hell to disable emisison module and I gotta say that garbage collection or not, this coding style violates principle of least astonishment.

    To avoid garbage collection, modules should be returned as references rather than structs and maybe implement IDisposable (and be taken care of during object's death) OR there should be paired helper methods (akin to "setEnabled(bool)").

    Would be nice to ahve this redesigned in a more programmer-intuitive way.

    P.S. Things like this makes me miss C++-style classes where an indexer can return a reference that can be written into.
     
    landon912 likes this.
  43. AnOrdinarySandwich

    AnOrdinarySandwich

    Joined:
    Feb 9, 2017
    Posts:
    7
    I'm glad to see other people find this style of coding as disgusting as I do (richardzzzarnold & neginfinity).

    For the record, here's how to set the emission rate with 5.5 getting around all the current obsolete/deprecated parameters and methods.

    Code (CSharp):
    1. ParticleSystem.EmissionModule module = _system.emission;
    2. ParticleSystem.MinMaxCurve curve = module.rateOverTime;
    3. curve.mode = ParticleSystemCurveMode.Constant;
    4. curve.constant = x; //  <--- here is where you put your constant value
    5. module.rateOverTime = curve;
     
    JDatUnity likes this.
  44. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,228
    karl_jones likes this.
  45. AnOrdinarySandwich

    AnOrdinarySandwich

    Joined:
    Feb 9, 2017
    Posts:
    7
    Hey Richard,

    First, I didn't know that you could assign a straight float value to a MinMaxCurve. I swear I tried something similar and it didn't work for me, but I just tried and it did, so kudos and thanks for teaching me something!

    Question, does setting a straight float also make sure the curve is set to constant?

    As well, does that make sure the value is applied? If I use my code but leave out the reassign of the curve to rateOverTime, it doesn't apply the changes.
     
  46. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    3,573
    Yes setting a constant value will also set the curve mode to constant. You have to assign it to the rateOverTime, assigning it to the curve wont work as its just a value type.
     
    richardkettlewell likes this.
  47. AnOrdinarySandwich

    AnOrdinarySandwich

    Joined:
    Feb 9, 2017
    Posts:
    7
    Hi Karl, that's good to know, thanks for the reply
     
    karl_jones likes this.
  48. AnOrdinarySandwich

    AnOrdinarySandwich

    Joined:
    Feb 9, 2017
    Posts:
    7
    Off topic:

    I've been thinking a great deal about my initial post here, calling some current trends of the coding style "disgusting". Frankly, I feel bad for using such a harsh term. I do have some things I don't like about the way some of the code works, but in the end it's just my opinion. And I'm typically not one to be so brash in announcing my opinion. Maybe I was frustrated or tired, who knows, it's really not important. What's important is that I offer my apologies for being rude. I'm sorry to anyone that may have taken offense to my wording. I'll try to take better care in the future :)