Skip to content

Technical Direction

Max: Detecting illegal/cyclic references?

May 25, 2012

Charles

I’m working with weak references in a script controller and trying to get around an issue. If the reference is validated incorrectly from keyframe changes (moving, deleting etc) I get a hard script controller error – “illegal cyclic reference”.

It appears nothing can catch the error before the script controller does – callbacks, node events, all happen after the controller is evaluated.

I’d love a way to essentially ping the controller – but im not sure its possible as cyclic-error have to be caught early.

I may have to resort to creating a rollout to move edit keys etc, but that affects usability.

Absolute poses in weight space.

May 23, 2012

Charles

From my earlier posts if we break the idea of a pose being directly attached to weight 1:1,  we can place it anywhere in a n-dimensional space made up of multiple weights. E.g.

pose A = weight A @ 1.0
pose B = weight B @ 1.0
pose C = weight A @ 1.0 * weight B @ 1.0

The @ denotes the position along the weight governing its interpolation e.g. if the position was at 0.5 the interpolation would go from 0.0 – 1.0 (0.5) – 0.0. Likewise if the position was at 0.0 the interpolation would go from 1.0 – 0.0 and vice verse if it was at 1.0.

Zero value positions

If we include  dimensions with zero values we can have absolute interpolation. We can show this with a 2d space:

Pose A = weight A @ 1.0 * weight B @ 0.0
Pose B = weight A @ 0.0 * weight B @ 1.0

If weight A is at 1.0 and weight B at 0.0 the pose A will be at 1.0, once we start to introduce weight B,  pose A gets reduced until 0.0 when weight B is at 1.0.

Mixing additive and absolute poses

This can be done simply by deciding on the dimensionality of the poses. If we have three weights: A, B and C we could have poses for weights A and B additive and absolute for C:

Pose A = weight A @ 1.0 * weight C @ 0.0
Pose B = weight B @ 1.0 * weight C @ 0.0
Pose C  = weight C @ 1.0

Plus a corrective could still be applied:

Pose D = weight A @ 1.0 * weight B @ 1.0

Multiplying rotations..

February 27, 2012

Charles

Never really needed to do this, but if you try to scale a rotation as a quaternion all you do is scale it’s axis’. The only way I know of is summation:

(
local rot = (eulerAngles 0 45 0) as quat
local sum = quat 0 0 0 1
local scl = 2.5

 for i = 1 to floor(scl) do
(
sum += rot
)


sum += slerp (quat 0 0 0 1) rot (mod floor(scl) scl)
)

 

 

Multi-directional constraints

February 25, 2012

Charles

So Maulik over at his blog is looking into developing multi-directional constraints. I’ve recently started looking into this and wanted to share my thoughts.

Essentially bi-directional/multi-directional constraints are a sub-set of regular transform space switching – crucially the difference comes not in the abstraction and application of spaces but in the ‘messaging’ of transformations. With a standard space switch your basically pushing the source objects transform into the targets and then multiplying it by an offset transform to keep it in its original place. Something like so:

1. We store the transform of B relative to A.
2. We set A’s transform to B’s relative to A’s parent space.
3. We apply the stored offset back.

A = B * A.parent^-1 * Offset

Deriving the type of switch (rotational/entire) is a trivial case of just returning that part of the matrix. With bi-directional/multi-directional constraints everything described above is that same, what changes is the messaging of the transforms being applied. If we take the example of two characters A and B playing a game of tug-of-war, we can see that if they both pull nothing happens. Each is sending its transform notifications to the other and its causing a stalemate. This is our cyclic dependency.

To rectify this you need to control how/when transform messages are sent. On initialization of the system only one party should be sending messages to the other  – when the switch happens, you invalidate i.e switch the transform messages being sent to the controlled party with a neutral one e.g world. Now you can send transform messages in the opposite direction from the original controlled party to the controlling one:

1. B sends transform messages to A.
2. Invalidate A (so it’s messages being sent to it are neutral e.g from the world).
3. Send A’s transform messages to B.

Weak References

If you’re software supports weak referencing things get easier – basically a weak reference (in 3ds max) monitors a nodes transforms without referencing the node directly. Only when changes occur does the monitor tell its actual dependencies – so how this works in practice is that you make the weak reference to the node, (an array of targets for example) but only pass transform messages once the nodes been invalidated. There’s some trickery too – adding a blank pointer to the target so it still updates for example.

1. Two nodes: A and B.
2. A’s targets = #(B,world) – weak references without referencing the targets themselves.
3. B’s targets = #(A,world).
4. A’s transform is set to world, B’s set to A.
5. Invalidate B’s by setting it to world.
6. Set A’s transform to B’s

Once you’ve set the transform, its messages flow through correctly. No cyclic nature happens because its has been invalidated first. I will try to discuss more on the ui side of this – it gets a little tricky..

Function hierarchies, templates and schemas…

October 30, 2011

Charles

I don’t know if anyones used this idea, but I’ve been looking to a rigging frameworks recently. At a discussion I started on LinkedIn JSON was mentioned as a friendly humanly readable format for building a rigging framework – I concur, its a very simple a clean system of objects e.g:

{
“myObject” : {“a property” : “a value”, “another property” : “another value”}
}

The template

At its heart you simply want to build a skeleton apply a template to it and let it build the rest – you don’t need a visual template or guide, infact the skeleton doesn’t need to know anything about the template or vice versa – all thats needed is inputs to the template.

What is this template? To me it’s essentially a hierarchy of functions, with each function defined in a schema. The hierarchy aspect comes in when a function can pass its results to the input of the next function. The ‘intial’ function in the chain could have inputs that get passed to a gui – and the nice thing with this is that it satisfies users needs at each level. At its simplest a layman builds a skeleton, assigns a template to the whole skeleton or a part of it.

The intermediate  user doesn’t need to understand each function of the template, ( defined by the schema) but is skilled enough to build templates mix functions and pass inputs correctly.

The expert user would have full understanding of the schema that drives the functions and the code of the function itself.

The power of this approach is you have a schema that defines functions that are ordered in a template. You can change the order of the functions, remove functions etc in the template, and allow the template to point to a different schema to completely change the results. Very much how an html document uses css to structure the data.

How would a schema work? Something like this I’d imagine:

{
“schema” :
[
{“id” : “ik_system”, “path” : “path.module.def.function”, “arguments” : [{“name”:”joint”, “type” : “node”},”boolean”, “node”], “returns” : [“float”,”list”, “boolean”]}
]
}

How would a template use this schema? This is the hardest part; i’m guessing something like this:

{
“passedToGui” : [{“id” : “joint”, “type” : “node”}, {“id” : “allowStretch” : “boolean”}],

“functionHierarchy” :
[
{“id” : “buildLeg” , “type” : “ik_system”, “arguments” :[“passedToGui.joint”, “passedToJoint.allowStretch”] },
{“id” : “buildFoot” , “type” : “foot_system” , “arguments” : [“buildLeg[0]” , “passedToGui.allowStretch”, 10]
]
}

With objects/attributes following ‘.’ or ‘[#]’ methodology –  argument passing is still something i’m looking at. But the nice thing with this approach is that is could be used with pretty much any 3d package all your doing is associating functions/defs/methods to a schema and using that schema in a simple template  that users could edit ‘visually’ in the viewport or just by the script itself. Error handling would be to validate the template can work (function results allowed to be passed to other functions) using the schema.

A New Chapter

October 2, 2011

Charles

I’ve transfered to EA Capture from Bioware to start a new chapter in my career. I’ll be working on performance capture and tools development. My blogs been pretty quiet lately, but it should start to pick up with new insights!

Isolation at the neck, head or both?

May 29, 2011

Charles

Most bipedal rigs tend to have isolation at the head, but a lot of quadrupedal rigs have it at the neck – is it really a case of spreading the isolation from the chest to the head over the length of the neck? This doesn’t seem true of a giraffe – in its case the neck is a column that can be independent of the spine, with secondary bending at its center.

I’ve done both, but am thinking if there’s a commonality between – i.e an approach that can use both.

General/common approaches..

May 22, 2011

Charles

I do an general review of rigs and processes every few years. It’s by no means the be and end all of rigs – just what seems to be common and consistent throughout the industry.

With rig, essentially what’s coming across is independence and counter rotation avoidance:

Gross Torso control
Independent hips/chest control
Break joints (Bendbone) at the spine, neck, arms & legs
Isolation in the head, arms and legs in FK (local/parent/world space)
Independence of the head, hands & feet in IK (local/parent/world space)
Natural/Reverse Foot
Stretching in spine, neck, arms & legs
Pinnable Elbows/Knees

Keyable pivots are appearing in several rigs but its definitely not mainstream yet. With facial rigs, one common approach is rising through – morphs, driving on face controls driving bones.

Surface capture has made its debut with LA:Noire. Wonder if there will be a bridging of disciple between both approaches.

A request…

May 15, 2011

Charles

My girlfriend recently graduated and is looking for illustration work, if your interested please take a look at her site and get in touch.

http://mariyakarpenko.wordpress.com/

http://www.coroflot.com/mariyakarpenko

Mapping data..

March 27, 2011

Charles

Data is becoming more and more important to share across multiple rigs, skeletons, skin etc. Data itself can essentially be dependent e.g. skin weights are dependent on a model and a list of bones or non-dependent, a skeleton in the scene for example. Mapping too can either be online i.e live captured or offline i.e baked/plotted down. I’m slowly working on a format the allows for mapping different types of data in max.

My idea is to first store a list of id’s for the source objects, and a list of ids for the destination objects. An objects controller (treated as a string – exprForMaxObject) would get mapped to several other objects via there id and im guessing some sort of expression. Mapping a value to multiple values is the trickiest part and also calling an expression on them. Heres an example:

1 "root_a"                                              1

2 "root_b"                                              2
3 "spine_b"

1 bezier_float "pos.controller[1].controller" 2         3
2 "pos.controller[2].controller"                        4
3 "pos.controller[1].controller"
"@2+@3 + 10.0" 4.0                                      5

So firstly (1) we store the ids for the source objects and there names, they could be hierarchal in theory if we add an additional id for there order. Secondly we do the same for the destination objects. The meat of the mapping (3) basically stores firstly the id of the object being mapped, then the class of its controller, and the controllers “object” lastly we store the amount of target objects its going to be controlled/mapped to.(4) we store the target objects id and there controller “objects” – we don’t need to define the class of there controller object i think because its an explicit approach i.e it inherits the type from the ‘mapped object’ – this my bite me in the ass later though as for example point3 and bezier_pos look identical.

(5) lastly we call and expression using the target objects id’s – this is a little messy as i have to determine if the expression is using the id or just a regular value. “@” is an idea for the minute. In theory you could call whole functions e.g “myFunction #(@1,@2)” as long as it returns a correct type . Lastly i store an offset value, why?, well if were not passing a function but still want a offset value applied – e.g. transform offset.

This just an idea for now, I’m not sure if ill store the target id’s in parenthesis “{“,”[” etc.. It’s pretty humanly readable which is good, and easy to change objects just by changing the string the id points to. Controller objects are harder to change, its why i specify a class type way at the front for them to compare against. How this works for simpler 1:1 mapping might get messier e.g. mapping a skeleton to another skeleton for skin weights..

1 "root"
2 "spine"

1 UndefinedClass "" 1
2 ""