Say I have two vectors:
V1 = { x: 3.296372727813439, y: -14.497928014719344, z: 12.004105246875968 }
V2 = { x: 2.3652551657790695, y: -16.732085083053185, z: 8.945905454164146 }
How can I figure out what angle v1 needs to be rotated to look directly at v2?
Put into English: say I knew exactly where I was in space, and exactly where another person was somewhere else in space.... Mathematically, how could I figure out what angles to put my finger at to point at them?
Here's what my axis looks like
My current (incorrect) formula
v2.x -= v1.x; // move v2 (vector 2) relative to the new origin
v2.y -= v1.y;
v2.z -= v1.z;
v1.x = 0; // set v1 (vector 1) as the origin
v1.y = 0;
v1.z = 0;
var r = Math.sqrt(Math.pow(v2.x,2) + Math.pow(v2.y,2) + Math.pow(v2.z,2));
var θ = Math.acos((Math.pow(v2.x,2) + Math.pow(v2.z,2))/(r*Math.sqrt(Math.pow(v2.x,2) + Math.pow(v2.z,2))));
var ϕ = Math.acos(v2.x/Math.sqrt(Math.pow(v2.x,2) + Math.pow(v2.z,2)));
Then I rotate v1 with the theta and phi.
v1.rotation.y = θ;
v2.rotation.x = ϕ;
But this is giving me the wrong rotation.
θ = 0.6099683401012933
ϕ = 1.8663452274936656
But if I use THREE.js and use the lookAt function, it spits out these rotations instead, that work beautifully:
y/θ: -0.24106818240525682
x/ϕ: 2.5106584861123644
Thanks for all the help in advance! I cannot use THREE.js in my final result, I'm trying to go pure vanilla JS so I can port it to another language.
Informally: To rotate a shape, move each point on the shape the given number of degrees around a circle centered on the point of rotation. Make sure each new point is the same distance from the point of rotation as the corresponding original point.
Rotate Objects in 3D SpacePress W to select the 3D Rotation tool. Click the Global Transform button on the Tools panel to select it for global mode or deselect it for local mode. The default is global.
How about using matrix? I think v1 is your view point, and looking towards v2. matrix is a good way to show orientation. Euler Angle is another interpretation of orientation.
My idea is building a transformation matrix from object space to world space, what you want to do can be translated in three steps:
(0,0,0)
world space is same as object space. v1'(0,0,0)
.v1(3.296372727813439,-14.497928014719344,12.004105246875968)
, object space has an offset with world space, but object space axises are parallel with world space axises, camera rotation is still (0,0,0).v2
, as you see, camera rotation would change.If I can build a transformation matrix represent all action above, I can get the orientation.
we use basis axis to get rotation matrix.
you may need to set the camera up vector. the default is (0,1,0)
. in object space, the basis z axis can be calculated by v1-v2
.
z = (v1.x-v2.x,v1.y-v2.y,v1.z-v2.z).normalize()
basis x vector: we know basis vector is a vector perpendicular to z-up plane, we get the x vector by cross product up and z.
x = up.crossproduct(z)
basis y vector, y is prependicular to z-x plane.
y = z.product(x)
we can build the rotation matrix as a 3 x 3 matrix:
then, we finally get the transformation matrix:
we can use the matrix represent the camera orientation. if you need Euler Angle or Quaternion. there some ways convert between them. you can find in this book: 3D Math Primer for Graphics and Game Developmen
Three.js implements LookAt()
function same as my way.
Here is three.js source code, and I add some comments:
function lookAt( eye, target, up ) //eye : your camera position; target : which point you want to look at; up : camera up vector
{
if ( x === undefined ) {
x = new Vector3();
y = new Vector3();
z = new Vector3();
}
var te = this.elements; //this.elements is a 4 x 4 matrix stored in a list.
z.subVectors( eye, target ).normalize(); // set z vector with the direction from your camera to target point.
if ( z.lengthSq() === 0 ) {
z.z = 1;
}
x.crossVectors( up, z ).normalize(); // set the x vector by cross product up and z vector, you know cross product would get a //vector which perpendicular with these two vectors.
if ( x.lengthSq() === 0 ) {
z.z += 0.0001; // if z is ZERO vector, then, make a little addition to z.z
x.crossVectors( up, z ).normalize();
}
y.crossVectors( z, x ); // set y by cross product z and x.
// using basic axises to set the matrix.
te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
return this;
};
// now you get the transformation matrix, you can set the rotation or orientation with this matrix.
You can implement Matrix with list like three.js does.
I also have another idea--Spherical Polar Coordinates System. Spherical coordinates always be noted like (r,Θ,Φ), Θ is heading angle, and Φ is pitch angle. what you need to do is convert v1 and v2 Cartesian coordinates to spherical coordinates. because the second and third element in spherical is angle, we can calculate angular displacement between v1 and v2. then, make this displacement as an addition to you camera rotation.
Here is my code(suppose you camera is at the world origin(0,0,0)):
//convert v1 and v2 Cartesian coordinates to Spherical coordinates;
var radiusV1 = Math.sqrt( Math.pow(v1.x) + Math.pow(v1.y) + Math.pow(v1.z));
var headingV1 = Math.atan2(v1.x , v1.z);
var pitchV1 = Math.asin(-(v1.y) / radiusV1);
var radiusV2 = Math.sqrt( Math.pow(v2.x) + Math.pow(v2.y) + Math.pow(v2.z));
var headingV2 = Math.atan2(v2.x , v2.z);
var pitchV2 = Math.asin(-(v2.y) / radiusV2);
//calculate angular displacement.
var displacementHeading = headingV2 - headingV1;
var displacementPitch = pitchV2 - pitchV1;
//make this displacement as an addition to camera rotation.
camera.rotation.x += displacementPitch;
camera.rotation.y += displacementHeading;
By the way, 3D math is very helpful and worth to learn, all the formula or concept I reference can be found in the book.
Wish it can help you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With