Copy link to clipboard
Copied
Hi gang!
My colleague and I are working on a plugin which requires the implementation of After Effects' 3D camera.
We have been refereng this helpful thread: https://community.adobe.com/t5/after-effects-discussions/glator-for-dummies-and-from-dummy/m-p/69303...
But unfortunately we are struggling to get it working. I don't think there's any sample project that shows how to do this. My colleague suggested I post some of the code we've developed to see if anyone can spot where our issues might be stemming from.
We have points in 3D space, in the range of -1.0 to 1.0 which we are trying to get to display correctly with the AE camera.
This is the LookAt function we have developed:
A_Matrix4 TransposeMat4(const A_Matrix4& m)
{
A_Matrix4 r;
for (int j = 0; j < 4; ++j) {
for (int i = 0; i < 4; ++i) {
r.mat[j][i] = m.mat[i][j];
}
}
return r;
}
A_Matrix4 LookAt(
Vector3<A_FpLong> eye, // camera pos
Vector3<A_FpLong> target, // target position
Vector3<A_FpLong> up // camera up direction
)
{
A_Matrix4 m;
ZeroMemory(&m, sizeof(m));
Vector3<A_FpLong> d{ target.x- eye.x, target.y- eye.y, target.z- eye.z };
Vector3<A_FpLong> f = normalize(d);
Vector3<A_FpLong> r = normalize(cross(up,f)); // right
Vector3<A_FpLong> u = normalize(cross(f,r)); // up
m.mat[0][0] = r.x;
m.mat[0][1] = r.y;
m.mat[0][2] = r.z;
//m.mat[0][3] = -dot(r,eye);
m.mat[1][0] = u.x;
m.mat[1][1] = u.y;
m.mat[1][2] = u.z;
//m.mat[1][3] = -dot(u, eye);
m.mat[2][0] = f.x;
m.mat[2][1] = f.y;
m.mat[2][2] = f.z;
//m.mat[2][3] = dot(f,eye);
m.mat[3][3] = 1.0;
A_Matrix4 m2;
ZeroMemory(&m2, sizeof(m2));
m2.mat[0][0] = m2.mat[1][1] = m2.mat[2][2] = m2.mat[3][3];
m2.mat[0][3] = -eye.x;
m2.mat[1][3] = -eye.y;
m2.mat[2][3] = -eye.z;
return m;// MulMatrix4(m2, m);
m.mat[0][0] = r.x;
m.mat[0][1] = r.y;
m.mat[0][2] = r.z;
m.mat[0][3] = -dot(eye, r);
m.mat[1][0] = u.x;
m.mat[1][1] = u.y;
m.mat[1][2] = u.z;
m.mat[1][3] = -dot(eye, u);
m.mat[2][0] = -f.x;
m.mat[2][1] = -f.y;
m.mat[2][2] = -f.z;
m.mat[2][3] = dot(eye, f);
m.mat[3][0] = 0.;
m.mat[3][1] = 0.;
m.mat[3][2] = 0.;
m.mat[3][3] = 1.;
m = TransposeMat4(m);
return m;
}
And this is our projection matrix:
A_long width, height, fullWidth, fullHeight;
width = output_worldP->width;
height = output_worldP->height;
fullWidth = width * in_data->downsample_x.den;
fullHeight = height * in_data->downsample_y.den;
float aspect = (float)width / (float)height;
float camx = matrix.mat[3][0];// (2.0 * matrix.mat[3][0] - fullWidth) / fullHeight; //<-Trans X
float camy = matrix.mat[3][1];// (2.0 * matrix.mat[3][1] - fullHeight) / fullHeight; //<-Trans Y
float camz = matrix.mat[3][2];// (2.0 * matrix.mat[3][2] - fullHeight) / fullHeight; //<-Trans Z
// calc projection matrix
PF_FpLong fovy = 2.0 * atan(fullHeight / (2.0 * cameraZoom)) / PF_RAD_PER_DEGREE;
PF_FpLong tanfov2 = tan(fovy * PF_PI/360.0);
A_Matrix4 proj_matrix;
PF_FpLong zfar = 1000., znear = 0.05;
PF_FpLong halfh = tanfov2 * znear;
PF_FpLong halfw = halfh * aspect;
PF_FpLong l = -halfw;
PF_FpLong r = halfw;
PF_FpLong b = -halfh;
PF_FpLong t = halfh;
proj_matrix.mat[0][0] = 2.0 * znear / (r-l);
proj_matrix.mat[0][1] = 0.0;
proj_matrix.mat[0][2] = (r+l)/(r-l);
proj_matrix.mat[0][3] = 0.0;
proj_matrix.mat[1][0] = 0.;
proj_matrix.mat[1][1] = 2.0 * znear / (t - b);
proj_matrix.mat[1][2] = (t + b) / (t - b);
proj_matrix.mat[1][3] = 0.0;
proj_matrix.mat[2][0] = 0.0;
proj_matrix.mat[2][1] = 0.0;
proj_matrix.mat[2][2] = (zfar + znear) / (zfar - znear);
proj_matrix.mat[2][3] = -(2. * zfar * znear) / (zfar - znear);
proj_matrix.mat[3][0] = 0.0;
proj_matrix.mat[3][1] = 0.0;
proj_matrix.mat[3][2] = 1.0;
proj_matrix.mat[3][3] = 1.0;
// Calc lookat matrix
Vector3<A_FpLong> origin, target;
origin.x = camx;
origin.y = camy;
origin.z = camz;
float distCam = magnitude(matrix.mat[3][0] - fullWidth * .5,
matrix.mat[3][1] - fullHeight * .5,
matrix.mat[3][2]);
target.x = matrix.mat[2][0] * distCam + camx;
target.y = matrix.mat[2][1] * distCam + camy;
target.z = matrix.mat[2][2] * distCam + camz;
A_Matrix4 invMat = matrix;
A_Matrix4 invMat2;
InvertMatrix((A_FpLong*)invMat.mat, (A_FpLong*)invMat2.mat);
Vector3<A_FpLong> orientation_vector = { 0,1,0 };
orientation_vector.x = invMat2.mat[0][1];
orientation_vector.y = invMat2.mat[1][1];
orientation_vector.z = invMat2.mat[2][1];
A_Matrix4 view_matrix = LookAt(origin, target, orientation_vector);
A_Matrix4 vp_matrix = MulMatrix4(view_matrix, proj_matrix); // view-projection matrix
And finally, the invert matrix and a few other used functions:
bool InvertMatrix(A_FpLong m[16], A_FpLong invOut[16])
{
A_FpLong inv[16], det;
int i;
inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15]
+ m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15]
- m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15]
+ m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14]
- m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15]
- m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15]
+ m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15]
- m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14]
+ m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15]
+ m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15]
- m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15]
+ m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14]
- m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11]
- m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11]
+ m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11]
- m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10]
+ m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
if (det == 0)
return false;
det = 1.0 / det;
for (i = 0; i < 16; i++)
invOut[i] = inv[i] * det;
return true;
}
template <typename T> struct Vector3 { T x, y, z; };
template <typename T> Vector3<T> cross(const Vector3<T>& v1, const Vector3<T>& v2) {
return Vector3<T>{
v1.y*v2.z - v1.z*v2.y,
v1.z*v2.x - v1.x*v2.z,
v1.x*v2.y - v1.y*v2.x
};
}
template <typename T> T dot(const Vector3<T>& v1, const Vector3<T>& v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
template <typename T> T magnitude(const Vector3<T>& v) {
return sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}
template <typename T> T magnitude(T vx, T vy, T vz) {
return sqrt(vx * vx + vy * vy + vz * vz);
}
// this could be optimized with Q_rsqrt or instrinsics later
template <typename T> Vector3<T> normalize(const Vector3<T>& v) {
T len = sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
return Vector3<T>{
v.x / len,
v.y / len,
v.z / len
};
}
I understand getting a solution from all of this is unlikely but I'm posting it on behalf of my colleague to see if anyone here has experience in this and could let us know what we are doing wrong. Or maybe you can spot something that doesn't look right - it might not be the fix but it might lead us in the right direction. If I mistakenly left out any functions, please let me know and I can add them.
It would be helpful if AE SDK provided with a project example but it seems it does not.
Thanks so much in advance for any help.
Regards,
-Richard
Copy link to clipboard
Copied
a basic question: are you trying to match AE's comp active camera? if so, you can get the camera matrix directly using AEGP_GetEffectCameraMatrix(). you'll need to concat with the perspective matrix, but all of the transforamation will be handed to you ready made.