I have two identical objects and two cameras. What I'd like to achieve is the following:
1) Capture the position and rotation of Cube A relative to Camera A
2) Transfer that to a Cube B, so that in Camera B (which I cannot move), Cube B looks exactly as Cube A looks in Camera A
I was successful doing that with position with the following code:
positionDifference = CubeA.InverseTransformPoint(CameraA.transform.position);
To transfer it onto Cube B, I do:
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);
}
That's clunky, but works. However, when I try to transfer rotations, Cube B starts to pivot around the origin. Interestingly, when I move Cube A in world coordinates, Cube B moves in local, and vice versa. I suspect local-to-world coordinate translation is an issue, but I also think my rotation code is naive. I tried to capture rotation in two ways, first like this:
rotationDifference = Quaternion.Inverse(CubeA.transform.rotation) * CameraA.transform.rotation;
CubeB.transform.rotation = Quaternion.Inverse(rotationDifference);
Second attempt:
rotationDifference = new Vector3(transform.eulerAngles.x, transform.eulerAngles.y, transform.eulerAngles.z);
CubeB.transform.eulerAngles = rotationDifference;
Both approaches resulted in weird rotational offsets. I tried using localPosition and localEulerAngles, didn't help.
I'm hoping there's a smarter way to do this :)
EDIT: Here's a Dropbox link to the project
The problem is that you are treating position and rotation separately although they influence each other. Let's put both together and say we have model transforms for the two cameras and the two cubes (represented as homogeneous matrices; assuming column vectors). Then, we want to find the transform for cube B TCubeB
, such that:
TCameraA^-1 * TCubeA = TCameraB^-1 * TCubeB
Note that TCamera
is the model transform of the camera, not the view matrix. If you have the view matrix, simply leave the inverse away.
We can immediately solve for TCubeB
:
TCameraB * TCameraA^-1 * TCubeA = TCubeB
I'm not too familiar with the Unity API but it seems like you cannot use transformation matrices directly. So let's split the transformation matrix T
in a rotational part R
and a translational part Tr
:
TrCameraB * RCameraB * (TrCameraA * RCameraA)^-1 * TrCubeA * RCubeA = TrCubeB * RCubeB
TrCameraB * RCameraB * RCameraA^-1 * TrCameraA^-1 * TrCubeA * RCubeA = TrCubeB * RCubeB
If we care only about the rotation, we can calculate the respective quaternion by simply doing:
QCameraB * QCameraA^-1 * QCubeA = QCubeB
The translation becomes a bit more difficult. We need to find the translation transform, such that
TrCameraB * RCameraB * RCameraA^-1 * TrCameraA^-1 * TrCubeA * RCubeA * RCubeB^-1 = TrCubeB
To find the translation vector, simply multiply the origin to the left-hand side:
TrCameraB * RCameraB * RCameraA^-1 * TrCameraA^-1 * TrCubeA * RCubeA * RCubeB^-1 * (0, 0, 0, 1)
In pseudo-code, this boils down to (the matrices that appear stand for the respective translation vectors):
Vector4 translation = (0, 0, 0, 1)
translation += TrCubeA
translation -= TrCameraA
translation = RCameraA.Inverse().Transform(translation)
translation = RCameraB.Transform(translation)
translation += TrCameraB
Again, I barely know the Unity API and it might use some different conventions than I did (conventions in transformation math are especially tricky). But I am sure you can adapt the above derivations if something is not correct.