Skip to content

Instantly share code, notes, and snippets.

@gregoiredehame
Last active October 15, 2024 01:38
Show Gist options
  • Select an option

  • Save gregoiredehame/a227f7e2bc4e80983632a0e282d64b4e to your computer and use it in GitHub Desktop.

Select an option

Save gregoiredehame/a227f7e2bc4e80983632a0e282d64b4e to your computer and use it in GitHub Desktop.
maya api 2.0 parent matrix custom node, that maintain 0.0.0 rotations angles on joints.
import maya.api.OpenMaya as om2
def maya_useNewAPI():
pass
class parentJointMatrix(om2.MPxNode):
id_ = om2.MTypeId(0x00124dfe)
def __init__(self) -> None:
super(parentJointMatrix, self).__init__()
@classmethod
def creator(cls) -> None:
return cls()
@classmethod
def initialize(cls) -> None:
fnMatrix = om2.MFnMatrixAttribute()
fnUnit = om2.MFnUnitAttribute()
fnNumeric = om2.MFnNumericAttribute()
fnEnum = om2.MFnEnumAttribute()
# INPUTS
cls.input_matrix = fnMatrix.create("inputMatrix", "im")
fnMatrix.storable = True
fnMatrix.keyable = True
fnMatrix.connectable = True
cls.addAttribute(cls.input_matrix)
cls.offset_matrix = fnMatrix.create("offsetMatrix", "ofm")
cls.addAttribute(cls.offset_matrix)
cls.parent_matrix = fnMatrix.create("jointParentMatrix", "jpm")
cls.addAttribute(cls.parent_matrix)
cls.joint_orient_x = fnUnit.create("jointOrientX", "jox", om2.MFnUnitAttribute.kAngle, 0.)
cls.joint_orient_y = fnUnit.create("jointOrientY", "joy", om2.MFnUnitAttribute.kAngle, 0.)
cls.joint_orient_z = fnUnit.create("jointOrientZ", "joz", om2.MFnUnitAttribute.kAngle, 0.)
cls.joint_orient = fnNumeric.create("jointOrient", "jo", cls.joint_orient_x, cls.joint_orient_y, cls.joint_orient_z)
cls.addAttribute(cls.joint_orient)
cls.input_rotate_order = fnEnum.create("inputRotateOrder", "iro", 0)
[fnEnum.addField(["xyz", "yzx", "zxy", "xzy", "yxz", "zyx"][i], i) for i in range(6)]
cls.addAttribute(cls.input_rotate_order)
# OUPUTS
cls.output_matrix = fnMatrix.create("outputMatrix", "om")
fnMatrix.storable = False
fnMatrix.keyable = False
fnMatrix.connectable = True
cls.addAttribute(cls.output_matrix)
cls.output_translate_x = fnUnit.create("outputTranslateX", "otx", om2.MFnUnitAttribute.kDistance, 0.0)
cls.output_translate_y = fnUnit.create("outputTranslateY", "oty", om2.MFnUnitAttribute.kDistance, 0.0)
cls.output_translate_z = fnUnit.create("outputTranslateZ", "otz", om2.MFnUnitAttribute.kDistance, 0.0)
cls.output_translate = fnNumeric.create("outputTranslate", "ot", cls.output_translate_x, cls.output_translate_y, cls.output_translate_z)
cls.addAttribute(cls.output_translate)
cls.output_rotate_x = fnUnit.create("outputRotateX", "orx", om2.MFnUnitAttribute.kAngle, 0.)
cls.output_rotate_y = fnUnit.create("outputRotateY", "ory", om2.MFnUnitAttribute.kAngle, 0.)
cls.output_rotate_z = fnUnit.create("outputRotateZ", "orz", om2.MFnUnitAttribute.kAngle, 0.)
cls.output_rotate = fnNumeric.create("outputRotate", "or", cls.output_rotate_x, cls.output_rotate_y, cls.output_rotate_z)
cls.addAttribute(cls.output_rotate)
cls.output_scale_x = fnNumeric.create("outputScaleX", "osx", om2.MFnNumericData.kDouble, 1.0)
cls.output_scale_y = fnNumeric.create("outputScaleY", "osy", om2.MFnNumericData.kDouble, 1.0)
cls.output_scale_z = fnNumeric.create("outputScaleZ", "osz", om2.MFnNumericData.kDouble, 1.0)
cls.output_scale = fnNumeric.create("outputScale", "os", cls.output_scale_x, cls.output_scale_y, cls.output_scale_z)
cls.addAttribute(cls.output_scale)
cls.output_shear_x = fnNumeric.create("outputShearX", "oshx", om2.MFnNumericData.kDouble, 0.0)
cls.output_shear_y = fnNumeric.create("outputShearY", "oshy", om2.MFnNumericData.kDouble, 0.0)
cls.output_shear_z = fnNumeric.create("outputShearZ", "oshz", om2.MFnNumericData.kDouble, 0.0)
cls.output_shear = fnNumeric.create("outputShear", "osh", cls.output_shear_x, cls.output_shear_y, cls.output_shear_z)
cls.addAttribute(cls.output_shear)
cls.attributeAffects(cls.input_matrix, cls.output_matrix)
cls.attributeAffects(cls.offset_matrix, cls.output_matrix)
cls.attributeAffects(cls.parent_matrix, cls.output_matrix)
cls.attributeAffects(cls.joint_orient, cls.output_matrix)
cls.attributeAffects(cls.input_rotate_order, cls.output_matrix)
cls.attributeAffects(cls.input_matrix, cls.output_translate)
cls.attributeAffects(cls.offset_matrix, cls.output_translate)
cls.attributeAffects(cls.parent_matrix, cls.output_translate)
cls.attributeAffects(cls.joint_orient, cls.output_translate)
cls.attributeAffects(cls.input_rotate_order, cls.output_translate)
cls.attributeAffects(cls.input_matrix, cls.output_rotate)
cls.attributeAffects(cls.offset_matrix, cls.output_rotate)
cls.attributeAffects(cls.parent_matrix, cls.output_rotate)
cls.attributeAffects(cls.joint_orient, cls.output_rotate)
cls.attributeAffects(cls.input_rotate_order, cls.output_rotate)
cls.attributeAffects(cls.input_matrix, cls.output_scale)
cls.attributeAffects(cls.offset_matrix, cls.output_scale)
cls.attributeAffects(cls.parent_matrix, cls.output_scale)
cls.attributeAffects(cls.joint_orient, cls.output_scale)
cls.attributeAffects(cls.input_rotate_order, cls.output_scale)
cls.attributeAffects(cls.input_matrix, cls.output_shear)
cls.attributeAffects(cls.offset_matrix, cls.output_shear)
cls.attributeAffects(cls.parent_matrix, cls.output_shear)
cls.attributeAffects(cls.joint_orient, cls.output_shear)
cls.attributeAffects(cls.input_rotate_order, cls.output_shear)
def compute(self, plug:om2.MPlug, data:om2.MDataBlock) -> None:
if plug == self.output_matrix or plug == self.output_translate or plug == self.output_rotate or plug == self.output_scale or plug == self.output_shear:
input_matrix = data.inputValue(self.input_matrix).asMatrix()
parent_matrix = data.inputValue(self.parent_matrix).asMatrix()
orient_matrix = om2.MTransformationMatrix()
joint_orient_val = data.inputValue(self.joint_orient).asDouble3()
orient_matrix.setRotation(om2.MEulerRotation(joint_orient_val).asQuaternion())
output_matrix = om2.MTransformationMatrix(data.inputValue(self.offset_matrix).asMatrix() * input_matrix * parent_matrix.inverse())
offset_orient_matrix = om2.MTransformationMatrix(input_matrix * (orient_matrix.asMatrix() * parent_matrix).inverse())
output_matrix.setRotation(offset_orient_matrix.rotation())
data.outputValue(self.output_matrix).setMMatrix(output_matrix.asMatrix())
data.outputValue(self.output_translate).set3Double(*output_matrix.translation(om2.MSpace.kTransform))
data.outputValue(self.output_rotate).set3Double(*om2.MEulerRotation(*output_matrix.rotation(asQuaternion=False), data.inputValue(self.input_rotate_order).asShort()))
data.outputValue(self.output_scale).set3Double(*output_matrix.scale(om2.MSpace.kTransform))
data.outputValue(self.output_shear).set3Double(*output_matrix.shear(om2.MSpace.kTransform))
data.setClean(plug)
def initializePlugin(obj:om2.MObject) -> None:
fn_plugin = om2.MFnPlugin(obj)
fn_plugin.registerNode(parentJointMatrix.__name__, parentJointMatrix.id_, parentJointMatrix.creator, parentJointMatrix.initialize)
def uninitializePlugin(obj:om2.MObject) -> None:
fn_plugin = om2.MFnPlugin(obj)
fn_plugin.deregisterNode(parentJointMatrix.id_)
@gregoiredehame
Copy link
Author

gregoiredehame commented Oct 5, 2024

maya api 2.0 parent matrix custom node, that maintain 0.0.0 rotations angles on joints:
( also decompose matrix for direct translate, rotate, scale, shear connections )

parentJointMatrix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment