Page 1 of 1

Need Help modifying the Duik's Connector Code

Posted: Sat May 04, 2019 7:02 pm
by jetrotal
Image

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:

Code: Select all

//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;
I added an img attachment file, comparing both original code (left/red) and the code that i wrote (right/green).



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:

Code: Select all

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

Code: Select all

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...

Re: Need Help modifying the Duik's Connector Code

Posted: Tue May 14, 2019 7:04 pm
by jetrotal
I did it! Thanks to Filip Vandueren, from CreativeCow.
https://github.com/jetrotal/Duik.Connec ... poseMOD.js


I had to add

Code: Select all

	ctrlNearK = ctrlFrames.nearestKey(time);

	try{
		ctrlPrevK = ctrlNearK.time&lt;time ? ctrlNearK : ctrlFrames.key(ctrlNearK.index-1);
	}catch(err){
		ctrlPrevK = ctrlNearK.time&lt;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:

Code: Select all

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 guys have any advise to clean it up, would be welcome...