0
\$\begingroup\$

Assuming I have a spline that I want a camera to follow, is there a simple way to compute the orientation of the camera such that its optical center aligns with the vector defining the derivative of the spline?

In other words I want the camera to be oriented so the spline goes through the center of the image created.

I am using axis angle orientation for attitude but I can convert to any.

I'm not using an engine, I just need the mathematical details.

\$\endgroup\$
4
  • \$\begingroup\$ The exact steps depend on your spline type (if you need help computing the derivative), your tech stack (so we know what transformation API you have to orient your camera — e.g. do you need a quaternion, Tait-Bryan angles, etc.) and how your coordinate system is set up. Can you edit your question to clarify these details? \$\endgroup\$
    – DMGregory
    Commented Dec 7 at 22:50
  • \$\begingroup\$ I tried to add some. \$\endgroup\$
    – maxical
    Commented Dec 8 at 3:04
  • \$\begingroup\$ So, your question reduces to: "How can I compute an axis-angle rotation that transforms direction A to direction B?" where A is your camera's viewing axis, and B is the spline's derivative? \$\endgroup\$
    – DMGregory
    Commented Dec 8 at 3:34
  • \$\begingroup\$ I think so, but rotation about the axis is undefined so is to be kept constant. \$\endgroup\$
    – maxical
    Commented Dec 8 at 3:39

1 Answer 1

0
\$\begingroup\$

Maintaining a constant orientation about the viewing axis is unfortunately not something we can guarantee - the Hairy Ball Theorem strikes again - see this past Q&A for more on that.

For a camera, what we usually want is that our local "up" vector should remain continuous frame to frame (no big jumps / discontinuities), and when the spline is not too steep, we should gradually rotate to get that up vector as close to the world up direction as we can.

Here's a procedure we can use for that:

Vector3 viewDirection = spline.GetUnitTangentAt(progress);

Vector3 targetUp = previousUp + worldUp * untwistRate * deltaTime;

// Ensure localUp is perpendicular to viewDirection and of unit length
Vector3 localUp = Normalize(targetUp - Dot(viewDirection, targetUp) * viewDirection);

From these two basis vectors, we can construct a 3x3 rotation matrix, and either use that directly (if your code allows for it) or extract an angle-axis form from it.

The remaining steps depend on your coordinate system, which you haven't specified, so I'll use a common left-handed convention of {x+ = right, y+ = up, z+ = forward}

Our rotation matrix would then look like, this, where our localUp and viewDirection (forward) vectors form the second and third columns, and the first column is their cross product.

$$R = \begin{bmatrix} \left(\vec u \times \vec f \right) & \vec u & \vec f \end{bmatrix} = \begin{bmatrix} u_y f_z - u_z f_y & u_x & f_x \\ u_z f_x - u_x f_z & u_y & f_y \\ u_x f_y - u_y f_x & u_z & f_z \end{bmatrix}$$

As shown on Wikipedia here, we can compute the rotation angle using the trace of this matrix:

$$\begin{align} \theta &= \cos^{-1} \frac {\text {tr}(R) - 1} 2\\ &= \cos^{-1} \frac {u_yf_z - u_zf_y + u_y + f_z - 1} 2\\ \end{align}$$

If that comes out to zero, the object is still in its default orientation, and you can pick a rotation axis arbitrarily (rotating 0° around any axis gives the same result).

If it comes out less than 180°, we can extract the axis \$\vec a\$ like so:

$$\vec a = \begin{bmatrix} R_{32} - R_{23} \\ R_{13} - R_{31} \\ R_{21} - R_{12} \end{bmatrix} = \begin{bmatrix}u_z - f_y \\ f_x - u_xf_y + u_yf_x \\ u_zf_x - u_xf_z - u_x\end{bmatrix}$$

For exactly 180° rotations, this will give us a zero vector, and for rotations close to that, we may lose numeric stability. As Wikipedia states:

In this case, it is necessary to diagonalize R and find the eigenvector corresponding to an eigenvalue of 1.

You can use that eigenvector as your rotation axis. I'm a little rusty on eigenvectors (I usually work with rotations as quaternions or matrices, rather than angle-axis form), so the last few steps for this case are left as an exercise for the reader. 😉

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .