捕获一个对象相对于另一个对象的位置和旋转
Capture position and rotation of an object relative to another object
我有两个相同的物体和两个相机。我想要实现的是:
1) 捕捉Cube A相对于Camera 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 开始围绕原点旋转。有趣的是,当我在世界坐标中移动 Cube A 时,Cube 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
问题在于,尽管位置和旋转相互影响,但您将它们分开处理。让我们把两者放在一起,假设我们有两个相机和两个立方体的模型转换(表示为齐次矩阵;假设为列向量)。然后,我们要找到立方体 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,它可能使用一些与我不同的约定(转换数学中的约定特别棘手)。但我相信如果有不正确的地方,你可以调整上面的推导。
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;
它不是一对一的,但它实现了我希望的:如果立方体 A 是静止的,而相机 A 围绕它移动,那么立方体 B 相对于相机 B 移动,使得立方体 A 和立方体B 相对于各自的相机始终具有完全相同的位置和旋转。
我有两个相同的物体和两个相机。我想要实现的是:
1) 捕捉Cube A相对于Camera 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 开始围绕原点旋转。有趣的是,当我在世界坐标中移动 Cube A 时,Cube 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问题在于,尽管位置和旋转相互影响,但您将它们分开处理。让我们把两者放在一起,假设我们有两个相机和两个立方体的模型转换(表示为齐次矩阵;假设为列向量)。然后,我们要找到立方体 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,它可能使用一些与我不同的约定(转换数学中的约定特别棘手)。但我相信如果有不正确的地方,你可以调整上面的推导。
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;
它不是一对一的,但它实现了我希望的:如果立方体 A 是静止的,而相机 A 围绕它移动,那么立方体 B 相对于相机 B 移动,使得立方体 A 和立方体B 相对于各自的相机始终具有完全相同的位置和旋转。