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

时间:2017-10-03 19:47:01

标签: c# unity3d rotation quaternions

我有两个相同的物体和两个相机。我想要实现的目标如下:

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

2)将其传输到立方体B,以便在摄像机B(我无法移动)中,立方体B看起来与摄像机A中的立方体A看起来完全相同

我通过以下代码成功地完成了这项工作:

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

要将它传输到Cube 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,没有帮助。

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

编辑: 这是项目的Dropbox link

2 个答案:

答案 0 :(得分:2)

问题是你是在分别对待位置和旋转,尽管它们相互影响。让我们把它们放在一起说我们有两个摄像机和两个立方体的模型变换(表示为齐次矩阵;假设列向量)。然后,我们想要找到多维数据集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,它可能会使用一些不同的约定(转换数学中的约定特别棘手)。但我相信如果有些不正确,你可以调整上述推导。

答案 1 :(得分:0)

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;

它不是一对一的,但它实现了我所希望的:如果Cube A静止且摄像机A在其周围移动,则Cube B相对于摄像机B移动,使得Cube A和Cube B始终如此与各自的相机具有完全相同的位置和旋转。