The logic behind mirrorJoint tool / mirroring


#1

Hi,

I’m trying to figure out how Maya orients joints with “behavior” option when using mirrorJoint tool.

I thought i figured it out, because with mirroring across “x” and “y” everything works, with “z” there’s something different happens.

So what I’m doing:

  1. get the translation attribute corresponding to the axis we’re mirroring across. (".tx" for mirroring across x axis)
  2. get the rotation values.
  3. set the mirrored transforms translation value to “.tx” * (-1)
  4. set the mirrored transforms rotate axis corresponding to the mirror axis(".rx" in this case) to 180 - abs(".rx") * (-1 if “.rx” was greater than 0 and vice versa )
  5. set the other rotation values to “.ry” * (-1) and “.rz” * (-1)

As I mentioned, this works for x and y fine, but for z, apparently i don’t need to reverse the rotation values for the other channels (5)

I don’t get the logic why in some cases Maya reverses them and in other don’t when using mirrorJoint.

Would appreciate some explanation, pointers in the right direction or maybe texts explaning this stuff.


#2

I came here looking for the same. I’m curious about the math behind mirrorJoint as well. Except I think it gets a little more complicated than swapping signs. What it seems to be doing is mirroring the joint’s matrix about a world plane at the parent joint’s position. To keep the channel box rotation values unchanged, it then moves an extra rotation into the jointOrients.

For example:
#create joint at origin
j1 = pm.joint()
#create second joint and add some translate and rotate values
j2 = pm.joint()
j2.setTranslation((5,8,10))
j2.setRotation((45,45,0))
#create third joint and offset again
j3 = pm.joint()
j3.setTranslation((5,8,10))
j3.setRotation((45,45,0))
#mirror j3
pm.mirrorJoint(j3, mirrorYZ=True, mirrorBehavior=True)

This results in the jointOrients of my new joint4 to read 135, -45, 90.

I can get a new joint to line up with the mirrored one like this:

j3m = j3.getMatrix(worldSpace=True) 
parentM = j2.getMatrix(worldSpace=True)

m = pm.dt.Matrix(j3m[0][0], -j3m[0][1], -j3m[0][2], j3m[0][3],
                 j3m[1][0], -j3m[1][1], -j3m[1][2], j3m[1][3],
                 j3m[2][0], -j3m[2][1], -j3m[2][2], j3m[2][3],
                 j3m[3][0], j3m[3][1], j3m[3][2], j3m[3][3])
j5 = pm.duplicate(j3)[0]
j5.setMatrix(m, worldSpace=True)
j5.setTranslation((parentM[3][0] - (j3m[3][0] - parentM[3][0]),j3m[3][1],j3m[3][2]), worldSpace=True)

But this has no values in the jointOrient. Does anyone know how to extract the correct jointOrient values to emulate the joint mirroring?


#3

I may have figured it out. Store the rotations first, then zero them out before mirroring the joint. After mirroring, copy the new rotate values into the jointOrients, then reapply the stored rotations to the new joint. This is for YZ mirroring in Y up.

j1 = pm.joint()
#create second joint and add some translate and rotate values
j2 = pm.joint()
j2.setTranslation((-5,-8,10))
j2.setRotation((-45,45,0))
#create third joint and offset again
j3 = pm.joint()
j3.setTranslation((5,8,10))
j3.setRotation((45,-45,0))
#mirror j3
pm.mirrorJoint(j3, mirrorYZ=True, mirrorBehavior=True)

#get local rotations
j3rots = j3.getRotation()
#zero out rotations
j3.setRotation((0,0,0))
#get worldspace matrix
j3m = j3.getMatrix(worldSpace=True)
#get parent worldspace matrix
parentM = j2.getMatrix(worldSpace=True)
#mirrored matrix in place
m = pm.dt.Matrix(j3m[0][0], -j3m[0][1], -j3m[0][2], j3m[0][3],
j3m[1][0], -j3m[1][1], -j3m[1][2], j3m[1][3],
j3m[2][0], -j3m[2][1], -j3m[2][2], j3m[2][3],
j3m[3][0], j3m[3][1], j3m[3][2], j3m[3][3])

#create new joint
j5 = pm.duplicate(j3)[0]
#set joint matrix
j5.setMatrix(m, worldSpace=True)
#set joint translate
j5.setTranslation((parentM[3][0] - (j3m[3][0] - parentM[3][0]),j3m[3][1],j3m[3][2]), worldSpace=True)

#get new local rotations
j5rots = j5.getRotation()
#set jointOrients to match local rotations
j5.jointOrient.set(j5rots)
#set original joint rotations
j5.setRotation(j3rots)
#restore rotations on original joint
j3.setRotation(j3rots)

The result is that our joint5 that was mirrored manually, should match joint4 that was mirrored using Maya’s mirrorJoint. I suppose if it had any children that it would just be a matter of inverting the translation values? I’d love a sanity check! Thanks!