-
Notifications
You must be signed in to change notification settings - Fork 21
Core Concepts
People use language differently. This is our attempt to shed light on what we mean with the language we use in helping users make the most use our tools.
We also have a general site terminology article
if you don't find what you need here.
The way we've set things up is that the metaClass cgmRigBlock (cgm.core.mrs.RigBlocks.cgmRigBlock
) is our template object for rig creation. These are used to generate the controls, wiring and structures of our rigs. At the end of the rig process, the rig itself can be exported off to keep all the extra data and nodes out of production assets.
Let's talk about the current rigBlock spread and their profiles which let's you specify what sub type of block you're dealing with. When you start messing with these you'll see other options in the ui that we're playing with. I'm only going to talk about the ones that are more tested for now.
Block | Status | Description |
---|---|---|
Master |
Production | Root block. Almost all rig structures should be under a master |
Limb |
Production | Arm,Finger,Thumb,Nub,Plantigrade,Digigrade,Ungulate,Unigrade, |
Segment |
Production | Spine, Tail, Tentacle, Ear Up |
Hand |
Early Alpha | BlockFrame |
Brow |
Active Dev | Facial brow setup |
Eye |
Active Dev | Eye setup |
Muzzle |
Active Dev | Mouth, nose, jaw |
Handle |
Production | Simple, snapPoint, shaperList, box, more... |
eyeMain |
Active Dev | Way to manually place master control. |
-
Rig block types are not subclasses. Instead each block is tagged with it's type which then tells it which module it uses.
- After experimenting a lot over the years with subclasses and dealing with specific reloads
-
At build how a given rigBlock of a type is setup is specified by two on creation flags which will both have their own core concept sections:
-
blockProfile
| This is what helps specify a spine segment rigBlock from a tail for example. -
buildProfile
| This mainly affects joint/roll counts
-
So, we start with a the dag. A few basic concepts
- The actual rigBlock as maya sees it is a dag node with a curve shape - currently using a shape we call locatorForm
- This dag has the core attributes of the rigBlock. There are some attributes that are shared among the different rigBlock types and many that are only on those given rigBlock types.
- State Nulls are dags that hold the dags,shapes and other bits for a given state of a rigBlock. States are covered in another fundamentals sections.
- No transform nulls are state nulls that hold those items for a given state we don't want to be transformed in anyway. Things like | track curves, curve/surface track dags and more
- attachPoint | Where the rig should attach to on it's blockParent's rig
- Base | Attach to the base of the parent block
- End | Attach to the end of the parent block
- Closest | Attach to the closest joint of the parent block
- Surface | Planned but not implemented
- baseSize | The stored base size values on a given rigBlock
The active block is the rigBlock that is loaded to the mrsBuilder ui. Several calls require an active block or it can be a point of context via the Push menu. Also the active block blockDat section works off the active block and has no function without it.
You can set the active block a couple of ways.
- Top bar of setup | There is a button
<<
which when pressed with a selected block will set that block as the active block- Right click menu | right clicking a selected rigBlock in the scroll list will provide an option
To Active
which will make that block the active blockUtilites | Contextual Section
| There is a buttonTo Active
that does the same.
BlockDat is the what we call the core data set of a rigblock. It comprises everything necessary for the replication of a given rigblock.
BlockFrames are a special kind of rigBlock. These are designed to help layout other blocks.
Some important notes:
- They never go beyond the define state even though they changes states like the others. The have a flag that just passes the block through those processes
- They are intended as a framework that you can get rid of after you're happy with the subBlocks. It's just to aid their placement you don't even have to mirror the frame you can just get one side's subblocks good and then push them as they are
A rigBlock may have a single blockMirror rigblock connected to it. This sets up a relationship for block mirroring functions as well as rig mirroring after build.
The rigblock that would be seen like a hierarchical parent to another block. However it's more of a controller block rather than a parent as it can be connected to that parent rigblock in multiple ways at rig.
The given state of a rigblock. Check the post more more info
A rigblock is our rigging guide. They are setup and controlled by mrsBuilder. You can find more information at the post for the concept.
Horse Template - 04.19
A collection of connected rigblocks usually saved as a file in order to generate an asset rig. Currently you can work off others templates though we have plans to have a fuller config system for blocks to come online sometime in 2019
Build profiles are our way of defining how we want our rigBlocks to build.
The idea is to allow you to save the same templates with different build options so you could customize similar proportioned rigs for different use cases. Need different LOD options with different join counts for your main character and side NPCs? No problem. Just create the custom build profiles for your templates and quickly build different rigs using the same template.
Profile | Status | Description |
---|---|---|
unityLow |
In development | Mobile game development |
unityMed |
Testing | Typical game projects |
unityToon |
In development | Squash and stretch game dev |
hik |
Planned | User is looking into requirements to implement |
Commercial |
Planned | No holds bar deformer options |
BlockDat is the what we call the core data set of a rigblock. It comprises everything necessary for the replication of a given rigblock.
We currently store data to a rigBlock as an indexed json Dict. That looks something like this:
{u'baseName': u'middle',
u'blockScale': 1.037493482218997,
u'blockState': u'form',
u'blockType': u'limb',
u'define': {u'orients': [[52.22471587773368,
-71.93779744222662,
-16.535790332436875],
[52.22471587773368,
-71.93779744222662,
-16.535790332436875],
[52.22471587773368,
-71.93779744222662,
-16.535790332436875],
[5.389233579525813,
-78.6114656770376,
-3.2547763552193154]],
u'positions': [[-74.79985247829057,
89.59468401000198,
6.8309683204825085],
[-67.3221197598987,
96.5377039202826,
5.137624991826678],
[-66.42490656915008,
95.59145818175912,
5.888416325692915],
[-62.11273142938996,
96.97845763451818,
3.656240724223191]],
u'scales': [[2.1279380321502686,
1.6460264921188354,
1.886982262134552],
[1.0, 1.0, 1.0],
[1.0, 1.0, 1.0],
[1.0, 1.0, 1.0]]},
u'orient': [52.22471587773366, -71.93779744222662, -16.53579033243688],
u'position': [-66.74114618435289, 95.68534753799752, 4.876879197491775],
u'rootOrientHelper': [0.0, 0.0, 0.0],
u'scale': [1.037493482218997, 1.037493482218997, 1.037493482218997],
u'form': {u'loftCurves': {u'0': {u'p': [-62.11273142938995,
96.97845763451818,
3.6562407242231947]},
u'1': {u'p': [-66.74114618435289,
95.68534753799753,
4.876879197491785]},
u'3': {u'p': [-69.4273789294334,
93.65512839221766,
5.528241587126501]},
u'4': {u'p': [-72.11361973321017,
91.62490315578187,
6.179605930847902]},
u'5': {u'p': [-75.0427217839515,
89.95100176945735,
6.939970093867182],
u's': [0.43219668963492186,
0.432196689634922,
0.4321966896349216],
u't': [-2.5891706859925808e-15,
0.4447799814925754,
-1.6077368156588644e-14]}},
u'orientHelpers': {},
u'orients': [[34.22581051559483,
-72.67783981267927,
-19.86320553000147],
[52.22471587773368,
-71.93779744222662,
-16.535790332436875],
[52.22471587773368,
-71.93779744222662,
-16.535790332436875],
[52.22471587773368,
-71.93779744222662,
-16.535790332436875],
[52.22471587773368,
-71.93779744222662,
-16.535790332436875],
[52.22471587773368,
-71.93779744222662,
-16.535790332436875]],
u'positions': [[-62.112731429389946,
96.97845763451815,
3.656240724223186],
[-66.74114618435289,
95.68534753799752,
4.876879197491773],
[-66.74114618435287,
95.68534753799753,
4.876879197491779],
[-69.4273789294334,
93.65512839221766,
5.528241587126499],
[-72.11361973321016,
91.62490315578185,
6.1796059308479006],
[-74.79985247829057,
89.59468401000197,
6.830968320482507]],
u'scales': [[1.0, 1.0000000000000002, 0.9999999999999997],
[1.0, 1.0, 1.0],
[1.0, 1.0000000000000002, 1.0],
[1.0, 1.0, 1.0],
[1.0, 1.0, 1.0],
[1.0000000000000002,
1.0000000000000002,
1.0000000000000002]],
u'subShapers': {u'0': {u'o': [[34.22581051559291,
-72.67783981267887,
-19.863205529999515]],
Let's break it down a bit.
-
version
| when this rigBlock was made originally - The first level of data is root data
- Then each state has a dict
- Sorted by ordered index lists for the handles of that state
- Sub shapers and others have sub dicts further still
-
ud
| these are a simple collection of userdefined attributes on the rigBlock
For example, let's look at the form state data.
-
orientHelpers
is empty because this block doesn't have data there -
orients
| indexed list of form handle orients -
positions
| indexed list of form handle positions -
scales
| indexed list of form handle scales -
loftCurves
| this is a keyed sub dict which has data indexed by the handle's list index- This sub dict has data that it finds:
-
p
- position -
s
- scale -
r
- rotate -
t
- tranlsate -
o
- orient
-
- This sub dict has data that it finds:
-
subShapers
- Keyed sub dicts with data per subShaper
BlockFrames are a special kind of rigBlock. These are designed to help layout other blocks.
Some important notes:
- They never go beyond the define state even though they changes states like the others. The have a flag that just passes the block through those processes
- They are intended as a framework that you can get rid of after you're happy with the subBlocks. It's just to aid their placement you don't even have to mirror the frame you can just get one side's subblocks good and then push them as they are
The intention is that blockFrames in the future share the special calls framework to make things work together nicely.
These are from the HAND .
Builds the drivers from our eventual rigBlocks to be driven by the system
Checks and/or rebuilds the rigBlocks driven by this rigBlock. Typically LIMB block fingers or thumbs.
Call to snap/shape rig blocks to the blockFrame.
mBlockArg
str/mNode
| What we want to process. If none, it does them all. If a rigBlock passed that has this as it's blockFrame, will use that one.
templateScale
enum
| Whether to scale the template loft curves or not
prerig tearoff
Again, we need some special options for blockFrames as they work differently than the define>>>rig setup or or base rigBlocks. Here's the example from
Has right click menu via mrsBuilder.
-
Verify Drivers
| Rebuilds the drivers. If you change the finger count for example you'd want to do this - Sub
-
Verify
| Make sure we have the driven rigBlocks we expect -
Rebuild
| Force a rebuild on the sub blocks -
Snap
| Position and orient relevant handles -
Shape
| Cast shape the loft curves as well as position and orient relevant handles
-
The first attempt at this is the HAND which creates LIMB blocks with the blockProfile of finger/thumb.
We have a class we did a couple of years ago that goes into this in much more detail which you can find here. However some basis of knowledge is important for you to understand how things work. I'm going to cover a portion of that here but if you want deeper knowledge you should check out that class.
People define metadata differently. For our purposes metadata is our means of storing and retrieving data. This is core to how rigBlocks function as the calls change their processes based on the data stored on a given block.
First of all a few bits about how we have implemented meta
- We built our foundation on Mark Jackson's fantastic red9 toolset and specifically his MetaClass. Most of our metaclass nodes are subclassed to his. We've been working with him for years and push bugs/fixes/optimizations to him that get put into his main branch and pull his fixes to our core. red9's base package is included with the cgmToolbox.
- This setup is very object oriented and allows for a number of useful items
- mClass instance wiring | This means that nodes that are wired and tagged with a specific attribute return instances rather than strings when coding
- Caching | several years ago he implemented node caching which improved speed a great deal.
- Json support | He's got json built in with string attributes
We use this data to do things like:
- Store node relationships one to another
- Store other information via index managed methods
- Set toggles that are picked up by our build process
What ways do we store our data:
-
Json
| String dictionary setup for complex data -
Multimessage
| Standard maya method for wiring lots of nodes -
Message
| Single message connection attribute -
msgList/datList
| This was our answer to having index managed message lists. It is a managed system for handling message connections and other data lists (strings,floats,etc) in connectable indexed lists. It does this as a series of single message attributes sharing a base name and treated as a single list by our system. You'll see these calls all over our code base -
Bool
| Simple flag for yes/no setup options - hasBallJoint -
Enum
| Multiple option setup attribute - ikSetup type, segment type, etc -
Int
| Whole number value options - joint counts, roll counts, etc -
Float
| Floating point value options - shape offset for example
Why was it necessary to do msgLists? Maya has a bug that comes up not infrequently in versions where multimessage connected objects duplicate their wiring even when you have index matters or other options set. When you need very specific data lists | say a joint chain and you don't want that list if joints getting messed up you need a solution. This was ours.
It seemed a better answer than accounting for the bug creeping up in different iterations of maya.
Last year we added the datList support mainly for name work but it's expanded some. For our MRS joint naming we use something called name tagging so that a given node is tagged in a way that when you mNode.doName() for example it is able to detect it's appropriate name by how it's tagged. Name's are inherited hierarchically and via connections.
This may be unwieldy at times but it's served it's purposes over the years. We'll go into more detail on these concepts when we get to a Workshop on making your own rigBlocks.
Generally speaking there are a number of post process we want to hit after we do a rig build. Let's walk through them.
Most of what we do will be done via MRS Builder.
These items work on a puppet wide basis where as the contextual menu items work by selected rigBlock and context.
You can find more info on the special ui section
mrsBuilder>Post>Gather Blocks
Use the post call to group all the rig blocks we've got laying around in our scene under an easily hideable group. You'd want to delete these for any rig files.
I try to keep my template files at the skeleton state and don't keep them in the built rig files.
mrsBuilder>Post>Mirror verify
If you want mirroring to work, you need to run this. This call walks our rig and maps our mirror setup following Red9's mirror setup. It does this by:
- Walking our module/puppet setup to get our hierarchical relationship
- Maps mirror modules/controls it can figure out
- Indexes Controls to follow this order
- Verifies all controls have the Red9
- Gather Space Drivers
- Grabs and space driver objects that aren't where we want them and puts them in the hierarchy. This is for our dynParent setup. Target objects don't know where to go at creation and need to be collected at the end.
mrsBuilder>Post>Up to date?
Rudimentary call at this point. Eventually we'd like this to do more than what it does. What it does do is:
- Check each rig module's version against the stored version dat on the rig Module
- Let's you know what isn't up to date.
Much room for expansion here.
mrsBuilder>Post>Gather space driver
Clean up call to gather world space dynParent group drivers to our puppet.
mrsBuilder>Post>Qss...
-
Bake set
| makes a bake set (currently targetting Unity workflow) -
Delete set
| Same but for deleting stuff -
Export Set
| Implemented in Dec 2018. This attempts to gather geo and joints in an export set
mrsBuilder>Post>Is Historically Interesting>
We're experimenting with this one on Brad (Rigging Dojo) recommendation. We turn off the ihi attribute on all nodes in our scene which makes our channel box much much cleaner. This is our first implementation and could use some work.
⚠ WARNING: Current implementation is scene wide.
mrsBuilder>Post>Puppet Mesh>
An idea we're playing with. It generates an part-based or unified mesh to use for modeling ref or a skinning frame
- Unified | Creates a unified mesh from all of the prerig loft meshes of the entire puppet so you have one mesh
- Unified[Skinned] | ...skinned to the bind skeleton
- Parts Mesh | Creates a separate mesh per part...
- Parts Mesh[Skinned] | ...skinned to the bind skeleton
- ProxyMesh[Parented] | ...parented
- Delete | Delete whatever we have stored as the puppet mesh
Remember contextual items work per rigBlock based on context. Not puppet wide unless you're in a masterSelect/below setup.
mrsBuilder>Utilities-Contextual > Rig > Verify Proxy
Creates the proxy mesh you've seen. It also replaces the direct control shapes of the rig with transparent proxy mesh shapes for easy selection
You can modify the root geo option on some rigBlocks by the proxyGeoRoot attributes. See shared settings for more info.
mrsBuilder>Utilities-Contextual > Rig > Reset Controls
Reset all the rig controls of the puppet.
mrsBuilder>Utilities-Contextual > Rig > Query Nodes
RigNodes thing we're playing with. During rig creation all the nodes created during the rig process are wired to the module so that we can cleanly delete them.
You can query them though note, there are a LOT of nodes. This will be very helpful information as we dig into rig optimization.
Here's an example report on a leg rig module.
# cgm.core.mrs.lib.block_utils : ---------------------------------------------------------------------------------------------------- #
|rigNodes_get| >> aimConstraint : 22
|rigNodes_get| >> blendTwoAttr : 9
|rigNodes_get| >> clamp : 3
|rigNodes_get| >> closestPointOnSurface : 12
|rigNodes_get| >> cluster : 2
|rigNodes_get| >> clusterHandle : 14
|rigNodes_get| >> condition : 67
|rigNodes_get| >> curveFromSurfaceIso : 4
|rigNodes_get| >> curveInfo : 3
|rigNodes_get| >> dagPose : 4
|rigNodes_get| >> distanceDimShape : 6
|rigNodes_get| >> follicle : 44
|rigNodes_get| >> group : 95
|rigNodes_get| >> groupId : 11
|rigNodes_get| >> groupParts : 11
|rigNodes_get| >> ikEffector : 3
|rigNodes_get| >> ikHandle : 3
|rigNodes_get| >> joint : 53
|rigNodes_get| >> locator : 30
|rigNodes_get| >> materialInfo : 1
|rigNodes_get| >> multiplyDivide : 31
|rigNodes_get| >> nurbsCurve : 429
|rigNodes_get| >> nurbsSurface : 12
|rigNodes_get| >> objectSet : 12
|rigNodes_get| >> orientConstraint : 14
|rigNodes_get| >> parentConstraint : 12
|rigNodes_get| >> phong : 1
|rigNodes_get| >> plusMinusAverage : 32
|rigNodes_get| >> pointConstraint : 9
|rigNodes_get| >> pointOnCurveInfo : 12
|rigNodes_get| >> poleVectorConstraint : 1
|rigNodes_get| >> rebuildCurve : 4
|rigNodes_get| >> setRange : 3
|rigNodes_get| >> shadingEngine : 1
|rigNodes_get| >> skinCluster : 4
|rigNodes_get| >> transform : 65
|rigNodes_get| >> tweak : 5
|rigNodes_get| >> unitConversion : 19
|rigNodes_get| >> Total: 1063 | (node: 'L_leg_limbBlock' | mClass: cgmRigBlock | class: <class 'cgm.core.mrs.RigBlocks.cgmRigBlock'>)
mrsBuilder>Utilities-Contextual > Rig Connect > [Connect][Disconnect]
Because we have a separate rig structure from the bind one, this connects and disconnects that setup
Here's a running list of other stuff we do.
- Delete rigBlock group
-
Shaders
- Delete duplicate shader nodes.
- Check paths for relative pathing
And after that?
- We'd skin in a final mesh if we had one
- Throw it to some animators for testing and iterate
- Generate a proxy mesh for a modeler to work from and tweak our template when we got the final mesh and rebuild.
After we rig, we're done. Right? Right?!
After we think we have everything how we want it, we should check our controls again.
When we think we have it all, then it's best to do a little test animation or throw it to an animator to get some notes for the inevitable next iteration.
==============
==============
==============
RigBlock Guide shapes are our word for handles we using during our build process to make the magic happen. These are used for things like:
- Defining points of articulation
- Visualizing asset forms, bounding boxes and joint chains
- Handles are often colored by their side so they may not always look exactly like what you see here
- Some only show up based on your rigBlock settings and state
Segment define state
The define state is the state of minimal information | points in space, vectors and volume.
The most common shape for the rigBlock root ``1`` is the locator form. Currently they are almost always white in color to make them easily visible.
These are the core dag node of the rigBlock. Moving it will move your all the sub handles of a rigBlock (providing you haven't constrained anything anywhere).
Some rigBlock types have main handles 2
to define a few items.
-
Size
| Scaling the end in some cases drives the bounding box size -
Length
| The distance from start to end defines the. Often the start is just defined by the rigBlock dag at the define state. - Sometimes there is extra information on the handles. See the marked image above.
Some of the common handles we use are:
-
End
| The end point of the rigBlock.2
on right side of image -
RP
| the vector of the rotation plane for our block4
-
Up
| the up vector for our block4
-
Lever
| Where we want our lever to be | think clavicle or the lever like hinge at the base of a finger in the hand
At times we use special handles with define handles to help show more information but not necessarily directly interact with.
Vector
Vector helpers are cylinders you rotate - 4
and 5
. They are to help see vectors in 3d when we start getting more complicated.
The bounding box 3
is simply to show a visual volume which is only there to be helpful with sizing assets when you don't have a mesh to work from.
- They are usually hidden or template locked at the form state
- If they prove cumbersome to users in time we may revisit.
Most main handles of our rigBlocks have jointLabels 6
to help you know what you're looking at.
Note:
You can control the visibility of these via the vis menu.
Segment form state
The form state is the state of shape | proportion, form.
Here is a segment with shapers and 2 sub shapers at the form state. We'll use this to walk through the shapers of this state.
The dark rounded corner handles 1
(color will vary by side). They are used for big movements and scaling. Sub shaper handles are controlled by these. What that means is that if we take one of the handles and move and scale it...
Note:
* Our other form handles are unaffected
* The form of our loft mesh however does change and scale to blend between the shape and form of handle before and after.
These are the actual curve handles 2
that our form loft runs through. Here's what happens when I take the last step and move and scale one of the loft handles.
Again, note the other loft handles are unaffected
The loft handles are what we use to really shape our proxy. For our purposes we spend a good bit of time here as it is a good way to play with character looks before committing to modeling time as well as testing proportions.
Note:
You can change the cvs on these however that data isn't currently stored in our blockDat so rebuilding will wipe it
This arrow shape 3
controls the 'up' of our segment root for rigBlock aiming and joint aiming.
You can see it all of the images above.
note::
There is a function to snap the RP define handle if one exists to the plane defined by the orient helper.
This surface is really important.
- It is the nurbs surface loft created driven by the other form handles
- It is used for proxy mesh creation and control curve casting. At rig creation this surface is used to cast rays at to find curves to then offset and connect to other curves on the surface to create the controls of our character which is how they match our form so well.
- You can affect its shape via the loft handles and the settings to some degree.
Segment form state
The prerig state is the state of dags- points of articulation, joint chains, important controls
This is our segment in prerig state and I visually toggled .template
mode on to only look at the prerig stuff.
The default prerig handle is a two part control. There is a split so that we don't have to have our rig dags match our joints unless we want to.
Dag Handle
The cubeOpen control shape 1
. This dag is to define our actual points of articulation structure.
Joint Handle
The locatorForm shape is the joint handle 2
. The prerig joint loft runs through these.
- When the joint count matches the handle count these are the exact positions that will be used
- When the count is different, the splits will happen along a curve very similar to the joint loft
Prerig IK Orientation handle
Sometimes there are special prerig handles that are designated by a colored 3d axis.
This denotes that this is an orientation handle. For example, the ik wrist, ankle would use this controls orientation rather than the joint.
Note:
These are important controls. When you see these, orient matters. The y up is used for joint orientation actions.
The much thinner lofted surface 2
running through our joint handles is for visualizing the joint chain.
There are several layers of face prerig handles.
Dag Handle
The lolipop looking handle. This is our affector that makes other stuff move. This doesn't actually become a rig control but just acts as a helper for moving the other prerig bits.
Handle
These actually matter for the rig.
- Squircle | These will be the control shapes for our major controls. Size and position them how you want. Most blocks have an offset value you push them off the surface.
- Locator Form | These are the dags for the control handles. This is where the pivot for those handle transformations will be. Generally you want them to be right with the joint chain but it's not a requirement. At rig time, the ribbons will use joints from these as influences.
Joint Helper
These are for each joint. Changing the joint number on the block will require rebuilding the prerig state to get an accurate represntation here.
-
3d Axis | The represents the joint orient and position for the skeleton state as well as rig. Most blocks have an
jointDepth
attribute to push these together into the mesh. - Semi Circle | This is the direct shape for the joint. When rigged, this will be the direct controller shape for this joint. Most blocks have an direct offset attribute to push these together offset from the proxy surface.
These are optional handles that only create under certain conditions
This is our Cog helper. There are two parts to it, the dag and the shape.
- If you select the pyramids, that's the shape and you can move it it irrespective of the dag.
- The dag is represented by the curve text 'cog'. You can pick walk up once from the shape to get it and move both
-
At rig time:
- The dag is where the rig Cog dag is generated from
- The cog shape uses our shape helper
- It only builds if we have addCog True on your rigBlock
- The joint loft represents what our joint chain will be at the skeleton state
We've toyed with the idea of having exact joint handles at the prerig state and we may end up doing that. Our main concern is that you'd have to rebuild the prerig state everytime you changed the count and the way we currently do the state load it will break your data.
You can manually move joints at the skeleton state if you just want to move a roll joint.
Space Pivot Shape
Space Pivots are our solution for having a visible constrainable space for use with our dynParent system
Originally I added this concept on Morpheus 1 as a way to have a constrainable space when animating. Say you want your hand to follow something and still have control over it. Well that's what this was designed to address. They are added to our dynamic parent system as dynamic targets.
MRS currently utilized these mainly on IK controls though they are optional item for building.
Note:
_ We have calls to switch space without that snapping via the marking menu and mrsAnimate.
_ The are created with a constrain group one level above their main dag level
bool
| Whether to add a cog helper to our rigBlock
int
| Parent joint index if attachPoint
mode is index and only then
enum
| Where we want our rigBlock to attach to it's blockParent
-
base
| 0 index on the blockParent -
end
| -1 index on the blockParent -
closest
| closest joint/dag on the blockParent -
index
| -
surface
| NOT IMPLEMENTED
float3
| The stored base size values on a given rigBlock
enum
| What shape to use for our loft. We've got a number of options
Lofted Shapes
-
TriNeg
[1] -
TriPos
[2] -
TriDown
[3] -
TriUp
[4] -
Digit
[5] -
SquareRoundDown
[6] -
SquareRoundUp
[7] -
SquircleDiamond
[8] -
WidNeg
[9] -
WidePos
[10] -
WideDown
[11] -
WideUp
[12] -
Circle
[13] -
SquareNeg
[14] -
SquarePos
[15] -
SquareDown
[16] -
SquareUp
[17] -
Squircle
[18] -
SquircleNeg
[19] -
SquirclePos
[20] -
SquircleNeg
[21] -
SquircleUp
[22] -
Diamond
[23] -
Square
[24]
Here are some arm limbs of circle and square type.
enum
| Pick the start (lever) or end (foot/pad) loft shape.
.. figure:: _static/img/coreconcepts/leg_loftSwap.gif :width: 450 :align: center :figclass: align-center
enum datList
| Option to set the loft shape per handle.
enum
| Pick the kind of loft setup you want
-
default
| One shape for all handles -
loftList
| See above
enum
| Linear/cubic loft
<img src="http://mrsdocs.cgmonastery.com/_images/limb_degree.gif
int
| Number of sides for the loft. Only visible with cubic mode.
int
| Sub split on the loft
int
| The number of shapers for a given section or block to help define it
On Limb this acts as numSubShaper does on Segment
note::
you must change setting and rebuild form to see changes.
int
| The number of sub shapers between each main shaper
int
| A main value for how many roll joints per segment of joints.
int/datList
| A datList chain of attributes to set the roll count per segment of our LIMB. Currently
enum
| If we want an end joint or not. Adds a handle to our count. For game work we often don’t want extra joints that don’t do anything. As an example with a finger, you don’t really need that last tip joint for skinning most of the time. This is for allowing that to be removed without affecting our setup.
float
| Distance direct controls offset from surface
float
| Distance main control shapes offset from surface
float
| Distance joint dags and shapes inset from surface
int
| The number of controls for a given block. Note, you must change setting and rebuild form to see changes.
Settings for the rig setup type.
enum
| Whether you want sdk groups on
-
none
| No sdk setup -
dag
| Sdk groups on controls -
only
| No rig structure, just direct controls and sdk groups (NOT FULLY IMPLEMENTED)
enum
| What kinda of ik setup for this particular rigBlock
-
none
| No IK -
rp
| Rotation plane setup -
spline
| Not fully implemented as ribbons work for the most part. Future proofing -
ribbon
| Uses our ribbon setup which has a myriad of options
enum
| The kind of ik base we want.
-
none
| No special base setup -
cube
| Cube shape base (depreciating) -
simple
| Simple handle at the end -
hips
| Does some special setup to have have localized hip control on the segment
enum
| The kind of ik end we want.
-
default
| Simple ik end shape. Cube created at end of the ik chain -
bank
| bank setup added at the end of the block -
foot
| Assumes you will have at least a ball. Single Toe setup possible too -
pad
| Assumes animal like setup with a bank -
hand
| Future proofing for hand setup we want to do -
tipBase
| IK pivot at the second to last prerig handle -
tipMid
| IK Pivot at the mid point of the chain -
tipEnd
| IK Pivot at the end of the chain
foot
The foot setup can be done with buildToe
or not...
bool
| Toggles whether to setup aim down closest axis setup to the ik controls of the rigBlock.
This snaps ik controls to the closest world vector at build and sets up a custom defaultValue
setup for these controls that must be reset with cgm reset calls to see the custom data. Manually zeroing a given control will not be bind, it will be aligned to the closest world vector
Games animators requested this and usually want it on
Other animators tend to find this annoying and want it off
There are ways of undoing this post build but it is advised to iterate and nail down your project’s settings on the first few rigs and then ensure all rigs adhere to those standards moving forward.
int
| number of space pivots to use for controls. When 0, they won't be added but constain groups will replace where those would have been
bool
| Whether to use proxyShapes for direct controls where possible
enum
|
-
none
| just attach to the ribbon with no aim -
stable
| Stablized aiming with the out vector being another follicle on the surface -
stableBlend
| Blended aim down the chain where every joint except start/end blend their aim forward and back. This option sometimes gives better results
enum
| How we want our rig dags to connect to our ribbon.
-
constraint
| connect by constraint -
matrix
| NOT IMPLEMENTED
enum
|
-
fixed
-Fixed attachment to our ribbon -
floating
| Float on the surface in an even distribution -
blend
| Add option to blend between two
enum
| Which direction from the settings targed position we want our settings cast relative to the joint axis.
up
down
out
in
note::
On a left limb, the out /in would be reversed
enum
| Where we want this rigBlock's setting placed at rig time
- start
- end
- cog | just use the cog shape. Used on default spine for example
enum
| What kind of sub chain setup we want on our LIMB/HEAD/SEGMENT
- ribbon | default setup
- curve | our newer setup. Uses a curve. added Aug 2021
- linear| WIP, not recommended
- parent | When you have matching numbers of joints as controls this will parent them under the main blend chain (or FK when no blend is present)
bool
| Whether to setup space switching on direct controls
Not sure on the speed hit on this so have it off by default.
bool
| Whether to setup for scaling
enum
| Options for seeing up squash and stretch
-
none
| no squash stretch setup -
Simple
| only use aim measure -
Single
| single channel measuring (out) -
both
| independent channels. Churro squash/stretch
bool
| Whether to wire up ability to turn off squash stretch and set scale factor per joint
bool
|
-
None
| no squash setup -
arcLength
| Use a curve to measure the length of the segment as it's more consistent than -
pointDist
| Per joint measuring on aim
float
| Peak influence on squash and stretch on the segment chain. Most often 1
float
| Minimum influence on the squash chain. Use 0 if you want the start and end to have to squash stretch from the
bool
| Whether to show our measure nodes on our rigBlock.
Settings for post processes.
bool
| Reverse the normal on the lofts. Because maya is consistently inconsistent with lofting. Between sessions. It's nutty.
enum
| What kind and whether you want a proxy geo root
-
none
| Nothing. -
loft
| Our current default -
ball
| Simple sphere
==============
The Morpheus Rig System is designed to push rigBlocks through states as we call them.
There are five states:
-
Define
| Size, vectors, points in space -
Form
| Shaping the form of our proxy -
Prerig
| Points of articulation, shapes for rigging, more -
Skeleton
| Build our joints -
Rig
| Rig it, rig it!
The define state is the barest of information for the block. What you will see will depend on the block type but you usually at least have a handle for the block root. You might see a number of visualizers:
- Bounding Box | An open cube shape driven size wize by the baseSize attr on the rigBlock
- Vector helpers | global up for the block module
- Plane | visual plane for the block to see the center line
This is by far the easiest one. At most the define state should be a dag node and is the core node of our rigBlock.
Examples of things you might do here:
- Reset transform data if desirable (like a master block)
- Verify attribute alias, min/max, lock and hide
- A rigBlock node
- Define handles
- State nulls where necessary
The form state is about shaping our proxy to give the rest of our processes the best picture of what it is we're working with and be able to generate appropriate shapes and proxy meshes later on.
-
d_wiring_template
| dictionary of data the state check calls look for to see if the state requirements are met -
msgLinks
| Message attributes to check for data -
msgLists
| cgm msgList attrs to check -
form
| The blockType's setup caller
Optional
-
templateDelete
| There is a general shared call that works for most purposes but that call checks the rigBlocks module for this call for special case needs.
The form call pushes a block from define to form state
- ""formNull** | A null to go under our rigBlock under which most of our form state items are parented for easy cleanup
- noFormNull | For those things that can't be transformed. Lofts for example
- Form handles | These are our proxy shaping handles and they are loosely connected to the subsequent prerig handles.
- Template null
- noTransform null(sometimes)
- Template handles
- Template proxy mesh (usually)
The prerig state is about joints, controls and prep for moving on to rig creation..
-
d_wiring_prerig
| dictionary of data the state check calls look for to see if the state requirements are met -
msgLinks
| Message attributes to check for data -
msgLists
| cgm msgList attrs to check -
prerig
| The blockType's setup caller
-
prerigDelete
| There is a general shared call that works for most purposes but that call checks the rigBlocks module for this call for special case needs.
For example, turning back on overrides for the form state
The prerig call pushes a block from form to prerig state
- Prerig Null | A null to go under our rigBlock under which most of our prerig state items are parented for easy cleanup
- Prerig handles | These are our control handles which then have...
- Joint Handles | These are the handles which will layout the joint chains for the given module
- Joint loft mesh | This is the result of lofting our joint handles. It is for visualizing the joint chain position relative to the proxy without regard to the form handles
- Prerig null
- Prerig handles
- Joint loft mesh (usually)
The skeleton state is simply the joint creation state where our bind joints are created, oriented, named and connected.
-
skeleton_build
call | It needs to use the BLOCKUTILS.skeleton_connectToParent
The skeleton call pushes a block from prerig to skeleton state
- Bind skeleton | Oriented, named and wired bind skeleton
- Joint chain
This is where we take all the information and bits we've laid out and make an actual rig. It's a multi call process.
-
__l_rigBuildOrder__
- List of string calls for the rigFactory calls in the module for a successful rig build.
The rig call pushes a block from skeleton to rig state. It's bit more complicated than what we've looked at before. First of all self for our calls is not our rig block but a rigFactory instance .
Instead of one call we break up or steps into separate calls as it makes troubleshooting much more easy than one behemoth call.
In general we still go through a series of specific actions regardless of the block type.
In order for a block to go to a given state, it's parent blocks must be at least that state. For example if you want to take an arm to rig, the spine must be rigged
==============
We use the term context in several places in our tools. Simply but it is those things which will be affected by any given action.
With mrsAnimate based on a given control selection you could be working in a context of control,part,puppet, with our without siblings/children/mirror.
-
self
|selected
- Only that selected block will be affected by contextual actions -
self
|active
- Only the active block ... -
self
|below
- Selected and children blocks -
root
|below
- Gets root from selected, then root below
A string datList we use for having connectable and indexable string attributes to plug into multiple things - wrist being pushed to joints, dags, controls etc for naming.
We use a naming system in our tools and setups that allows an object to know what it should be named. It does this by getting it's name dictionary. Then that name dictionary is compiled to a given name based on core setting that can be changed.
We'll flesh this more out later.
This was our answer to having index managed message lists. It is a managed system for handling message connections and other data lists (strings,floats,etc) in connectable indexed lists. It does this as a series of single message attributes sharing a base name and treated as a single list by our system. You'll see these calls all over our code base.
Why was it necessary to do msgLists?
Maya has a bug that comes up not infrequently in versions where multimessage connected objects duplicate their wiring even when you have index matters or other options set. When you need very specific data lists - say a joint chain and you don't want that list if joints getting messed up you need a solution. This was ours.
It seemed a better answer than accounting for the bug creeping up in different iterations of maya.
Last year we added the datList support mainly for name work but it's expanded some. For our MRS joint naming we use something called name tagging so that a given node is tagged in a way that when you mNode.doName() for example it is able to detect it's appropriate name by how it's tagged. Name's are inherited hierarchically and via connections.
This may be unwieldy at times but it's served it's purposes over the years. We'll go into more detail on these concepts when we get to a Workshop on making your own rigBlocks.
Our rigs utilize red9's mirroring paradigm for their setup which involves a series of attribute and mirror index values to determine how and in what order things are mirrored.
We use some language in our tools that would be helpful to understand:
-
Push
| Push my values to whatever would be in my mirrorable context -
Pull
| Pull values from my mirror to me -
Symmetry Left/Right
| Make me symmetrical with the given side being the prime axis to make that symmetry happen.
The mesh that is generated from our rigblock lofts to create approximated versions of a given asset. Check the post for more info <https://www.cgmonastery.com/2018/09/intro-to-proxy-rigs/>
_.
RP Plane
A plane as defined by the rotate plane handle to the rigblock root, then aimed at the end handle.
Used for snapping the prerig/joint handles to a consistent plane so that they might rotate over themselves in a chain rather than crookedly.