# Creative Communities of the World Forums

The peer to peer support community for media production professionals.

Forums Adobe After Effects Expressions Object Move speed according to the path curvature

• # Object Move speed according to the path curvature

• I just came across this problem, if some senior most person can help me. I wanted to move an object’s position according to a path’s curvature, it slows down when it comes to more curvy portion, and speeds up when it straight line. here is some example someone done in JS at github. if anyone can help me to translate it in AE.

here are the links for that project.

https://github.com/acarapetis/curve-appreciator/blob/master/main.js

here is demo

https://a.carapetis.com/curve-appreciator/

just put/drag any path in svg format here to see the demo.

i want same functionality in AE, is there any clue or help, thank you very much in advance.

• Can you show a demo of how this might work as a resulting animation? I understand the desire to have the solution be procedural, and it would be helpful to see how you would like the result to move.

• I have posted the links above, pls have a look upon, thank you very much for earlier reply.

• ### Filip Vandueren

September 16, 2020 at 11:18 am

An expression like below works, but it can be slow to compute (has to iterate over every past frame)

I’ve tweaked the curviness determination function such that it looks 8 times further forwards than backwards, this mimics a race driver: going slower into a curve, but accelerating as soon as the curve is behind us.

the Math.pow( ,0.2) is also arbitrary: it slopes the difference between 0 curviness and 1 curviness by a power of 1/5, sort of like a gamma.

<pre class=””>

p=thisComp.layer(“Shape Layer 1”).content(“Shape 1”).content(“Path 1”).path;

function curviness(path, pos_on_path, width, samples) {

var c = 0;

for (i=0; i<=width/2; i+=width/samples/2) {

c+=length(

p.normalOnPath((1+pos_on_path-i/8)%1),

p.normalOnPath((pos_on_path+i)%1)

);

}

return Math.pow(c/samples/2,0.2);

}

// speeds in percentage of path per second.

minSpeed = 2;

maxSpeed = 50;

travel = 0;

for (t=0; t<time; t+=thisComp.frameDuration) {

curve = curviness(p, travel, 0.06, 8);

travel+=linear(curve, 0, 1, maxSpeed, minSpeed)/100*thisComp.frameDuration;

}

travel%=1;

thisComp.layer(“Shape Layer 1”).toComp(p.pointOnPath(travel));

• Thank you very much Mr. Filip. Its great, but seems taking more processing, did u see the code at github, can we use that approach?

if have to use with a lot of layers, it would take a lot of processing power, i think. is there any other solution sir.

BTW i am really thankful to you for this kindness.

• I didn’t look at the github code in detail, but we have to work with the limitation of expressions: every frame you have to recalculate everything, because the layer does not know where the dot was 1 frame ago.

One approach to speed things up: calculate the curvature of the path once, store it in an array and lookup/interpolate from the array.

You would need one text-layer per shape to store the array. This can be achieved with an expression on the sourceText, the layer should be hidden from view.

`posterizeTime(0); // only calculate oncep=thisComp.layer("Shape Layer 1").content("Shape 1").content("Path 1").path;function curviness(path, pos_on_path, width, samples) {	var c = 0;	for (i=0; i<=width/2; i+=width/samples/2) {		c+=length(			p.normalOnPath((1+pos_on_path-i/8)%1),			p.normalOnPath((pos_on_path+i)%1)		);	}	return Math.pow(c/samples/2,0.2);}num=250; // number of samples along the path, more is better for larger or more complex pathscurves=[];for (j=0; j<num; j++) {	curves.push(curviness(p, j/num, 0.08, 30) ); }JSON.stringify(curves);`

Then the layers that need to move on the path can use this code for position:

```// get the pre-calculated curvesa=eval(thisComp.layer("shape 1 array").text.sourceText);
p=thisComp.layer("Shape Layer 1").content("Shape 1").content("Path 1").path;function lookup(t) {	t%=1;	b=t*a.length;	sample1 = a[Math.floor(b)];	sample2 = a[Math.floor((b+1)%a.length)];	return linear(b%1,0,1,sample1, sample2);}// speeds in percentage of path per second.minSpeed = 0.2; maxSpeed = 50;travel = 0;for (t=0; t<time; t+=thisComp.frameDuration) {	curve = lookup(travel);	travel+=linear(curve, 0, 1, maxSpeed, minSpeed)/100*thisComp.frameDuration;}travel%=1;thisComp.layer("Shape Layer 1").toComp(p.pointOnPath(travel));```

Rendering 20 seconds with this pre-calculated method took 16seconds, faster than realtime.

The previous version takes 20-30 minutes for 20 seconds!, keeps getting slower and slower.

• The heavy calculatio has to be done once, so if you have many many samples, then After Effects may be unresponsive for a time, but once those values on the text-layers are cached, you’re fine.

although: posterizeTime(0) is a new function, in older versions of after effects it might calculate more often. I would then use my script to convert the calculation of the text-layer to 1 keyframe: https://we.tl/t-ZVNS5Lj0c9

• waao you rock. real hero;

one question what if i have to change the path points, would it recalculate the path?

• Yes, you can change the path at any time and the array will recalculate, but you cannot keyframe it.

If you keyframe it, you cannot use posterizeTime(0) and things will get slower again (though not as slow as the first version)

Viewing 1 - 9 of 9 posts