Javascript 找到旋转点的角度,使其面向三维空间中的另一点

Javascript 找到旋转点的角度,使其面向三维空间中的另一点,javascript,3d,three.js,rotation,Javascript,3d,Three.js,Rotation,假设我有两个向量: V1={x:3.296372727813439,y:-14.497928014719344,z:12.004105246875968} V2={x:2.3652551657790695,y:-16.73208508053185,z:8.945905454164146} 我如何计算v1需要旋转什么角度才能直接看v2 换成英语:假设我确切地知道我在太空中的什么地方,以及另一个人在太空中的什么地方。。。。从数学上讲,我如何计算出手指指向它们的角度 我当前(不正确)的公式 v2.x

假设我有两个向量:

V1={x:3.296372727813439,y:-14.497928014719344,z:12.004105246875968}

V2={x:2.3652551657790695,y:-16.73208508053185,z:8.945905454164146}

我如何计算v1需要旋转什么角度才能直接看v2

换成英语:假设我确切地知道我在太空中的什么地方,以及另一个人在太空中的什么地方。。。。从数学上讲,我如何计算出手指指向它们的角度

我当前(不正确)的公式

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)));
然后我用θ和φ旋转v1

v1.rotation.y = θ;
v2.rotation.x = ϕ;
但这给了我错误的旋转

θ=0.6099683401012933

ν=1.8663452274936656

但是如果我使用THREE.js并使用lookAt函数,它会产生这些旋转,这非常好:

y/θ:-0.24106818240525682

x/ñ:2.5106584861123644


提前谢谢你的帮助!我无法在最终结果中使用THREE.js,我尝试使用纯香草js,以便将其移植到另一种语言。

正确的公式是:

 var dx = v2.x-v1.x; //-0.93
 var dy = v2.y-v1.y; //-31.22
 var dz = v2.z-v1.z;
 var rxy = Math.sqrt( Math.pow(dx,2) + Math.pow(dy,2) );
 var lambda = Math.atan(dy/dx);
 var phi = Math.atan(dz/rxy)
需要根据向量所处的四分之一,调整上述的
phi
lambda
公式。我让你很容易:

 //if you do the calculations in degrees, you need to add 180 instead of PI
 if (dx < 0) phi = phi + Math.PI;
 if (dz < 0) lambda = -1 * lambda;
//如果以度为单位进行计算,则需要添加180而不是PI
如果(dx<0)phi=phi+Math.PI;
如果(dz<0)λ=-1*lambda;

使用矩阵怎么样?我认为v1是您的观点,并展望v2。矩阵是显示方向的好方法。欧拉角是方位的另一种解释

我的想法是建立一个从对象空间到世界空间的转换矩阵,你想做的事情可以分为三个步骤:

  • 开始时,摄影机位于世界空间原点,摄影机旋转为
    (0,0,0)
    世界空间与对象空间相同<代码>v1'(0,0,0)
  • 我们将摄影机转换为
    v1(3.296372727813439,-14.497928014719344,12.004105246875968)
    ,对象空间与世界空间有偏移,但对象空间轴与世界空间轴平行,摄影机旋转仍为(0,0,0)
  • 我们让摄影机看
    v2
    ,正如您所看到的,摄影机旋转会发生变化
  • 如果我能建立一个表示上述所有动作的变换矩阵,我就能得到方向

  • 首先,计算平移矩阵:因为平移是仿射变换,所以我们需要使用4x4矩阵来表示平移。我们可以很容易地得到矩阵:
  • 我们使用基轴得到旋转矩阵

    您可能需要设置摄影机的上方向向量。默认值为
    (0,1,0)
    。在对象空间中,可以通过
    v1-v2
    计算基础z

    z=(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z)。normalize()

    x向量:我们知道基向量是垂直于z-up平面的向量,我们通过向上和z的叉积得到x向量

    x=up.crossproduct(z)

    y向量,yz-x平面前

    y=z.产品(x)

    我们可以将旋转矩阵构建为3 x 3矩阵:

    然后,我们最终得到变换矩阵:

    我们可以用矩阵表示摄像机的方位。如果你需要欧拉角或四元数。他们之间有一些相互转换的方式。您可以在本书中找到:

    Three.js实现了与my way相同的
    LookAt()
    功能

    下面是three.js源代码,我添加了一些注释:

    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.
    
  • 您可以像three.js一样使用list实现矩阵

    我还有另一个想法——球面极坐标系。球坐标总是像(r,Θ,Φ)一样标注,Θ是航向角,Φ是俯仰角。您需要做的是将v1和v2笛卡尔坐标转换为球坐标。因为球面中的第二和第三个元素是角,所以我们可以计算v1和v2之间的角位移。然后,将此置换作为摄影机旋转的一个补充

    这是我的代码(假设您的相机位于世界原点(0,0,0)):

    顺便说一下,3D数学非常有用,值得学习,我参考的所有公式或概念都可以在书中找到


    希望它能帮助你。

    x/ñ是绕x轴旋转的,因此它等于y,z之间的角度,对于y/θ,我们必须找到x,z之间的角度

    V1={x:3.296372727813439,y:-14.497928014719344,z:12.004105246875968}
    V2={x:2.3652551657790695,y:-16.73208508053185,z:8.945905454164146}
    var v={dx:V2.x-V1.x,dy:V2.y-V1.y,dz:V2.z-V1.z}
    测试向量(v);
    函数测试向量(vec){
    console.log();
    可变角度=角(vec);
    控制台日志(“φ:+角度。φ+”θ:+角度。θ);
    }
    函数角(vec){
    返回{
    θ:(Math.PI/2)+Math.atan2(vec.dz,vec.dx),
    phi:(3*Math.PI/2)+Math.atan2(vec.dz,vec.dy)
    };
    
    }
    我从THREE.js(r84)的最新版本中提取了相关代码。 我认为这是获得你想要的结果的最好方法

    //除非注释中另有说明,否则所有函数都源自最新版本的THREE.js(r84)
    // https://github.com/mrdoob/three.js/tree/master
    //THREE.js根据麻省理工学院授权(版权所有©2010-2017 THREE.js作者)
    // 
    //K Scandrett已将某些功能更改为在此设置下工作,
    //但不是计算。
    //任何错误都被认为是我的,而不是THREE.js的作者。
    //我不保证在修改原始代码时没有产生任何bug
    //因此,使用风险自负。享受比萨饼吧。
    var v1={x:3.296372727813439,y:-14.497928014719344,z:12.004105246875968};
    var v2={x:2.3652551657790695,y:-16.732085
    
    //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;