def mirrorMatrix(matrix, axis=AX_X, orientAxis=AX_X): ''' axis is the axis things are flipped across orientAxis is the axis that gets flipped when mirroring orientations ''' assert isinstance(matrix, Matrix) mirroredMatrix = Matrix(matrix) #make sure we've been given a Axis instances... don't bother testing, just do it, and make it absolute (non-negative - mirroring in -x is the same as mirroring in x) mirrorAxis = abs(Axis(axis)) axisA = abs(Axis(orientAxis)) #flip all axes axisB, axisC = axisA.otherAxes() mirroredMatrix[axisB][mirrorAxis] = -matrix[axisB][mirrorAxis] mirroredMatrix[axisC][mirrorAxis] = -matrix[axisC][mirrorAxis] #the above flipped all axes - but this results in a changing of coordinate system handed-ness, so flip one of the axes back nonMirrorAxisA, nonMirrorAxisB = mirrorAxis.otherAxes() mirroredMatrix[axisA][ nonMirrorAxisA] = -mirroredMatrix[axisA][nonMirrorAxisA] mirroredMatrix[axisA][ nonMirrorAxisB] = -mirroredMatrix[axisA][nonMirrorAxisB] #if the input matrix was a 4x4 then mirror translation if matrix.size == 4: mirroredMatrix[3][mirrorAxis] = -matrix[3][mirrorAxis] return mirroredMatrix
def setup(self, axis=None): ''' sets up the initial state of the pair node ''' if axis: axis = abs(Axis(axis)) setAttr('%s.axis' % self.node, axis) #if we have two controls try to auto determine the orientAxis and the flipAxes if self.controlA and self.controlB: worldMatrixA = getWorldRotMatrix(self.controlA) worldMatrixB = getWorldRotMatrix(self.controlB) #so restPoseB = restPoseA * offsetMatrix #restPoseAInv * restPoseB = restPoseAInv * restPoseA * offsetMatrix #restPoseAInv * restPoseB = I * offsetMatrix #thus offsetMatrix = restPoseAInv * restPoseB offsetMatrix = worldMatrixA.inverse() * worldMatrixB AXES = AX_X.asVector(), AX_Y.asVector(), AX_Z.asVector() flippedAxes = [] for n in range(3): axisNVector = Vector(offsetMatrix[n][:3]) #if the axes are close to being opposite, then consider it a flipped axis... if axisNVector.dot(AXES[n]) < -0.8: flippedAxes.append(n) for n, flipAxes in enumerate(self.FLIP_AXES): if tuple(flippedAxes) == flipAxes: setAttr('%s.flipAxes' % self.node, n) break #this is a bit of a hack - and not always true, but generally singular controls built by skeleton builder will work with this value elif self.controlA: setAttr('%s.flipAxes' % self.node, 0) self.setWorldSpace(False)
def doIt(self, mArgs): ret, argData = self.grabArgDb(mArgs) if ret: return sel = OpenMaya.MSelectionList() argData.getObjects(sel) objs = [] for n in range(sel.length()): obj = MObject() sel.getDependNode(n, obj) objs.append(obj) # if argData.isQuery(): rotNode = objs[0] if argData.isFlagSet(self.kFlagAxis): self.setResult(cmd.getAttr('%s.mirrorAxis' % rotNode)) elif argData.isFlagSet(self.kFlagMode): self.setResult(cmd.getAttr('%s.mirrorTranslation' % rotNode)) return #if we're in edit mode, find the node elif argData.isEdit(): rotNode = objs[0] #otherwise we're in creation mode - so build the node and connect things up else: obj, tgt = objs #is dummy mode set? isDummyMode = argData.isFlagSet( self.kFlagDummy) or argData.isFlagSet(self.kFlagDummy) #see if there is already a node connected existing = cmd.listConnections('%s.t' % tgt, '%s.r' % tgt, type=MirrorNode.NODE_TYPE_NAME) if existing: self.displayWarning( "There is a %s node already connected - use edit mode!" % MirrorNode.NODE_TYPE_NAME) self.setResult(existing[0]) return else: rotNode = cmd.createNode('rotationMirror') cmd.connectAttr('%s.worldMatrix' % obj, '%s.inWorldMatrix' % rotNode) cmd.connectAttr('%s.parentInverseMatrix' % obj, '%s.inParentInverseMatrix' % rotNode) cmd.connectAttr('%s.parentInverseMatrix' % tgt, '%s.targetParentInverseMatrix' % rotNode) joAttrpath = '%s.jo' % tgt if cmd.objExists(joAttrpath): cmd.connectAttr(joAttrpath, '%s.targetJointOrient' % rotNode) cmd.connectAttr('%s.rotateOrder' % tgt, '%s.targetRotationOrder' % rotNode) if not isDummyMode: cmd.connectAttr('%s.outTranslate' % rotNode, '%s.t' % tgt) cmd.connectAttr('%s.outRotate' % rotNode, '%s.r' % tgt) cmd.select(obj) #set the result to the node created... self.setResult(rotNode) #set any attributes passed in from the command-line if argData.isFlagSet(self.kFlagAxis): axisInt = Axis.FromName( argData.flagArgumentString(self.kFlagAxis, 0)) cmd.setAttr('%s.mirrorAxis' % rotNode, axisInt) if argData.isFlagSet(self.kFlagMode): modeStr = argData.flagArgumentString(self.kFlagMode, 0) modeIdx = list(MirrorNode.MIRROR_MODE_NAMES).index(modeStr) cmd.setAttr('%s.mirrorTranslation' % rotNode, modeIdx)
def compute(self, plug, dataBlock): dh_mirrorTranslation = dataBlock.inputValue(self.mirrorTranslation) mirrorTranslation = Axis(dh_mirrorTranslation.asShort()) inWorldMatrix = dataBlock.inputValue(self.inWorldMatrix).asMatrix() inParentInvMatrix = dataBlock.inputValue( self.inParentMatrixInv).asMatrix() dh_mirrorAxis = dataBlock.inputValue(self.mirrorAxis) axis = Axis(dh_mirrorAxis.asShort()) ### DEAL WITH ROTATION AND POSITION SEPARATELY ### R, S = inWorldMatrix.asPy( 3).decompose() #this gets just the 3x3 rotation and scale matrices x, y, z = R #extract basis vectors #mirror the rotation axes and construct the mirrored rotation matrix idxA, idxB = axis.otherAxes() x[idxA] = -x[idxA] x[idxB] = -x[idxB] y[idxA] = -y[idxA] y[idxB] = -y[idxB] z[idxA] = -z[idxA] z[idxB] = -z[idxB] #factor scale back into the matrix mirroredMatrix = Matrix(x + y + z, 3) * S mirroredMatrix = mirroredMatrix.expand(4) #now put the rotation matrix in the space of the target object dh_targetParentMatrixInv = dataBlock.inputValue( self.targetParentMatrixInv) tgtParentMatrixInv = dh_targetParentMatrixInv.asMatrix() matInv = tgtParentMatrixInv.asPy() #put the rotation in the space of the target's parent mirroredMatrix = mirroredMatrix * matInv #if there is a joint orient, make sure to compensate for it tgtJoX = dataBlock.inputValue(self.targetJointOrientX).asDouble() tgtJoY = dataBlock.inputValue(self.targetJointOrientY).asDouble() tgtJoZ = dataBlock.inputValue(self.targetJointOrientZ).asDouble() jo = Matrix.FromEulerXYZ(tgtJoX, tgtJoY, tgtJoZ) joInv = jo.inverse() joInv = joInv.expand(4) mirroredMatrix = mirroredMatrix * joInv #grab the rotation order of the target rotOrderIdx = dataBlock.inputValue(self.targetRotationOrder).asInt() #grab euler values R, S = mirroredMatrix.decompose( ) #we need to decompose again to extract euler angles... eulerXYZ = outX, outY, outZ = mayaRotationOrders[rotOrderIdx]( R) #R.ToEulerYZX() dh_outRX = dataBlock.outputValue(self.outRotateX) dh_outRY = dataBlock.outputValue(self.outRotateY) dh_outRZ = dataBlock.outputValue(self.outRotateZ) #set the rotation dh_outRX.setDouble(outX) dh_outRY.setDouble(outY) dh_outRZ.setDouble(outZ) dataBlock.setClean(plug) ### NOW DEAL WITH POSITION ### #set the position if mirrorTranslation == self.M_COPY: inLocalMatrix = inWorldMatrix * inParentInvMatrix pos = MPoint(inLocalMatrix(3, 0), inLocalMatrix(3, 1), inLocalMatrix(3, 2)) elif mirrorTranslation == self.M_INVERT: inLocalMatrix = inWorldMatrix * inParentInvMatrix pos = MPoint(-inLocalMatrix(3, 0), -inLocalMatrix(3, 1), -inLocalMatrix(3, 2)) elif mirrorTranslation == self.M_MIRROR: pos = MPoint(inWorldMatrix(3, 0), inWorldMatrix(3, 1), inWorldMatrix(3, 2)) pos = [pos.x, pos.y, pos.z] pos[axis] = -pos[axis] pos = MPoint(*pos) pos = pos * tgtParentMatrixInv else: return dh_outTX = dataBlock.outputValue(self.outTranslateX) dh_outTY = dataBlock.outputValue(self.outTranslateY) dh_outTZ = dataBlock.outputValue(self.outTranslateZ) dh_outTX.setDouble(pos[0]) dh_outTY.setDouble(pos[1]) dh_outTZ.setDouble(pos[2])
def getAxis(self): return Axis(getAttr('%s.axis' % self.node))
def compute( self, plug, dataBlock ): dh_mirrorTranslation = dataBlock.inputValue( self.mirrorTranslation ) mirrorTranslation = Axis( dh_mirrorTranslation.asShort() ) inWorldMatrix = dataBlock.inputValue( self.inWorldMatrix ).asMatrix() inParentInvMatrix = dataBlock.inputValue( self.inParentMatrixInv ).asMatrix() dh_mirrorAxis = dataBlock.inputValue( self.mirrorAxis ) axis = Axis( dh_mirrorAxis.asShort() ) ### DEAL WITH ROTATION AND POSITION SEPARATELY ### R, S = inWorldMatrix.asPy( 3 ).decompose() #this gets just the 3x3 rotation and scale matrices x, y, z = R #extract basis vectors #mirror the rotation axes and construct the mirrored rotation matrix idxA, idxB = axis.otherAxes() x[ idxA ] = -x[ idxA ] x[ idxB ] = -x[ idxB ] y[ idxA ] = -y[ idxA ] y[ idxB ] = -y[ idxB ] z[ idxA ] = -z[ idxA ] z[ idxB ] = -z[ idxB ] #factor scale back into the matrix mirroredMatrix = Matrix( x + y + z, 3 ) * S mirroredMatrix = mirroredMatrix.expand( 4 ) #now put the rotation matrix in the space of the target object dh_targetParentMatrixInv = dataBlock.inputValue( self.targetParentMatrixInv ) tgtParentMatrixInv = dh_targetParentMatrixInv.asMatrix() matInv = tgtParentMatrixInv.asPy() #put the rotation in the space of the target's parent mirroredMatrix = mirroredMatrix * matInv #if there is a joint orient, make sure to compensate for it tgtJoX = dataBlock.inputValue( self.targetJointOrientX ).asDouble() tgtJoY = dataBlock.inputValue( self.targetJointOrientY ).asDouble() tgtJoZ = dataBlock.inputValue( self.targetJointOrientZ ).asDouble() jo = Matrix.FromEulerXYZ( tgtJoX, tgtJoY, tgtJoZ ) joInv = jo.inverse() joInv = joInv.expand( 4 ) mirroredMatrix = mirroredMatrix * joInv #grab the rotation order of the target rotOrderIdx = dataBlock.inputValue( self.targetRotationOrder ).asInt() #grab euler values R, S = mirroredMatrix.decompose() #we need to decompose again to extract euler angles... eulerXYZ = outX, outY, outZ = mayaRotationOrders[ rotOrderIdx ]( R ) #R.ToEulerYZX() dh_outRX = dataBlock.outputValue( self.outRotateX ) dh_outRY = dataBlock.outputValue( self.outRotateY ) dh_outRZ = dataBlock.outputValue( self.outRotateZ ) #set the rotation dh_outRX.setDouble( outX ) dh_outRY.setDouble( outY ) dh_outRZ.setDouble( outZ ) dataBlock.setClean( plug ) ### NOW DEAL WITH POSITION ### #set the position if mirrorTranslation == self.M_COPY: inLocalMatrix = inWorldMatrix * inParentInvMatrix pos = MPoint( inLocalMatrix(3,0), inLocalMatrix(3,1), inLocalMatrix(3,2) ) elif mirrorTranslation == self.M_INVERT: inLocalMatrix = inWorldMatrix * inParentInvMatrix pos = MPoint( -inLocalMatrix(3,0), -inLocalMatrix(3,1), -inLocalMatrix(3,2) ) elif mirrorTranslation == self.M_MIRROR: pos = MPoint( inWorldMatrix(3,0), inWorldMatrix(3,1), inWorldMatrix(3,2) ) pos = [ pos.x, pos.y, pos.z ] pos[ axis ] = -pos[ axis ] pos = MPoint( *pos ) pos = pos * tgtParentMatrixInv else: return dh_outTX = dataBlock.outputValue( self.outTranslateX ) dh_outTY = dataBlock.outputValue( self.outTranslateY ) dh_outTZ = dataBlock.outputValue( self.outTranslateZ ) dh_outTX.setDouble( pos[0] ) dh_outTY.setDouble( pos[1] ) dh_outTZ.setDouble( pos[2] )