Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find angle to rotate point so it faces another point in 3d space

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.

like image 210
Darryl Huffman Avatar asked Mar 01 '17 16:03

Darryl Huffman


People also ask

How do I rotate a point around another point?

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.

How do you rotate an object in 3D space?

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.


1 Answers

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:

  1. at the beginning, the camera is at the world space origin, camera rotation is (0,0,0) world space is same as object space. v1'(0,0,0).
  2. we translate camera to 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).
  3. we make camera look at v2, as you see, camera rotation would change.

If I can build a transformation matrix represent all action above, I can get the orientation.

  1. First, calculating translation matrix: Because translation is an affine transformation, we need to use a 4x4 matrix to represent translation. we can easily get the matrix: translation matrix
  2. 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:

    rotation matrix

    then, we finally get the transformation matrix:

    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.

like image 60
Craig.Li Avatar answered Sep 24 '22 16:09

Craig.Li