-
-
Save aztack/a5073c89ebe4fbe2a95c4c8400b15bd9 to your computer and use it in GitHub Desktop.
After Effects cubic-bezier exporter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Source: https://community.adobe.com/t5/after-effects-discussions/convert-ae-keyframes-info-to-cubicbezier-points/m-p/6139286#M135604 | |
// Usage: select a layer, then File -> Scripts -> Run Script File... -> select this script | |
var curItem = app.project.activeItem; | |
var selectedLayers = curItem.selectedLayers; | |
var selectedProperties = curItem.selectedProperties; | |
var output=""; | |
if (selectedLayers == 0) { | |
output="Please Select at least one Layer"; | |
} | |
else if (selectedLayers != 0) { | |
for (var i = 0; i < selectedLayers.length; i++) { | |
for (var f in selectedProperties) { | |
var currentProperty = selectedProperties[f]; | |
if (currentProperty.numKeys > 1) { | |
for (var i = 1; i < currentProperty.numKeys; i++) { | |
var t1 = currentProperty.keyTime(i); | |
var t2 = currentProperty.keyTime(i + 1); | |
var val1 = currentProperty.keyValue(i); | |
var val2 = currentProperty.keyValue(i + 1); | |
//converting float to array | |
if (val1.constructor !== Array) { | |
var temp = new Array(); | |
temp[0] = val1; | |
val1 = temp; | |
} | |
if (val2.constructor !== Array) { | |
var temp = new Array(); | |
temp[0] = val2; | |
val2 = temp; | |
} | |
//multi dimension values | |
for (var y = 0; y < val1.length; y++) { | |
var delta_t = t2 - t1; | |
var c_val1 = parseFloat(val1[y]); | |
var c_val2 = parseFloat(val2[y]); | |
var delta = c_val2 - c_val1; | |
avSpeed = Math.abs(delta) / (delta_t); | |
/* $.write("val1 " + c_val1 + "--"); | |
$.write("val2 " + c_val2 + "\n"); | |
$.write("avSpeed " + avSpeed + "\n");*/ | |
output+=('dimension ' + y + ':\n'); | |
//values dispatch | |
if (c_val1 != c_val2) { | |
getBezier(currentProperty, i, c_val1, c_val2, avSpeed); | |
} | |
else { //if (c_val1 == c_val2) | |
var minmax = getMinMaxPoints(t1, t2, currentProperty, curItem); | |
var maxp_val = minmax.maxPoint.value; | |
var hasmax = true; | |
var hasmin = true; | |
var minp_val = minmax.minPoint.value; | |
if (!(c_val1 < maxp_val) || !(c_val1 > minp_val)) { | |
if (c_val1 < maxp_val) { | |
//create temp keyframe to "cut" the curve | |
var tempkey_i = currentProperty.addKey(minmax.maxPoint.time); | |
var tempavSpeed = Math.abs(maxp_val - c_val1) / (minmax.maxPoint.time - t1); | |
//get the 2 bezier-curves | |
getBezier(currentProperty, i, c_val1, maxp_val, tempavSpeed);//part going up | |
getBezier(currentProperty, tempkey_i, maxp_val, c_val1, tempavSpeed);//part going down | |
currentProperty.removeKey(tempkey_i);//remove temp key | |
}else { | |
hasmax = false; | |
} | |
if (c_val1 > minp_val) { | |
var tempkey_i = currentProperty.addKey(minmax.minPoint.time); | |
var tempavSpeed = Math.abs(maxp_val - c_val1) / (minmax.minPoint.time - t1); | |
getBezier(currentProperty, i, c_val1, minp_val, tempavSpeed);//part going down | |
getBezier(currentProperty, tempkey_i, minp_val, c_val1, tempavSpeed);//part going up | |
currentProperty.removeKey(tempkey_i);//remove temp key | |
}else{ | |
hasmin = false; | |
} | |
if(!hasmax || !hasmin)//if flat curve | |
output+=("keyframe " + i + " has no animation\n\n"); | |
} else { //if (c_val1 < maxp_val && c_val1 > minp_val) | |
//sort values | |
output+=('equal minmax '); | |
var first_time, sec_time, first_val, sec_val; | |
if (minmax.maxPoint.time < minmax.minPoint.time) { | |
//max value if first: | |
first_time = minmax.maxPoint.time; | |
first_val = maxp_val; | |
sec_time = minmax.minPoint.time; | |
sec_val = minp_val; | |
} else { | |
//min value if first: | |
first_time = minmax.minPoint.time; | |
first_val = minp_val; | |
sec_time = minmax.maxPoint.time; | |
sec_val = maxp_val; | |
} | |
// we have 2 extreme points, we need to "cut" twince (it gives 3 curves) | |
var tempkey_i = currentProperty.addKey(first_time); | |
var tempkey2_i = currentProperty.addKey(sec_time); | |
var tempavSpeed_1 = Math.abs(first_val - c_val1) / (first_time - t1);//avspeed 1rst curve | |
var tempavSpeed_2 = Math.abs(sec_val - first_val) / (sec_time - first_time);//avspeed 1nd curve | |
var tempavSpeed_3 = Math.abs(c_val2 - sec_val) / (t2 - sec_time);//avspeed 3rd curve | |
//get the 3 bezier-curves | |
getBezier(currentProperty, i, c_val1, first_val, tempavSpeed_1); | |
getBezier(currentProperty, tempkey_i, first_val, sec_val, tempavSpeed_2); | |
getBezier(currentProperty, tempkey2_i, sec_val, c_val2, tempavSpeed_3); | |
currentProperty.removeKey(tempkey_i);//remove temp key | |
currentProperty.removeKey(tempkey2_i);//remove temp key | |
} | |
}//end value dispatch | |
} | |
} | |
} | |
} | |
} | |
} | |
alert(output); | |
function getMinMaxPoints(t1, t2, currentProperty, curItem) { | |
var P = currentProperty; | |
var t = t1; | |
var min = 999999; | |
var max = -999999; | |
var tmin = 0; | |
var tmax = 0; | |
while (t <= t2) { | |
var val = P.valueAtTime(t, true); | |
if (val > max) { | |
max = val; | |
tmax = t; | |
} | |
if (val < min) { | |
min = val; | |
tmin = t; | |
} | |
t += curItem.frameDuration; | |
} | |
if (max == -999999) | |
max = P.valueAtTime(t1, true); | |
if (min == 999999) | |
min = P.valueAtTime(t1, true); | |
var maxPoint = { | |
value: max, | |
time: tmax | |
} | |
var minPoint = { | |
value: min, | |
time: tmin | |
} | |
return { minPoint: minPoint, maxPoint: maxPoint } | |
} | |
function getBezier(currentProperty, i, c_val1, c_val2, avSpeed) { | |
if (c_val1 < c_val2) { | |
x1 = currentProperty.keyOutTemporalEase(i)[0].influence / 100; | |
y1 = x1 * currentProperty.keyOutTemporalEase(i)[0].speed / avSpeed; | |
x2 = 1 - currentProperty.keyInTemporalEase(i + 1)[0].influence / 100; | |
y2 = 1 - (1 - x2) * (currentProperty.keyInTemporalEase(i + 1)[0].speed / avSpeed); | |
} | |
if (c_val2 < c_val1) { | |
x1 = currentProperty.keyOutTemporalEase(i)[0].influence / 100; | |
y1 = (-x1) * currentProperty.keyOutTemporalEase(i)[0].speed / avSpeed; | |
x2 = currentProperty.keyInTemporalEase(i + 1)[0].influence / 100; | |
y2 = 1 + x2 * (currentProperty.keyInTemporalEase(i + 1)[0].speed / avSpeed); | |
x2 = 1 - x2; | |
} | |
output+=("keyframe: " + i + " Cubic-bezier[" + x1.toFixed(2) + ", " + y1.toFixed(2) + ", " + x2.toFixed(2) + ", " + y2.toFixed(2) + "]\n\n"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment