Adobe After Effects ExtendScript code
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
/* | |
Jim Schmitz | |
2017.11.27 | |
NYU-ITP 2019 | |
http://ixora.io/itp/ | |
Script for duplicating the special effects of "simulacra" in After Effects. | |
https://vimeo.com/123006429 | |
My rendition is here: https://vimeo.com/244769141 | |
Created for Gabe's Animation class. | |
*/ | |
{ | |
function alignFrame() | |
{ | |
var scriptName = "Align Frame"; | |
var BASEDIR = "D:/Projects/ITP/Animation/ITP Walk"; | |
// is a composition selected? | |
var activeItem = app.project.activeItem; | |
if ((activeItem == null) || !(activeItem instanceof CompItem)) { | |
alert("Please select or open a composition first.", scriptName); | |
return false; | |
} | |
var activeComp = activeItem; | |
var compName = activeComp.name; | |
// is there a camera? | |
var cameraLayer = activeComp.activeCamera; | |
if (cameraLayer == null) { | |
alert("Composition has no active camera", scriptName); | |
} | |
// is a single layer selected? | |
var selectedLayers = activeComp.selectedLayers; | |
if (activeItem.selectedLayers.length != 1) { | |
alert("Please select a single null layer", scriptName); | |
return false; | |
} | |
// is that single layer a null layer? | |
var nullLayer = selectedLayers[0]; | |
if (nullLayer == null || !nullLayer.nullLayer) { | |
alert("Single layer selected must be a null layer", scriptName); | |
return false; | |
} | |
// import the correct image | |
var frameNum = nullLayer.time / activeComp.frameDuration; | |
var options = new ImportOptions(); | |
// looks for files in a "frames" subdirectory | |
options.file = new File(BASEDIR + "/frames/" + compName + "/" + compName + "_" + pad(frameNum, 5) + ".jpg"); | |
var imageLayer = activeComp.layers.add(app.project.importFile(options)); | |
imageLayer.moveBefore(nullLayer); | |
// gather variables | |
var camera = cameraLayer.position.value; | |
var orientation = cameraLayer.orientation.value; | |
var r0 = nullLayer.position.value; | |
var width = imageLayer.width; | |
var theta = 110; | |
app.beginUndoGroup(scriptName); | |
// necessary prework | |
imageLayer.threeDLayer = true; | |
imageLayer.parent = nullLayer; | |
nullLayer.orientation.setValue(orientation); | |
imageLayer.orientation.setValue([0, 0, 0]); | |
// now do the math | |
var rot = new RotationMatrix(orientation); | |
var xp = rot.preMult([1, 0, 0]); | |
var yp = rot.preMult([0, 1, 0]); | |
var zp = rot.preMult([0, 0, 1]); | |
var a = dot(zp, r0 - camera); | |
var b = (width / 2) / dtan(theta / 2); | |
var r = camera + a * zp; | |
var scale = 100 * a / b; | |
var position = [dot(xp, r - r0), dot(yp, r - r0), 0] | |
// position into place | |
imageLayer.scale.setValue([scale, scale, scale]); | |
imageLayer.position.setValue(position); | |
// position in time | |
imageLayer.inPoint = nullLayer.time; | |
app.endUndoGroup(); | |
return true; | |
} | |
alignFrame(); | |
} | |
// helper functions | |
function pad(num, size) { | |
var s = "000000000" + num; | |
return s.substr(s.length-size); | |
} | |
function deg2rad(val) { | |
// convert radians to degrees | |
return Math.PI * val / 180; | |
} | |
function dcos(value) { | |
// cos of angle in degrees | |
return Math.cos(deg2rad(value)); | |
} | |
function dsin(value) { | |
// sin of angle in degrees | |
return Math.sin(deg2rad(value)); | |
} | |
function dtan(value) { | |
// tan of angle in degrees | |
return Math.tan(deg2rad(value)); | |
} | |
function dot(a, b) { | |
// dot product | |
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; | |
} | |
// Tait-Bryan XYZ rotation matrix | |
function RotationMatrix(orientation) { | |
var c1 = dcos(orientation[0]); | |
var s1 = dsin(orientation[0]); | |
var c2 = dcos(orientation[1]); | |
var s2 = dsin(orientation[1]); | |
var c3 = dcos(orientation[2]); | |
var s3 = dsin(orientation[2]); | |
var m11 = c2 * c3; | |
var m12 = -c2 * s3; | |
var m13 = s2; | |
var m21 = c1 * s3 + c3 * s1 * s2; | |
var m22 = c1 * c3 - s1 * s2 * s3; | |
var m23 = -c2 * s1; | |
var m31 = s1 * s3 - c1 * c3 * s2; | |
var m32 = c3 * s1 + c1 * s2 * s3; | |
var m33 = c1 * c2; | |
this.row1 = [m11, m12, m13]; | |
this.row2 = [m21, m22, m23]; | |
this.row3 = [m31, m32, m33]; | |
this.preMult = function(vec) { | |
return [dot(this.row1, vec), | |
dot(this.row2, vec), | |
dot(this.row3, vec)]; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment