Skip to main content
Inspiring
August 1, 2023
Answered

Trace path: Y-position follows path based on X-position

  • August 1, 2023
  • 3 replies
  • 1235 views

Alright: I'm going to try to ask this as clearly as I can because I'm not exactly sure how to word it. 

 

I am trying to have some objects/properties linked to a null object which is tracing a path. The "progress" of path-trace null is based on a trim path effect applied to the original path. The issue I run into is that the path goes up and down somewhat inconsistently so the X-position of the null is traveling at an inconsistent speed (since trim paths is based on the length of the path and now a particular dimension).

 

Ideally, I want the Y-position to follow the null so that I can change the X-position at a constant rate but the objects would stay glued to the path. I've attached a video to clarify. The green line moves across the screen at the desired speed and the organe line is the speed it moves when tied to the null (with the circle added to show the null's position)

This topic has been closed for replies.
Correct answer Dan Ebberts

I'm not sure this is exactly what you're looking for, but if you animate the End parameter of your Trim Paths from 0 to 100, and the path never crosses back on itself (x is always increasing), adding this expression to the End parameter should make the x speed constant:

resolution = .005;
p = content("Shape 1").content("Path 1").path;
v = p.points();
xStart = v[0][0];
xEnd = v[v.length-1][0];
d = xEnd- xStart;
curX = xStart + d*value/100;
x = 0;
while (p.pointOnPath(x)[0] < curX && x < 1){
  x += resolution;
}
x*100

3 replies

Community Expert
August 2, 2023

Another option would be to use the Window/Create Nulls From Paths/Trace Path script to add a null to your timeline that follows the path. Then add this expression to the End property of Trim Paths:

 

 

thisComp.layer("Trace Shape Layer 1: Path 1 [1.1]").effect("Trace Path")("Progress")

 

 

And then add this expression to the Position Property of the layer you want to follow the null along the X axis:

 

 

x = thisComp.layer("Trace Shape Layer 1: Path 1 [1.1]").transform.position[0];
[x, value[1]]

 

 

 This assumes that you are using the shape layer's default name and the first path for Trim paths. If you renamed anything in the Shape layer, Creating the null will give you different names, but you should be able to figure it out. 

 

I use the Create Nulls from Paths script for all kinds of motion-tracking and path-following workflows. It's a very handy tool. This combination of expressions will allow the path to cross over, change direction, or even loop. 

Inspiring
August 2, 2023

Thank you for this! I think my example video might have muddied things a little bit because of the lines, but this is esentially what I did to create the red line that followed the path (with the exception that I had separated out the dimensions so that I wouldn't have to write an array. 

I do love the included "Create Nulls from Paths" script and use it frequently, so I'm always glad to see it getting some love!

I also really enjoy the script made by Good Boy Ninja which does the inverse: Create Paths from Nulls.

 

Dan Ebberts
Community Expert
Dan EbbertsCommunity ExpertCorrect answer
Community Expert
August 1, 2023

I'm not sure this is exactly what you're looking for, but if you animate the End parameter of your Trim Paths from 0 to 100, and the path never crosses back on itself (x is always increasing), adding this expression to the End parameter should make the x speed constant:

resolution = .005;
p = content("Shape 1").content("Path 1").path;
v = p.points();
xStart = v[0][0];
xEnd = v[v.length-1][0];
d = xEnd- xStart;
curX = xStart + d*value/100;
x = 0;
while (p.pointOnPath(x)[0] < curX && x < 1){
  x += resolution;
}
x*100
Inspiring
August 2, 2023

This worked perfectly! The only thing I had to do was decrease the resolution from .005 to .001 so that it would would keep up with this particular comp's frame rate, though that is a reallllllllly minor fix (and was only needed because I was running at 60fps which I normally don't do).

I'm trying to understand what's happening with the rest of it, because right now it seems like absolute, total magic.

Thank you!

Mylenium
Legend
August 1, 2023

Not easily doable. Yet one more of those scenarios where one would have to re-create the entire Bezier formula to normalize the speeds. Perhaps you could have something with .velocityAtTime() and compare speeds, but it would still require a somewhat complex loop to integrate the values and find a median.

 

Mylenium