Getting Started with Expressions (Part 1)

May 24, 2017 Technology, Tips 0 Comments

We agree that this topic really sounds as dry as a bone, but expressions are one of the most underestimated features in RealFlow. Once you’re familiar with the basic principles you’ll be able to describe complex motions and behaviours within seconds. An expression is a formula or a condition that always consists of a single line of “code”.

Expressions are, for example, perfectly suited for:

  • all kinds of motions like oscillations, circles, and spirals
  • on-off switches
  • randomizing parameters
  • triggering events.

But that’s by far not everything, because expressions don’t:

  • require any scripting knowledge
  • influence on simulation time
  • need animation keys
  • have to be simulated, but can be evaluated through playback or scrubbing the timeline.

It’s also possible to transfer expressions to other nodes with just a few clicks, and they can be created through Python scripts to make them parametrical with a custom GUI – but that’s a different story.

Linear motions

Let’s start with something simple: A “Null” object should perform a linear motion along the X axis. In order to create and apply an expression it’s not absolutely necessary to open RealFlow’s “Curve Editor” and you can add an expression to any animatable parameter by starting with “=”. But, for beginners it’s definitely better to use this tool, because it gives you an idea of the node’s motion or behavior.

As said, the motion should be performed along the X axis, so right-click on “Position.X” and choose “Edit Curve…”. Below the canvas you will see an input field. There, enter f/fps. This means that the current frame is being divided by the adjusted frame rate. What you get is a jagged line and with a frame rate of 25 fps the “Null” jumps 1/25th meters per frame in positive X direction.

Position.X parameter with expression f/fps.

For a “Null” object the adjusted precision is certainly enough, but if we want an object to collide with fluids or other nodes we need a higher resolution. Therefore enter just t. Now the line is smooth and RealFlow will be able to evaluate the exact time at any point of the simulation.

Position.X parameter with expression t.

Controlling Speed and Start Position

The red line’s inclination is an indicator for the “Null” object’s speed. A steep curves represents a fast motion, and slower objects have a flat curve. To manipulate the curve t has to be multiplied with a factor. With t*0.5 speed is halved, and with t*2.0 speed is doubled. If the factor is

  • < 1.0 the motion will be slower
  • > 1.0 the motion will be faster
  • = 1.0 the motion will not be affected.

We’re able to influence the object’s speed already, but everything starts exactly at X = 0.0. How can we change an object’s initial position? Fortunately, that’s very easy, because all we have to do is to add the desired X value: 3.0+t or -4.2+t. Our first common formula is:

position_offset+t*speed_factor

Of course the placeholders have to be replaced through actual numbers. And it’s possible to use this (or any other) expression for the Y and Z coordinates to get a 3-dimensional motion.

Oscillations

In the previous example the motion was either in positive or negative direction. Now we’ll be dealing with back-and-forth, and up-and-down motions. When we take a look at formula above we’ll recognize that there is no way to change our object’s direction over time and make it move like a pendulum. We need something that creates a kind of wave. If you go back to your time at school you might remember the sine function. The graph of this curve is a wave with ups and downs. This is exactly what we need and we’ll be utilizing this function to achieve an oscillating motion. Delete the current expression and type

sin(t)

A basic since curve has hills and valleys between -1.0 and 1.0.

When we take a closer look at the resulting curve we can see that we have steep and flat parts. This indicates that speed is not constant, and there are faster and slower motion segments. Anyway, the global motion can be influenced in exactly the same way as we did before. Again we multiply a factor, but here the factor is called amplitude:

sin(t)*amplitude

Sine curves with different heights (“amplitudes”).

With 3.0, for example, the node will oscillate between -3.0 and 3.0. But, why should this be faster? We have just changed the start and end positions? The reason is the definition of speed: speed is the distance covered in a certain time:

speed = distance/time

With sin(t), the distance covered per second is roughly 0.84 m. With sin(t)*3.0 the distance is 2.52 m, and that’s definitely faster.

That’s just one third of our options with the sine function, and the second way to manipulate the curve is, again, to add a position offset:

position_offset+sin(t)*amplitude

The third method is to multiply time with a factor to change the number of ups and downs, the so-called frequency. Values

  • < 1.0 are responsible for a lower frequency (= less ups and downs)
  • > 1.0 create a higher frequency (= more ups and downs).

So, our complete formula looks as shown here:

position_offset+sin(t*frequency)*amplitude

To be precise: there’s also a fourth way, because you can also add a value to t. This way it’s possible to shift the starting point of the sine curve – mind the brackets:

position_offset+sin((time_offset+t)*frequency)*amplitude

Ok, this looks complex, but in fact that’s just very basic maths and all we do is to add and multiply a few values, nothing more. And you only have to take what you need. If you don’t need time or position offsets, leave them out and again the formula will be much easier to read.

Damped Oscillations

Endless oscillations are great for many things, but sometimes it’s necessary to mimic a loss of energy, e.g. through friction. You know this behaviour when you watch pendulum, because after a certain time it comes to rest. An expression is the perfect way to do this. We’ve searched the internet for a suited formula and came up with this one:

This looks super complex and very technical, but in fact it’s exactly what we’ve discussed before:

  • The term’s first part (1) is just a factor to determine the amplitude, the curve’s “direction” and its falloff. The factor 5 describes the maximum elongation.
  • Then we have a cosine function (2) instead of a sine.
  • Time t is multiplied with 2*pi (3) to change frequency.

That’s it and the only question is how to express the exponential function e and pi. Pi is simply written as PI, but it’s not really needed and we can also use a single factor to get more ups and downs, e.g. cos(6*t). With -1 we get rather quick falloff and if we want to slowly decelerate the pendulum, we have to use values smaller than 1. Our complete formula is:

max_elongation*exp(-falloff*t)*cos(frequency*t)

A damped oscillation with 5*exp(-0.25*t)*cos(6*t).

And here the expression in action. As you can see the sphere’s speed decreases over time:

Pouring Effects

A typical field of application for oscillations are pouring effects, e.g. when water is being poured out of a bottle. Here, we’ll be working with rotations instead of positions, but the principle is exactly the same. In this example we want to create an oscillation between 30° and 50° around the Z axis. We start with a basic sine function:

sin(t)

With this expression we get a slight wiggle effect between -1° and 1°, but the total angle covered should be:

total_angle = 50°-30° => total_angle = 20°

What does this mean for our factor? Since basic sine curves always oscillate between a negative and a positive value, total_angle has to be halved:

sin(t)*20*0.5 or just sin(t)*10

When you take a look at the curve you will see that the values oscillate between -10° and 10° – they cover a total range of 20°. Now we only have to find a value that will be added to get angles between 30° and 50°:

-10° + 40° = 30° and 10° + 40° = 50°

The complete expression, here with a frequency of 10, is therefore

40+sin(t*10)*10

All you have to do now is to adjust the function’s frequency by multiplying t with another factor, and then you’ll have a nice pouring effect:

Switches

Switches are another important field of application for expressions. Instead of adding and manipulating keys you just define a certain moment in time when a parameter’s state should be changed. This way you’re able to (de)activate simulation states, stop emitters from creating particles, change values, or create gradients for parameters. A typical case is to turn on an object’s “Soft body” state at a certain time. To achieve this a condition, introduced by an “if” statement, is required:

if(t>0.5,3,0)

This cryptic notation contains the entire information already. As soon as time is greater than 0.5 s the state will be switched from “No” to “Soft body”. The object’s “Dynamics” states are represented as numbers in expressions. The numbers correspond with the order of entries in the “Dynamics” drop-down menu:

You might ask why the expression above contains a “greater than” operator instead of “equal”? With “equal” the expression will only be fulfilled when time is exactly 0.5. All points in time before or after 0.5 will not fulfill the expression.

Another limitation is that RealFlow’s expression do not provide “greater/lower than or equal to” (“>=” and “<=”) operators. So, if you want to trigger a certain event at exactly 0.5 the expression has to be

if(t>0.499999,3,0)

Of course it’s also possible to stop particle emission, e.g. by setting an emitter’s “Speed” from 3.5 to 0 at time = 1.0 s:

if(t>0.99999,0,3.5)

Randomization

Random values are often essential for realistic simulations, because they help us to achieve variations and a more natural behavior. The keyword for random expressions is

rnd(value)

Let’s randomize an emitter’s “Speed” value between 0 and 1

rnd(1)

With rnd(5) we get random values between 0 and 5, and so on. By adding an offset we’re able to use greater speed values, here between 3 and 4:

3+rnd(1)

Of course it’s also possible to combine a function like sine with the random number generator, e.g. to create an erratic wiggle effect:

rnd(15)*sin(t)+45

In the case above it’s very difficult to predict anything and it’s perhaps better to limit the random effect to ± 2°:

(rnd(2)+13)*sin(t)+45

Another idea is to randomize emitter speed at a certain point in time. The following expression increases speed over time starting at t = 1.0 s, but with a random component of 1.5 m/s:

if(t>0.99999,2.0+rnd(1.5)+t*0.5,3.5)

Conclusion

Expressions are a fast and easy way to spice up your simulations and create even complex motions and behaviors within seconds. Imagine you have to keyframe all the curves and functions we have discussed in the chapters above. With expressions you’re not only much faster, but it’s also easy to change, extend, or modify a parameter’s or object’s behaviors. Since expressions are so powerful we’ll be adding another blog post, where we show you how to create circular, spiral, and helical motions with full control.

And now, fire off RealFlow and create your own expressions!