Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question How to use Multiply Velocity over Life in VFX graph? (slow-down motion effect)

Discussion in 'Visual Effect Graph' started by Opaweynch, Sep 6, 2023.

  1. Opaweynch

    Opaweynch

    Joined:
    Jan 23, 2023
    Posts:
    8
    Hey!

    I am struggling with the "Multiply Velocity over Life" node in VFX graph. I tried different things but I do not see any effect on the result (as if it was deactivated). What I try to achieve is to create a slow down effect at the end of the animation.

    Here is a very simple VFX graph where I reproduce the issue + the resulting effect in scene.
    sample_graph.png sample_vfx.gif
    - I put the node in the 'Output' but it does not have any effect as you can see on the gif.
    - Putting it in 'Initialize' or 'Update' works but results in a different behavior as the one I am looking for (initialize: only the first value of the curve is sampled; update: samples accumulate each frame, resulting in a convergence to zero).
    - Oddly, the Multiply Size over Life node in the output works as I would expect. I guess this means there is something about velocity I did not catch?
    - I tried to change the Composition, Sample Mode and Mode of the node without success.
    - I also tried to change the sampling mode to custom using 'Age over Lifetime' attribute as input but this did not work either.
    - I would like to avoid controlling the play rate of the visual effect through script as I plan to use more complex curves for more complex effects (not only a slow down but also a burst effect at the beginning).

    Many thanks for your help!
     
    Last edited: Sep 6, 2023
  2. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    1,108
    There are two reasons, first the modification in output is not premament, and second it is anyway too late to change this value. If you do multiply every frame (in Update) then the result will accumulate what might be not desired, so for this reason you must override this value to avoid that. Multiply size over life works, because it affects value that is used to display the particle, so you change size and use that size directly to render it, but if you override velocity here, then it has no effect as simulation is processed in update, not rendering, so those changes are just discarded.

    You could cache initial/desired velocity (if it does not change in other way) in custom attribute and use that to multiply over curve to slow them down like this:
    upload_2023-9-6_15-2-44.png

    However, unless you are trying to get very specific movement it is better to just use linear drag in the update or multiply by curve as it's simple and enough for most of effects, especially if you create some burst/explosion. Method above does not work if there are other sources affecting velocity during lifetime, so it is up to you if this suits you.

    // edit: actually there is another way to multiply velocity - you can disable default integration and apply your own, it would be the same as default one, except you would multiply by your curve:
    Code (CSharp):
    1. position += velocity * deltaTime * curve
    This way you don't accumulate those changes to velocity, but you still get simulation affected by some value provided by you.
     
    Last edited: Sep 6, 2023
    Opaweynch likes this.
  3. OrsonFavrel

    OrsonFavrel

    Unity Technologies

    Joined:
    Jul 25, 2022
    Posts:
    128
    Hello and thanks for your questions, I will try my best to answer.
    First thing first, let's talk about Contexts:

    Contexts have different purposes:

    The Initialize Context lets you set the “Initial” values and properties of your particles. In other words: What are the properties of my particles when they're spawn? Those properties, How long do they live, Position, Velocity are called “Particles Attributes”. So usually, in the Initialize Context, we set the Initial values of those particles attributes.

    So, while it make sense to set the Velocity attribute in the Init Context, the "Over-life" isn't really useful as in the Init Context, particles are just born and have an Age of zero which mean that you will always sample the Overlife curve at position 0.

    The Update Context:

    The Update Context is where the particle's behaviors and properties are going to be updated.
    If you select, this Context, in the Inspector, you'll find different checkboxes. By default, even without any Blocks/nodes inside it, the Update Context does some implicit calculation for you (Velocity Integration, Aging, Kill Particles if age>= Lifetime).

    Update Position: → Velocity Integration, This means that each frame, the Update context takes the Velocity Attributes values of your particles and uses it to calculate the new Position of your Particles.

    upload_2023-9-6_14-21-44.png

    Update Position: → Each Frame, the Update Context is also increasing the values of the Age attribute.
    So this Context is usually where you're going to set or modify attributes' values over time and/or Particles's Lifetime.

    While It makes sense to use the Multiply Velocity over lifetime in the Update, you need to understand that the Update is called each Frame. So each frame the current Velocity is going to be multiplied, so it can change exponential.
    A stupid examples with an initial Speed of 1.0 being multiply by a Constant 0.9 in the Update:

    Frame 01 = 1 × 0.9 = 0.9 | F2 = 0.9 × .9 = 0.81| F3 = .81 × .9 = 0.72| F4 = 0.72 × .9 = 0.64| F5 = 0.64 × 0.9 = 0.57
    F6 = 0.57 ×0.9 = 0.51 | F7 = 0.51 × 0.9 = 0.45 | F8 = 0.45 × 0.9 = 0.40 etc…


    Output Context:
    This Context Render the particles based on their properties (Attributes). So here, we typically set attributes that drives what the particles will look like: Their visual's properties : Size, Alpha, Color etc…

    So while it make sense to use a Size overLife in this Context, doing a "Velocity overlife” in this context will not yield any results as the Velocity Integration is done before in the Update Context.

    I'm guessing that now, you must be saying: This is really nice and all, but how do you slow down the Particles's velocity over their Lifetime.
    Well as always with VFX Graph they're multiples ways of doing of thing. Here are some of those solutions:

    A:
    As you did, use a Multiply Over Lifetime block. But as mention earlier, be sure to change the curve so that you don't multiply by low values as it's going to be executed each-frame. The pleasant thing is that you can manipulate the tangent of your curve.
    upload_2023-9-6_15-2-7.png

    B:
    You can use a Multiply Velocity in Custom mode in the Update context, and use the DeltaTime as sample time.
    This is simple to set up and can give some pleasant control while keeping the Curve in a 0-1 range. But it's not on the Particle's Lifetime.

    C:
    Another very simple solution is to use a Linear Drag Force Block. This will apply a force on particles that will slow them down. While it very simple to use, it can be hard to master and isn't the adequate solution if you want to control precisely when your particles slow-down on their lifetime.

    D:
    The Last solution that I want to provide is little but more involved and use Custom Attributes.
    upload_2023-9-6_15-15-23.png

    I'm finishing this post here as I see that @Qriva already made a great answer.
    Hope this helps a bit and I wish you a great day.
     
    XieJiJun, Opaweynch and Qriva like this.
  4. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    1,108
    Oh my, yours is way more detailed than mine xD
    I wish there was "someone is typing..." feature in the forum :D
     
  5. OrsonFavrel

    OrsonFavrel

    Unity Technologies

    Joined:
    Jul 25, 2022
    Posts:
    128
    Same :) This forum deserves some modern feature like this
     
  6. Opaweynch

    Opaweynch

    Joined:
    Jan 23, 2023
    Posts:
    8
    Many thanks for your very helpful answers! I ended up using the solution of caching velocities and it works great! :D

    Btw, I did not know we could cache attribute values like this. Is there a way to expose cached values so that we could access them from script?

    Sorry if this is a bit off-topic, tell me if I should start another thread!