.. toctree:: ******************** Core Concepts ******************** Last Updated: 08.21.2020 -------- .. figure:: _static/img/mrs_x400.png :width: 200 :align: right :figclass: align-right 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. RigBlocks =============== 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. -------- Current RigBlocks ------------------ 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. .. list-table:: :widths: 15 10 30 :header-rows: 1 * - 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. -------- Basics --------- * **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 -------- Dag Structure ---------------- 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 -------- Core Settings ------------------ * 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 -------- Block work ============== Active Block ------------- 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 block * ``Utilites | Contextual Section`` | There is a button ``To Active`` that does the same. ---------- blockDat ------------- BlockDat is the what we call the core data set of a rigblock. It comprises everything necessary for the replication of a given rigblock. ---------- blockFrame ------------ 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 `More info on the site article `_. ---------- blockMirror ------------ 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. ---------- blockParent ------------- 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. ---------- blockState ------------- The given state of a rigblock. `Check the post more more info `_. ---------- Rigblock ---------- A rigblock is our rigging guide. They are setup and controlled by mrsBuilder. You can find more information at the `post for the concept `_. ---------- Template ------------ .. figure:: _static/img/terminology/horse_02.png :width: 250 :align: center :figclass: align-right 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 ================ 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. .. list-table:: :widths: 10 10 30 :header-rows: 1 * - 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 ============== BlockDat is the what we call the core data set of a rigblock. It comprises everything necessary for the replication of a given rigblock. How data is stored -------------------- We currently store data to a rigBlock as an indexed json Dict. That looks something like this: .. code-block:: python {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 * ``subShapers`` * Keyed sub dicts with data per subShaper -------- BlockFrame ============== 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 -------- Special Calls --------------- The intention is that blockFrames in the future share the special calls framework to make things work together nicely. These are from the HAND . -------- verify_drivers ^^^^^^^^^^^^^^^ Builds the drivers from our eventual rigBlocks to be driven by the system -------- verify_subBlocks ^^^^^^^^^^^^^^^^^ Checks and/or rebuilds the rigBlocks driven by this rigBlock. Typically LIMB block fingers or thumbs. -------- subBlock_align ^^^^^^^^^^^^^^^ 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 -------- UI ---- .. figure:: _static/img/coreconcepts/blockFrame_ui.png :width: 200 :align: center :figclass: align-right 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 First iteration ------------------- The first attempt at this is the HAND which creates LIMB blocks with the blockProfile of finger/thumb. -------- MetaData ============== 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. -------- Post Processes =============== 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. -------- Rig Prep ---------- .. figure:: _static/img/builder/mrsBuilder_topPostMenu.png :width: 200 :align: right :figclass: align-right 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 `_ Gather Rig Blocks ------------------- ``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. -------- Mirror Verify ---------------- ``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. -------- Up to Date? ------------- ``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. -------- Gather Space Drivers ---------------------- mrsBuilder>Post>Gather space driver Clean up call to gather world space dynParent group drivers to our puppet. -------- Qss -------- ``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 -------- isHistoricallyInteresting ------------------------------ ``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 -------- Puppetmesh ----------- ``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 -------- Utilities | Contextual ------------------------ Remember contextual items work per rigBlock based on context. Not puppet wide unless you're in a masterSelect/below setup. -------- Verify Proxy ------------- ``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. -------- Reset Controls --------------- ``mrsBuilder>Utilities-Contextual > Rig > Reset Controls `` Reset all the rig controls of the puppet. -------- Query Nodes --------------------------------- ``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. .. code:: python # 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: ) ------------ Connect/Disconnect Rig ------------------------- ``mrsBuilder>Utilities-Contextual > Rig Connect > [Connect][Disconnect]`` Because we have a separate rig structure from the bind one, this connects and disconnects that setup ------------ Other bits ------------------ 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. -------- Proxy Rigs ============== `See the post on the site `_ -------- PuppetMesh ============== `See the post on the site `_ -------- Guide Shapes ============== 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 Things to remember: * **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 -------- Define -------- .. figure:: _static/img/coreconcepts/segment_define.PNG :width: 75% :align: center :figclass: align-center Segment define state The define state is the state of minimal information | **points in space, vectors** and **volume**. -------- RigBlock Root ^^^^^^^^^^^^^^ .. figure:: _static/img/coreconcepts/rigBlock_root.png :width: 150 :align: center :figclass: align-right 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). -------- Define Handles ^^^^^^^^^^^^^^^^ Some rigBlock types have main handles ``2`` to define a few items. .. figure:: _static/img/coreconcepts/define_handle.png :width: 100% :align: center :figclass: align-center * ``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 block ``4`` * ``Up`` | the up vector for our block ``4`` * ``Lever`` | Where we want our lever to be | think clavicle or the lever like hinge at the base of a finger in the hand -------- Visual Define Helpers ^^^^^^^^^^^^^^^^^^^^^^ 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. .. figure:: _static/img/coreconcepts/vectorHandles.gif :width: 100% :align: center :figclass: align-center -------- Bounding Box ^^^^^^^^^^^^^^^ 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. .. figure:: _static/img/coreconcepts/boundingBox_02282019.png :width: 100% :align: center :figclass: align-center -------- Joint Labels ^^^^^^^^^^^^^^^ 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. `_ -------- Form ------- .. figure:: _static/img/coreconcepts/segment_form.PNG :width: 75% :align: center :figclass: align-center 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. -------- Form Handles ^^^^^^^^^^^^^^^^^^ 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. -------- Loft Handles ^^^^^^^^^^^^^^^^^^ 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 -------- Orient Helper ^^^^^^^^^^^^^^^^^^ 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. -------- Template Loft Mesh ^^^^^^^^^^^^^^^^^^^^ 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. -------- Prerig -------- .. figure:: _static/img/coreconcepts/segment_prerig.PNG :width: 75% :align: center :figclass: align-center 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. -------- Prerig Handle ^^^^^^^^^^^^^^^^^^^^ .. figure:: _static/img/coreconcepts/prerig_handles.PNG :width: 150 :align: center :figclass: align-right 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** .. figure:: _static/img/coreconcepts/prerig_specialHandle.png :width: 200 :align: center :figclass: align-right 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. -------- Joint Loft ^^^^^^^^^^^^^^^^^^^^ The much thinner lofted surface ``2`` running through our joint handles is for visualizing the joint chain. -------- Face Handles ^^^^^^^^^^^^^^^^^^^^ .. figure:: _static/img/coreconcepts/face_handles.gif :width: 500 :align: center :figclass: align-center 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. -------- Special Handles ------------------- These are optional handles that only create under certain conditions Cog Helper ^^^^^^^^^^^^^^^^^^^^ .. figure:: _static/img/coreconcepts/cog_helper.png :width: 400 :align: center :figclass: align-right 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 -------- Possibilities ------------------- Specific joint handles ^^^^^^^^^^^^^^^^^^^^^^^^ 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 Pivots =================== .. figure:: _static/img/coreconcepts/spacePivot_example.png :width: 200 :align: center :figclass: align-right 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 -------- Shared attributes =================== Define -------- addCog ^^^^^^^^ ``bool`` | Whether to add a cog helper to our rigBlock -------- attachIndex ^^^^^^^^^^^^^^ ``int`` | Parent joint index if ``attachPoint`` mode is index and only then -------- attachPoint ^^^^^^^^^^^^^^ ``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 -------- baseSize ^^^^^^^^^^^^^^ ``float3`` | The stored base size values on a given rigBlock -------- Form ----------- loftShape ^^^^^^^^^^^^^^ ``enum`` | What shape to use for our loft. We've got a number of options .. figure:: _static/img/coreconcepts/loftShapes_labeled_2.png :width: 75% :align: center :figclass: align-center 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] .. figure:: _static/img/coreconcepts/limb_loftShapes.png :width: 450 :align: center :figclass: align-center Here are some arm limbs of circle and square type. -------- loftShapeStart/End ^^^^^^^^^^^^^^^^^^^^ ``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 -------- loftList ^^^^^^^^^^^^^^ ``enum datList`` | Option to set the loft shape per handle. .. figure:: _static/img/coreconcepts/arm_loftList.gif :width: 450 :align: center :figclass: align-center -------- loftSetup ^^^^^^^^^^^^^^ ``enum`` | Pick the kind of loft setup you want * ``default`` | One shape for all handles * ``loftList`` | See above -------- loftDegree ^^^^^^^^^^^^^^ ``enum`` | Linear/cubic loft .. figure:: _static/img/coreconcepts/limb_degree.gif :width: 450 :align: center :figclass: align-center -------- loftSides ^^^^^^^^^^^^^^ ``int`` | Number of sides for the loft. Only visible with cubic mode. .. figure:: _static/img/coreconcepts/limb_loftSides.gif :width: 450 :align: center :figclass: align-center -------- loftSplit ^^^^^^^^^^^^^^ ``int`` | Sub split on the loft .. figure:: _static/img/coreconcepts/loftSplit.gif :width: 450 :align: center :figclass: align-center -------- numShapers ^^^^^^^^^^^^^^ ``int`` | The number of shapers for a given section or block to help define it On Limb this acts as numSubShaper does on Segment .. figure:: _static/img/coreconcepts/limb_numControls.gif :width: 450 :align: center :figclass: align-center .. note:: you must change setting and rebuild form to see changes. -------- numSubShapers ^^^^^^^^^^^^^^ ``int`` | The number of sub shapers between each main shaper -------- Skeleton ----------- numRoll ^^^^^^^^^^^^^^ ``int`` | A main value for how many roll joints per segment of joints. -------- rollCount ^^^^^^^^^^^^^^ ``int/datList`` | A datList chain of attributes to set the roll count per segment of our LIMB. Currently -------- Prerig ----------- buildEnd ^^^^^^^^^^^^^^ ``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. -------- conDirectOffset ^^^^^^^^^^^^^^ ``float`` | Distance direct controls offset from surface -------- controlOffset ^^^^^^^^^^^^^^ ``float`` | Distance main control shapes offset from surface -------- jointDepth ^^^^^^^^^^^^^^ ``float`` | Distance joint dags and shapes inset from surface -------- numControls ^^^^^^^^^^^^^^ ``int`` | The number of controls for a given block. Note, you must change setting and rebuild form to see changes. -------- Rig ------ Settings for the rig setup type. -------- buildSDK ^^^^^^^^^^^^^^ ``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) -------- ikSetup ^^^^^^^^^^^^^^ ``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 -------- ikBase ^^^^^^^^^^^^^^ ``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 -------- ikEnd ^^^^^^^^^^^^^^ ``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`` .. figure:: _static/img/coreconcepts/limb_footToe.gif :width: 450 :align: center :figclass: align-center or not... .. figure:: _static/img/coreconcepts/limb_footNoToe.gif :width: 450 :align: center :figclass: align-center -------- ikOrientToWorld ^^^^^^^^^^^^^^^^^ ``bool`` | Toggles whether to setup aim down closest axis setup to the ik controls of the rigBlock. At rig setup, the last prerig handle is used to figure out the closest vector to a world axis. This rotation value is used as zero for that control and there is an extra setup to allow for non zero reset values on control's base transforum attributes. -------- numSpacePivots ^^^^^^^^^^^^^^^^ ``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 -------- proxyDirect ^^^^^^^^^^^^^^ ``bool`` | Whether to use proxyShapes for direct controls where possible -------- ribbonAim ^^^^^^^^^^^^^^ ``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 -------- ribbonConnectBy(TESTING) ^^^^^^^^^^^^^^^^^^^^^^^^^ ``enum`` | How we want our rig dags to connect to our ribbon. * ``constraint`` | connect by constraint * ``matrix`` | NOT IMPLEMENTED -------- ribbonParam ^^^^^^^^^^^^^^ ``enum`` | * ``fixed`` -Fixed attachment to our ribbon * ``floating`` | Float on the surface in an even distribution * ``blend`` | Add option to blend between two -------- settingsDirection ^^^^^^^^^^^^^^^^^^ ``enum`` | Which direction from the settings targed position we want our settings cast relative to the joint axis. * ``up`` * ``down`` * ``out`` * ``in`` .. figure:: _static/img/coreconcepts/limb_settingsDirection.png :width: 450 :align: center :figclass: align-center .. note:: On a left limb, the out /in would be reversed -------- settingsPlace ^^^^^^^^^^^^^^ ``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 -------- spaceSwitch_direct ^^^^^^^^^^^^^^^^^^^ ``bool`` | Whether to setup space switching on direct controls Not sure on the speed hit on this so have it off by default. -------- scaleSetup ^^^^^^^^^^^^^^ ``bool`` | Whether to setup for scaling -------- squash ^^^^^^^^^^^^^^ ``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 -------- squashExtraControl ^^^^^^^^^^^^^^^^^^^ ``bool`` | Whether to wire up ability to turn off squash stretch and set scale factor per joint -------- squashMeasure ^^^^^^^^^^^^^^ ``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 -------- squashFactorMax ^^^^^^^^^^^^^^^^^ ``float`` | Peak influence on squash and stretch on the segment chain. Most often 1 -------- squashFactorMin ^^^^^^^^^^^^^^^^^ ``float`` | Minimum influence on the squash chain. Use 0 if you want the start and end to have to squash stretch from the -------- visMeasure ^^^^^^^^^^^^^^ ``bool`` | Whether to show our measure nodes on our rigBlock. -------- Post ---------- Settings for post processes. -------- loftReverseNormal ^^^^^^^^^^^^^^^^^^^ ``bool`` | Reverse the normal on the lofts. Because maya is consistently inconsistent with lofting. Between sessions. It's nutty. -------- proxyGeoRoot ^^^^^^^^^^^^^^ ``enum`` | What kind and whether you want a proxy geo root * ``none`` | Nothing. * ``loft`` | Our current default * ``ball`` | Simple sphere +-------------+-------------+-------------+ | |proxyNone| | |proxyBall| | |proxyLoft| | +-------------+-------------+-------------+ .. |proxyNone| image:: _static/img/coreconcepts/proxyRoot_none.png .. |proxyBall| image:: _static/img/coreconcepts/proxyRoot_ball.png .. |proxyLoft| image:: _static/img/coreconcepts/proxyRoot_loft.png -------- States ============== 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! -------- Define -------- 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 Main call ^^^^^^^^^ 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 Results ^^^^^^^^^^ * A rigBlock node * Define handles * State nulls where necessary -------- Form ----------- 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. Requirements ^^^^^^^^^^^^^^ * ``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. Main call ^^^^^^^^^^ 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. * **prerigLoftMesh** | This is the result of lofting our shapers and is important to the rest of our calls Results ^^^^^^^^^ * Template null * noTransform null(sometimes) * Template handles * Template proxy mesh (usually) -------- Prerig ------------ The prerig state is about joints, controls and prep for moving on to rig creation.. Requirements ^^^^^^^^^^^^^^^^ * ``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 Optional ^^^^^^^^^^ * ``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 Main call ^^^^^^^^^^^ 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 Results ^^^^^^^^^ * Prerig null * Prerig handles * Joint loft mesh (usually) -------- Skeleton ---------- The skeleton state is simply the joint creation state where our bind joints are created, oriented, named and connected. Requirements ^^^^^^^^^^^^^^^ * ``skeleton_build`` call | It needs to use the BLOCKUTILS.skeleton_connectToParent Main call ^^^^^^^^^^^ The skeleton call pushes a block from prerig to skeleton state * **Bind skeleton** | Oriented, named and wired bind skeleton Results ^^^^^^^^^^^ * Joint chain -------- Rig ------ 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. Requirements ^^^^^^^^^^^^^^ * ``__l_rigBuildOrder__`` - List of string calls for the rigFactory calls in the module for a successful rig build. Main calls ^^^^^^^^^^^^ 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. Things to remember ^^^^^^^^^^^^^^^^^^^ 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 -------- Updating Blocks ================ `See the post on the site `_ -------- Terminology ============== Context ----------- 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 nameList ----------- 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. ---------- Name Tags ----------- 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. ---------- 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. **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. ---------- Mirroring -------------- 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. ---------- Proxy Mesh\prioximus animaximus --------------------------------- The mesh that is generated from our rigblock lofts to create approximated versions of a given asset. `Check the post for more info `_. ---------- Rotate Plane -------------- .. figure:: _static/img/terminology/prerig_snapHandlesToRotatePlane2.png :width: 250 :align: center :figclass: align-center 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.