Skip to content

Instantly share code, notes, and snippets.

@gregoiredehame
Last active February 20, 2024 20:32
Show Gist options
  • Select an option

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

Select an option

Save gregoiredehame/a7224fb04a9090ac1f24c772dd6b693c to your computer and use it in GitHub Desktop.
native maya push matrix collider
import maya.cmds as cmds
import maya.mel as mel
import maya.api.OpenMaya as om2
if __name__ == '__main__':
from kata import core as kcore
from kata import rig as krig
else:
from .. import core as kcore
from .. import rig as krig
def create(node:str=None, targets:str=None, **kwargs) -> str:
"""function that will create a push matrix connection.
this is based on maya muscles node, but will clean up nodes connections.
compared to default maya muscle, we are going to use target node world matrix attribute instead of creating a new transform.
if target have only one children, the matrix connections will be made on children, otherwise will create a new transform.
usually, we want to use this tool for lower lips and upper lips connections.
/!\ maya muscles shape nodes will be parented under the node's transforms.
Args:
node: (str): - string node of the collider mesh / nurbs surface
targets: (str, list): - string or list of node(s) to use as push matrix
maya muscles nodes explained:
Riham Toulan: (collar rig): - https://www.rihamtoulan.com/blog/2018/3/24/faking-collisions-with-joints-based-setup-8snd2
Perry Leijten: (skirt rig): - https://www.perryleijten.com/en/works/skirtColliderRD
"""
if not node or not isinstance(node, str) or not cmds.objExists(node):
raise AttributeError('unable to create push matrix rig. no node given and/or given node might not be a <str> existing object.')
if not kcore.mesh.is_mesh(node) and not kcore.surface.is_surface(node):
raise AttributeError('unable to create push matrix rig on "%s". type needs to be a <mesh> or a <nurbsSurface>. current <%s> does not work.'% (node, kcore.utilities.get_type(node)))
kcore.plugin.load('MayaMuscle.mll')
muscle = cmds.ls(cmds.listHistory(node), type="cMuscleObject")
if muscle:
muscle = muscle[0]
cmds.setAttr("%s.stickyStrength"% muscle, 0)
cmds.setAttr("%s.slidingStrength"% muscle, 1)
cmds.setAttr("%s.reverseNormals"% muscle, 0)
cmds.setAttr("%s.relative"% muscle, 0)
cmds.setAttr("%s.lockStickyWt"% muscle, 0)
cmds.setAttr("%s.lockSlidingWt"% muscle, 0)
cmds.setAttr("%s.affectSticky"% muscle, 0)
cmds.setAttr("%s.affectSliding"% muscle, 0)
cmds.setAttr("%s.userScaleX"% muscle, 0)
cmds.setAttr("%s.userScaleY"% muscle, 0)
cmds.setAttr("%s.userScaleZ"% muscle, 0)
cmds.setAttr("%s.draw"% muscle, 1)
cmds.setAttr("%s.shaded"% muscle, 0)
cmds.setAttr("%s.highlight"% muscle, 0)
cmds.setAttr("%s.highlightShaded"% muscle, 0)
if not kcore.attributes.is_exists(node, "collisionWidth"):
cmds.addAttr(node, longName="collisionWidth", niceName="Collision Width", attributeType="float", keyable=True, min=0, max=1, defaultValue=0)
cmds.connectAttr("%s.collisionWidth"% node, "%s.fat"% muscle)
kcore.attributes.animable(node, "collisionWidth")
if not kcore.attributes.is_exists(node, "collisionLod"):
cmds.addAttr(node, longName="collisionLod", niceName="Collision LOD", attributeType="enum", enumName="Full:Medium:Low", defaultValue=2)
kcore.attributes.animable(node, "collisionLod")
else:
cmds.select(node)
mel.eval("cMuscle_makeMuscle(0)")
return create(node, targets)
for target in kcore.utilities.as_list(targets):
childrens = cmds.listRelatives(target, children=True, type="transform") or []
reconnection = True if len(childrens) == 1 else None
cmds.select(target)
mel.eval("cMuscle_rigKeepOutSel();")
cmds.select(node, cmds.listConnections("%s.msgKeepOutXForm"% target, source=True)[0])
mel.eval("cMuscle_keepOutAddRemMuscle(1);")
keep_out = cmds.listConnections("%s.msgKeepOutXForm"% target, source=True)[0]
keep_out_shape = cmds.listRelatives(keep_out, shapes=True)[0]
keep_out_transform = cmds.listConnections("%s.msgKeepOutDriven"% target, source=True)[0]
cmds.parent(keep_out_shape, node, relative=True, shape=True)
cmds.setAttr("%s.draw"% keep_out_shape, 0)
cmds.connectAttr("%s.collisionLod"% node, "%s.quality"% keep_out_shape)
cmds.connectAttr("%s.worldMatrix[0]"% target, "%s.worldMatrixAim"% keep_out_shape, force=True)
if reconnection:
try:
cmds.connectAttr("%s.outTranslateLocal"% keep_out_shape, "%s.translate"% childrens[0])
for children in cmds.listRelatives(keep_out_transform, children=True, type="transform") or []:
cmds.parent(children, target)
cmds.delete(keep_out_transform)
except:
cmds.parent(keep_out_transform, target)
else:
cmds.parent(keep_out_transform, target)
for attribute in ("msgKeepOut", "msgKeepOutDriven", "msgKeepOutXForm"):
[cmds.disconnectAttr(connection, "%s.%s"% (target, attribute)) for connection in cmds.listConnections("%s.%s"% (target, attribute), source=True, plugs=True) or []]
cmds.deleteAttr("%s.%s"% (target, attribute))
if not kcore.attributes.is_exists(target, "enableCollision"):
cmds.addAttr(target, longName="enableCollision", niceName="Collision", attributeType="bool", keyable=True, defaultValue=True)
kcore.attributes.animable(target, "enableCollision")
cmds.connectAttr("%s.enableCollision"% target, "%s.enable"% keep_out_shape)
for vector in ("X", "Y", "Z"):
if not kcore.attributes.is_exists(target, "inDirection%s"% vector):
cmds.addAttr(target, longName="inDirection%s"% vector, niceName="Collision Vector %s"% vector, attributeType="float", keyable=True, min=0, max=1, defaultValue=1 if vector == "Y" else 0)
kcore.attributes.animable(target, "inDirection%s"% vector)
cmds.connectAttr("%s.inDirection%s"% (target, vector), "%s.inDirection%s"% (keep_out_shape, vector))
cmds.delete(keep_out)
return node
if __name__ == '__main__':
create(node="nurbsSphere1", targets=["locator1", "locator2", "locator3"])
@gregoiredehame
Copy link
Author

e70fdf7802167e3a1e44b685ad2e80fd.mp4

@gregoiredehame
Copy link
Author

muscle

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