ADOBE AFTER EFFECTS: Forum Expressions Tutorials Creative Cloud

Issues modifying the Duik's Connector Code

COW Forums : Adobe After Effects Expressions

<< PREVIOUS   •   FAQ   •   VIEW ALL   •   PRINT   •   NEXT >>
Mauro Junior
Issues modifying the Duik's Connector Code
on May 8, 2019 at 5:28:20 pm
Last Edited By Mauro Junior on May 8, 2019 at 7:03:11 pm



It is Known that Duik's Connector cycles through every keyframe that is connected to a controller. It works like using Time Remap on a Property.

I Thought that would be useful if we had an "Absolute" animation mode. That interpolates only the values between the two nearest keyframes from a controller, ignoring all the other keyframes that the connected propriety has. The example above explains a little better what am i trying to do.

That said, i started tinkering the Connector's code and found a way to do this "Absolute" animation with it:

Here's what i wrote:

//Duik.connector "absolute animation" mod
var ctrlLayer =thisComp.layer("C | Slider 2");

var ctrlValue = ctrlLayer.effect("Slider")(18);
var ctrlEffect = ctrlLayer.effect("Value Connector");
var useVelocity = ctrlEffect(1).value == 2;
if (useVelocity) ctrlValue = ctrlValue.velocity;
else ctrlValue = ctrlValue.value;

var tHasKeys = ctrlLayer.transform.xPosition.numKeys > 1;

function connect(keyF){



var ctrlMin = ctrlEffect(2).value; //0
var ctrlMax = ctrlEffect(3).value; //100
var result = value;
if (numKeys >= 2 && ctrlEffect.enabled)
{

var t = 0;
var beginTime = key(1).time;
var endTime = key(numKeys).time;
if (ctrlMin > ctrlMax)
{
t = linear(keyF, ctrlMin, ctrlMax, endTime, beginTime);
// t = linear(time, 0, 100, 0.5, 0.0); ????????
}
else
{
t = linear(keyF, ctrlMin, ctrlMax, beginTime, endTime);
}
result = valueAtTime(t);
}
var driver = Math.floor(result);

//
return driver;
}


sliderController = ctrlLayer.transform.xPosition;

poses = [];
temp = 1;

while ( temp <= thisComp.marker.numKeys ) {
poses.push ( this.value );
i = temp++ ;
}


function getValues(){

var obj_A = sliderController
var ID_A = obj_A.nearestKey(time).index;
var value_A;
var time_A;
var keyF_A;
var keyF_B;

if (obj_A.nearestKey(time).time <= time ){
value_A = obj_A.key(ID_A).value;
time_A = obj_A.key(ID_A).time;

} else {

try{
obj_A.key(ID_A-1).value;
value_A = obj_A.key(ID_A-1).value;
time_A = obj_A.key(ID_A-1).time;

}catch(err){
value_A = obj_A.key(ID_A).value;
time_A = obj_A.key(ID_A).time;
}


}




var obj_B = sliderController
var ID_B = obj_B.nearestKey(time).index;
var value_B;
var time_B;

if (obj_B.nearestKey(time).time >= time ){
value_B = obj_B.key(ID_B).value;
time_B = obj_B.key(ID_B).time;
} else {

try{
obj_B.key(ID_B+1).value;
value_B = obj_B.key(ID_B+1).value;
time_B = obj_B.key(ID_B+1).time;
}catch(err){
value_B = obj_B.key(ID_B).value;
time_B = obj_B.key(ID_B).time;
}


}

keyF_A = connect(value_A);
keyF_B = connect(value_B);
return linear(time,time_A, time_B, keyF_A, keyF_B);
// time value can't read the easing from the slider keyframes, I must discover a way to mimic the ctrlEffect + UseVelocity shenanigans from the original code.
}

if(tHasKeys) getValues() else key(1).value;

Here's a link that compares the original code (left/red) and the code that i wrote (right/green):
https://www.diffchecker.com/0YTR5aNV


The code kinda works as intended.
I only have three issues with it:

- I can't translate the connector's speed and easing from the connector to the to the connected properties.
Somehow the original code can do it, i believe it's because of how the linear that determines the current value was built

OG CODE:
t = linear(ctrlValue, ctrlMin, ctrlMax, endTime, beginTime);
result = valueAtTime(t);


MODDED CODE:
keyF_A = connect(value_A);
keyF_B = connect(value_B);
return linear(time,time_A, time_B, keyF_A, keyF_B);

The thing is that i couldn't think any other way to capture and interpolate the values from both nearest keyframes.


- It Can't work natively with shape layers.
The OG code can because it is written based on the valueAtTime() function.
To avoid cycling through every frame i had base myself on the .value property instead. This is not a big deal to me, since i can work with points follow nulls or something similar.


- The code has tons of ugly and unnecessaries sintaxes.
Well, i'm not a programmer. I can't read very cleary what i'm doing with my code.
I know some of the issues listed above could be solved if i wrote the code more likely to how the original was written, but I burned out all my knowledge about expressions trying to figure out the solutions i wrote.

I can't argue about the last two issues, the easing issue could already make the code 100% usable.
With it done, we could have a powerfull LipSync/Facial expressions Rig that can jump straight to desired poses on an animation.


Thanks in advance and sorry if i did not made clear what i'm trying to do. English is not my native language...


Return to posts index

Filip Vandueren
Re: Issues modifying the Duik's Connector Code
on May 13, 2019 at 11:56:05 am

Hi Mauro,

I don't have duIK instaleld ATM, but you can see in this thread that we accomplished kind of the same thing with Joysticks n Sliders:

https://forums.creativecow.net/thread/2/1136899#1136919

Let me know if that helped you in solving your challenge.



Return to posts index

Mauro Junior
Re: Issues modifying the Duik's Connector Code
on May 14, 2019 at 9:44:44 am

Hi Filip, you have an ellegant soution there!

I have a quesion, do your code consider the Easing from the slider? if it does, how?

what i got with my code is:



keyF_A = connect(value_A);
keyF_B = connect(value_B);
return linear(time,time_A, time_B, keyF_A, keyF_B);



where, keyF_A is the previous pose keyframe that will be controlled by a controller, and KeyF_B is the next.

Then we have, the time whe the poses happens as time_A and time_B.


Return to posts index


Mauro Junior
Re: Issues modifying the Duik's Connector Code
on May 14, 2019 at 6:56:58 pm

I did it! Thank you so much Filip!
https://github.com/jetrotal/Duik.Connector-pose2pose-MOD/blob/master/Connec...


I had to add


ctrlNearK = ctrlFrames.nearestKey(time);

try{
ctrlPrevK = ctrlNearK.time<time ? ctrlNearK : ctrlFrames.key(ctrlNearK.index-1);
}catch(err){
ctrlPrevK = ctrlNearK.time<time ? ctrlNearK : ctrlFrames.key(ctrlNearK.index);

}try{
ctrlNextK = ctrlFrames.key(ctrlPrevK.index+1);
}catch(err){
ctrlNextK = ctrlFrames.key(ctrlPrevK.index)
}



and change the last linear(); function to:

keyF_A = connect(value_A);
keyF_B = connect(value_B);


if (ctrlPrevK.value<ctrlNextK.value) {
return linear(ctrlFrames.value, ctrlPrevK.value, ctrlNextK.value, keyF_A, keyF_B);
} else {
return linear(ctrlFrames.value, (ctrlNextK.value+0.1), ctrlPrevK.value, keyF_B, keyF_A);
}

}



My code is a messy hell, with tons of try and catch, but at least it works.

If you have any advise to clean it up, would be welcome...
You can test it without Duik, just by pasting the entire code into a property that you want to have multiple poses

and changing the

var ctrlLayer =thisComp.layer("C | Slider 2");
var ctrlFrames = ctrlLayer.transform.xPosition


to any controller layer and property.

Thank you once again Filip


Return to posts index

<< PREVIOUS   •   VIEW ALL   •   PRINT   •   NEXT >>
© 2019 CreativeCOW.net All Rights Reserved
[TOP]