Home > database >  Custom LookAt and what's the math behind it
Custom LookAt and what's the math behind it

Time:10-28

I've been trying to understand the math (trigonometry and linear algebra) behind the transform.LookAt() function. I followed a tutorial and tried to modify it to fit my needs, but I haven't succeeded so far.

I'm trying to achieve a camera (in 3d space) that is following a player with a custom offset but at the same time the user can zoom the camera in and out all while still having that Vector3 offset. I'm also locking the other axes, and just only want to apply the rotation to the X axis. The problem with my script is that the angle seems to be clamped between 45° and 90° degrees. I think I'm missing something

private void LookAt(Transform t) 
{
    Vector3 forward = _camPos - (t.position   new Vector3(0, t.GetComponent<CapsuleCollider>().height / 2, 0));
    Debug.DrawRay(forward, -forward, Color.blue);
    Vector3 right = Vector3.Cross(target.up, forward);
    Debug.DrawRay(forward, right, Color.magenta);
    Vector3 newUp = Vector3.Cross(Vector3.forward, right);
    Debug.DrawRay(forward, newUp, Color.yellow);

    float angle = Mathf.Atan2(forward.magnitude, newUp.magnitude) * Mathf.Rad2Deg;

    mainCam.transform.rotation = Quaternion.Euler(angle, 0, 0);
}
  • My code first get's the forward vector (hypotenuse in a right triangle) from the camera to the target. Side note here, that this gives the opposite direction, but it doesn't matter because
  • it then calculates the "right" vector by having the cross product of the forward vector and the target's up vector
  • then it calculates the "newUp" vector (opposite in a right triangle) by having the cross product of the forward and right vector
  • calculates the X rotation by using Arcus tangent which is the ratio between the hpyotenuse/opposite

As you can see, the vector calculations are right like on the screenshot

  • blue -forward vector
  • magenta right vector
  • yellow newUp vector

forward, right and newUp vectors

Still, the camera is only focusing on the character properly when I decrease the zoom rate, a.k.a moving the camera closer to it:

Only looking at the target (properly) after a distance

What am I missing? Help greatly be appreciated!

CodePudding user response:

To provide an actual answer. It looks like you got the correct idea, i.e. taking the cross-product between the look-at direction and an arbitrary up-vector, and then another cross product to ensure all the vectors are orthogonal. I'm not sure I understand exactly what the offset does, but I assume that is working as intended. There are a few things I would do:

  1. Make sure everything is normalized, I do not think this is strictly necessary, but it helps to keep values small.
  2. Add a check to handle if the forward direction and the target.up is close to parallel, and either pick some other up-vector, or give an error so you can detect the problem.
  3. Construct a rotation matrix directly.

I strongly prefer to handle rotations as vectors, quaternions or matrices. I find euler angles confusing and difficult to use since there are multiple variants that apply the rotations in different order, and they are difficult to visualize.

A rotation matrix (i.e. 3x3) are in practice just three orthogonal vectors, this is also super useful way to visualize matrices. I think each vector should correspond to a row in the matrix, but I'm not familiar with unity, and the conventions can be different.

And a 4x4 matrix is just a rotation matrix a column for translation and an extra row. So just use SetRow (Or SetColumn) for each of your forward/right/up vectors, using a 0 for the w-value of the vector 4. You can then convert the matrix to a quaternion, I can't fund such a builtin function in unity, and that seem a bit odd, but the link should show the principle, and there should be many other articles that show the math behind it.

  • Related