Mirror hierarchy in local space

Started by
14 comments, last by JohnnyCode 8 years, 7 months ago

Here the actual code used to mirror the pose :


for( UInt32 t = 0; t < MirrorPose.m_TransformationArray.GetSize(); ++t )
{
  // Get the transformation where the mirrored pose is stored.
  CTransformation& MirrorTransformation = MirrorPose.m_TransformationArray[ t ];

  // Get the transformation which will be mirrored.
  const CTransformation& OutputTransformation = m_OutputPose.m_TransformationArray[ MirrorTableArray[ t ] ];

  // Mirror the translation.
  MirrorTransformation.m_Translation = VectorMirror( OutputTransformation.m_Translation, CVector3( 1.0f, 0.0f, 0.0f ) );

  // Mirror the rotation.
  const CQuaternion& OutputRotation = OutputTransformation.m_Rotation;
  const CVector3 MirrorQuatXYZ = VectorMirror( CVector3( OutputRotation.x, OutputRotation.y, OutputRotation.z ), CVector3( 1.0f, 0.0f, 0.0f ) );
  MirrorTransformation.m_Rotation = CQuaternion( MirrorQuatXYZ.x, MirrorQuatXYZ.y, MirrorQuatXYZ.z, -OutputRotation.w );

  // Set the scaling.
  MirrorTransformation.m_Scaling = OutputTransformation.m_Scaling;
}

I use Y as up axis and left handed coordinate system, my meshes are imported from FBX using the FBX SDK.

Transformation of each node is modified by the FBX to have correct orientation/translation for this coordinate system.

For example on this character, the bind pose of the root bone and all geometry node are stored as :


T: 0.000000,0.000000,0.000000
R: 0.000000,0.000000,0.000000,-1.000000
S: 1.000000,1.000000,1.000000

The mirror table logged to check it's correct :


[2015/08/24-00:30:59] 0: 0 (Root: Root)
[2015/08/24-00:30:59] 1: 1 (Hips: Hips)
[2015/08/24-00:30:59] 2: 2 (Spine: Spine)
[2015/08/24-00:30:59] 3: 3 (Spine1: Spine1)
[2015/08/24-00:30:59] 4: 33 (LeftShoulder: RightShoulder)
[2015/08/24-00:30:59] 5: 34 (LeftArm: RightArm)
[2015/08/24-00:30:59] 6: 35 (LeftArmRoll: RightArmRoll)
[2015/08/24-00:30:59] 7: 36 (LeftForeArm: RightForeArm)
[2015/08/24-00:30:59] 8: 37 (LeftForeArmRoll: RightForeArmRoll)
[2015/08/24-00:30:59] 9: 38 (LeftHand: RightHand)
[2015/08/24-00:30:59] 10: 39 (LeftHandIndex1: RightHandIndex1)
[2015/08/24-00:30:59] 11: 40 (LeftHandIndex2: RightHandIndex2)
[2015/08/24-00:30:59] 12: 41 (LeftHandIndex3: RightHandIndex3)
[2015/08/24-00:30:59] 13: 42 (LeftHandIndex4: RightHandIndex4)
[2015/08/24-00:30:59] 14: 43 (LeftHandMiddle1: RightHandMiddle1)
[2015/08/24-00:30:59] 15: 44 (LeftHandMiddle2: RightHandMiddle2)
[2015/08/24-00:30:59] 16: 45 (LeftHandMiddle3: RightHandMiddle3)
[2015/08/24-00:30:59] 17: 46 (LeftHandMiddle4: RightHandMiddle4)
[2015/08/24-00:30:59] 18: 47 (LeftHandPinky1: RightHandPinky1)
[2015/08/24-00:30:59] 19: 48 (LeftHandPinky2: RightHandPinky2)
[2015/08/24-00:30:59] 20: 49 (LeftHandPinky3: RightHandPinky3)
[2015/08/24-00:30:59] 21: 50 (LeftHandPinky4: RightHandPinky4)
[2015/08/24-00:30:59] 22: 51 (LeftHandProp: RightHandProp)
[2015/08/24-00:30:59] 23: 52 (LeftHandRing1: RightHandRing1)
[2015/08/24-00:30:59] 24: 53 (LeftHandRing2: RightHandRing2)
[2015/08/24-00:30:59] 25: 54 (LeftHandRing3: RightHandRing3)
[2015/08/24-00:30:59] 26: 55 (LeftHandRing4: RightHandRing4)
[2015/08/24-00:30:59] 27: 56 (LeftHandThumb1: RightHandThumb1)
[2015/08/24-00:30:59] 28: 57 (LeftHandThumb2: RightHandThumb2)
[2015/08/24-00:30:59] 29: 58 (LeftHandThumb3: RightHandThumb3)
[2015/08/24-00:30:59] 30: 59 (LeftHandThumb4: RightHandThumb4)
[2015/08/24-00:30:59] 31: 31 (Neck: Neck)
[2015/08/24-00:30:59] 32: 32 (Head: Head)
[2015/08/24-00:30:59] 33: 4 (RightShoulder: LeftShoulder)
[2015/08/24-00:30:59] 34: 5 (RightArm: LeftArm)
[2015/08/24-00:30:59] 35: 6 (RightArmRoll: LeftArmRoll)
[2015/08/24-00:30:59] 36: 7 (RightForeArm: LeftForeArm)
[2015/08/24-00:30:59] 37: 8 (RightForeArmRoll: LeftForeArmRoll)
[2015/08/24-00:30:59] 38: 9 (RightHand: LeftHand)
[2015/08/24-00:30:59] 39: 10 (RightHandIndex1: LeftHandIndex1)
[2015/08/24-00:30:59] 40: 11 (RightHandIndex2: LeftHandIndex2)
[2015/08/24-00:30:59] 41: 12 (RightHandIndex3: LeftHandIndex3)
[2015/08/24-00:30:59] 42: 13 (RightHandIndex4: LeftHandIndex4)
[2015/08/24-00:30:59] 43: 14 (RightHandMiddle1: LeftHandMiddle1)
[2015/08/24-00:30:59] 44: 15 (RightHandMiddle2: LeftHandMiddle2)
[2015/08/24-00:30:59] 45: 16 (RightHandMiddle3: LeftHandMiddle3)
[2015/08/24-00:30:59] 46: 17 (RightHandMiddle4: LeftHandMiddle4)
[2015/08/24-00:30:59] 47: 18 (RightHandPinky1: LeftHandPinky1)
[2015/08/24-00:30:59] 48: 19 (RightHandPinky2: LeftHandPinky2)
[2015/08/24-00:30:59] 49: 20 (RightHandPinky3: LeftHandPinky3)
[2015/08/24-00:30:59] 50: 21 (RightHandPinky4: LeftHandPinky4)
[2015/08/24-00:30:59] 51: 22 (RightHandProp: LeftHandProp)
[2015/08/24-00:30:59] 52: 23 (RightHandRing1: LeftHandRing1)
[2015/08/24-00:30:59] 53: 24 (RightHandRing2: LeftHandRing2)
[2015/08/24-00:30:59] 54: 25 (RightHandRing3: LeftHandRing3)
[2015/08/24-00:30:59] 55: 26 (RightHandRing4: LeftHandRing4)
[2015/08/24-00:30:59] 56: 27 (RightHandThumb1: LeftHandThumb1)
[2015/08/24-00:30:59] 57: 28 (RightHandThumb2: LeftHandThumb2)
[2015/08/24-00:30:59] 58: 29 (RightHandThumb3: LeftHandThumb3)
[2015/08/24-00:30:59] 59: 30 (RightHandThumb4: LeftHandThumb4)
[2015/08/24-00:30:59] 60: 67 (LeftUpLeg: RightUpLeg)
[2015/08/24-00:30:59] 61: 68 (LeftLeg: RightLeg)
[2015/08/24-00:30:59] 62: 69 (LeftFoot: RightFoot)
[2015/08/24-00:30:59] 63: 70 (LeftToeBase: RightToeBase)
[2015/08/24-00:30:59] 64: 71 (LeftToeBase_END: RightToeBase_END)
[2015/08/24-00:30:59] 65: 72 (LeftLegRoll: RightLegRoll)
[2015/08/24-00:30:59] 66: 73 (LeftUpLegRoll: RightUpLegRoll)
[2015/08/24-00:30:59] 67: 60 (RightUpLeg: LeftUpLeg)
[2015/08/24-00:30:59] 68: 61 (RightLeg: LeftLeg)
[2015/08/24-00:30:59] 69: 62 (RightFoot: LeftFoot)
[2015/08/24-00:30:59] 70: 63 (RightToeBase: LeftToeBase)
[2015/08/24-00:31:00] 71: 64 (RightToeBase_END: LeftToeBase_END)
[2015/08/24-00:31:00] 72: 65 (RightLegRoll: LeftLegRoll)
[2015/08/24-00:31:00] 73: 66 (RightUpLegRoll: LeftUpLegRoll)
[2015/08/24-00:31:00] 74: 74 (BodyMESH: BodyMESH)
[2015/08/24-00:31:00] 75: 75 (GlassesMESH: GlassesMESH)
[2015/08/24-00:31:00] 76: 76 (HeadMESH: HeadMESH)
[2015/08/24-00:31:00] 77: 77 (HelmetMESH: HelmetMESH)
[2015/08/24-00:31:00] 78: 78 (BackpackMESH: BackpackMESH)
[2015/08/24-00:31:00] 79: 80 (ArmorArmRightMESH: ArmorArmLeftMESH)
[2015/08/24-00:31:00] 80: 79 (ArmorArmLeftMESH: ArmorArmRightMESH)
[2015/08/24-00:31:00] 81: 81 (StuffMESH: StuffMESH)
[2015/08/24-00:31:00] 82: 82 (RadioMESH: RadioMESH)
[2015/08/24-00:31:00] 83: 83 (HolsterMESH: HolsterMESH)
[2015/08/24-00:31:00] 84: 84 (LegStrapsMESH: LegStrapsMESH)
[2015/08/24-00:31:00] 85: 85 (ChestStrapsMESH: ChestStrapsMESH)

Link from the UDK documentation which shows correctly the feature with screenshots and explanations :

https://udn.epicgames.com/Three/AnimationMirroring.html

Advertisement
Are you mirroring the local transforms or the final one? Both should work, as long as you do it before multiplying by the inverse bind pose. The images you posted might look like you're also inverting the bind poses.

I mirror the pose in local space, once all blending finished the pose is transformed to world space and is used for rendering, this world space pose is multipled by inverse bind pose only in rendering.

I am suspicious about taking x,y,z components of normalized quaternion and provide them as the vector to that vector mirroring formula along with inversing w. I myself droped using quaternions for rotation presentation, and instead I use 2 base vectors of rotation, 2 more numbers, much less hassle, since converting matrix to quaternion is analytic pain. With matrix presentation you could derive corresponded "mirrored" orientation around some axises plane quite easily, but with quaternion I have no slightest idea.

It is definitely the correct way of mirroring a quaternion. If you think of it as [sin(w/2)*axis,cos(w/2)], then you see that inverting the X component effectively mirrors the axis, and inverting W inverts the angle.

Do you multiply the new orientation immediately by the inverse of the target bone bind transform? Pivots differ greatly from left to right.

This topic is closed to new replies.

Advertisement