Search Unity

Particle System preview scrubbing by script

Discussion in 'General Graphics' started by FeastSC2, Oct 6, 2018.

  1. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    603
    I want to reproduce the behaviour of the Particle System where one can change the time of the ParticleSystem and see it at particular playback positions.

    This can be done with the "Playback Time" but I need to do it by script.
    upload_2018-10-6_20-0-50.png


    I only need this to work in editor mode and not in playmode.
    I tried using ParticleSystem.Simulate and ParticleSystem.time to no avail.
    How can I set the Playback Time value of that popup window by script?

    Code (CSharp):
    1. // my failed attempts
    2. if (Ps != null)
    3. {
    4.     // Ps.Simulate(adjustedTime, true, false);
    5.     Ps.Pause(true);
    6.     Ps.time = adjustedTime;
    7. }
     
  2. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    ps.Simulate is correct. Be sure to set the restart param.
     
    karl_jones likes this.
  3. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    603
    Ah yes, the restart parameter I had forgotten about that. ;)

    I thought the script would allow to preview properly but something's amiss.
    An issue I found was due to the particles having a different seed @ every simulation. But there still are deeper problems and I really hope you can take a look at this: I provided a package of the example I show in the video.

    Here's a video of the difference between clicking on the Particle System's Restart button and the ParticleSystem.Simulate by script.
    As you can see the 1st particle isn't disappearing and the blue one can't even be seen going up.


    Why is it behaving like that?

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [RequireComponent(typeof(ParticleSystem))]
    4. [ExecuteInEditMode]
    5. public class TestAnimate : MonoBehaviour
    6. {
    7.     [Range(0,3f)] public float Timeline;
    8.     private ParticleSystem Ps;
    9.  
    10.     void OnValidate()
    11.     {
    12.         Ps = GetComponent<ParticleSystem>();
    13.         Ps.Simulate(Timeline, true, true);
    14.         Ps.Pause(true);
    15.         Ps.time = Timeline;
    16.     }
    17. }
     

    Attached Files:

  4. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    Instead of:

    Code (CSharp):
    1. Ps.Simulate(Timeline, true, true);
    2. Ps.Pause(true);
    3. Ps.time = Timeline;
    Try:

    Code (CSharp):
    1. Ps.Simulate(Timeline, true, true);
    And you'll also need to control the seed yourself in your script:

    Code (CSharp):
    1. var main = Ps.main;
    2. main.randomSeed = 5; // enter your seed here. maybe generate using Random API
    However, looking at the video, it's possible you're hitting this long-standing bug... https://issuetracker.unity3d.com/issues/particle-system-simulate-issues
    The bug report for that has a similar looking stuttering behavior.
     
  5. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    603
    When I'm moving the playback time when the particle system is paused, it works perfectly.
    It means that the Editor is calling something that allows to preview without bugs, I just need to call the same thing then.

    What is the editor calling when modifying this value?
    Or how can I set that value to something I want through script?
    I only need this to work in the editor and not in playmode.

    upload_2018-10-8_16-20-14.png
     
  6. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    It calls internal API that you don't have access to, sorry :(

    However, if you are really determined, there are ways to call internal API. If you want to go down that route, here is what you need to call:

    Code (CSharp):
    1. ParticleSystemEditorUtils.playbackTime = playbackTime;
    2. ParticleSystemEditorUtils.PerformCompleteResimulation();
    This can only work if the system in question is also selected, because it operates on the set of selected systems.

    I'm not advocating the use of the following, but with a bit of googling, these came up:
    https://gist.github.com/MattRix/9205bc62d558fef98045
    https://stackoverflow.com/questions/135443/how-do-i-use-reflection-to-invoke-a-private-method

    Obviously, internal methods may also change without warning in future versions of Unity.

    Sorry I don't have a good answer for this. I'll try find time to look at that bug again in the near future... it's literally the oldest open Particle System bug.. we haven't managed to find a fix for it (yet).
     
    FeastSC2 likes this.
  7. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    603
    Thanks a lot for answering all this Richard, it's much appreciated!

    I will have to use the reflection temporarily until you find out how to fix that bug because my vfx artist needs that previewer asap. However, I haven't used reflection yet so do you know why it's not finding the PsUtils in the SetPlaybackTime() method here?


    Code (CSharp):
    1. using System.Reflection;
    2. using UnityEngine;
    3.  
    4. [RequireComponent(typeof(ParticleSystem))]
    5. [ExecuteInEditMode]
    6. public class TestAnimate : MonoBehaviour
    7. {
    8.     [Range(0,3f)] public float Timeline;
    9.     private ParticleSystem Ps;
    10.  
    11.     protected static MethodInfo Resimulation;
    12.     protected static FieldInfo PlaybackTimeField;
    13.  
    14.     void SetPlaybackTime(float _time)
    15.     {
    16.         if (PlaybackTimeField == null || Resimulation == null)
    17.         {
    18.             var PsUtils = typeof(UnityEditor.EditorUtility).Assembly.GetType("ParticleSystemEditorUtils", true);
    19.             PlaybackTimeField = PsUtils.GetField("playbackTime", BindingFlags.Static | BindingFlags.NonPublic);
    20.             Resimulation = PsUtils.GetMethod("PerformCompleteResimulation", (BindingFlags.Static | BindingFlags.NonPublic));
    21.         }
    22.         PlaybackTimeField.SetValue(null, _time);
    23.         Resimulation.Invoke(null, null);
    24.     }
    25.  
    26.     void OnValidate()
    27.     {
    28.         Ps = GetComponent<ParticleSystem>();
    29.  
    30.         SetPlaybackTime(Timeline);
    31.     }
    32. }
     
  8. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    If I remember correctly, the GetType needs to be prefixed with the assembly name, in the string. I.e “UnityEditor.ParticleSystemEditorUtils”

    But I’m no expert with this stuff..
     
    FeastSC2 likes this.
  9. dpizzle

    dpizzle

    Joined:
    Feb 2, 2013
    Posts:
    28
  10. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    There are no plans.. all I can say is that I can try find time to take another look at it. Sorry it’s causing you problems.
     
  11. SugoiDev

    SugoiDev

    Joined:
    Mar 27, 2013
    Posts:
    245
    Also an annoyance for us. It ate quite a few hours and I was beginning to suspect I was going insane for a bit.
    I used a pile of hacks to get it somewhat working, but would appreciate a lot if it was officially fixed.
     
    richardkettlewell likes this.
  12. dpizzle

    dpizzle

    Joined:
    Feb 2, 2013
    Posts:
    28
    Thanks for the reply, I'm quite sad this isn't at least in the pipeline since it's over 3 years now. Would really appreciate anything you can do.
     
  13. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    @dpizzle @SugoiDev can you confirm whether this statement from the original post is also true for you?

    I ask because, looking at the repro project for the bug we have (https://issuetracker.unity3d.com/issues/particle-system-simulate-issues) the steps demonstrate the issue in a playmode scenario. (and thus any fix would only be guaranteed to fix the playmode issue in that project, and might miss an editmode isuse, if there is one)

    If you have an editmode scenario, please report it as a separate bug and reply here with the case number so I can track it.
     
  14. dpizzle

    dpizzle

    Joined:
    Feb 2, 2013
    Posts:
    28
    I only need play mode bug fixed. I do not need editor mode fixed. Sorry, I posted on this thread because it seemed most active and relevant. Many thanks for looking into it.
     
    richardkettlewell likes this.
  15. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    We are currently testing a fix for this issue which aims to resolve it in Play Mode (and players).

    To reiterate about Edit Mode: the bug report doesn't show an Edit Mode problem and we don't know of any problem with this in Edit Mode, so, if you're reading this and thinking "Hey, I get this bug in Edit Mode!", then please report a bug for us and we'll investigate it :)

    There's always been something that seemed more important (and arguably there still is!) but you're right that it's been a long time (too long, probably!) and we want to be able to help you out, so we've diverted a bit of time towards trying to figure this one out. Hopefully it's a good fix and will pass testing.
     
  16. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    603
    First, thanks Richard for looking deeper into this issue.
    I never managed to use the trick with UnityEditor.ParticleSystemEditorUtils you had once mentioned.

    Could it be that the play and editor mode bugs are one and the same?
    There shouldn't be a doubt as to whether there is a bug in the editor mode with what I showed in the video above by the way. I could make a project with the scripts and post them as a bug if they are indeed different bugs.

    Can we expect a bugfix for Unity 2018?
     
  17. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    I don't think so, because the fix I've applied should (in theory) only affect playmode.

    Ah, good point! I had forgotten about that. I've just loaded it up and yes you're right, it reproduces what I think is a different issue. I'm currently on a version of 2019.1 one so i can't say right now if the other fix would fix this too (thougth I'm still speculating that it won't)

    I think what you have in your video is probably different to what's currently logged, but I'll check for sure next week, before asking you to do anything. I can log it myself, to be honest, as it's so simple, it just depends if you want to benefit from the bug notifications by logging it yourself.

    Hard to say.. it has quite a few votes on the issue tracker. It might make the cut.
     
    FeastSC2 likes this.
  18. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    603
    I'll leave it to you then ;). Good luck with the bugs, squash em good.
     
    richardkettlewell likes this.
  19. dpizzle

    dpizzle

    Joined:
    Feb 2, 2013
    Posts:
    28
    Thanks Richard, you're the best! Fingers crossed it passes testing...
     
  20. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    Hey, another update - the editmode repro did indeed still fail. I now have a fix for that too, and we are beginning testing of the changes. After that, assuming all goes well, we will look at what versions we can get this into.
     
    dpizzle and FeastSC2 like this.
  21. sisi0616

    sisi0616

    Joined:
    Jan 17, 2019
    Posts:
    3
    Code (CSharp):
    1. void SetPlaybacktime(float _time)
    2.     {
    3.         if(PlaybackTime == null || Resimulation == null)
    4.         {
    5.             var PsUtils = typeof(UnityEditor.EditorUtility).Assembly.GetType("UnityEditor.ParticleSystemEditorUtils");
    6.  
    7.             PlaybackTime = PsUtils.GetProperty("playbackTime", BindingFlags.Static | BindingFlags.NonPublic);
    8.             Resimulation = PsUtils.GetProperty("resimulation", BindingFlags.Static | BindingFlags.NonPublic);
    9.  
    10.             getPlaybackTime = (Func<float>)Delegate.CreateDelegate(typeof(Func<float>), PlaybackTime.GetGetMethod(true));
    11.         }
    12.         PlaybackTime.SetValue(null, _time, null);
    13.     }
    There is no change when you change the playback Time by calling PropertyInfo.SetValue in the above way. is there any other way?
     
  22. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    Hey @dpizzle and @FeastSC2 , we are still working on this. Testing threw up some issues :( At this point, it's looking too risky for 2018.3, which is well into stabilisation now as it approaches LTS status. (https://unity3d.com/unity/qa/lts-releases) We must strive to avoid all risk once a version gets to this point.

    So I think we have to instead look at fixing it for the 2019 version cycle. The good news is that we've hopefully fixed the problems and it's back in testing.

    @sisi0616, If you want to do it via reflection to get at internal methods, setting `ParticleSystemEditorUtils.playbackTime` should be enough, as you are doing. But calling internal methods is not officially supported, so I don't know if it can be made to work. At the very least, the system you want to control should be selected before you call that code.
     
    FeastSC2 likes this.
  23. dpizzle

    dpizzle

    Joined:
    Feb 2, 2013
    Posts:
    28
    Understandable it wouldn't be fixed so soon, it does seem like a fundamental change. 2019 cycle would be great, thanks for the hard work on it!
     
  24. sisi0616

    sisi0616

    Joined:
    Jan 17, 2019
    Posts:
    3

    If so, can not you use Simulate perfectly with the current Unity version?
     
  25. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    Wow so this bug took a long time to get the fix right. It's taken a lot more time than I thought it possibly could! :(

    But the good news is that it has finally landed in 2019.2.0a12!
     
    SugoiDev and FeastSC2 like this.
  26. SugoiDev

    SugoiDev

    Joined:
    Mar 27, 2013
    Posts:
    245
    That's awesome! Can we expect a backport in the 2019.1 cycle as well?
     
  27. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,189
    Nope - it was hard enough to land it in any release :p
     
  28. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    603
    Good job man :)
     
    richardkettlewell likes this.
  29. SugoiDev

    SugoiDev

    Joined:
    Mar 27, 2013
    Posts:
    245
    Pitty. But stoked to see this fixed anyway. It is a really annoying thing that cost us many hours.
    We'll finally be able to have proper edit-time particle sequence editing with our cutscene and time rewind stuff.

    Thanks for getting it done!
     
  30. dpizzle

    dpizzle

    Joined:
    Feb 2, 2013
    Posts:
    28
    Heck yeah! Can't wait to try it out. Sooo appreciated.
     
  31. sayiliromer

    sayiliromer

    Joined:
    May 30, 2017
    Posts:
    9
    Looks like it is fixed on 2019.2 any chance fix for 2018.4 LTS cycle ?