Monday, December 27, 2010

[Rigging FAQ] Constraint Spaces Explained

While working on a bug report today, I remembered that the "space conversions" stuff for constraints (added during my 2.45/2.46 Constraints Refactor) often seems to be a point of contention for some (many?) riggers.
This will be a brief guide to the various spaces and how they relate to each other to hopefully act as a starting point for further investigations by yourselves.

[Side note: I'm trying to get this out between aftershocks here, so apologies in advance for anything that isn't clear]


Some Terminology First
I'll be referring to the:
  • "Owner" as the Object/Bone that the constraint lives on, and 
  • "Target" as the Object/Bone/VertexGroup that the constraint gets values from
You'll also want to be familiar with Blender's Evaluation Pipeline and the idea of "matrices" (you don't need to understand all the finer points of operations,etc. on them though). See this post to refresh your memory if you feel the need :)

How "Space Conversions" Work
As you'll be aware from the UI, constraints belong to a "constraint stack" on their owner. This simply means that one by one, each constraint down the stack operates on the owners matrix and thus applying their magic to the matrix they received. Starting from just the effects of the owner's parent + the owner's own transforms, the matrix accumulates the effects of each constraint, with each successive constraint building on the work of the preceeding ones. To achieve this, each constraint receives several matrices to use/work on: the owner's current matrix (with accumulated results), and the matrices for its targets.

So how then do "Space Conversions" fit into this system?

"Space Conversions" simply mean that a matrix has the effects of some factor, be it some parent relationship, or restpose frame of reference, etc. added or removed from itself so that the resultant matrix contains or doesn't contain these factors. This is useful so that factors can be ignored while performing some operations and then put back later, thus filtering the transforms that are taken into account.

So, the way that these conversions fit in is that they are performed before a matrix is used (i.e. usually to remove some effects), the constraint is then let loose on these matrices, and the reverse (or 'inverse') conversions are performed to reapply (or unapply) any effects that the initial conversion applied.

---

BTW, one 'easy' way to think about these spaces is to concentrate only on the locations of the Objects/Bones involved. To make things simple, let's just think of them as dots.

Now, suppose we draw one such dot on a piece of glass, and then another one at one corner. The second dot you drew is the origin for the "local" space for the dot you drew.

Now, if you grab another piece of glass, and draw another dot anywhere on that piece of glass, then placed the first piece of glass on top of this second one, lining the first piece's dotted corner with the dot on the second.

If you use the dot on the bottom-most piece of glass as your point of reference, you'll see that for the time being, the original dot is still in the same place as it was (relative to your point of reference). Now, if you move the first glass plate around, the original dot will also move, as you're moving its parent around. However, if you look within just that plate, the original dot hasn't moved - it is still the same distance as it always was from the second dot all along.

Space conversions therefore are like saying which glass plate you'd like to look at the dots from.
---

Spaces for Objects (as Owners or Targets)
  • World Space - this is just the final matrix (matrix_world) of the object. This includes the effects of the Object's Parent and the Object's own transforms (including those of previous constraints)
  • Local (Without Parent) Space - as the name says, this is just the "World Space" matrix but without the effects of the parent of the object (if it exists)
Spaces for Bones (as Owners or Targets)
  • World Space - this is equivalent to treating the bones as individual objects with their own transforms. This includes the effects of the Bone's "Pose Space" transform with the Armature Object's transforms added on top (so that the Bone's transforms are relative to the World axes instead of to the origin of the Armature/Pose)
  • Pose Space - this is like the World Space without the Armature Object transform. This (should) be matrix_pose matrix for bones, which contains ALL the transform info necessary for the bone, including restpose + parent-transforms + local transforms + constraint transforms
  • Local With Parent - this is Pose Space without the restpose only
  • Local - this is just local transforms + constraint transforms

5 comments:

  1. Hey!! This is a GREAT post!! Some time ago, I had difficulties using this stuff for rigging, and more or less I knew what I had to use for what I wanted... but I never really understood how it worked :)
    Now I do... more or less hahah I need to give this post another slow reading :D

    Also, I never found information about this. The explanation you just made should be on the Blender Manual!

    Good job! Thanks and Happy Holidays! ;)

    ReplyDelete
  2. Agree.. this should be sticky on blender wiki :)

    Thank you, Happy Holidays !

    ReplyDelete
  3. There's a project going on to fill in missing tooltips in blender, and I wrote some for space conversions in constraints. Because I don't comprehend all of the above maybe you can check them?
    Link:
    https://spreadsheets.google.com/ccc?key=0AsUOVkqtGC1KdG1nR1pRSDkxLV8zdFhzZXRKSFdScWc&hl=en&authkey=COWLv4MF

    ReplyDelete
  4. I've got to agree that this is information that should be expounded upon a lot more elsewhere. Even in the Blender API reference, it says
    "
    matrix_channel

    4x4 matrix, before constraints
    "
    and yet, from the testing I've done, the matrix_channel is clearly affected by(at least some) constraints.

    i'm currently having a great deal of difficulty deriving the contribution of constraints/drivers to a bone's rotation without baking, which i need to export animations because there's no data that simply represents the rotation of the bone itself from the world "base vector"(in other words the head>tail vector with 0 roll that produces an identity matrix on an object bone) of (0,1,0), which at least some other systems use for rotation import/export.

    i'm not sure what to do or where to go other than studying matrix transforms more but i'm just going to have to keep trying. thank you for the info.

    ReplyDelete