Copy link to clipboard
Copied
Hi,
I'm looking for an expression, script, or option to filter the rotations of a 3d camera output from the camera tracker so that the rotations shown in the graph editor are allowed to be greater than 360 or less than 0. For example, I'm trying to avoid seeing the kind of graph in the image below when the camera is only rotating about 20 derees in any direction but the graph "pops between 359.xx and 0.xx quite often. This would make it much more intuative for me to read on modify the curves. Any ideas of how I can fix this?
Copy link to clipboard
Copied
Unlike 3D programs, AE does not have such a filter that adjusts the graph automatically. An expression might be as trivail as value % 360, though it still flips and pops between keyframes when the values jump over. At the end of the day you can't really avoid cleaning up your graphs, but I'm sure there are soem scripts on AEScripts.com that can help.
Mylenium
Copy link to clipboard
Copied
Thanks for your help. I had forgot that I ran into this problem earilier and I had found a solution many years ago buried on an old HD. It's called "advanced camera tracking.jsxbin". Can't seem to find it on google anymore, but it solved the problem.
Copy link to clipboard
Copied
The Camera Tracker does not manipulate Rotation. It only makes changes to Orientation on the One-node Camera that is created. Orientation is limited to X, Y, and Z values from 0º to 359º. There is no 360 value available. There is no way to count rotations.
You can't add an offset expression to Orientation and see the results in the Graph Editor because Orientation is one of the few properties that does not have a Show Post Expression Graph switch.
It would help if we knew what you were trying to do. You cannot modify any keyframed transform Properties Camera Tracking generates without fouling up the track. If you have a jittery track, you might be able to use the Smoother on Position, but Orientation has no smoothable (is that a word) properties. The only options are the Spatial Path and Temporal Graph.
There is a free Normalize Track script that I use all the time to reset the Camera Track starting point to the comp center. Normalizing the track makes using Element 3D, Particular, and other 3D effects easy. I don't know what you are trying to accomplish, so I don't know if the Normalize Track script would help.
Copy link to clipboard
Copied
Well you can always pickwhip and bake out the orientations to be rotations. I'm basically trying to get "human readible curves" in my graph editor that don't "pop" from 0 to 360 when they change by only 1 degree. I can
Copy link to clipboard
Copied
Sounds like a perfect job for Automation Blocks 🙂
If you want to pick-whip and bake the rotation values to 1D properties, you can then select these 1D properties and run the tool "Euler Filter 1D Rotation", which I just created for you. You find it in the Community Library of Automation Blocks now at
Layer Properties/Keyframes/Filter/Euler Filter 1D Rotation
If you are curious - this is what the full implementation of the tool looks like:
Copy link to clipboard
Copied
That's very interesting! I don't suppose this tool has anything that could support offsetting a tracked camera's orientation (or rotation) the "correct" way by converting the euler rotations to quaternions, performing the offsetting math, and returning the quaternions back to euler rotations?
Copy link to clipboard
Copied
If just processes each component individually and solves the pops from 359.x to 0.x, which you describe.
I.e. for each frame it checks the value of the previous frame and then chooses for the current frame among all the equivalent rotation valuesthe one that is closest to the value of the previous frame.
Copy link to clipboard
Copied
In my case, I imported Maya rotations into After Effects. The keyframs were applied to the Orientation property. The following script copies the keyframes onto the Rotation properties (xRotation, yRotation, and zRotation), and then applies a Euler filter, finally deleting the original Orientation keyframes:
{
var comp = app.project.activeItem;
var selectedLayers = app.project.activeItem.selectedLayers;
if(selectedLayers.length == 0)
{
alert("Please select at least one layer...");
}
else
{
app.beginUndoGroup("Convert 3D Orientation to X-Y-Z Rotation");
for (var i = 0; i < selectedLayers.length; i++)
{
var layer = selectedLayers[i];
CopyOrientationKeysToRotation(layer);
EulerFilterKeyframes(layer, "xRotation");
EulerFilterKeyframes(layer, "yRotation");
EulerFilterKeyframes(layer, "zRotation");
}
app.endUndoGroup();
}
}
function EulerFilterKeyframes(layer, layer_property)
{
var property = layer.property(layer_property);
var key_index = property.nearestKeyIndex(0);
var key_time = property.keyTime(key_index);
var previous_value = null;
while(key_index < property.numKeys)
{
var current_value = property.keyValue(key_index);
if(previous_value != null)
{
current_value = EulerFilterValue(previous_value, current_value);
property.setValueAtTime(key_time, current_value);
}
previous_value = current_value;
key_index++;
key_time = property.keyTime(key_index);
}
}
function EulerFilterValue(previous_value, current_value)
{
var full_rotations = 1/360;
var delta = (current_value % 360) - (previous_value % 360);
if(delta >= 180)
{
full_rotations--;
}
else if(delta <= -180)
{
full_rotations++;
}
return (full_rotations * 360) + (current_value % 360);
}
function CopyOrientationKeysToRotation(layer)
{
var property = layer.orientation;
for (var j = 0; j < property.numKeys; j++)
{
var keyVal = property.keyValue(j+1);
var keyPos = property.keyTime(j+1);
layer.property("xRotation").setValueAtTime(keyPos, keyVal[0]);
layer.property("yRotation").setValueAtTime(keyPos, keyVal[1]);
layer.property("zRotation").setValueAtTime(keyPos, keyVal[2]);
}
while (property.numKeys != 0)
{
property.removeKey(1);
}
// Set orientation back to zero
property.setValue([0, 0, 0])
}
Copy link to clipboard
Copied
Just select as menu layers as you want that has Orientation keyframes, and then run the script. It's not perfect, but it does the job. If there a section that just isn't aligned correctly, move your play-head to the start of those keyframes, select them all, click on the rotation value (X, Y, or Z) and just type after the value, +360 or -360. It should realign those keyframes.
Copy link to clipboard
Copied
I updated the script to run more accurately:
{
var comp = app.project.activeItem;
var selectedLayers = app.project.activeItem.selectedLayers;
if(selectedLayers.length == 0)
{
alert("Please select at least one layer...");
}
else
{
app.beginUndoGroup("Convert 3D Orientation to X-Y-Z Rotation");
for (var i = 0; i < selectedLayers.length; i++)
{
var layer = selectedLayers[i];
CopyOrientationKeysToRotation(layer);
EulerFilterKeyframes(layer, "xRotation");
EulerFilterKeyframes(layer, "yRotation");
EulerFilterKeyframes(layer, "zRotation");
}
app.endUndoGroup();
}
}
function EulerFilterKeyframes(layer, layer_property)
{
var property = layer.property(layer_property);
if(property.numKeys < 1) return;
var key_index = property.nearestKeyIndex(0);
var key_time = property.keyTime(key_index);
var previous_value = null;
while(key_index < property.numKeys)
{
var current_value = property.keyValue(key_index);
if(previous_value != null)
{
current_value = EulerFilterValue(previous_value, current_value);
property.setValueAtTime(key_time, current_value);
}
previous_value = current_value;
key_index++;
key_time = property.keyTime(key_index);
}
}
function EulerFilterValue(previous_value, current_value)
{
var full_rotations = Math.floor(1/360);
var delta = (current_value % 360) - (previous_value % 360);
if(delta >= 180)
{
full_rotations--;
}
else if(delta <= -180)
{
full_rotations++;
}
return (full_rotations * 360) + (current_value % 360);
}
function CopyOrientationKeysToRotation(layer)
{
var property = layer.orientation;
for (var j = 0; j < property.numKeys; j++)
{
var keyVal = property.keyValue(j+1);
var keyPos = property.keyTime(j+1);
layer.property("xRotation").setValueAtTime(keyPos, keyVal[0]);
layer.property("yRotation").setValueAtTime(keyPos, keyVal[1]);
layer.property("zRotation").setValueAtTime(keyPos, keyVal[2]);
}
while (property.numKeys != 0)
{
property.removeKey(1);
}
// Set orientation back to zero
property.setValue([0, 0, 0])
}