def vectorDegreesToRadians(self, vector): """ Convert degree angles to radians. Returns MVector. Parameters: vector (Tuple(x,y,z) or MVector)""" vector = om.MVector(vector) vector.x = om.MAngle(vector.x, unit = om.MAngle.kDegrees).asRadians() vector.y = om.MAngle(vector.y, unit = om.MAngle.kDegrees).asRadians() vector.z = om.MAngle(vector.z, unit = om.MAngle.kDegrees).asRadians() return om.MVector(vector)
def vectorRadiansToDegrees(self, vector): """ Convert radian angles to degrees. Returns MVector. Parameters: vector (Tuple(x,y,z) or MVector)""" vector = om.MVector(vector) vector.x = om.MAngle(vector.x, unit = om.MAngle.kRadians).asDegrees() vector.y = om.MAngle(vector.y, unit = om.MAngle.kRadians).asDegrees() vector.z = om.MAngle(vector.z, unit = om.MAngle.kRadians).asDegrees() return om.MVector(vector)
def __init__(self, curve, idx): super(KeyFrame, self).__init__() self.curveobj = curve self.idx = idx self.timeobj = oma.MTime() self.time = 0.0 self.value = 0.0 self.inTanWT = (om.MAngle(0, om.MAngle.kRadians), 1.0) self.inTanXY = (1.0, 0.0) self.outTanWT = (om.MAngle(0, om.MAngle.kRadians), 1.0) self.outTanXY = (1.0, 0.0) self.load(idx)
def getRotation(normal): vector = om.MVector(0, 1, 0) vNormal = om.MVector(normal[0], normal[1], normal[2]) quat = om.MQuaternion(vector, vNormal) quat.normalizeIt() # to normalize rot = quat.asEulerRotation() return [ om.MAngle(rot.x).asDegrees(), om.MAngle(rot.y).asDegrees(), om.MAngle(rot.z).asDegrees() ]
def addAttributesFromList(node, data): """Creates an attribute on the node given a list(dict) of attribute data :param data: The serialized form of the attribute [{ "channelBox": true, "default": 3, "isDynamic": true, "keyable": false, "locked": false, "max": 9999, "min": 1, "name": "jointCount", "softMax": null, "softMin": null, "Type": 2, "value": 3 "isArray": True }] :type data: dict :return: A list of create MPlugs :rtype: list(om2.MPlug) """ created = [] for attrData in iter(data): Type = attrData["Type"] default = attrData["default"] value = attrData["value"] name = attrData["name"] if Type == attrtypes.kMFnDataString: default = om2.MFnStringData().create(default) elif Type == attrtypes.kMFnDataMatrix: default = om2.MFnMatrixData().create(om2.MMatrix(default)) elif Type == attrtypes.kMFnUnitAttributeAngle: default = om2.MAngle(default, om2.MAngle.kDegrees) value = om2.MAngle(value, om2.MAngle.kDegrees) plug = om2.MPlug(node, addAttribute(node, name, name, Type, isArray=data.get("array", False), apply=True)) plugs.setPlugDefault(plug, default) plug.isChannelBox = attrData["value"] plug.isKeyable = attrData["keyable"] plugs.setLockState(plug, attrData["locked"]) plugs.setMin(plug, attrData["min"]) plugs.setMax(plug, attrData["max"]) plugs.setSoftMin(plug, attrData["softMin"]) plugs.setSoftMax(plug, attrData["softMax"]) if not plug.attribute().hasFn(om2.MFn.kMessageAttribute): plugs.setPlugValue(plug, value) created.append(plug) return created
def get_attribute_default_value(plug): """ Get the default value for the given plug :param plug: Plug for the attribute :type plug: om.MPlug :return: Default value of the attribute found on the plug :rtype: float or None """ attr = plug.attribute() api = attr.apiType() if api == om.MFn.kNumericAttribute: typeFn = om.MFnNumericAttribute(attr) return float(typeFn.default) if api in [om.MFn.kDoubleLinearAttribute, om.MFn.kFloatLinearAttribute]: typeFn = om.MFnUnitAttribute(attr) default = om.MDistance(typeFn.default) return default.value if api in [om.MFn.kDoubleAngleAttribute, om.MFn.kFloatAngleAttribute]: typeFn = om.MFnUnitAttribute(attr) default = om.MAngle(typeFn.default) return default.value return None
def _get_angle(obj_path): node = obj_path.node() plug = om.MPlug(node, AngleConeHelperNode.angle) value = om.MAngle(0.0) if not plug.isNull: value = plug.asMAngle() return value
def asEuler(rotation): """Converts tuple(float3) into a MEulerRotation :param rotation: a tuple of 3 elements in degrees which will be converted to redians for the eulerRotation :type rotation: tuple(float) :rtype: MEulerRotation """ return om2.MEulerRotation( [om2.MAngle(i, om2.MAngle.kDegrees).asRadians() for i in rotation])
def compute(self, pPlug, pDataBlock): ## Obtain the data handles for each attribute # Input Data Handles J0DataHandle = pDataBlock.inputValue( robotAccumRotation.J0Attr ) JinDataHandle = pDataBlock.inputValue( robotAccumRotation.JinAttr ) JflipDataHandle = pDataBlock.inputValue( robotAccumRotation.JflipAttr ) ikDataHandle = pDataBlock.inputValue( robotAccumRotation.ikAttr ) # Output Data Handles JoutDataHandle = pDataBlock.outputValue( robotAccumRotation.JoutAttr ) ## Extract the actual value associated to our input attribute J_0 = J0DataHandle.asAngle().asDegrees() J_in = JinDataHandle.asAngle().asDegrees() Jflip = JflipDataHandle.asBool() ik = ikDataHandle.asBool() # Accumulate Rotation Solve Code # If we're in IK mode, check to see if the current rotation value and # the previous value differ by a large amount (e.g. 300 degrees) if ik: try: if abs(J_in - J_0) > 300: # If so, we assume that the inverse kinematic solver has # flipped, so we manually flip the value back # E.G. if J_0 = 179 and J_in = -179, we assume the output, # J_out, should actually be +181 J_out = J_in - (abs(J_in)/J_in) * 360 else: J_out = J_in except: J_out = J_in # If the flipAxis boolean on the robot rig is set to True, we # invert the output by +/- 360 degrees. So +235 becomes -125 if Jflip: try: J_out = J_out - (abs(J_out)/J_out) * 360 except: pass # If ik is flase, we are in forward kinematic mode; in which case, we # pass the input straight through else: J_out = J_in # Set the Output Values Jout = JoutDataHandle.setMAngle( OpenMaya.MAngle( J_out , 2 ) ) # Mark the output data handle as being clean; it need not be computed # given its input. JoutDataHandle.setClean()
def initialize(cls): unitFn = om.MFnUnitAttribute() AngleHelperNode.radius1 = unitFn.create("radius1", "r1", om.MFnUnitAttribute.kDistance) unitFn.channelBox = True unitFn.default = om.MDistance(0) unitFn.setMin(om.MDistance(0)) om.MPxNode.addAttribute(AngleHelperNode.radius1) AngleHelperNode.radius2 = unitFn.create("radius2", "r2", om.MFnUnitAttribute.kDistance) unitFn.default = om.MDistance(1) unitFn.setMin(om.MDistance(0)) unitFn.channelBox = True om.MPxNode.addAttribute(AngleHelperNode.radius2) AngleHelperNode.angle1 = unitFn.create("angle1", "a1", om.MFnUnitAttribute.kAngle) unitFn.default = om.MAngle(0) unitFn.channelBox = True om.MPxNode.addAttribute(AngleHelperNode.angle1) AngleHelperNode.angle2 = unitFn.create("angle2", "a2", om.MFnUnitAttribute.kAngle) unitFn.default = om.MAngle(0) unitFn.channelBox = True om.MPxNode.addAttribute(AngleHelperNode.angle2) numericFn = om.MFnNumericAttribute() AngleHelperNode.colorR = numericFn.create("colorR", "cr", om.MFnNumericData.kFloat, 1) numericFn.channelBox = True om.MPxNode.addAttribute(AngleHelperNode.colorR) AngleHelperNode.colorG = numericFn.create("colorG", "cg", om.MFnNumericData.kFloat, 0) numericFn.channelBox = True om.MPxNode.addAttribute(AngleHelperNode.colorG) AngleHelperNode.colorB = numericFn.create("colorB", "cb", om.MFnNumericData.kFloat, 0) numericFn.channelBox = True om.MPxNode.addAttribute(AngleHelperNode.colorB)
def pythonTypeToMayaType(dataType, value): if dataType == attrtypes.kMFnDataMatrixArray: return map(om2.MMatrix, value) elif attrtypes.kMFnDataVectorArray: return map(om2.MVector, value) elif dataType == attrtypes.kMFnUnitAttributeDistance: return om2.MDistance(value) elif dataType == attrtypes.kMFnUnitAttributeAngle: return om2.MAngle(value, om2.MAngle.kDegrees) elif dataType == attrtypes.kMFnUnitAttributeTime: return om2.MTime(value) return value
def fk_to_ik(node): """ Calculates ik values corresponding to the current fk values and applies them. Args: node """ # Get relevant data ik_pole_off = get_parent(node.ik_pole_conn) world_trans_ik_pole_off = get_world_trans(ik_pole_off) world_trans_fk_01 = get_world_trans(node.fk_01_conn) world_trans_fk_02 = get_world_trans(node.fk_02_conn) world_trans_fk_03 = get_world_trans(node.fk_03_conn) world_trans_ik_pole = get_world_trans(node.ik_pole_conn) world_rot_fk_03 = get_world_rot(node.fk_03_conn) # calculate ik pole position ik_pole_mid_point = (world_trans_fk_01 + world_trans_fk_03) / 2 ik_pole_base = world_trans_fk_02 - ik_pole_mid_point # Handle the case when the leg is fully stretched if ik_pole_base.length() <= 0.0001: rot_fk_01 = get_rot_as_quat(node.fk_01_conn) rot_fk_02 = get_rot_as_quat(node.fk_02_conn) rot = rot_fk_01 * rot_fk_02 ik_pole_base = oMa.MVector(2 * (rot.x * rot.z + rot.w * rot.y), 2 * (rot.y * rot.z - rot.w * rot.x), 1 - 2 * (rot.x * rot.x + rot.y * rot.y)) ik_pole_len = (world_trans_ik_pole - world_trans_fk_02).length() pos_ik_pole = world_trans_fk_02 + ik_pole_base.normalize( ) * ik_pole_len - world_trans_ik_pole_off # Get the destination MPlugs ik_main_trans_plugs = get_trans_plugs(node.ik_main_conn) ik_main_rot_plugs = get_rot_plugs(node.ik_main_conn) ik_pole_trans_plugs = get_trans_plugs(node.ik_pole_conn) # Set the new values for i, plug in enumerate(ik_main_trans_plugs): plug.setFloat(world_trans_fk_03[i]) for i, plug in enumerate(ik_main_rot_plugs): plug.setMAngle(oMa.MAngle(world_rot_fk_03[i], oMa.MAngle.kRadians)) for i, plug in enumerate(ik_pole_trans_plugs): plug.setFloat(pos_ik_pole[i])
def initialize(cls): unitFn = om.MFnUnitAttribute() AngleConeHelperNode.angle = unitFn.create("angle", "a", om.MFnUnitAttribute.kAngle) unitFn.default = om.MAngle(0) unitFn.setMin(om.MAngle(0)) unitFn.setMax(om.MAngle(math.pi)) unitFn.channelBox = True om.MPxNode.addAttribute(AngleConeHelperNode.angle) numericFn = om.MFnNumericAttribute() AngleConeHelperNode.origin = numericFn.createPoint("origin", "o") numericFn.channelBox = True om.MPxNode.addAttribute(AngleConeHelperNode.origin) AngleConeHelperNode.target = numericFn.createPoint("target", "t") numericFn.channelBox = True om.MPxNode.addAttribute(AngleConeHelperNode.target) AngleConeHelperNode.colorR = numericFn.create("colorR", "cr", om.MFnNumericData.kFloat, 1) numericFn.channelBox = True om.MPxNode.addAttribute(AngleConeHelperNode.colorR) AngleConeHelperNode.colorG = numericFn.create("colorG", "cg", om.MFnNumericData.kFloat, 0) numericFn.channelBox = True om.MPxNode.addAttribute(AngleConeHelperNode.colorG) AngleConeHelperNode.colorB = numericFn.create("colorB", "cb", om.MFnNumericData.kFloat, 0) numericFn.channelBox = True om.MPxNode.addAttribute(AngleConeHelperNode.colorB)
def compute(self, pPlug, pDataBlock): ## Obtain the data handles for each attribute # Input Data Handles JinDataHandle = pDataBlock.inputValue(robotLimitRotation.JinAttr) upperLimitDataHandle = pDataBlock.inputValue( robotLimitRotation.upperLimitAttr) lowerLimitDataHandle = pDataBlock.inputValue( robotLimitRotation.lowerLimitAttr) ikDataHandle = pDataBlock.inputValue(robotLimitRotation.ikAttr) # Output Data Handles JoutDataHandle = pDataBlock.outputValue(robotLimitRotation.JoutAttr) ## Extract the actual value associated to our input attribute J_in = JinDataHandle.asAngle().asDegrees() upperLimit = upperLimitDataHandle.asAngle().asDegrees() lowerLimit = lowerLimitDataHandle.asAngle().asDegrees() ik = ikDataHandle.asBool() #===================================# # Limit Rotation Solve Code # #===================================# # If the input is greater than the robot's upper rotation limit, or # less than the robot's lower rotation limit, we flip the axis rotation # by 360 degrees to achieve a value that fits within the robots limits if ik: if J_in > upperLimit: J_out = J_in - 360 if J_out < lowerLimit and (abs(J_out - lowerLimit) > abs(J_in - upperLimit)): J_out = J_out + 360 elif J_in < lowerLimit: J_out = J_in + 360 if J_out > upperLimit and (abs(J_out - upperLimit) > abs(J_in - lowerLimit)): J_out = J_out - 360 else: J_out = J_in else: J_out = J_in # Set the Output Values Jout = JoutDataHandle.setMAngle(OpenMaya.MAngle(J_out, 2)) # Mark the output data handle as being clean; it need not be computed given its input. JoutDataHandle.setClean()
def setUnitAttr(plug, value, obj): apiType = obj.apiType() if apiType in [ api2.MFn.kDoubleLinearAttribute, api2.MFn.kFloatLinearAttribute ]: unit = api2.MDistance.uiUnit() val = api2.MDistance(value, unit=unit) return plug.setMDistance(val) elif apiType in [ api2.MFn.kDoubleAngleAttribute, api2.MFn.kFloatAngleAttribute ]: unit = api2.MAngle.uiUnit() val = api2.MAngle(value, unit=unit) return plug.setMAngle(val) elif apiType == api2.MFn.kTimeAttribute: unit = api2.MTime.uiUnit() val = api2.MTime(value, unit=unit) return plug.setMTime(val) return None
def simplyfyAnimCurve(animationCurve, epsilon): """remove keys of the animation curve but preserving the overal shape Args: animationCurve (str): name of the animation curve epsilon (float): how much preserve the original keys """ points = list() cacheAttrName = getCacheAttribute(animationCurve) points = cmds.getAttr(cacheAttrName) if not points: points = cacheCurvePoints(animationCurve) if not points: return animPoints = [a[:-1] for a in points] newPoints = rpd.simplify(animPoints, epsilon) fnAnimcurve = mUtils.getFn(animationCurve) #clear keys clearAnimCurve(fnAnimcurve) conversionValue = 1.0 if fnAnimcurve.animCurveType == oma.MFnAnimCurve.kAnimCurveTA: conversionValue = om.MAngle(1.0).asDegrees() for time, value in newPoints: fnAnimcurve.addKey(om.MTime(time, TIMEUNIT), value/conversionValue)
def ik_to_fk(node): """ Calculates fk values corresponding to the current ik values and applies them. Args: node """ ik_main_off = get_parent(node.ik_main_conn) fk_01_off = get_parent(node.fk_01_conn) fk_02_off = get_parent(node.fk_02_conn) fk_03_off = get_parent(node.fk_03_conn) ik_main_world_trans = get_world_trans(node.ik_main_conn) fk_01_world_trans = get_world_trans(node.fk_01_conn) ik_main_off_world_trans = get_world_trans(ik_main_off) fk_01_off_world_trans = get_world_trans(fk_01_off) fk_02_off_world_trans = get_world_trans(fk_02_off) fk_03_off_world_trans = get_world_trans(fk_03_off) # calculate base information def_len = (ik_main_off_world_trans - fk_01_off_world_trans).length() # Calculate ik direction ik_dir_01 = ik_main_off_world_trans - fk_01_off_world_trans ik_dir_02 = ik_main_world_trans - fk_01_world_trans ik_dir_rot = ik_dir_01.rotateTo(ik_dir_02).asEulerRotation() # Apply ik direction -> important to calculate correct pole rotations fk_01_rot_plugs = get_rot_plugs(node.fk_01_conn) for i, plug in enumerate(fk_01_rot_plugs): plug.setMAngle(oMa.MAngle(ik_dir_rot[i], oMa.MAngle.kRadians)) # Calculate ik pole rotations ik_pole_world_mat = get_world_matrix(node.ik_pole_conn, 0) fk_03_world_inv_mat = get_world_inv_matrix(node.fk_01_conn, 0) ik_pole_rot_mat = ik_pole_world_mat * fk_03_world_inv_mat ik_pole_vec = oMa.MTransformationMatrix(ik_pole_rot_mat).translation( oMa.MSpace.kWorld) ik_pole_vec.y = 0 ik_pole_rot = oMa.MVector.kZaxisVector.rotateTo( ik_pole_vec).asEulerRotation() # Calculate ik rotations tri_a_len = (fk_02_off_world_trans - fk_01_off_world_trans).length() tri_b_len = (fk_03_off_world_trans - fk_02_off_world_trans).length() tri_c_len = (ik_main_world_trans - fk_01_world_trans).length() if tri_c_len >= def_len: fk_02_angle = 0 fk_01_angle = 0 else: fk_02_angle = math.pi - solve_triangle(tri_a_len, tri_b_len, tri_c_len, "C") fk_01_angle = -solve_triangle(tri_a_len, tri_b_len, tri_c_len, "B") # Add rotations together fk_01_temp = oMa.MEulerRotation(fk_01_angle, ik_pole_rot.y, 0) ik_dir_mat = compose_mat(ik_dir_rot) fk_01_mat = compose_mat(fk_01_temp) rot_mat = fk_01_mat * ik_dir_mat # Apply everything fk_01_rot = get_rot_from_mat(rot_mat) fk_02_rot = (fk_02_angle, 0, 0) fk_01_rot_plugs = get_rot_plugs(node.fk_01_conn) for i, plug in enumerate(fk_01_rot_plugs): plug.setMAngle(oMa.MAngle(fk_01_rot[i], oMa.MAngle.kRadians)) fk_02_rot_plugs = get_rot_plugs(node.fk_02_conn) for i, plug in enumerate(fk_02_rot_plugs): if not plug.isLocked: plug.setMAngle(oMa.MAngle(fk_02_rot[i], oMa.MAngle.kRadians)) # Calculate ankle rotation fk_03_rot = rot_world_space_to_local_space(node.ik_main_conn, get_parent(node.fk_03_conn)) fk_03_rot_plugs = get_rot_plugs(node.fk_03_conn) for i, plug in enumerate(fk_03_rot_plugs): plug.setMAngle(oMa.MAngle(fk_03_rot[i], oMa.MAngle.kRadians))
def compute(self, plug, dataBlock): # get the incoming data inOverridingPoseIndex = dataBlock.inputValue( MatrixCombine.inOverridingPoseIndex).asInt() inOverridingWeight = dataBlock.inputValue( MatrixCombine.inOverridingWeight).asFloat() inOverridingIntensity = dataBlock.inputValue( MatrixCombine.inOverridingIntensity).asFloat() inInitialMatrix = dataBlock.inputValue( MatrixCombine.inInitialMatrix).asMatrix() inAllPoseInfoDataHandle = dataBlock.inputArrayValue( MatrixCombine.inAllPoseInfoList) inEditMode = dataBlock.inputValue(MatrixCombine.inEditMode).asFloat() inEditMatrix = dataBlock.inputValue( MatrixCombine.inEditMatrix).asMatrix() identityMatrix = om.MMatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) poseTranslation = om.MVector() poseQuaternion = om.MQuaternion() poseTransformMatrix = om.MTransformationMatrix(identityMatrix) if inOverridingIntensity > 0.0: # set the outgoing plug inAllPoseInfoDataHandle.jumpToPhysicalElement( inOverridingPoseIndex) currentPoseInfoDataHandle = inAllPoseInfoDataHandle.inputValue() inPoseMatrixDataHandle = currentPoseInfoDataHandle.child( MatrixCombine.inPoseMatrix) poseMatrixData = inPoseMatrixDataHandle.asMatrix() poseMatrix = om.MMatrix(poseMatrixData) poseTransformMatrix = om.MTransformationMatrix(poseMatrix) poseTranslation = poseTransformMatrix.translation(1) poseQuaternion = om.MQuaternion( poseTransformMatrix.rotationComponents(asQuaternion=True)) else: poseMatrixList = [] poseWeightsList = [] for i in range(len(inAllPoseInfoDataHandle)): inAllPoseInfoDataHandle.jumpToPhysicalElement(i) currentPoseInfoDataHandle = inAllPoseInfoDataHandle.inputValue( ) inPoseWeightDataHandle = currentPoseInfoDataHandle.child( MatrixCombine.inPoseWeights) inPoseMatrixDataHandle = currentPoseInfoDataHandle.child( MatrixCombine.inPoseMatrix) inPoseWeightArrayDataHandle = om.MArrayDataHandle( inPoseWeightDataHandle) poseMatrixData = inPoseMatrixDataHandle.asMatrix() poseMatrix = om.MMatrix(poseMatrixData) poseMatrixList.append(poseMatrix) poseWeight = 0 for w in range(len(inPoseWeightArrayDataHandle)): inPoseWeightArrayDataHandle.jumpToPhysicalElement(w) poseWeight += inPoseWeightArrayDataHandle.inputValue( ).asFloat() if poseWeight > 1: poseWeight = 1 if poseWeight < 0: poseWeight = 0 poseWeightsList.append(poseWeight) # print 'poseWeightsList', poseWeightsList for i in range(len(poseMatrixList)): if poseWeightsList[i] > 0: transMatrix = om.MTransformationMatrix(poseMatrixList[i]) translation = transMatrix.translation(1) poseTranslation += translation * poseWeightsList[i] quatTarget = om.MQuaternion( transMatrix.rotationComponents(asQuaternion=True)) quatIdentity = om.MQuaternion() quatBlend = om.MQuaternion.slerp(quatIdentity, quatTarget, poseWeightsList[i]) poseQuaternion = poseQuaternion * quatBlend poseTransformMatrix.setRotationComponents(poseQuaternion, asQuaternion=True) poseTransformMatrix.setTranslation(poseTranslation, 1) inInitialTransform = om.MTransformationMatrix(inInitialMatrix) inInitialQuat = om.MQuaternion(inInitialTransform.rotationComponents()) inInitTranslation = om.MVector(inInitialTransform.translation(1)) poseTransformMatrix.translateBy(inInitTranslation, 1) finalTranslation = poseTransformMatrix.translation(1) finalQuaternion = poseQuaternion * inInitialQuat finalEuler = finalQuaternion.asEulerRotation() # set the outgoing plug outTranslationX = finalTranslation[0] outTranslationY = finalTranslation[1] outTranslationZ = finalTranslation[2] outRotationX = om.MAngle(finalEuler[0], 1) outRotationY = om.MAngle(finalEuler[1], 1) outRotationZ = om.MAngle(finalEuler[2], 1) # set the outgoing plug dataHandle0 = dataBlock.outputValue(MatrixCombine.outTranslationX) dataHandle0.setFloat(outTranslationX) dataHandle1 = dataBlock.outputValue(MatrixCombine.outTranslationY) dataHandle1.setFloat(outTranslationY) dataHandle2 = dataBlock.outputValue(MatrixCombine.outTranslationZ) dataHandle2.setFloat(outTranslationZ) dataHandleRot0 = dataBlock.outputValue(MatrixCombine.outRotationX) dataHandleRot0.setMAngle(outRotationX) dataHandleRot1 = dataBlock.outputValue(MatrixCombine.outRotationY) dataHandleRot1.setMAngle(outRotationY) dataHandleRot2 = dataBlock.outputValue(MatrixCombine.outRotationZ) dataHandleRot2.setMAngle(outRotationZ) dataBlock.setClean(plug)
# Time input = mfnAnimCurve.input(keyIndex) mTime = om.MTime(input) currenttime = mTime.value timeList.append(currenttime) # Value value = mfnAnimCurve.value(keyIndex) valueList.append(value) # InTangent inTangentType = mfnAnimCurve.inTangentType(keyIndex) inTangentTypeList.append(inTangentType) inTangentAngleWeight = mfnAnimCurve.getTangentAngleWeight( keyIndex, 1) inTangetMAngle = om.MAngle(inTangentAngleWeight[0]) inTangentAngleValue = inTangetMAngle.value inTangentAngleList.append(inTangentAngleValue) inTangentWeightList.append(inTangentAngleWeight[1]) # OutTangent outTangentType = mfnAnimCurve.outTangentType(keyIndex) outTangentTypeList.append(outTangentType) outTangentAngleWeight = mfnAnimCurve.getTangentAngleWeight( keyIndex, 0) outTangetMAngle = om.MAngle(outTangentAngleWeight[0]) outTangentAngleValue = outTangetMAngle.value outTangentAngleList.append(outTangentAngleValue) outTangentWeightList.append(outTangentAngleWeight[1]) # Store the attribute vales to dictionary variable
def addAttribute(node, longName, shortName, attrType=attrtypes.kMFnNumericDouble, isArray=False, apply=True): """This function uses the api to create attributes on the given node, currently WIP but currently works for string,int, float, bool, message, matrix. if the attribute exists a ValueError will be raised. :param node: MObject :param longName: str, the long name for the attribute :param shortName: str, the shortName for the attribute :param attrType: attribute Type, attrtypes constants :param apply: if False the attribute will be immediately created on the node else just return the attribute instance :rtype: om.MObject """ if hasAttribute(node, longName): raise ValueError("Node -> '%s' already has attribute -> '%s'" % (nameFromMObject(node), longName)) aobj = None attr = None if attrType == attrtypes.kMFnNumericDouble: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.kDouble) elif attrType == attrtypes.kMFnNumericFloat: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.kFloat) elif attrType == attrtypes.kMFnNumericBoolean: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.kBoolean) elif attrType == attrtypes.kMFnNumericInt: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.kInt) elif attrType == attrtypes.kMFnNumericShort: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.kShort) elif attrType == attrtypes.kMFnNumericLong: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.kLong) elif attrType == attrtypes.kMFnNumericByte: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.kByte) elif attrType == attrtypes.kMFnNumericChar: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.kChar) elif attrType == attrtypes.kMFnNumericAddr: attr = om2.MFnNumericAttribute() aobj = attr.createAddr(longName, shortName) elif attrType == attrtypes.kMFnkEnumAttribute: attr = om2.MFnEnumAttribute() aobj = attr.create(longName, shortName) elif attrType == attrtypes.kMFnCompoundAttribute: attr = om2.MFnCompoundAttribute() aobj = attr.create(longName, shortName) elif attrType == attrtypes.kMFnMessageAttribute: attr = om2.MFnMessageAttribute() aobj = attr.create(longName, shortName) elif attrType == attrtypes.kMFnDataString: attr = om2.MFnTypedAttribute() stringData = om2.MFnStringData().create("") aobj = attr.create(longName, shortName, om2.MFnData.kString, stringData) elif attrType == attrtypes.kMFnUnitAttributeDistance: attr = om2.MFnUnitAttribute() aobj = attr.create(longName, shortName, om2.MDistance()) elif attrType == attrtypes.kMFnUnitAttributeAngle: attr = om2.MFnUnitAttribute() aobj = attr.create(longName, shortName, om2.MAngle()) elif attrType == attrtypes.kMFnUnitAttributeTime: attr = om2.MFnUnitAttribute() aobj = attr.create(longName, shortName, om2.MTime()) elif attrType == attrtypes.kMFnDataMatrix: attr = om2.MFnMatrixAttribute() aobj = attr.create(longName, shortName) elif attrType == attrtypes.kMFnDataFloatArray: attr = om2.MFnFloatArray() aobj = attr.create(longName, shortName) elif attrType == attrtypes.kMFnDataDoubleArray: data = om2.MFnDoubleArrayData().create(om2.MDoubleArray()) attr = om2.MFnTypedAttribute() aobj = attr.create(longName, shortName, om2.MFnData.kDoubleArray, data) elif attrType == attrtypes.kMFnDataIntArray: data = om2.MFnIntArrayData().create(om2.MIntArray()) attr = om2.MFnTypedAttribute() aobj = attr.create(longName, shortName, om2.MFnData.kIntArray, data) elif attrType == attrtypes.kMFnDataPointArray: data = om2.MFnPointArrayData().create(om2.MPointArray()) attr = om2.MFnTypedAttribute() aobj = attr.create(longName, shortName, om2.MFnData.kPointArray, data) elif attrType == attrtypes.kMFnDataVectorArray: data = om2.MFnVectorArrayData().create(om2.MVectorArray()) attr = om2.MFnTypedAttribute() aobj = attr.create(longName, shortName, om2.MFnData.kVectorArray, data) elif attrType == attrtypes.kMFnDataStringArray: data = om2.MFnStringArrayData().create(om2.MStringArray()) attr = om2.MFnTypedAttribute() aobj = attr.create(longName, shortName, om2.MFnData.kStringArray, data) elif attrType == attrtypes.kMFnDataMatrixArray: data = om2.MFnMatrixArrayData().create(om2.MMatrixArray()) attr = om2.MFnTypedAttribute() aobj = attr.create(longName, shortName, om2.MFnData.kMatrixArray, data) elif attrType == attrtypes.kMFnNumericInt64: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.kInt64) elif attrType == attrtypes.kMFnNumericLast: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.kLast) elif attrType == attrtypes.kMFnNumeric2Double: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.k2Double) elif attrType == attrtypes.kMFnNumeric2Float: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.k2Float) elif attrType == attrtypes.kMFnNumeric2Int: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.k2Int) elif attrType == attrtypes.kMFnNumeric2Long: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.k2Long) elif attrType == attrtypes.kMFnNumeric2Short: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.k2Short) elif attrType == attrtypes.kMFnNumeric3Double: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.k3Double) elif attrType == attrtypes.kMFnNumeric3Float: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.k3Float) elif attrType == attrtypes.kMFnNumeric3Int: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.k3Int) elif attrType == attrtypes.kMFnNumeric3Long: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.k3Long) elif attrType == attrtypes.kMFnNumeric3Short: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.k3Short) elif attrType == attrtypes.kMFnNumeric4Double: attr = om2.MFnNumericAttribute() aobj = attr.create(longName, shortName, om2.MFnNumericData.k4Double) if aobj is not None and apply: attr.array = isArray mod = om2.MDGModifier() mod.addAttribute(node, aobj) mod.doIt() return attr
class robotLimitBlender(OpenMaya.MPxNode): # Static variables which will later be replaced by the node's attributes. # Inputs value_in_attr = OpenMaya.MAngle() upper_limit_attr = OpenMaya.MAngle() lower_limit_attr = OpenMaya.MAngle() shader_range_attr = OpenMaya.MObject() # Outputs blend_attr = OpenMaya.MAngle() def __init__(self): OpenMaya.MPxNode.__init__(self) ################################################## def compute(self, pPlug, pDataBlock): if pPlug == robotLimitBlender.blend_attr: ## Obtain the data handles for each attribute # Input Data Handles value_in_data_handle = pDataBlock.inputValue( robotLimitBlender.value_in_attr) upper_limit_data_handle = pDataBlock.inputValue( robotLimitBlender.upper_limit_attr) lower_limit_data_handle = pDataBlock.inputValue( robotLimitBlender.lower_limit_attr) shader_range_data_handle = pDataBlock.inputValue( robotLimitBlender.shader_range_attr) # Output Data Handles blend_data_handle = pDataBlock.outputValue( robotLimitBlender.blend_attr) ## Extract the actual value associated to our input attribute value_in = value_in_data_handle.asAngle().asDegrees() upper_limit = upper_limit_data_handle.asAngle().asDegrees() lower_limit = lower_limit_data_handle.asAngle().asDegrees() shader_range = shader_range_data_handle.asFloat() #==================================# # Limit Blender Solve Code # #==================================# upper_threshold = upper_limit - shader_range lower_threshold = lower_limit + shader_range if value_in >= upper_threshold: # If the value exceeds the upper limit, # clamp the value to the upper limit value = max(min(value_in, upper_limit), upper_threshold) # Remap the value between 0 and 1 blend = (1.0 / (upper_limit - upper_threshold)) * (value - upper_threshold) elif value_in <= lower_threshold: # If the value exceeds the lower limit, # clamp the value to the lower limit value = min(max(value_in, lower_limit), lower_threshold) # Remap the value between 0 and 1 blend = (1.0 / (lower_limit - lower_threshold)) * (value - lower_threshold) else: blend = 0 # Set the Output Values blend_data_handle.setFloat(blend) # Mark the output data handle as being clean; it need not be computed given its input. blend_data_handle.setClean()
curLen = i * size + moduloLenHalf param = curveFn.findParamFromLength(curLen) # Get the transformation values for the current object pos = curveFn.getPointAtParam(param, om2.MSpace.kWorld) tangent = curveFn.tangent(param, om2.MSpace.kWorld).normalize() upVector = om2.MVector(0.0, 1.0, 0.0) aim = tangent ^ upVector aim.normalize() normal = aim ^ tangent normal.normalize() qBasis = om2.MQuaternion() qAim = om2.MQuaternion(aimAxis, aim) qBasis *= qAim secAxis = upAxis.rotateBy(qAim) angle = secAxis.angle(normal) qNormal = om2.MQuaternion(angle, aim) if not normal.isEquivalent(secAxis.rotateBy(qNormal), 1.0e-5): angle = 2.0 * math.pi - angle qNormal = om2.MQuaternion(angle, aim) qBasis *= qNormal rot = qBasis.asEulerRotation() rot = [ om2.MAngle(rot.x).asDegrees(), om2.MAngle(rot.y).asDegrees(), om2.MAngle(rot.z).asDegrees() ] # Create an instance of the original obj and apply the transformation instObj = cmds.instance(srcObj, n="%sInstance1" % srcObj, lf=True)[0] cmds.xform(instObj, t=(pos.x, pos.y, pos.z), ro=(rot[0], rot[1], rot[2]))
def setRotation(node, rotation, space=om2.MSpace.kTransform): path = om2.MFnDagNode(node).getPath() trans = om2.MFnTransform(path) if isinstance(rotation, (list, tuple)): rotation = om2.MEulerRotation([om2.MAngle(i, om2.MAngle.kDegrees).asRadians() for i in rotation]) trans.setRotation(rotation, space)
def setPlugInfoFromDict(plug, **kwargs): """Sets the standard plug settings via a dict. :param plug: The Plug to change :type plug: om2.MPlug :param kwargs: currently includes, default, min, max, softMin, softMin, value, Type, channelBox, keyable, locked. :type kwargs: dict .. code-block:: python data = { "Type": 5, # attrtypes.kType "channelBox": true, "default": 1.0, "isDynamic": true, "keyable": true, "locked": false, "max": 99999, "min": 0.0, "name": "scale", "softMax": None, "softMin": None, "value": 1.0, "children": [{}] # in the same format as the parent info } somePLug = om2.MPlug() setPlugInfoFromDict(somePlug, **data) """ children = kwargs.get("children", []) # just to ensure we dont crash we check to make sure the requested plug is a compound. if plug.isCompound: # cache the childCount childCount = plug.numChildren() if not children: #not a huge fan of doing a deepcopy just to deal with modifying the value/default further down children = [copy.deepcopy(kwargs) for i in xrange(childCount)] # now iterate the children data which contains a dict which is in the format for i, childInfo in enumerate(children): # it's possible that no data was passed for this child so skip if not childInfo: continue # ensure the child index exists if i in range(childCount): # modify the value and default value if we passed one in, this is done because the # children would support a single value over and compound i.e kNumeric3Float value = childInfo.get("value") defaultValue = childInfo.get("default") if value is not None and i in range(len(value)): childInfo["value"] = value[i] if defaultValue is not None and i in range( len(defaultValue)): childInfo["default"] = defaultValue[i] setPlugInfoFromDict(plug.child(i), **childInfo) else: # now iterate the children data which contains a dict which is in the format for i, childInfo in enumerate(children): # it's possible that no data was passed for this child so skip if not childInfo: continue # ensure the child index exists if i in range(childCount): setPlugInfoFromDict(plug.child(i), **childInfo) default = kwargs.get("default") min = kwargs.get("min") max = kwargs.get("max") softMin = kwargs.get("softMin") softMax = kwargs.get("softMax") value = kwargs.get("value") Type = kwargs.get("Type") # certain data types require casting i.e MDistance if default is not None and Type is not None: if Type == attrtypes.kMFnDataString: default = om2.MFnStringData().create(default) elif Type == attrtypes.kMFnDataMatrix: default = om2.MMatrix(default) value = om2.MMatrix(value) elif Type == attrtypes.kMFnUnitAttributeAngle: default = om2.MAngle(default, om2.MAngle.kRadians) value = om2.MAngle(value, om2.MAngle.kRadians) elif Type == attrtypes.kMFnUnitAttributeDistance: default = om2.MDistance(default) value = om2.MDistance(value) elif Type == attrtypes.kMFnUnitAttributeTime: default = om2.MTime(default) value = om2.MTime(value) try: setPlugDefault(plug, default) except Exception: logger.error("Failed to set plug default values: {}".format( plug.name()), exc_info=True, extra={"data": default}) if value is not None and not plug.attribute().hasFn(om2.MFn.kMessageAttribute) and not plug.isCompound and not \ plug.isArray: setPlugValue(plug, value) if min is not None: setMin(plug, min) if max is not None: setMax(plug, max) if softMin is not None: setSoftMin(plug, softMin) if softMax is not None: setSoftMax(plug, softMax) plug.isChannelBox = kwargs.get("channelBox", False) plug.isKeyable = kwargs.get("keyable", False) plug.isLocked = kwargs.get("locked", False)
def eulerToDegrees(euler): return [om2.MAngle(i, om2.MAngle.kRadians).asDegrees() for i in euler]
def compute(self, pPlug, pData): # only compute if output is in out array if not pPlug.isChild: return if (pPlug.parent() == generalIk.aOutArray): # descend into coordinated cycles # inputs solver = pData.inputValue(generalIk.aSolver).asInt() maxIter = pData.inputValue(generalIk.aMaxIter).asInt() tolerance = pData.inputValue(generalIk.aTolerance).asDouble() globalWeight = pData.inputValue(generalIk.aGlobalWeight).asDouble() cacheOn = pData.inputValue(generalIk.aCacheOn).asShort() # target targetMat = pData.inputValue(generalIk.aTargetMat).asMatrix() # end endMat = pData.inputValue(generalIk.aEndMat).asMatrix() # extract input world matrices from array then leave it alone inJntArrayDH = pData.inputArrayValue(generalIk.aJnts) inLength = inJntArrayDH.__len__() worldInputs = [None] * inLength orients = [None] * inLength ups = [None] * inLength jointData = [None] * inLength # ARRAY OF STRUCTS REEEEEEEE for i in range(inLength): inJntArrayDH.jumpToPhysicalElement(i) childCompDH = inJntArrayDH.inputValue() worldInputs[i] = childCompDH.child( generalIk.aJntMat).asMatrix() ups[i] = childCompDH.child(generalIk.aJntUpMat).asMatrix() orients[i] = om.MEulerRotation( childCompDH.child(generalIk.aOrientRot).asDouble3()) # extra data weight = childCompDH.child(generalIk.aJntWeight).asDouble() upDir = childCompDH.child(generalIk.aJntUpDir).asDouble3() jointData[i] = { "weight": weight, "upDir": upDir, } # from world inputs, reconstruct localised chain chainData = buildChains(worldInputs, orients, ups, length=inLength) localMatrices = chainData["localMatrices"] localUpMatrices = chainData["localUpMatrices"] ikSpaceMatrices = chainData["ikSpaceMatrices"] ikSpaceUpMatrices = chainData["ikSpaceUpMatrices"] # ikSpace and local matrices are correct # CACHE STUFF -------------------------------- # extract cached matrices from previous graph evaluation cacheMatrices = pData.inputValue(generalIk.aCacheMatrices) cacheArray = om.MFnMatrixArrayData(cacheMatrices.data()).array() if len(cacheArray) != inLength: print("cache length different, rebuilding") cacheArray.clear() for n in localMatrices: cacheArray.append(n) for i in range(inLength): if positionFromMatrix(localMatrices[i]) != \ positionFromMatrix(cacheArray[i]): print("cache entry {} position has changed, substituting". format(i)) cacheArray[i] = localMatrices[i] if cacheOn == 1 or cacheOn == 2: # bind or bound # set local matrices to cached ------ for i in range(inLength): localMatrices[i] = cacheArray[i] if cacheOn == 1: pData.inputValue(generalIk.aCacheOn).setShort(2) """ I don't think there is any point in treating the end matrix separately - it only adds a special case at every turn refactor to include it in normal local matrices """ # main loop ---------------- n = 0 tol = 100 endIkSpace = endMat * worldInputs[0].inverse() # endIkSpace is correct targetMat = neutraliseRotations(targetMat) endLocalSpace = endMat * worldInputs[-1].inverse() """ localise target into ikSpace """ targetIkSpace = targetMat * worldInputs[0].inverse() # targetIkSpace is correct while n < maxIter and tol > tolerance: debug() debug("n", n) data = iterateChainCCD( worldMatrices=worldInputs, ikSpaceMatrices=ikSpaceMatrices, localMatrices=localMatrices, length=inLength, targetMat=targetIkSpace, endMat=endIkSpace, localEndMat=endLocalSpace, upMatrices=ups, jointData=jointData, globalWeight=globalWeight, ikSpaceUpMatrices=ikSpaceUpMatrices, tolerance=tolerance, ) localMatrices = data["results"] debug("results", localMatrices) tol = data["tolerance"] endIkSpace = data["end"] targetMat = data["target"] n += 1 if tol < tolerance: # process is complete break results = localMatrices worldSpaceTarget = worldInputs[0] * targetMat ikSpaceOutputs = [ multiplyMatrices(localMatrices[:i + 1]) for i in range(inLength) ] endLocalSpace = endIkSpace * ikSpaceOutputs[-1].inverse() # save cached matrices for next evaluation # BEFORE reapplying world space to base cacheArray.clear() for i in localMatrices: cacheArray.append(i) # restore world space root position results[0] = results[0] * worldInputs[0] # outputs --------------- spaceConstant = 1 outDebugDH = pData.outputValue(generalIk.aDebugTarget) outDebugDH.setMMatrix(worldSpaceTarget) outDebugOffsetDH = pData.outputValue(generalIk.aDebugOffset) outDebugOffsetDH.setDouble(tol) # end transform endTfMat = om.MTransformationMatrix(endLocalSpace) outEndTransDH = pData.outputValue(generalIk.aOutEndTrans) outEndTransDH.set3Double(*endTfMat.translation(spaceConstant)) # convert jntArray of matrices to useful rotation values outArrayDH = pData.outputArrayValue(generalIk.aOutArray) for i in range(inLength): outArrayDH.jumpToPhysicalElement(i) outCompDH = outArrayDH.outputValue() outRotDH = outCompDH.child(generalIk.aOutRot) outRxDH = outRotDH.child(generalIk.aOutRx) outRyDH = outRotDH.child(generalIk.aOutRy) outRzDH = outRotDH.child(generalIk.aOutRz) # apply jointOrient ----- outMat = om.MTransformationMatrix(results[i]).rotateBy( orients[i].inverse(), spaceConstant) # set output rotations ------- outRot = outMat.rotation() # unitConversions bring SHAME on family xAngle = om.MAngle(outRot[0]) yAngle = om.MAngle(outRot[1]) zAngle = om.MAngle(outRot[2]) outRxDH.setMAngle(xAngle) outRyDH.setMAngle(yAngle) outRzDH.setMAngle(zAngle) outTranslate = (results[i][12], results[i][13], results[i][14]) outTransDH = outCompDH.child(generalIk.aOutTrans) outTransDH.set3Double(*outTranslate) outArrayDH.setAllClean() pData.setClean(pPlug)
class robotIKS(OpenMaya.MPxNode): """ """ # Define Node Input Attributes tcp_x_attr = OpenMaya.MObject() tcp_y_attr = OpenMaya.MObject() tcp_z_attr = OpenMaya.MObject() tcp_mat_attr = OpenMaya.MMatrix() lcs_x_attr = OpenMaya.MObject() lcs_y_attr = OpenMaya.MObject() lcs_z_attr = OpenMaya.MObject() lcs_mat_attr = OpenMaya.MMatrix() target_x_attr = OpenMaya.MObject() target_y_attr = OpenMaya.MObject() target_z_attr = OpenMaya.MObject() target_mat_attr = OpenMaya.MMatrix() a1_attr = OpenMaya.MObject() a2_attr = OpenMaya.MObject() b_attr = OpenMaya.MObject() c1_attr = OpenMaya.MObject() c2_attr = OpenMaya.MObject() c3_attr = OpenMaya.MObject() c4_attr = OpenMaya.MObject() axis1_offset_attr = OpenMaya.MObject() axis2_offset_attr = OpenMaya.MObject() axis3_offset_attr = OpenMaya.MObject() axis4_offset_attr = OpenMaya.MObject() axis5_offset_attr = OpenMaya.MObject() axis6_offset_attr = OpenMaya.MObject() flip_a1_attr = OpenMaya.MObject() flip_a2_attr = OpenMaya.MObject() flip_a3_attr = OpenMaya.MObject() flip_a4_attr = OpenMaya.MObject() flip_a5_attr = OpenMaya.MObject() flip_a6_attr = OpenMaya.MObject() sol_1_attr = OpenMaya.MObject() sol_2_attr = OpenMaya.MObject() sol_3_attr = OpenMaya.MObject() ik_attr = OpenMaya.MObject() a1_fk_attr = OpenMaya.MAngle() a2_fk_attr = OpenMaya.MAngle() a3_fk_attr = OpenMaya.MAngle() a4_fk_attr = OpenMaya.MAngle() a5_fk_attr = OpenMaya.MAngle() a6_fk_attr = OpenMaya.MAngle() solver_type_attr = OpenMaya.MObject() # Outputs theta1_attr = OpenMaya.MAngle() theta2_attr = OpenMaya.MAngle() theta3_attr = OpenMaya.MAngle() theta4_attr = OpenMaya.MAngle() theta5_attr = OpenMaya.MAngle() theta6_attr = OpenMaya.MAngle() def __init__(self): OpenMaya.MPxNode.__init__(self) ################################################## def compute(self, pPlug, pDataBlock): # Obtain the data handles for each attribute ## Input Data Handles ## tcp_x_data_handle = pDataBlock.inputValue(robotIKS.tcp_x_attr) tcp_y_data_handle = pDataBlock.inputValue(robotIKS.tcp_y_attr) tcp_z_data_handle = pDataBlock.inputValue(robotIKS.tcp_z_attr) tcp_mat_data_handle = pDataBlock.inputValue(robotIKS.tcp_mat_attr) lcs_x_data_handle = pDataBlock.inputValue(robotIKS.lcs_x_attr) lcs_y_data_handle = pDataBlock.inputValue(robotIKS.lcs_y_attr) lcs_z_data_handle = pDataBlock.inputValue(robotIKS.lcs_z_attr) lcs_mat_data_handle = pDataBlock.inputValue(robotIKS.lcs_mat_attr) target_x_data_handle = pDataBlock.inputValue(robotIKS.target_x_attr) target_y_data_handle = pDataBlock.inputValue(robotIKS.target_y_attr) target_z_data_handle = pDataBlock.inputValue(robotIKS.target_z_attr) target_mat_data_handle = pDataBlock.inputValue(robotIKS.target_mat_attr) a1_data_handle = pDataBlock.inputValue(robotIKS.a1_attr) a2_data_handle = pDataBlock.inputValue(robotIKS.a2_attr) b_data_handle = pDataBlock.inputValue(robotIKS.b_attr) c1_data_handle = pDataBlock.inputValue(robotIKS.c1_attr) c2_data_handle = pDataBlock.inputValue(robotIKS.c2_attr) c3_data_handle = pDataBlock.inputValue(robotIKS.c3_attr) c4_data_handle = pDataBlock.inputValue(robotIKS.c4_attr) axis1_offset_data_handle = pDataBlock.inputValue(robotIKS.axis1_offset_attr) axis2_offset_data_handle = pDataBlock.inputValue(robotIKS.axis2_offset_attr) axis3_offset_data_handle = pDataBlock.inputValue(robotIKS.axis3_offset_attr) axis4_offset_data_handle = pDataBlock.inputValue(robotIKS.axis4_offset_attr) axis5_offset_data_handle = pDataBlock.inputValue(robotIKS.axis5_offset_attr) axis6_offset_data_handle = pDataBlock.inputValue(robotIKS.axis6_offset_attr) flip_a1_data_handle = pDataBlock.inputValue(robotIKS.flip_a1_attr) flip_a2_data_handle = pDataBlock.inputValue(robotIKS.flip_a2_attr) flip_a3_data_handle = pDataBlock.inputValue(robotIKS.flip_a3_attr) flip_a4_data_handle = pDataBlock.inputValue(robotIKS.flip_a4_attr) flip_a5_data_handle = pDataBlock.inputValue(robotIKS.flip_a5_attr) flip_a6_data_handle = pDataBlock.inputValue(robotIKS.flip_a6_attr) sol_1_data_handle = pDataBlock.inputValue(robotIKS.sol_1_attr) sol_2_data_handle = pDataBlock.inputValue(robotIKS.sol_2_attr) sol_3_data_handle = pDataBlock.inputValue(robotIKS.sol_3_attr) ik_data_handle = pDataBlock.inputValue(robotIKS.ik_attr) a1_fk_data_handle = pDataBlock.inputValue(robotIKS.a1_fk_attr) a2_fk_data_handle = pDataBlock.inputValue(robotIKS.a2_fk_attr) a3_fk_data_handle = pDataBlock.inputValue(robotIKS.a3_fk_attr) a4_fk_data_handle = pDataBlock.inputValue(robotIKS.a4_fk_attr) a5_fk_data_handle = pDataBlock.inputValue(robotIKS.a5_fk_attr) a6_fk_data_handle = pDataBlock.inputValue(robotIKS.a6_fk_attr) solver_type_data_handle = pDataBlock.inputValue(robotIKS.solver_type_attr) # Extract the actual value associated to our input attribute tcp = [tcp_x_data_handle.asFloat(), tcp_y_data_handle.asFloat(), tcp_z_data_handle.asFloat()] tcp_mat = tcp_mat_data_handle.asMatrix() lcs = [lcs_x_data_handle.asFloat(), lcs_y_data_handle.asFloat(), lcs_z_data_handle.asFloat()] lcs_mat = lcs_mat_data_handle.asMatrix() target = [target_x_data_handle.asFloat(), target_y_data_handle.asFloat(), target_z_data_handle.asFloat()] target_mat = target_mat_data_handle.asMatrix() # Robot Definition robot_definition = [a1_data_handle.asFloat(), a2_data_handle.asFloat(), b_data_handle.asFloat(), c1_data_handle.asFloat(), c2_data_handle.asFloat(), c3_data_handle.asFloat(), c4_data_handle.asFloat()] # Axis Offset Values (robot's zero position in relation to IK solver zero position) axis1_offset = axis1_offset_data_handle.asFloat() axis2_offset = axis2_offset_data_handle.asFloat() axis3_offset = axis3_offset_data_handle.asFloat() axis4_offset = axis4_offset_data_handle.asFloat() axis5_offset = axis5_offset_data_handle.asFloat() axis6_offset = axis6_offset_data_handle.asFloat() angle_offsets = [axis1_offset, axis2_offset, axis3_offset, axis4_offset, axis5_offset, axis6_offset] # Flip Axis Direction bools flip_a1 = flip_a1_data_handle.asBool() flip_a2 = flip_a2_data_handle.asBool() flip_a3 = flip_a3_data_handle.asBool() flip_a4 = flip_a4_data_handle.asBool() flip_a5 = flip_a5_data_handle.asBool() flip_a6 = flip_a6_data_handle.asBool() flip_rot_directions = [flip_a1, flip_a2, flip_a3, flip_a4, flip_a5, flip_a6] # Joint config solution bools sol = [sol_1_data_handle.asBool(), sol_2_data_handle.asBool(), sol_3_data_handle.asBool()] ik = ik_data_handle.asBool() # FK Handle inputs a1_fk = a1_fk_data_handle.asAngle().asDegrees() a2_fk = a2_fk_data_handle.asAngle().asDegrees() a3_fk = a3_fk_data_handle.asAngle().asDegrees() a4_fk = a4_fk_data_handle.asAngle().asDegrees() a5_fk = a5_fk_data_handle.asAngle().asDegrees() a6_fk = a6_fk_data_handle.asAngle().asDegrees() # Solver Type solver_type = solver_type_data_handle.asInt() ## Output Data Handles ## theta1_out_data_handle = pDataBlock.outputValue(robotIKS.theta1_attr) theta2_out_data_handle = pDataBlock.outputValue(robotIKS.theta2_attr) theta3_out_data_handle = pDataBlock.outputValue(robotIKS.theta3_attr) theta4_out_data_handle = pDataBlock.outputValue(robotIKS.theta4_attr) theta5_out_data_handle = pDataBlock.outputValue(robotIKS.theta5_attr) theta6_out_data_handle = pDataBlock.outputValue(robotIKS.theta6_attr) if ik: thetas = inverse_kinematics.solve( tcp, tcp_mat, lcs, lcs_mat, target, target_mat, robot_definition, solver_type, sol) # Apply axis offsets thetas = inverse_kinematics.apply_offsets(thetas, angle_offsets, flip_rot_directions) # Convert to MAngle data type for output # (the "2" is for data type degrees. 1 = radians) a1 = OpenMaya.MAngle(thetas[0], 2) a2 = OpenMaya.MAngle(thetas[1], 2) a3 = OpenMaya.MAngle(thetas[2], 2) a4 = OpenMaya.MAngle(thetas[3], 2) a5 = OpenMaya.MAngle(thetas[4], 2) a6 = OpenMaya.MAngle(thetas[5], 2) # Set the Output Values theta1 = theta1_out_data_handle.setMAngle(a1) theta2 = theta2_out_data_handle.setMAngle(a2) theta3 = theta3_out_data_handle.setMAngle(a3) theta4 = theta4_out_data_handle.setMAngle(a4) theta5 = theta5_out_data_handle.setMAngle(a5) theta6 = theta6_out_data_handle.setMAngle(a6) # Mark the output data handle as being clean; it need not be computed given its input. theta1_out_data_handle.setClean() theta2_out_data_handle.setClean() theta3_out_data_handle.setClean() theta4_out_data_handle.setClean() theta5_out_data_handle.setClean() theta6_out_data_handle.setClean() else: # Set the Output Values theta1 = theta1_out_data_handle.setMAngle(OpenMaya.MAngle(a1_fk, 2)) theta2 = theta2_out_data_handle.setMAngle(OpenMaya.MAngle(a2_fk, 2)) theta3 = theta3_out_data_handle.setMAngle(OpenMaya.MAngle(a3_fk, 2)) theta4 = theta4_out_data_handle.setMAngle(OpenMaya.MAngle(a4_fk, 2)) theta5 = theta5_out_data_handle.setMAngle(OpenMaya.MAngle(a5_fk, 2)) theta6 = theta6_out_data_handle.setMAngle(OpenMaya.MAngle(a6_fk, 2)) # Mark the output data handle as being clean; it need not be computed given its input. theta1_out_data_handle.setClean() theta2_out_data_handle.setClean() theta3_out_data_handle.setClean() theta4_out_data_handle.setClean() theta5_out_data_handle.setClean() theta6_out_data_handle.setClean()
MFnAnimCurve.create(attributeMPlug, animCurveType) # set value MFnAnimCurve.setPreInfinityType(preInfinity) MFnAnimCurve.setPostInfinityType(postInfinity) MFnAnimCurve.setIsWeighted(weightedTangents) MTimeArray = om.MTimeArray() MDoubleValueList = om.MDoubleArray() for index in range(len(timeList)): MTimeArray.append(om.MTime(timeList[index]), om.MTime.uiUnit()) MDoubleValueList.append(valueList[index]) MFnAnimCurve.addKeys(MTimeArray, MDoubleValueList, 0, 0, 1) for index in range(len(timeList)): MFnAnimCurve.setInTangentType(index, inTangentTypeList[index]) MFnAnimCurve.setOutTangentType(index, outTangentTypeList[index]) inTangentAngle = om.MAngle(inTangentAngleList[index]) outTangentAngle = om.MAngle(outTangentAngleList[index]) MFnAnimCurve.setAngle(index, inTangentAngle, 1) MFnAnimCurve.setAngle(index, outTangentAngle, 0) MFnAnimCurve.setWeight(index, inTangentAngleWeightList[index], 1) MFnAnimCurve.setWeight(index, outTangentAngleWeightList[index], 0)
def setPlugValue(plug, value): """ Sets the given plug's value to the passed in value. :param plug: MPlug, The node plug. :param value: type, Any value of any data type. """ if plug.isArray: count = plug.evaluateNumElements() if count != len(value): return for i in range(count): setPlugValue(plug.elementByPhysicalIndex(i), value[i]) return elif plug.isCompound: count = plug.numChildren() if count != len(value): return for i in range(count): setPlugValue(plug.child(i), value[i]) return obj = plug.attribute() if obj.hasFn(om2.MFn.kUnitAttribute): attr = om2.MFnUnitAttribute(obj) ut = attr.unitType() if ut == om2.MFnUnitAttribute.kDistance: plug.setMDistance(om2.MDistance(value)) elif ut == om2.MFnUnitAttribute.kTime: plug.setMTime(om2.MTime(value)) elif ut == om2.MFnUnitAttribute.kAngle: plug.setMAngle(om2.MAngle(value)) elif obj.hasFn(om2.MFn.kNumericAttribute): attr = om2.MFnNumericAttribute(obj) at = attr.numericType() if at in (om2.MFnNumericData.k2Double, om2.MFnNumericData.k2Float, om2.MFnNumericData.k2Int, om2.MFnNumericData.k2Long, om2.MFnNumericData.k2Short, om2.MFnNumericData.k3Double, om2.MFnNumericData.k3Float, om2.MFnNumericData.k3Int, om2.MFnNumericData.k3Long, om2.MFnNumericData.k3Short, om2.MFnNumericData.k4Double): data = om2.MFnNumericData().create(value) plug.setMObject(data.object()) elif at == om2.MFnNumericData.kDouble: plug.setDouble(value) elif at == om2.MFnNumericData.kFloat: plug.setFloat(value) elif at == om2.MFnNumericData.kBoolean: plug.setBool(value) elif at == om2.MFnNumericData.kChar: plug.setChar(value) elif at in (om2.MFnNumericData.kInt, om2.MFnNumericData.kInt64, om2.MFnNumericData.kLong, om2.MFnNumericData.kLast): plug.setInt(value) elif at == om2.MFnNumericData.kShort: plug.setInt(value) elif obj.hasFn(om2.MFn.kEnumAttribute): plug.setInt(value) elif obj.hasFn(om2.MFn.kTypedAttribute): attr = om2.MFnTypedAttribute(obj) at = attr.attrType() if at == om2.MFnData.kMatrix: mat = om2.MFnMatrixData().create(om2.MMatrix(value)) plug.setMObject(mat) elif at == om2.MFnData.kString: plug.setString(value) elif obj.hasFn(om2.MFn.kMatrixAttribute): mat = om2.MFnMatrixData().create(om2.MMatrix(value)) plug.setMObject(mat) elif obj.hasFn(om2.MFn.kMessageAttribute) and isinstance(value, om2.MPlug): # connect the message attribute connectPlugs(plug, value) else: raise ValueError( "Currently we don't support dataType ->{} contact the developers to get this implemented" .format(obj.apiTypeStr))
def importAnimCurve( selectionList, animPath, ): animData = open(animPath, 'r') data = json.load(animData) animData.close() if data and selectionList: for eachObject in selectionList: for eachAnimCurveAttribute in data['animCurve'][eachObject]: # get value animCurveType = data['animCurve'][eachObject][ eachAnimCurveAttribute]['animCurveType'] preInfinity = data['animCurve'][eachObject][ eachAnimCurveAttribute]['preInfinity'] postInfinity = data['animCurve'][eachObject][ eachAnimCurveAttribute]['postInfinity'] weightedTangents = data['animCurve'][eachObject][ eachAnimCurveAttribute]['weightedTangents'] numKeys = data['animCurve'][eachObject][ eachAnimCurveAttribute]['numKeys'] timeList = data['animCurve'][eachObject][ eachAnimCurveAttribute]['timeList'] valueList = data['animCurve'][eachObject][ eachAnimCurveAttribute]['valueList'] inTangentTypeList = data['animCurve'][eachObject][ eachAnimCurveAttribute]['inTangentTypeList'] inTangentAngleList = data['animCurve'][eachObject][ eachAnimCurveAttribute]['inTangentAngleList'] inTangentAngleWeightList = data['animCurve'][eachObject][ eachAnimCurveAttribute]['inTangentAngleWeightList'] outTangentTypeList = data['animCurve'][eachObject][ eachAnimCurveAttribute]['outTangentTypeList'] outTangentAngleList = data['animCurve'][eachObject][ eachAnimCurveAttribute]['outTangentAngleList'] outTangentAngleWeightList = data['animCurve'][eachObject][ eachAnimCurveAttribute]['outTangentAngleWeightList'] # convert current object and attribute to a new MPlug object mSelectionList = om.MSelectionList() mSelectionList.add('%s.%s' % (eachObject, eachAnimCurveAttribute)) attributeMPlug = mSelectionList.getPlug(0) connectedList = attributeMPlug.connectedTo(1, 0) # whether to create a new curve or use the existed curve newAnimCurve = 1 if connectedList: connectedNode = connectedList[0].node() if connectedNode.hasFn(om.MFn.kAnimCurve): MFnAnimCurve = oma.MFnAnimCurve(connectedNode) newAnimCurve = 0 if newAnimCurve: MFnAnimCurve = oma.MFnAnimCurve() MFnAnimCurve.create(attributeMPlug, animCurveType) # set value MFnAnimCurve.setPreInfinityType(preInfinity) MFnAnimCurve.setPostInfinityType(postInfinity) MFnAnimCurve.setIsWeighted(weightedTangents) MTimeArray = om.MTimeArray() MDoubleValueList = om.MDoubleArray() for index in range(len(timeList)): MTimeArray.append( om.MTime(timeList[index], om.MTime.uiUnit())) MDoubleValueList.append(valueList[index]) MFnAnimCurve.addKeys(MTimeArray, MDoubleValueList, 0, 0, 1) for index in range(len(timeList)): MFnAnimCurve.setInTangentType(index, inTangentTypeList[index]) MFnAnimCurve.setOutTangentType(index, outTangentTypeList[index]) inTangentAngle = om.MAngle(inTangentAngleList[index]) outTangentAngle = om.MAngle(outTangentAngleList[index]) MFnAnimCurve.setAngle(index, inTangentAngle, 1) MFnAnimCurve.setAngle(index, outTangentAngle, 0) MFnAnimCurve.setWeight(index, inTangentAngleWeightList[index], 1) MFnAnimCurve.setWeight(index, outTangentAngleWeightList[index], 0) # read history historyData = data['history'] historyList = [ 'Owner: %s' % historyData[0], 'Created: %s' % historyData[1], 'Maya version: %s' % historyData[2], 'Module version: %s' % historyData[3] ] return historyList