Sprint | cgmDynFK and some pose issues

IN PROGRESS SPRINT

Branch: MRSDEV

This post brought to you by the support of our MRS Patrons.

Took a break from the mDrake/Facial sprint for a gig to do some dynamics work. The goal of this micro sprint is to build a foundation for a dynamic setup to build on and nail down some presets.

First thing is to think about what kinda of things we’ll be animating with this system.

  • Spine
  • Tail
  • Limb
  • Hair
  • Cloth

In order to be able to test stuff and get some user iteration they’re going to need a couple of things.

  • Scene – test scene with some stuff to animate to
  • Simple tutorial for how to set things up
  • Call to export settings to share

I need to build a few things.

  • Handle with some stuff stuck on it
    • Long chains
    • Vertical up/down chains
    • Flag?
    • Torso
    • Leg
    • Tail

cgmDynFK

We’ve been doing some work that has some parts of the assets that need dynamics and needed a way to do that with our setup. Bokser figured out the base setup and then I set up a metaclass with wiring and what not to make the setups more user friendly for data management and cleanup.

The general workflow is rig agnostic.

  • Set up a cgmDynFK node
  • Add a chain from an existing fk chain
  • Load a profile
  • Add collision objects (proxy mesh from MRS works great)
  • Tweak settings till happy
  • Bake the dynamic setup back to the rig via cgmLocinator

Tutorial

I’m going to give a quick rundown here and then talk about issues and thoughts after for those interested.

Currently there is no UI so you’ll have to break out the script editor to make use of this and you’ll need to be on mrsDev branch of our tools until I roll it to the main branch.

Have that, let’s go. Here’s a vid.

 

Here’s the demo scene.

Current setup

  • cgm.core.rig.dynamic_utils.cgmDynFK
    • Metaclass for handling things
  • cgm.core.presets.cgmDynFK_presets
    • Place to store hard coded presets until/if we do a with sep files
import cgm.core.rig.dynamic_utils as RIGDYN
reload(RIGDYN)
mDynFK = RIGDYN.cgmDynFK(baseName='tree')
mDynFK = RIGDYN.cgmDynFK(baseName='chain')
mDynFK = RIGDYN.cgmDynFK(baseName='cloth')
mDynFK = RIGDYN.cgmDynFK('tree_dynFK')#...existing

mDynFK.get_nextIdx()

mDynFK.chain_create(name='back')
mDynFK = RIGDYN.cgmDynFK(baseName='ponyTails')
mDynFK.chain_create(name = 'left',fwd='z-', up='y-')
mDynFK.profile_load()
mDynFK.profile_load('wind')

mDynFK.chain_deleteByIdx(1)
mDynFK.chain_removeAll()
mDynFK.targets_connect()#...constrain to drivers
mDynFK.targets_disconnect()#...remove contraints
mDynFK.get_dat()


RIGDYN.profile_get('base')
RIGDYN.profile_get('tree')
pprint.pprint(RIGDYN.get_dat('cgmDynFK_nucleus',differential=1))
pprint.pprint(RIGDYN.get_dat('tree_hairSysShape',differential=1))
RIGDYN.profile_load('tree_hairSysShape','spine', clean=False)

Demo Scene

Setup a scene with some stuff to try with dynamics to see how we stand.

Alrighty, we’ve got a bunch of stuff built with MRS to mess with via dynamics. Woot woot.

Pass one on settings

Notes

  • Prop isn’t working great. Will change setup after profiles working
  • Want to try some profiles between places
  • Change the aim setup on the driver chain to use each previous object as the up

Second Pass

Notes – 08.01.2019

  • Fixed issue with not properly wiring multiple chains one system.
  • The above is  9 chains on one nucleus and one hair system.
  • Wasn’t happy with aiming. Previously we’d tried a paramater on the curve .5 between the base and the target. Now it just aims at the next point.
  • Added extendStart to chain_create to let you decide if to extend the dynamic curve before the start. Previously it had been on all the time. This caused some collision issues. Fixed.

Third Pass

  • Don’t think the aim stuff is necessary in the args. Try just setting up the structure with our normal setup and parent the drivers to those.
  • Add a rebuild call
  • Add a no aim setup
  • Add the attach end/start enums to the dag node and wire to the follicles
  • Bokser | we can used a pointOnCurve node to get the normalizedNormal to get the ‘up’ rather than have an arg setup to track twist real time

Up setup

Experimented with a few different methods. There’s two different things we need.

  • upSetup – when no up is offered, we need to generate one. There are multiple ways to handle the up
    • arg – just use the arg values for what is up
    • guess – try to figure it out
  • upControl
    • Add a way to add an up control on the up group.
  • aimUpMode – There are a few ways to handle this.
    • sequential – each target used the previous ones up as it’s up
    • master – each target uses a upControl up
    • masterOrientTo – orient constrain to the upControl
    • curveNormal

Rebuild

Need to add the rebuild function.

  • Added
  • Fixed
    • report
    • get_nextIdx

Fourth Pass – 08.14

  • Added mDynFK.targets_select() | to select targets
  • Rebuild function added
  • More polish on setup

Adding setup to feathers…

_l = mc.ls(sl=1)
for i,o in enumerate(_l):
    mDynFK.chaincreate([o],name = 'left{0}'.format(i),fwd='z-', up='y-',upSetup = 'manual')

current snips for ponytails…

mDynFK.chain_create(name= 'back', aimUpMode='sequential',extendEnd=1.0)
mDynFK.chain_create(name= 'right', aimUpMode='sequential',upSetup='manual',extendEnd=1.0)
mDynFK.chain_create(name = 'left',aimUpMode='sequential', fwd='z-', up='y-',upSetup='manual',extendEnd=1.0)

Getting the differential dat for profile…

pprint.pprint(RIGDYN.get_dat('tentacle_hairSysShape',differential=1))

 

Things to remember

  • Make sure play all frames is on

Thoughts

Why not just put the dynamic setup in the rig itself?

We may well do that for some setups. I’ve got a fish setup from a long while back that has one but for lots of situations you only want the setup for part of a shot or part of a tail or chunk of hair and it’s easier to be able to just apply dynamics to what you want.

Also, it makes the rig lighter and not have to jump back to the rig asset to change certain settings.

How do we implement profiles well?

To start we just have a dict of profile settings for the nucleus and the hairSystem. We don’t want to store every single attribute everytime as that will just get to be too much. Instead, we’ll create a baseline dict of attributes for each. Then for each attribute that is a different value than those settings we’ll use as our differential to save off.

Issues

Locinator

Ran into issues with it not properly backing because of mc.refresh suspension. So.

  • Added a new global cgmDynMode optionVar to use between tools.
  • Added a flag to the baker for dynMode. If the kw is none, it checks for the optionVar value.
  • This mode makes every frame play and update so as to let dynamics resolve without having to cache it (which may be something we do later on)

Issue with baking on other key intervals

  • Need to make dynMode play every frame period
  • Canceling bake wasn’t dumping out totally

Pose Library Issues

We use Mark Jackson’s fantastic red9 libraries for a lot of how we work. We were running into some issues with how we were using the pose library stuff and duplicate control names.

After digging into it, we weren’t making full use of the tech. So I added the other match method options to our implementation. This resolved the name match issues.

TdataCompound Attrs

Haven’t really done a lot with these before now. I have basic functionality in our toolbox but in order to save/load dyn profiles I need the support. So…time to dig in.

So looking at the dynamic hair shape node we have stiffness scale which lets you create a curve to drive how the values are along the curve of the hair.

Working through this on ‘stiffnessScale’.

The way compound attrs are stored is via index. The have children attributes that values go into.

Pre play

mc.getAttr('tail_hairSysShape.stiffnessScale')mc.getAttr('tail_hairSysShape.stiffnessScale',multiIndices =1)]
for v in mc.getAttr('tail_hairSysShape.stiffnessScale',multiIndices =1):
   print mc.getAttr('tail_hairSysShape.stiffnessScale[{0}]'.format(v))
mc.getAttr('tail_hairSysShape.stiffnessScale[0]')
mc.getAttr('tail_hairSysShape.stiffnessScale[2]')

To do

  • ATTR.get | …
    • get values from single
    • get values form multi
      • Initially I was going to go with a list because the indices aren’t necessarily sequential
      • Instead I went with a dict for a multi return
  • ATTR.set |
    • set values to single
    • set values to all

New calls

  • get_nextCompoundIndex
  • get_compoundIndices

 

Profiles

We need to ability to get and store profiles for reuse.

  • Initially tried using keyable attributes on the targets. This misses things. Instead, I have attribute maps per node. This is not as ideal in case Autodesk adds attributes but whatcha gonna do.
  • Generated base list
  • Made call to get a differential dict from the base so we only need to store differences from that
  • Made call to apply just the profile or a clean load which takes the base dict, updates it with the profile dat and loads that
  • Created initial list of profiles

Initial List

  • Wind – Nucleus only data for our first pass on wind
  • Tree – firmer structure. Most firm at base
  • chain – heavier rope like setup
  • rope –
  • tentacle
  • limb
  • tail
  • prop
  • cloth
  • spine – for our internal setup. We have something riding stuff. This is to generate an initial pass of anim on the spine to speed up workflow

MRS Bugs

  • Duplicate names
    • Roots
      • LIMB
      • SEGMENT
      • HEAD
    • segMids
      • rig_skeleton
        • Add to the segmentMidIKControl part
          • _nameSet = NAMETOOLS.combineDict( ml_set[0].getNameDict(ignore=[‘cgmType’,’cgmDirection’]))
      • LIMB
      • SEGMENT
      • HEAD
    • pivots
      • New call for rigShapes using self.d_module[‘partName’]
      • handle,limb
Josh Burton

[MRS Project Lead | CG Monks] Josh is an animator turned TD who hails from Oklahoma, pre-undergrad in the Marine Corps, animation basics at Savannah College of Art and Design, cut his teeth in gaming and commercials before co-founding CG Monks and more recently the CG Monastery. The Morpheus Rigging System is a culmination of years of R&D and he is now thrilled to see what users can create, collaborate and expand on with this open source MRS platform.