Physics in Spark AR — The Hidden Power of Delay Value

Josh Beckwith
Popul-AR
Published in
9 min readJul 18, 2022

--

Physics in Spark have been a pipe dream ever since v1! A few people have managed to make it work, but there are “reactive” bottlenecks and difficulties managing performance. Fortunately, there’s a way to get some basic physics working in the patch editor, and it’s all powered by the new “delay value” patch.

The delay value patch was released recently without much fanfare, but I’ll show you how useful it is! It has the ability to side-step the reactive loop in the patch editor, so you can do things that were previously impossible in patches (like physics).

This article will explain the basic function of the delay value nodes. We’ll build up techniques until we finally have a few simple physics systems.

Delay Value Basics: Accumulation and Conditionals

Before getting into the really fun physics stuff, let’s go over the basics of what the delay frame patch does, and how we can take advantage of it.

At first glance, you might be wondering why you would want to delay a value using the delay value patch. We already have a “delay” patch, so what’s the point??

The most obvious difference is that delay expects a duration and delay value doesn’t. That’s because delay value works just like delay frame — it delays the value by a single frame. The most important difference is that the receiver for delay value is outside of the reactive loop, so you can feed it back into the delay value without the patch graph bugging out.

Normally can’t add to a number and update it in the same reactive frame.

Counting Frames

One of the simplest use-cases for delay value is a frame ticker. Just add 1 on every pass and you have the number of frames that have been rendered since the effect started.

Tick, tock, tick, tock…

Now that you know the total number of frames rendered, you can calculate the average frames-per-second (FPS). Divide the total frames by the runtime and you’ll get the average FPS. This will give you a rough idea of how well your effect is performing in terms of rendering speed. Thirty FPS is the target, so if you see something like twelve FPS, it’s time to work on optimizing your effect :)

Exercise: Average FPS isn’t very useful because the current FPS can suddenly drop, depending on what is being rendered. Try using delay value to calculate the CURRENT FPS. Hint: You will need to determine the time elapsed between frames.

If you are curious, I cover some details about FPS in Spark in the FPS block demo video.

Tracking Score

Tracking score is a pretty common thing to do in games. We can build on top of the frame counter, but add some conditional logic to determine when to add to the counter. Here’s a simple score counter using delay value. It just adds one every time the screen is tapped.

You could technically do this without delay value, but then you would inevitably run into reactive loop problems. Because we are using delay value, we can check the score and change the behavior of setting the score — something that can’t be done in a fully reactive loop. This example prevents the user from scoring more points if they have already reached the maximum.

Exercise: Make a simple game with 3 states (introduction, playing, game-over). Show the intro for a set duration, and block the user from scoring before the game starts. Use the score to trigger a change to the game-over state.

Smooth Motion with Linear Interpolation (LERP)

Now that you understand the basics of value accumulation and conditionals, let’s get into some motion!

LERP is an alternative to exponential smoothing. The basic idea is the same — delay and smooth the motion. LERP is more configurable (you can set the value type and smooth speed), and it’s likely more performant than expo smoothing. Watch this demo for a more in-depth explanation.

Linear interpolation works by moving the object a percentage of the way toward the target position on every frame. LERPing with .5 (50%) would move the object half way toward the target on every frame. The result is that it moves 50% on the first frame, 25% (of the initial value) on the next, 12.5% on the next, etc., etc.

Here’s a rough outline of the behavior we are looking for:

  1. Get the distance between the current position and the target position by subtracting them.
  2. Apply the smoothness by multiplying the distance by a smoothness value.
  3. Move the follower by adding the result to its current position.
Three easy steps for a smoother you

I want to note that the delay value could be replaced by another local transform node, but using delay value makes everything a little simpler by caching that value for you.

The result is a smooth movement towards the target object. You can change the target position and the follower will react gracefully by changing direction.

Smoothing value of 0.1

Improving smoothness with time scale for frame-independent updates

Ideally we will be running at maximum FPS all the time, but sometimes the value dips temporarily. When that happens, we want our animations to stay as smooth as possible.

Obviously… but, what is the problem? Because we are using delay value, we only get to update positions once every frame. But what happens when the frame rate drops? Our animations will slow down too! We need to move our objects at a consistent rate, regardless of what the current FPS is.

Fortunately, determining the time scale for the current frame is pretty simple: divide delta time by the target FPS (1/30). Once you have it, just multiply it into your motion delta value and enjoy the extra smoothness.

Don’t let FPS control your life, or your animations

If you watch the time scale, you’ll notice that it generally bounces around 1. If your device is rendering slower than 30 FPS, it will speed up the animation. Conversely, if it’s rendering faster than 30 FPS, it will slow it down. The effect is that your animations will move according to time and not the FPS of the device doing the rendering.

Elastic Attraction

Now we are finally prepared to get into some physics behaviors! Elastic attraction is similar to LERP, but we will be using velocity and acceleration to calculate the movement. The end result is a springy gravitational behavior that is great for adding more life to your effects.

Elastic Physics demo video

Groundwork

We will need a number of variables in this elastic patch group, so let’s get that set up. Here’s a shopping list and a little explanation.

  1. Track position — same as in the LERP example. Store it in a delay value for easy retrieval.
  2. Velocity — added to the position on each frame.
  3. Acceleration — affects velocity on each frame. We will point the acceleration toward the target position and add to the velocity on each frame, based on the distance between the target and the follower.
No logic yet, just stubbing out our inputs and outputs

Now we can start building up our springy physics effect. Taking note of the steps I listed above, it translates into just a few simple patch connections.

  1. Add acceleration to velocity
  2. Add velocity to position
Basic motion physics

Nothing is moving yet, but you can play with the initial velocity and acceleration values if you want to get an idea of how it will affect your object. Acceleration accumulates into velocity on every frame, so you will need small numbers there. Changing the initial value for velocity will give you some linear motion. At this point, I encourage you to go off on your own and try plugging things into this stuff and see what happens.

Acceleration

The next step is to determine how acceleration works. Imagine pulling a rubber band — The idea for elasticity is that the greater the distance, the stronger the pull. So we’ll get the distance and direction by just subtracting the target position from the current position. For simplicity, we can just take a fraction of that value and use it to affect our acceleration.

At this point you’ll notice that the object flies off screen quickly, even starting with really really low speed values. This is because there’s nothing telling the acceleration or velocity to slow down. It keeps building up! We need to apply some drag to reign it back in.

Applying drag in a totally non-scientific manner

Tuning the speed and drag values can be a bit of a balancing act, but we did it! Check out the springy goodness!

Hey y’all, commence the jigglin’!

Exercise: Remember time scale? We still need to apply it to the elastic physics! What value/s do you think need to be modified by the time scale?

More physics

Now that you (hopefully) understand the basics of simple physics in Spark, try writing your own rules for acceleration. What would gravity or wind look like? How would you go about applying force impulses to your objects? Try chaining object positions together and see what happens.

Things are always easier with money

Of course that’s not always true… but if you don’t want to go through the hassle of building these tools yourself — or if you just enjoyed the article — and want to show your support; Here are some links to the product pages!

Related content

Technical / Emotional Support

Do you have questions about delay values, physics, or XR in general? Join our community on the Lab and let’s chat!

Before delay frame, we could hijack the local transform node to act as a value store, just like delay frame does. It was a little buggy, but I’m linking this here for posterity-sake.

If you want to learn more about coding physics from scratch, check out The Nature of Code by Daniel Shiffman.

Tomas is blazing new trails with physics in Spark AR. Highly experimental / cool stuff!

Springy chain physics from Mate Steinforth, purely in patches.

https://matesteinforth.gumroad.com/l/bcrxh

Before the built-in throttle patch was around, I created a throttle patch using delay frame. Might be worth reverse engineering for the purpose of learning.

🖖

--

--