def getAverageNodeDirectionVector(nodes, axis = mayaMathUtil.Axis()): averageDir = om.MVector() for node in nodes: orientation = mayaMathUtil.eulerToDirectionVector(getObjectWorldOrientation(node), axis) averageDir.x += orientation[0] averageDir.y += orientation[1] averageDir.z += orientation[2] averageDir.normalize() #force a direction vector if one isn't found if(averageDir.x == 0 and averageDir.y == 0 and averageDir.z == 0): averageDir.x = 1 return averageDir
def coplanarizeJoints(chainEnd, chainRoot, plane, forwardAxis=mayaMathUtil.Axis(axis=0), rotationAxis=mayaMathUtil.Axis(axis=2)): if (chainRoot is None or chainEnd is None or plane is None): return currJoint = chainEnd lastJoint = None while currJoint: currChildren = mayaUtil.getObjectChildren(currJoint) #unparent all children so this joint can move safely without affecting children if (currChildren is not None): for child in currChildren: cmds.parent(child, world=True) oldPos = mayaUtil.getJointWorldPosition(currJoint) oldOrient = mayaUtil.getObjectWorldOrientation(currJoint) #cmds.makeIdentity(currJoint, apply=True, translate=True, rotate=True, scale=True, jointOrient=True) #project the joint to the plane newPos = mayaMathUtil.closestPointOnPlane(plane=plane, point=oldPos) cmds.xform(currJoint, absolute=True, worldSpace=True, translation=[newPos.x, newPos.y, newPos.z]) #now orient the joint #don't orient if this is the last child in the chain and it has children of its own if (lastJoint is not None or (lastJoint is None and currChildren is None)): deleteAimTarget = False aimTarget = lastJoint #if no lastJoint, this is the last child in the joint chain so project its previous aim direction to a point on the plane and aim it in that direction to keep it approximately the same #there's probably a more mathematically correct way to do this but whatever... if (lastJoint is None): deleteAimTarget = True aimLocation = mayaMathUtil.closestPointOnPlane( plane=plane, point=oldPos + mayaMathUtil.eulerToDirectionVector( oldOrient, forwardAxis) * 10) aimTarget = cmds.spaceLocator() cmds.xform( aimTarget, worldSpace=True, absolute=True, translation=[aimLocation.x, aimLocation.y, aimLocation.z]) aimVector = mayaMathUtil.forwardVector(forwardAxis) turnVector = mayaMathUtil.forwardVector(rotationAxis) #not sure how else to do this easily, the idea is taken from Comet Joint Orient tempAimConstraint = cmds.aimConstraint( aimTarget, currJoint, weight=1, aimVector=[aimVector.x, aimVector.y, aimVector.z], upVector=[turnVector.x, turnVector.y, turnVector.z], worldUpVector=[ plane.normal().x, plane.normal().y, plane.normal().z ], worldUpType="vector") cmds.delete(tempAimConstraint) #delete the temporary locator we created if lastJoint was None if (deleteAimTarget): cmds.delete(aimTarget) cmds.joint(currJoint, edit=True, zeroScaleOrient=True) if (currChildren is not None): for child in currChildren: cmds.parent(child, currJoint) cmds.makeIdentity(child, apply=True, jointOrient=False) if (currJoint == chainRoot): return lastJoint = currJoint currJoint = mayaUtil.getObjectParent(currJoint) return
def coplanarizeJoints(chainEnd, chainRoot, plane, forwardAxis = mayaMathUtil.Axis(axis=0), rotationAxis = mayaMathUtil.Axis(axis=2)): if(chainRoot is None or chainEnd is None or plane is None): return currJoint = chainEnd lastJoint = None while currJoint: currChildren = mayaUtil.getObjectChildren(currJoint) #unparent all children so this joint can move safely without affecting children if(currChildren is not None): for child in currChildren: cmds.parent(child, world=True) oldPos = mayaUtil.getJointWorldPosition(currJoint) oldOrient = mayaUtil.getObjectWorldOrientation(currJoint) #cmds.makeIdentity(currJoint, apply=True, translate=True, rotate=True, scale=True, jointOrient=True) #project the joint to the plane newPos = mayaMathUtil.closestPointOnPlane(plane=plane, point=oldPos) cmds.xform(currJoint, absolute=True, worldSpace=True, translation=[newPos.x, newPos.y, newPos.z]) #now orient the joint #don't orient if this is the last child in the chain and it has children of its own if(lastJoint is not None or (lastJoint is None and currChildren is None)): deleteAimTarget = False aimTarget = lastJoint #if no lastJoint, this is the last child in the joint chain so project its previous aim direction to a point on the plane and aim it in that direction to keep it approximately the same #there's probably a more mathematically correct way to do this but whatever... if(lastJoint is None): deleteAimTarget = True aimLocation = mayaMathUtil.closestPointOnPlane(plane=plane, point=oldPos + mayaMathUtil.eulerToDirectionVector(oldOrient, forwardAxis) * 10) aimTarget = cmds.spaceLocator() cmds.xform(aimTarget, worldSpace=True, absolute=True, translation=[aimLocation.x, aimLocation.y, aimLocation.z]) aimVector = mayaMathUtil.forwardVector(forwardAxis) turnVector = mayaMathUtil.forwardVector(rotationAxis) #not sure how else to do this easily, the idea is taken from Comet Joint Orient tempAimConstraint = cmds.aimConstraint(aimTarget, currJoint, weight=1, aimVector=[aimVector.x, aimVector.y, aimVector.z], upVector=[turnVector.x, turnVector.y, turnVector.z], worldUpVector=[plane.normal().x, plane.normal().y, plane.normal().z], worldUpType="vector") cmds.delete(tempAimConstraint) #delete the temporary locator we created if lastJoint was None if(deleteAimTarget): cmds.delete(aimTarget) cmds.joint(currJoint, edit=True, zeroScaleOrient=True) if(currChildren is not None): for child in currChildren: cmds.parent(child, currJoint) cmds.makeIdentity(child, apply=True, jointOrient=False) if(currJoint == chainRoot): return lastJoint = currJoint currJoint = mayaUtil.getObjectParent(currJoint) return