2

I am trying to understand three.js's camera.lookAt function, and to implement my own.

I'm using eye = camera position, target = target look at point, and up is always (0, 1, 0). A friend proposed that the obvious way to rotate a camera to look at a point in space would be to get the desired forward by calculating target - eye, and compute the angle between the camera's forward vector (0, 0, -1) and the target forward (using atan2 method described in these answers), and this is the angle of rotation. I would be able to find the axis of the rotation by computing the crossProduct of the forward vector and the desired forward. I would use a function like setFromAxisAngle to get the resulting quaternion.

Tried to draw it here:

enter image description here

Would this work in theory? When testing it against the canonical lookAt method, which uses eye, up, and target and does z = (eye - target), x = Cross(up, z), y = Cross(x, z) -- (also, why is it eye - target instead of target - eye?) -- I see small ( < 0.1 differences).

gman
  • 100,619
  • 31
  • 269
  • 393
nic_m
  • 107
  • 5

1 Answers1

2

I personally think the implementation of three.js's Matri4.lookAt() method is somewhat confusing. It's also in the wrong class, it should be placed in Matrix3. Anyway, a more clear implementation can be found in the MathGeoLib, a C++ library for linear algebra and geometry manipulation for computer graphics.

https://github.com/juj/MathGeoLib/blob/ae6dc5e9b1ec83429af3b3ba17a7d61a046d3400/src/Math/float3x3.h#L167-L198 https://github.com/juj/MathGeoLib/blob/ae6dc5e9b1ec83429af3b3ba17a7d61a046d3400/src/Math/float3x3.cpp#L617-L678

A lookAt() method should first build an orthonormal linear basis A (localRight, localUp, localForward) for the object's local space. Then it builds an orthonormal linear basis B (worldRight, worldUp, targetDirection) for the desired target orientation. The primary task of lookAt() is to map from basis A to B. This is done by multiplying m1 (basis B) with the inverse of m2(basis A). Since this matrix is orthonormal, the inverse is computed by a simple transpose.

m1.makeBasis( worldRight, worldUp, targetDirection );
m2.makeBasis( localRight, localUp, localForward );

this.multiplyMatrices( m1, m2.transpose() );

this references to an instance of a 3x3 matrix class.

I suggest you carefully study the well-documented C++ code in order to understand each single step of the method.

Mugen87
  • 28,829
  • 4
  • 27
  • 50
  • Thank you, that's a good explanation and example-- I actually feel like I understand the lookAt function and how it is computing an orthonormal basis for the camera, I am mostly wondering why the same thing cannot be achieved by getting the angle and axis of rotation between the default camera forward vector and the desired forward vector (target - eye). – nic_m Apr 18 '19 at 14:37