Search Unity

Resolved Toggle IgnoreTimeScale in code?

Discussion in 'Visual Effect Graph' started by TheWanderingBen, Apr 24, 2023.

  1. TheWanderingBen

    TheWanderingBen

    Joined:
    Nov 3, 2015
    Posts:
    98
    Each VisualEffect asset has a checkbox called "Ignore Time Scale", which allows an effect to either update scaled by Time.timeScale or to ignore it.

    This is similar to setting an Animator's AnimatorUpdateMode to either Normal or UnscaledTime.

    In our project, we need to change this value at certain points during the game -- i.e.: we pause our world, but a few things should still move around. We can do this on Animators by changing the value of Animator.updateMode in code.

    Is there an equivalent call for VisualEffect assets?
     
  2. PaulDemeulenaere

    PaulDemeulenaere

    Unity Technologies

    Joined:
    Sep 29, 2016
    Posts:
    154
    Hello,
    The checkbox ignore time scale is affecting a serialized value in VisualEffectAsset at path "m_Infos.m_UpdateMode".
    Sadly, this setting isn't meant to be modified at runtime. It could technically be overridden at component level like initialEventName but we didn't exposed this ability.

    However, you can alter the pause or playRate properties of the VisualEffect (which aren't serialized) but you will have to do this in script because these values can't be controlled by animators.

    N.B.: While modifying time scale, you should probably be aware about how the default fixed time step is computed. You can potentially use actual delta time instead of fixed time step on your VisualEffectAsset.
     
    OrsonFavrel likes this.
  3. TheWanderingBen

    TheWanderingBen

    Joined:
    Nov 3, 2015
    Posts:
    98
    Hey @PaulDemeulenaere, thanks for the response!

    I think you may be misunderstanding my question -- I only brought up the Animator as a comparison, I'm not actually using any Animator to control VisualEffects. I do mean about adjustments in code, so we're on the same page!

    But my problem is, I need the VisualEffect, most of the time, to respect Time.timeScale. But in special moments, I need the effect to ignore that timeScale.

    The comparison with Animators was only meant to illustrate that Animators can do that -- I can set Animator.updateMode in code to change whenever I need it to change, which is why we've set up our logic to flow that way. But now that we're adding VisualEffects, I can't see a way to do that.

    If the VisualEffect is playing relative to Time.timeScale (i.e.: I leave the "Ignore Time Scale" box unchecked) then even trying to set playRate doesn't change the fact that, if time is paused, the effect is also paused.

    Is there a way, at runtime, to change whether or not an effect respects timeScale?
     
  4. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    1,314
    Can you share the reason why some effect would play while paused, while the other time not?
    I think that could be valuable feedback for devs as well.
     
  5. TheWanderingBen

    TheWanderingBen

    Joined:
    Nov 3, 2015
    Posts:
    98
    Sure! It's similar to how games like Super Mario Odyssey handle in-world conversations.

    In Super Mario Odyssey, there are monsters and NPCs and physics all simulating all the time. This is how the game is played most of the time while the player is running around. The player can pause the game in this state, and that should freeze everything in place. And sometimes the player can even speed up or slow down time too, and that should impact everything as well -- so by default, you want everything tied to Time.timeScale.

    But sometimes, the player is engaged in a conversation. The developers then pause the world so that nothing negative impacts the player mid-conversation -- i.e.: no bob-omb explodes on top of the player while they're talking to an NPC. However, the animations should still play on the NPC that the player is talking to. And, say, if that character is holding a fireball, we want that fireball to also animate, too!

    In my game, we do something similar: when our player is in a conversation, we set Time.timeScale to zero -- but for any Animators that need to play, we set them to use UnscaledTime when we're in the coversation (and revert them to Normal when we leave the conversation).

    Is there a way to achieve a similar outcome with a VisualEffect?
     
  6. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    1,314
    I think this is similar problem to time stop ability, it sounds quite simple until you realize you need to affect only some things and perhaps manage some special delta time.

    I've never tried it and I don't even know it's viable solution (maybe @PaulDemeulenaere can confirm that), but possibly you could add custom integration in update with use of time node:
    upload_2023-4-25_21-25-13.png

    However even if this is possible, its not handy - you would need to implement this in every ability that could possibly play in the cutscene, so perhaps it's better to pause them and then simulate systems manually with
    VisualEffect.Simulate()
    or
    VisualEffect.AdvanceOneFrame()
    ?
     
  7. PaulDemeulenaere

    PaulDemeulenaere

    Unity Technologies

    Joined:
    Sep 29, 2016
    Posts:
    154
    Indeed, your scenario description helps for a better understanding of the issue, it's really appreciated.

    You can theoretically process custom integration updating the position based on an exposed delta time but you will have to reproduce the internal behavior of a lot of blocks (collision, spawn constant rate, ...) which are using the VFX Delta Time. I don't think it's a viable solution.

    This use case is adding another reason to expose more overridable control from the Visual Effect Asset at component level but let's go back on the actual workarounds you can consider.

    Considering the different scaling and ignoring the fixed time step behavior, the final delta time is composed this way:
    Code (CSharp):
    1. float vfxDeltaTime = vfxAsset.IsUnscaledTime() ? Time.unscaledDeltaTime : Time.deltaTime;
    2. vfxDeltaTime = vfxDeltaTime * playRate;
    If it was only about half speed slow motion, I could have suggested you to invert the playRate to compensate the slow motion effect but it won't be possible if Time.deltaTime is zero.

    I'm seeing two ways of approaching a workaround for this case:
    - You can have all your VisualEffectAsset in unscaled delta time and reflect the change of Time.timeScale to every active VisualEffect.playRate
    - During conversation/cinematic, if the world around is paused with a timeScale at zero, invoke VisualEffect.Simulate every frames for the fireball hold by the character.

    You should be aware the simulate isn't meant to be used extensively for a large amount of VisualEffect, there is an internal overhead which is forcing the VisualEffect to be updated on mainthread during next frame.

    VisualEffect.AdvanceOneFrame is actually using the current delta time, the overlay in scene is using this method to inspect frame by frame the current selected VisualEffect.
     
    OrsonFavrel and Qriva like this.
  8. TheWanderingBen

    TheWanderingBen

    Joined:
    Nov 3, 2015
    Posts:
    98
    This sounds like it should work for us, thanks @PaulDemeulenaere!

    I've been pulled onto a couple more high-priority tasks, but I should get back to this pretty soon. I'll update here whether it worked on not.
     
    PaulDemeulenaere and OrsonFavrel like this.
  9. TheWanderingBen

    TheWanderingBen

    Joined:
    Nov 3, 2015
    Posts:
    98
    As always, it took longer to get back to this task than I thought :)

    But your solution works! I used your second suggestion:

    Thanks for the advice!
     
    PaulDemeulenaere likes this.