This a reference page for the lpDynamicChains tool.
DESCRIPTION
This tool allows for the creation of dynamic joint chains. User can specify joints to become dynamic. Can also turn any geometry into a collision object. Simulations can be cached to a file or baked as animation onto joints and dynamic nodes can be removed when done.
Suggested use: for tails, appendages, for secondary delayed movement - ex: jiggle
File: lpDynamicChains.py
Versions: 1.0 - 06/28/2013 - first version created
1.1 - 07/02/2013 - changed curve degree to work with 2-3 joints chain. fixed
complete removal of dynamic nodes for delete dynamic
2.0 - 07/13/2013 - added create collision object option
2.1 - 08/15/2013 - updated collision feature and entire tool to use nDynamics
and the nucleus solver unifying all simulations under one solver
2.2 - 08/19/2013 - added option to bake sim onto joint
USAGE NOTES
The UI
1. Place script in
Windows: C:/Program Files/Autodesk/Maya2013/Python/lib/site-packages/
Mac: Users/userName/Library/Preferences/Autodesk/maya/2013
-x64/scripts/
2. To open the UI:
import lpDynamicChains
reload(lpDynamicChains)
lpDynamicChains.UI()
The UI allows for the creation and interaction of dynamic chains in the scene. It also allows access to lpDynamicChains commands
Create Dynamic joints
Select the start joint, shift select the end joint and click the 'Make Joints Dynamic' button under the
Main section.
Commands:
from lpDynamicChains import *
dynChain = lpDynamiChain(startJoint, endJoint)
dynChain.create()
def lpDyanmicChain(startJoint="", endJoint="", node=""):
'''
Create the custom node
Parameters:
startJoint - Name of the first joint in the chain
endJoint - Name of the last joint in the chain
node - Name of the node to manage by the class
Returns:
Nothing
'''
def create(self):
'''
Create the actual dynamic joint chain node network
Parameters:
Nothing
Returns:
List of all new created nodes
'''
A custom locator node will be created at the start joint's position holding the parameters to be tweaked to customize the dynamic behavior of the joint chain.
All nodes created will be stored as meta data on the nodes themselves to allow for the tool to keep track of the nodes associated with every newly created dynamic chain.
You will get a window prompting which nucleus to connect the dynamicChain to.
A log window will display at the end of creation, listing all nodes created with the new dynamicChain.
Remove Dynamic Nodes
Select any node created for the dynamic chain to be deleted or the dynamic chain locator at the start joint, and click the 'Remove Dynamic' button under the
Main section.
Commands:
from lpDynamicChains import *
dynChain = lpDynamicChain(node=node)
dynChain.delete()
del(dynChain)
Note: Removing dynamic nodes will also check for any unused nucleus nodes and remove them as well.
All nodes created for the dynamic chain to be deleted will be removed from the scene returning it to its original state before the creation of the dynamic chain.
Iterate Through All Dynamic Chain Nodes
Commands:
# create instance
dynChain = lpDynamicChain()
# create iterable for all dynamic nodes in the scene
dynChains = dynChain.Iter()
for d in dynChains:
print d
Adding Collision Objects
Select the locator for the dynamic chain to be edited, shift select the geometry to be turned into a collision object and click the 'Create Collision Object' button under the
Options section.
Geometry object will be turned into a passive nRigid object to interact with the dynamic joints. A nRigid node will be created and stored in an array attribute keeping track of all collider nodes interacting with it.
Creating nCache
Select the locator or multiple locators for the dynamic chain(s) to be cached and click the 'Cache Simulation' button under the
Advanced -> nCache section.
The nCache option window will display so you can choose how to save out the cache file (or multiple files) for the dynamic simulations. For more information please refer to the
Autodesk Maya Help Docs
Removing nCache
Select the locator for the dynamic chain to be cached and click the 'Delete Cache' button under
Advanced -> nCache section.
Note: Removing dynamic nodes for a given dynamic chain will not delete the cache file on disk.
The Delete nCache option window will display. If there are multiple cache nodes for the dynamic chain, you will be able to select which ones to delete.
The option to delete or keep the cache files on disk will also be available.
Baking Simulation to Joints
Select the locator for the dynamic chain to be bake the simulation for and click the 'Bake Simulation' button under
Advanced -> Animation
Utility Commands
In addition to the UI functions, you can also access utility commands available with the script. Below are some examples.
Get and Set the Active Nucleus
from lpDynamicChains import *
nucleus = getActiveNucleus()
setActiveNucleus(nucleus)
def getActiveNucleus():
'''
Query the active nucleus node
Parameters:
Nothing
Returns:
Name of active nucleus node
'''
def setActiveNucleus(nucleus):
'''
Set the active nucleus node
Parameters:
nucleus - Name of nucleus node to set as current active nucleus
Returns:
Nothing
'''
Get Connected
Get commands to find the connected DynamicChain node or the nucleus node connected to the dynamicNode
from lpDynamicChains import *
# get selected object
obj = cmds.ls(sl=True)[0]
dNode = getConnectedDynamicChain(obj)
nucleus = getConnectedNucleusNode(dNode)
def getConnectedDynamicChain(node):
'''
Look for a valid DynamicChain node connected to the given node
Parameters:
node - Name of the node to find connection to DynamicChain
Returns:
Name of DynamicChain node connected to given node
'''
def getConnectedNucleusNode(node):
'''
Look for the nucleus node connected to the given node
Parameters:
node - Name of the node to find connection to nucleus
Returns:
Name of the nucleus node connected to the given node
'''
Checks
Check commands to verify if node is a DynamicChain node or node is a nucleus compatible nDynamics node.
from lpDynamicChains import *
# get selected object
obj = cmds.ls(sl=True)[0]
if isDynamicChain(obj):
dynChain = lpDynamicChain(obj)
# access attribute
hairShape = dynChain.hairSystemShape[0]
return isNType(hairShape, "hairSystem")
def isDynamicChain(node):
'''
Look for the identifier to check if node is 'dynamic'
Parameters:
node - Name of node to check for 'nodeType'
Returns:
Boolean value if node is dynamic or not, True or False
'''
def isNType(node, nodeType):
'''
Check if the given node is a nucleus compatible nDynamics node
Parameters:
node - Name of node to check for 'NType' compatibility
nodeType - Node type to check
Returns:
Boolean value if node is compatible with nDynamics solver
'''
Number of Colliders
Check how many collision objects are attached to the node
from lpDynamicChains import *
# get selected object
obj = cmds.ls(sl=True)[0]
if isDynamicChain(obj):
numColliders = findNumberOfCollisionObjects(obj)
def findNumberOfCollisionObjects(node):
'''
Find the number of collision objects attached to the node
Parameters:
node - Name of the node to check for collision objects
Returns:
Integer number of collision objects attached to the node
'''
Delete Unused Nucleus Nodes
Check nucleus nodes in the scene for their connections and remove any that are not being used.
from lpDynamicChains import *
deletedNodes = deleteUnusedNucleusSolvers()
def deleteUnusedNucleusSolvers():
'''
Delete all nucleus nodes not being used
Parameters:
Nothing
Returns:
List of nucleus node deleted
'''
Create and Connect
Creation and connection commands to create new nucleus nodes, nRigid nodes, connect DynamicChain node to nucleus or to connect a nRigid node to a nucleus.
from lpDynamicChains import *
# get selected objects
selected = cmds.ls(sl=True)[0]
dNode = selected[0]
mesh = selected[1]
nucleus = createNucleus()
if isDynamicChain(dNode):
nucleus = connectToNucleus(dNode, nucleus)
nRigid = createNRigid(mesh, nucleus)
index = connectNRigidToNucleus(nRigid, nucleus)
def createNucleus(name="", setActive=True):
'''
Create nucleus node
Parameters:
name - Name for the new nucleus node
setActive - Boolean to set the new nucleus as the current active nucleus
Returns:
Name of new nucleus node
'''
def createNRigid(obj, nucleus=""):
'''
Create a nRigig node from the given obj
Parameters:
obj - Name of the geo to create nRigid from
nucleus - Name of the nucleus to connect nRigid to
Returns:
Name of new nRigid node
'''
def connectToNucleus(node, nucleus):
'''
Connect the given node to the nucleus node
Parameters:
node - Name of the node to connect to the nucleus solver
nucleus - Name of nucleus solver to connect to
Returns:
Name of nucleus node (debug)
'''
def connectNRigidToNucleus(nRigid, nucleus, newNucleus=True):
'''
Connect the given nRigid node to the nucleus node, maintaining prior connections to
other nucleus nodes
Parameters:
nRigid - Name of nRigid node to connect to nucleus
nucleus - Name of nucleus node to connect
newNucleus - Boolean to create a new nucleus node if the specified nucleus doesn't exist
Returns:
Integer index of next available passive nRigid for the given nucleus
'''
Access connections
Command to get all nodes connected to custom node, like hairSystem, or the ikHandle. Access custom attributes through class _getattr_ method
from lpDynamicChains import *
# get selected object
obj = cmds.ls(sl=True)
if isDynamicChain(obj):
dNode = lpDynamicChain(node=obj)
nodes = dNode.listConnections()
# get hairSystemShape node
hairShape = dNode.hairSystemShape[0]
def listConnections(self):
'''
Wrapper to get all connections to the node to message attributes
Parameters:
Nothing
Returns:
List of connected nodes to all custom message attributes
'''