Skip to content

Commit

Permalink
Shifter: adding Chain_spring_gravity: Emilio Serrano Contribution: Ap…
Browse files Browse the repository at this point in the history
…plyop: added gear_spring_gravity_op function #451

(cherry picked from commit b8ed944)
  • Loading branch information
miquelcampos committed Feb 9, 2025
1 parent a624195 commit cde3fdc
Show file tree
Hide file tree
Showing 5 changed files with 446 additions and 11 deletions.
35 changes: 24 additions & 11 deletions release/scripts/mgear/core/applyop.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ def parentCns(driver, driven, maintain_offset=True, **kwargs):


def curvecns_op(crv, inputs=[]):

for i, item in enumerate(inputs):
node = pm.createNode("decomposeMatrix")
pm.connectAttr(item + ".worldMatrix[0]", node + ".inputMatrix")
Expand Down Expand Up @@ -297,7 +296,6 @@ def aimCns(
"upVectorZ",
]
):

pm.setAttr(node + "." + name, a[i])

return node
Expand Down Expand Up @@ -392,8 +390,12 @@ def gear_matrix_cns(
# calculate rotation rest pose
# we use the outputDriverOffsetMatrix to have in account the offset
# rotation when the rest pose is calculated
driver_m = om.MMatrix(pm.getAttr(node + ".outputDriverOffsetMatrix"))
driven_m = om.MMatrix(pm.getAttr(out_obj + ".parentInverseMatrix[0]"))
driver_m = om.MMatrix(
pm.getAttr(node + ".outputDriverOffsetMatrix")
)
driven_m = om.MMatrix(
pm.getAttr(out_obj + ".parentInverseMatrix[0]")
)
mult = driver_m * driven_m
pm.setAttr(node + ".drivenRestMatrix", mult, type="matrix")

Expand All @@ -409,20 +411,21 @@ def gear_matrix_cns(
return node


def gear_spring_op(in_obj, goal=False):
def gear_spring_op(in_obj, goal=False, solver="mgear_springNode"):
"""Apply mGear spring node.
Arguments:
in_obj (dagNode): Constrained object.
goal (dagNode): By default is False.
solver (str, optional): Spring solver
Returns:
pyNode: Newly created node
"""
if not goal:
goal = in_obj

node = pm.createNode("mgear_springNode")
node = pm.createNode(solver)

pm.connectAttr("time1.outTime", node + ".time")
dm_node = pm.createNode("decomposeMatrix")
Expand All @@ -447,6 +450,20 @@ def gear_spring_op(in_obj, goal=False):
return node


def gear_spring_gravity_op(in_obj, goal=False):
"""Apply mGear spring Gravity node.
Arguments:
in_obj (dagNode): Constrained object.
goal (dagNode): By default is False.
Returns:
pyNode: Newly created node
"""

return gear_spring_op(in_obj, goal=goal, solver="mgear_springGravityNode")


def gear_mulmatrix_op(mA, mB, target=False, transform="srt"):
"""Create mGear multiply Matrix node.
Expand Down Expand Up @@ -972,11 +989,7 @@ def create_proximity_constraints(shape, in_trans_list):


def create_uv_pin_constraint(
shape,
in_trans,
existing_pin=None,
out_trans=None,
**kwargs
shape, in_trans, existing_pin=None, out_trans=None, **kwargs
):
"""Create a UV pin constraint between a shape and a transform.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
Custom chain spring with gravitiy and colliders setup.

Following some insight from Hiroyuki Akasaki [https://x.com/akasaki1211/media](https://x.com/akasaki1211/status/1761769004715397579)

I managed to add gravity and colliders to the spring chain component.

I simply duplicated the component and hooked the mgear_springGravityNode to it, exposing the relevant parameters to the host control.

![image](https://github.com/user-attachments/assets/78e44fc2-92d1-4971-8ba5-447c1b026faa)

The component is exactly as the spring chain:

![image](https://github.com/user-attachments/assets/41a1bbe3-6a07-48cb-8158-8bcfcea02c2e)

Once built you can see the usual spring parameters plus the new ones exposed:

![image](https://github.com/user-attachments/assets/967c5e60-0436-4c3f-9d52-c2fc0c184b99)

Gravity per sections 0 to 10

Gravity direction pointing down (Y) per section

Use Ground. (infinite plane at 0.0.0) per section

Collide softness when you connect some basic primitives to the collider list and radius

![image](https://github.com/user-attachments/assets/14e556e4-8550-4f0b-9281-7f7957417107)





Download the zip, and extract into your mGear shifter Classic components:

![image](https://github.com/user-attachments/assets/6c38679d-1aca-42ee-84d6-d9c0e968f373)

Also, to define the component when building you need to add these lines to the applyop.py, or overwrite the file within the zip provided.

C:\Users\yourUserName\Documents\maya\modules\scripts\mgear\core

def gear_springG_op(in_obj, goal=False):
"""Apply mGear spring Gravity node.

Arguments:
in_obj (dagNode): Constrained object.
goal (dagNode): By default is False.

Returns:
pyNode: Newly created node
"""
if not goal:
goal = in_obj

node = pm.createNode("mgear_springGravityNode")

pm.connectAttr("time1.outTime", node + ".time")
dm_node = pm.createNode("decomposeMatrix")
pm.connectAttr(goal + ".parentMatrix", dm_node + ".inputMatrix")
pm.connectAttr(dm_node + ".outputTranslate", node + ".goal")

cm_node = pm.createNode("composeMatrix")
pm.connectAttr(node + ".output", cm_node + ".inputTranslate")

mm_node = pm.createNode("mgear_mulMatrix")

pm.connectAttr(cm_node + ".outputMatrix", mm_node + ".matrixA")
pm.connectAttr(in_obj + ".parentInverseMatrix", mm_node + ".matrixB")

dm_node2 = pm.createNode("decomposeMatrix")
pm.connectAttr(mm_node + ".output", dm_node2 + ".inputMatrix")
pm.connectAttr(dm_node2 + ".outputTranslate", in_obj + ".translate")

pm.setAttr(node + ".stiffness", 0.5)
pm.setAttr(node + ".damping", 0.5)

return node
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
"""Component Chain Spring 01 module"""

import pymel.core as pm
from pymel.core import datatypes

from mgear.shifter import component

from mgear.core import applyop, vector, node
from mgear.core import attribute, transform, primitive

#############################################
# COMPONENT
#############################################


class Component(component.Main):
"""Shifter component Class"""

# =====================================================
# OBJECTS
# =====================================================
def addObjects(self):

# blades computation
self.normal = self.guide.blades["blade"].z
self.binormal = self.guide.blades["blade"].x

self.fk_npo = []
self.fk_ctl = []
self.spring_cns = []
self.spring_aim = []
self.spring_lvl = []
self.spring_ref = []
self.spring_npo = []
self.spring_target = []
parent = self.root
self.previousTag = self.parentCtlTag
for i, t in enumerate(transform.getChainTransform(self.guide.apos,
self.normal,
self.negate)):
dist = vector.getDistance(self.guide.apos[i],
self.guide.apos[i + 1])

fk_npo = primitive.addTransform(parent,
self.getName("fk%s_npo" % i), t)

spring_aim = primitive.addTransform(
fk_npo,
self.getName("spring%s_aim" % i), t)

spring_cns = primitive.addTransform(
fk_npo,
self.getName("spring%s_cns" % i), t)

fk_ctl = self.addCtl(
spring_cns,
"fk%s_ctl" % i,
t,
self.color_fk,
"cube", w=dist,
h=self.size * .1,
d=self.size * .1,
po=datatypes.Vector(dist * .5 * self.n_factor, 0, 0),
tp=self.previousTag,
lp=False)

self.previousTag = fk_ctl

t = transform.getTransformFromPos(self.guide.apos[i + 1])
spring_npo = primitive.addTransform(
parent, self.getName("spring%s_npo" % i), t)
spring_target = primitive.addTransform(
spring_npo, self.getName("spring%s" % i), t)

parent = fk_ctl

self.spring_cns.append(spring_cns)
self.spring_aim.append(spring_aim)

self.addToGroup(spring_cns, "PLOT")

self.fk_npo.append(fk_npo)
self.fk_ctl.append(fk_ctl)
attribute.setKeyableAttributes(self.fk_ctl, self.tr_params)

self.spring_target.append(spring_target)

# Chain of deformers -------------------------------
self.loc = []
parent = self.root
for i, t in enumerate(transform.getChainTransform(self.guide.apos,
self.normal,
self.negate)):
loc = primitive.addTransform(parent, self.getName("%s_loc" % i), t)

self.loc.append(loc)
self.jnt_pos.append([loc, i])
parent = loc

# =====================================================
# ATTRIBUTES
# =====================================================
def addAttributes(self):
"""Create the anim and setupr rig attributes for the component"""

# Anim -------------------------------------------
self.aDamping = []
self.aGravity = []
self.aGravitydirectionY = []
self.ause_ground = []
self.acollide_softness = []
self.aStiffness = []
self.aSpring_intensity = self.addAnimParam("spring_intensity",
"Spring chain intensity",
"double",
0,
0,
1)
for i, tar in enumerate(self.spring_target):
aDamping = self.addAnimParam("damping_%s" % i,
"damping_%s" % i,
"double",
0.5,
0,
1)
self.aDamping.append(aDamping)

for i, tar in enumerate(self.spring_target):

aStiffness = self.addAnimParam(
"stiffness_%s" % i, "stiffness_%s" % i, "double", 0.5, 0, 1)

self.aStiffness.append(aStiffness)

for i, tar in enumerate(self.spring_target):

aGravity = self.addAnimParam(
"gravity_%s" % i, "gravity_%s" % i, "double", 0, 0, 10)

self.aGravity.append(aGravity)

for i, tar in enumerate(self.spring_target):

aGravity = self.addAnimParam(
"gravity_directionY_%s" % i, "gravity_directionY_%s" % i, "double", -1, -10, 10)

self.aGravitydirectionY.append(aGravity)

for i, tar in enumerate(self.spring_target):

ause_ground = self.addAnimParam(
"useGround_%s" % i, "useGround_%s" % i, "bool", 0, 0, 1)

self.ause_ground.append(ause_ground)

for i, tar in enumerate(self.spring_target):

acollide_softness = self.addAnimParam(
"collide_softness_%s" % i, "collide_softness_%s" % i, "double", 0, 0, 1)

self.acollide_softness.append(acollide_softness)

# =====================================================
# OPERATORS
# =====================================================
def addOperators(self):
"""Create operators and set the relations for the component rig
Apply operators, constraints, expressions to the hierarchy.
In order to keep the code clean and easier to debug,
we shouldn't create any new object in this method.
"""

# Chain of deformers -------------------------------
for i, loc in enumerate(self.loc):
pm.parentConstraint(self.fk_ctl[i], loc, maintainOffset=False)

# spring operators
# settings aim contraints
for i, tranCns in enumerate(self.spring_aim):
if self.negate:
aimAxis = "-xy"
else:
aimAxis = "xy"
applyop.aimCns(tranCns,
self.spring_target[i],
aimAxis,
2,
[0, 1, 0],
self.fk_npo[i],
False)
ori_cns = applyop.oriCns(tranCns, self.spring_cns[i])

springOP = applyop.gear_spring_gravity_op(self.spring_target[i])

blend_node = pm.createNode("pairBlend")

pm.connectAttr(ori_cns.constraintRotate, blend_node.inRotate2)
pm.connectAttr(self.aSpring_intensity, blend_node.weight)

pm.disconnectAttr(ori_cns.constraintRotate,
self.spring_cns[i].rotate)

pm.connectAttr(blend_node.outRotateX, self.spring_cns[i].rotateX)
pm.connectAttr(blend_node.outRotateY, self.spring_cns[i].rotateY)
pm.connectAttr(blend_node.outRotateZ, self.spring_cns[i].rotateZ)

pm.connectAttr(self.aSpring_intensity, springOP + ".intensity")
pm.connectAttr(self.aDamping[i], springOP + ".damping")
pm.connectAttr(self.aStiffness[i], springOP + ".stiffness")
pm.connectAttr(self.aGravity[i], springOP + ".gravity")
pm.connectAttr(self.ause_ground[i], springOP + ".use_ground")
pm.connectAttr(self.acollide_softness[i], springOP + ".collide_softness")
pm.connectAttr(self.aGravitydirectionY[i], springOP + ".gravity_directionY")

# =====================================================
# CONNECTOR
# =====================================================
def setRelation(self):
"""Set the relation beetween object from guide to rig"""

self.relatives["root"] = self.loc[0]
self.controlRelatives["root"] = self.fk_ctl[0]
self.jointRelatives["root"] = 0
for i in range(0, len(self.loc) - 1):
self.relatives["%s_loc" % i] = self.loc[i + 1]
self.controlRelatives["%s_loc" % i] = self.fk_ctl[i + 1]
self.jointRelatives["%s_loc" % i] = i + 1
self.relatives["%s_loc" % (len(self.loc) - 1)] = self.loc[-1]
self.controlRelatives["%s_loc" % (len(self.loc) - 1)] = self.fk_ctl[-1]
self.jointRelatives["%s_loc" % (len(self.loc) - 1)] = len(self.loc) - 1
Loading

0 comments on commit cde3fdc

Please sign in to comment.