Stopwatch click scripting

Find out why the . goes before the /

Moderator: Paul Tuersley

Post Reply
Posts: 18
Joined: May 6th, 2012, 2:11 pm

Hello all,
I have an expression I use often which I want to make a one-click script.

It requires an expression on the position parameter and one on the rotation parameter.

I started off by trying to not use expressions, I don't want to have expression but rather, set values. I managed to do this with the position part of the expression

Code: Select all

a = thisComp.layer(thisLayer, -1).position;
b = thisComp.layer(thisLayer, -2).position;
c = thisComp.layer(thisLayer, -3).position;
I changed this to

Code: Select all

var aP = selectedLayers[0].property("position").value;
var bP = selectedLayers[1].property("position").value;
var cP = selectedLayers[2].property("position").value;
var posValue = (aP+bP+cP)/3;
then I got to the orientation expression:

Code: Select all

//~ n = cross((a-b),(a-c));
//~ orientation+lookAt(a, n)
first issue was 'cross' is a Math method that is only in expressions (or am I wrong). I solved this by referencing the Sylvester.js library. And writing:

Code: Select all

var aX = aP[0];                                                                                             
var aY = aP[1];  
var aZ = aP[2];  

var bX= bP[0];  
var bY= bP[1];  
var bZ= bP[2];  

var cX= cP[0];  
var cY= cP[1];  
var cZ= cP[2];

var aVec = Vector.create([aX,aY,aZ]);
var bVec = Vector.create([bX,bY,bZ]);
var cVec = Vector.create([aX,bY,bZ]);

var aSubBVec = aVec.subtract(bVec);
var aSubCVec = aVec.subtract(cVec);

var n = aSubBVec.cross(aSubCVec);
now that last bit is proving tricky. first off orientation+lookAt(a, n), what orientation. The current orientation? and lookAt seems to be another expression only command (again, hopefully, I am wrong?)

So my new thought is to take the parameters I need, generate a string and use .expression to apply the expression. then selecting the properties and executing app.executeCommand(app.findMenuCommandId("Convert Expression to Keyframes"));

Now, this is all well and good, however, I would like the end result to be assigned values and not expressions.

So finally my question(s):
1) is cross and lookAt truly expression-only parameters?
2) is there a way once baked, to essentially "click" the stopwatch and kill all keys (i have seen for loops that remove keys from right to left but I don't want to introduce a performance hit especially when the value at each frame is indentical.
3) is there a manual setup to the lookAt expression which I could replicate (with or without the Sylvester library.) I am assuming this is matrix multiplication (which is not in JS?, references and resources here would be greatly appreciated.)
4) OR is there a way to interrupt convert expression to keyframes after the first frame, then delete the key on the first frame.

lots of questions and maybe I'm not being terribly clear, any help would be greatly appreciated.
Paul Tuersley
Posts: 704
Joined: June 5th, 2004, 7:59 am
Location: London, UK

Once you've applied the expression you can just read the resulting value, delete the expression then re apply that value. Something like:

theProperty.expression = "my expression";
var result = theProperty.valueAtTime(0,false); // return preExpression value = false;
theProperty.expression = "";
Posts: 18
Joined: May 6th, 2012, 2:11 pm

wow that is way cleaner than what I came up with.

Code: Select all"Position").expression = myPosString;"Orientation").expression = myOrientString;
        var newPos ="Position").valueAtTime(0, false);"Position").expressionEnabled = false;"Position").setValueAtTime(0, newPos);
        var newOrient ="Orientation").valueAtTime(0, false);
        alert(newOrient);"Orientation").expressionEnabled = false;       "Orientation").setValueAtTime(0, newOrient);
That said, I was getting some funky results with the var newOrient ="Orientation").valueAtTime(0, false); As I was not receiving the value same value as the expression was generating (if I'm understanding the false boolean.) I will rescript this to match your much cleaner version and see if this resolves the issue thanks.

Other stuff that has come up since starting this script is the following:


Code: Select all

 var selectedLayers = activeItem.selectedLayers;
               selectedLayers.sort(function(a, b){
                return a.index-b.index
represent a good way to sort a selectedLayers array so that no matter the order selected the go in smallest to highest, I am so confused by this. This is cobbled from non ae specific examples and I hope this is doing what I need or (like above) is there a better way of doing this?

Going along with the above, I'm getting the strange feeling more and more that the expression I'm using is fundamentally flawed. It shouldn't matter what order the three nulls are selected but it seems to. The forum thread for the expression I've been using is ... ient+layer I'm experiencing the same issues as another user there, orientation not always being right or consistent, is there some sort of sorting that needs to be done so the math is done in the correct order, most likely in regards to the cross (a-b),(a-c). Time to dust off the math textbooks I guess.

Paul Tuersley
Posts: 704
Joined: June 5th, 2004, 7:59 am
Location: London, UK

That sort function looks about right, but obviously you should test it to make sure it's doing what you expect. I would wrap something like this in a loop afterwards to check the result:

Another way would be to just loop through all layers in the comp, checking if they're selected and if so adding them to an array.

One small point, you don't really need to do the expression thing for position. It's as easy to do those calculations with your script.

The orientation/cross thing isn't a strength of mine. It's probably more of a question for Dan Ebberts. You could also try asking for help on that other post too.
Posts: 18
Joined: May 6th, 2012, 2:11 pm

thanks Paul, the sort is working but I'm still left with these darn orientation problems. I guess I'll need to force the script to do the matrix multiplication by hand, for the two vectors, and find the smaller of the two angles 0 and 0n - 0 to use in a sine equation (????) so It'll looks like I'm back to referencing Sylvester.js but on the flip side I shouldn't need to use expressions any longer in the script on account of calculating everything.

($&*$#!!!! (argh)
Post Reply