代码之家  ›  专栏  ›  技术社区  ›  mnen

捕捉对象相对于另一个对象的位置和旋转

  •  1
  • mnen  · 技术社区  · 7 年前

    1) 捕捉立方体A相对于摄像机A的位置和旋转

    我用以下代码成功地做到了这一点:

    positionDifference = CubeA.InverseTransformPoint(CameraA.transform.position);
    

    要将其转移到多维数据集B,我需要:

    cubeBpos = transform.InverseTransformPoint(CubeB.transform.localPosition);      
    
    while ( Mathf.Abs (cubeBpos.x + positionDifference.x) > 0.01f ) {
        if (cubeBpos.x + positionDifference.x > 0) {
            CubeB.transform.position += new Vector3(-0.01f, 0, 0);
        } 
        else if (cubeBpos.x + positionDifference.x < 0) {
            CubeB.transform.position += new Vector3(+0.01f, 0, 0);  
        }
        cubeBpos = transform.InverseTransformPoint(CubeB.transform.position);
    }
    

    这很笨重,但很有效。然而,当我尝试转移旋转时,立方体B开始围绕原点旋转。有趣的是,当我在世界坐标系中移动立方体A时,立方体B在局部坐标系中移动,反之亦然。我怀疑局部到世界坐标的转换是一个问题,但我也认为我的旋转代码很幼稚。我试图用两种方式捕捉旋转,第一种是这样:

    rotationDifference = Quaternion.Inverse(CubeA.transform.rotation) * CameraA.transform.rotation;
    
    CubeB.transform.rotation = Quaternion.Inverse(rotationDifference);
    

    第二次尝试:

    rotationDifference = new Vector3(transform.eulerAngles.x, transform.eulerAngles.y, transform.eulerAngles.z);
    
    CubeB.transform.eulerAngles = rotationDifference;
    

    这两种方法都导致了奇怪的旋转偏移。我试着使用localPosition和localEulerAngles,但没用。

    我希望有一种更聪明的方法来做到这一点:)

    编辑: 这是一个升降箱 link 到项目

    2 回复  |  直到 7 年前
        1
  •  2
  •   Nico Schertler    7 年前

    问题是,您将位置和旋转分开处理,尽管它们相互影响。让我们把两者放在一起,假设我们有两个摄像机和两个立方体的模型变换(表示为齐次矩阵;假设为列向量)。然后,我们想找到立方体B的变换 TCubeB ,以便:

    TCameraA^-1 * TCubeA = TCameraB^-1 * TCubeB
    

    请注意 TCamera

    我们可以立即解决 TCubeB公司 :

    TCameraB * TCameraA^-1 * TCubeA = TCubeB
    

    我对Unity API不太熟悉,但似乎无法直接使用转换矩阵。那么,让我们拆分变换矩阵 T 在旋转部分 R Tr :

    TrCameraB * RCameraB * (TrCameraA  * RCameraA)^-1 * TrCubeA * RCubeA = TrCubeB * RCubeB
    TrCameraB * RCameraB * RCameraA^-1 * TrCameraA^-1 * TrCubeA * RCubeA = TrCubeB * RCubeB
    

    如果我们只关心旋转,我们可以通过简单地执行以下操作来计算相应的四元数:

    QCameraB * QCameraA^-1 * QCubeA = QCubeB
    

    TrCameraB * RCameraB * RCameraA^-1 * TrCameraA^-1 * TrCubeA * RCubeA * RCubeB^-1 = TrCubeB
    

    要找到平移向量,只需将原点乘以左侧:

    TrCameraB * RCameraB * RCameraA^-1 * TrCameraA^-1 * TrCubeA * RCubeA * RCubeB^-1 * (0, 0, 0, 1)
    

    在伪代码中,这归结为(出现的矩阵代表各自的翻译向量):

    Vector4 translation = (0, 0, 0, 1)
    translation += TrCubeA
    translation -= TrCameraA
    translation = RCameraA.Inverse().Transform(translation)
    translation = RCameraB.Transform(translation)
    translation += TrCameraB
    

    同样,我几乎不知道Unity API,它可能使用了一些与我不同的约定(转换数学中的约定特别复杂)。但我相信,如果有什么不正确的地方,你可以修改上述推导。

        2
  •  0
  •   mnen    7 年前

    Nico的回答很好,解决了我的问题,但由于注释部分的代码格式不是为此而构建的,下面是我根据Nico的回答为Unity编写的代码:

        Vector3 translation = new Vector3(0,0,0);
        translation += cubeA.transform.position;
        translation -= cameraA.transform.position;
        translation = cameraA.transform.InverseTransformPoint(translation);
        translation = cameraB.transform.TransformPoint(translation/2);
    
        cubeB.transform.position = translation;
    
        Quaternion rotation = Quaternion.identity;
        rotation = cameraB.transform.rotation * Quaternion.Inverse(cameraA.transform.rotation) * cubeA.transform.rotation;
    
        cubeB.transform.rotation = rotation;