I am working on a virtual production app, and I need to be able to copy the transforms of one GameObject and all of its children to another. I asked previously here how to animate a character moving while allowing outside motion to override it, and it was suggested that I make a hidden copy of the character and transfer the positions of the bones to the main character in LateUpdate. Is there a way to copy all of the bone positions from one GameObject to another?
2 Answers
Something like this?
public static void CopyTransformTree(Transform sourceRoot, Transform destRoot) {
// Read local pose in one operation.
sourceRoot.GetLocalPositionAndRotation(out var localPos, out var localRot);
// Clone local pose to destination transform in one operation.
destRoot.SetLocalPositionAndRotation(localPos, localRot);
// Clone scale (skip if your bones don't use scale).
destRoot.localScale = sourceRoot.localScale;
// Iterate over as many children as both roots have.
int limit = Mathf.Min(sourceRoot.childCount, destRoot.childCount);
for (int i = 0; i < limit; i++) // Recurse on each child sub-tree.
CopyTransformTree(sourceRoot.GetChild(i), destRoot.GetChild(i));
}
void LateUpdate() {
CopyTransformTree(sourceRootBone, destRootBone);
}
-
\$\begingroup\$ Is there a way to do this with blendshapes as well? \$\endgroup\$ Mar 13 at 0:00
-
\$\begingroup\$ That's not what your question asked. You can post it as a new question, though it will be very similar, just calling
SkinnedMeshRenderer.GetBlendShapeWeight
/SetBlendShapeWeight
. \$\endgroup\$– DMGregory ♦Mar 13 at 0:20 -
\$\begingroup\$ Though rather than copying every shape weight, you might prefer to have your animation running on the invisible copy, and then clone selected bone rotations to the visible copy that's being driven by performance. Basically, choose whichever route is shorter to get to the same combined result. \$\endgroup\$– DMGregory ♦Mar 13 at 11:27
-
\$\begingroup\$ I did find a way, but it's rather specific. Your solution does indeed copy the bone positions, but still overrides them. \$\endgroup\$ Mar 13 at 19:56
-
\$\begingroup\$ I'm not able to understand the problem from that description. Want to update your question to clarify? Is it safe to assume you called this function only on the bones you wanted to copy, and not the entire skeleton? \$\endgroup\$– DMGregory ♦Mar 13 at 21:54
You can copy the transforms of one GameObject and all of its children to another using the Transform class's methods.
public void CopyTransforms(Transform sourceTransform, Transform targetTransform)
{
// Copy the position, rotation, and scale of the source transform to the target transform
targetTransform.position = sourceTransform.position;
targetTransform.rotation = sourceTransform.rotation;
targetTransform.localScale = sourceTransform.localScale;
// Copy the positions, rotations, and scales of all child transforms recursively
foreach (Transform sourceChild in sourceTransform)
{
Transform targetChild = targetTransform.Find(sourceChild.name);
if (targetChild)
{
CopyTransforms(sourceChild, targetChild);
}
}
}
```