Facial Animation, The Static KineState, and Dorritos?

May 23rd, 2007 by Steven Caron - Viewed 41923 times -




This is my first post at XSIBlog, so I want to thank Patrick and the other authors for keeping this going. I have always wanted to share but time is always against me not to mention having something worthy of sharing.

PLEASE NOTE: The following python scripts require this procedure to work properly.

Facial Animation

A thread started at XSI Base simply named, facial animation (questions), many facial rigging and animation concepts were shared. The two concepts discussed mostly were your traditional shape animation controlled by in scene controllers (a la Osipa) and also using Control Splines or curves with many complex rig elements that give you the desired motion. At the end of the day shape animation gets you pretty far with many character types ( realistic and stylized ) and setup time is pretty fast. The setup time is also important here, Softimage considers this a feature for FaceRobot that they market and rightfully so. Time is money, producers know this as should you! So if you will hear me out I am going to explain a way for you to continue to use shape animation and still get the low level control over subtle face movements.

The Static KineState

What is the Static KineState? I am sure anyone spending any amount of time rigging knows something about it. So lets define it for those that don’t.

The Static KineState indicates that an envelope is applied to the skeleton element. The StaticKineState is the initial position of the skeleton when the envelope was applied, and is used for envelope calculations.

If this property is storing these initial values then I must be able to change them. This is the gem that makes this rig work.

Dorritos

Now we are going to make the rig. This is not intended to be a tutorial so I apologize if I miss steps, all the project files are included at the bottom. So lets go over the rig!

I am starting with Primitive>Character>Face Man and I first made a quick “smile” shape, followed by a typical neck, head, and jaw for the character. I used nulls instead of joints for simplicity sake.

rignsmile.gif

Now I am going to make a clone of this enveloped head and immediately remove the duplicated shape cluster, envelope cluster, and the “ShapeWeights” property. The clone uses the “CopyOp”, with this we get all the deformations from the first head which include the envelope deform and shape deform. Now we need to setup the local deformers for the cloned mesh.

exploreclone.jpg

These local deformers use an “Object To Cluster” constraint. I like to use edge clusters but you could use any SubComponent you choose. So I picked an edge in the corner of the mouth and ran this handy script that creates the cluster, the object, constrains them, and makes the local deformer. You need to select a component on the original head, and run the script.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#imports
import win32com.client
from win32com.client import constants
 
#globals
xsi	= win32com.client.Dispatch( "XSI.Application" ).Application
xsiPrint = xsi.LogMessage
 
def setupDorrito():
	if xsi.Selection < 1:
		xsiPrint("Select an component!",constants.siError)
		return False
 
	root = xsi.ActiveSceneRoot
 
	#create cluster constrained null, setup its look
	clsCnsNull = root.AddNull("clsCnsNull")
	clsCnsNull.primary_icon.value = 0
	clsCnsNull.size.value = 0.1
	clsCnsNull.shadow_icon.value = 7
	clsCnsNull.shadow_colour_custom.value = 1
	clsCnsNull.B.value = 1
	clsCnsNull.G.value = 0.5
 
	#make cluster from selection
	subComponent = xsi.Selection(0).subComponent
	cnsCls = subComponent.CreateCluster("cnsCls")
 
	#constrain object to cluster
	cns = clsCnsNull.Kinematics.AddConstraint("ObjectToCluster",cnsCls)
	cns.tangent.value = 1
	cns.dirx.value = 0
	cns.diry.value = -1
	cns.upvct_active.value = 1
	cns.upx.value = 1
	cns.upy.value = 0
 
	#make dorrito
	dorrito = root.AddNull("dorrito")
	dorrito.primary_icon.value = 0
	dorrito.size.value = 0.2
	dorrito.shadow_icon.value = 8
	dorrito.shadow_colour_custom.value = 1
	dorrito.G.value = 1
	dorrito.shadow_offsetX.value = 0.1
	dorrito.shadow_scaleX.value = 0
 
	clsCnsNull.AddChild(dorrito)
	dorrito.kinematics.local.transform = XSIMath.CreateTransform()
 
setupDorrito()

The result…

setupdorrito.jpg

At work we call this controller a “Dorrito” because when the first “on the face” rig came out, one of our animators, Jason Taylor, started calling it that and it stuck. So my controller is a flat pyramid that looks like a Dorrito, so I suggest you do the same :) Now I will add an envelope to the cloned mesh and choose this Dorrito as a deformer. I now need to paint the cloned mesh’s envelope. The way I do this is add another deformer to the deformer list, set all the points to 100 % of this new deformer, and then choose the Dorrito and paint it’s influence. Once I am happy with the deformation I just remove the extra deformer from the envelope and I get zero weights except for where I painted the Dorrito’s influence. This deformer moves with the cluster constrained null, but it causes this nasty double transform when I rotate the head!

doubletransform.jpg

Why is this happening? Because you have the first envelope on the original head which is deforming the points based on the transformation of the deformers (neck, head, and jaw). Then you have a “CopyOp” and another envelope above that is getting transformed by the same movement so XSI just does it twice! What you want to do is subtract that first envelope transformation from the second envelope transformation. The Static KineState gives you access to that intial position. If you take your deformer’s Static KineState property and set it’s parameters equal to the global transform parameters of your cluster constrained null you will effectively be constantly reseting the deformer’s initial position. Here is a script to setup the expressions between the cluster constrained null and the local deformer. Just select cluster constrained null first, then the Dorrito.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#imports
import win32com.client
from win32com.client import constants
 
#globals
xsi	= win32com.client.Dispatch( "XSI.Application" ).Application
xsiPrint = xsi.LogMessage
 
def setupStaticState():
	defList = []
	clsList = []
	for i in xrange(0,len(xsi.Selection),2):
		clsList.append(xsi.Selection(i))
		defList.append(xsi.Selection(i+1))
 
	for a,b in zip(defList,clsList):
		defKineState = a.Properties("Static KineState")
		clsKine = b.Properties("Kinematics")
 
		defKineState.orix.AddExpression(clsKine.FullName + ".global.rotx")
		defKineState.oriy.AddExpression(clsKine.FullName + ".global.roty")
		defKineState.oriz.AddExpression(clsKine.FullName + ".global.rotz")
		defKineState.posx.AddExpression(clsKine.FullName + ".global.posx")
		defKineState.posy.AddExpression(clsKine.FullName + ".global.posy")
		defKineState.posz.AddExpression(clsKine.FullName + ".global.posz")
 
setupStaticState()

Now you can rotate the head or jaw and the deformer just rides the mesh, you can even use shape animation and the deformer just rides on top of that with no double transform.

nodoubletransform.jpg
Viewport Capture

Closing

There are many ways to rig a face and none should be discarded from any rigger's toolbox. I hope other riggers will get some use out of this technique and will share their work with us. Before I go, I want to thank my rigging supervisor Remi McGill for suggesting the usage of the Static KineState and Blur for allowing me to share with the community. Below are the project files which includes the scripts. Thanks for reading!

Project Files

22 Responses to “Facial Animation, The Static KineState, and Dorritos?”

  1. thanks a lot for sharing! nice reading.

    ciao
    franky

  2. matt morris says:

    Nice first blog post Steven!

    Are you aiming for some sponsorship money from Dorritos? ;)

  3. Nicolas Langlois says:

    I second that. Thanks a lot for sharing that technique. Very very interesting!

    niko

  4. Carlos Valcarcel says:

    Interesting technique, thanks for sharing. :)
    I’m just wondering why is the scale not included in the static kinestate expressions?
    I understand that the constrained null will only be constrained in position and orientation to the cluster, but if it is parented under the head and the head scaled wouldn’t you get double transformation there too? Where do you normally keep the dorritos parents in you rig hierarchy?

  5. Steven Caron says:

    normally these are under a different nested model, its kinda of “deformation” layer, and they also have a hierarchy buffer that could handle the scaling issue. i haven’t tested it but you could link up the scaling too if you would like. you could even link it too its own transform so its cancelled out

  6. Steven Caron says:

    @carlos

    i am actually going to suggest you do link up the scaling. i haven’t run into any problems not linking the scaling. the scene i provide works fine when you scale the head, no double transform on the dorrito.

  7. Carlos Valcarcel says:

    Cool, thanks for your answers :)

  8. Richard says:

    Hi there, thanks for the nice article! I’ve been wondering how to achieve this effect in XSI… you can do it in Maya by changing the deformer’s orders but I just couldn’t find a way to do it in XSI. :)

  9. Greg Punchatz says:

    VERY COOL!!! Damn I wish I would have figured this out a while ago!

    I will use this all the freaking time. Nice one!

    Greg

  10. Jason Taylor says:

    This stuff is pretty powerful if applied correctly. Ya the scaling can be wired in… should be fine… the more control on these Dorritos the better! :O)

  11. vladimir says:

    this is great.
    i was looking for a solution like this.

  12. Matthew Kapfhammer says:

    I’ve been thinking about how to make this work for the last month or so. Couldn’t have had better timing, Steven!

    I was looking around to get more info about what Richard was saying about using the deformer order in Maya and found this video Keith Lango posted about how to create a related set-up.

    http://www.keithlango.com/wordpress/?p=566

  13. Steven Caron says:

    @matthew

    i have seen keith’s facegui demo. while it is great, this wasn’t the inspiration for this blog. there was two previous ‘Dorrito’ rigs present at blur before i was tasked to conventionalize and simplify the setup. the means i think are the same, but these setups are different.

    the idea presented here is secondary deformation. you still use shapes to achieve expressions, what the ‘dorritos’ are doing is allowing local adjustment to the shape animation. it is to add subtleties to your shapes without having to go back to modeling of extra shapes and mix a ton of shapes at once. remember gollum’s first face rig? i remember bay mentioning 800 targets, yeesh?!. keith is using the controls to do all the deformation to the face, which isn’t the case for this rig. this setup doesn’t change anything about how your used to rigging. your make a rig for the character, envelope it, apply shapes, and then if you choose you can add this on top without much fuss. it doesn’t use third party tools to do attachments ( keith uses “dj_rivet” ) or deformations ( he also uses “softModManipulator” ).

    using the static kinestate i believe you can replicate keith’s setup very closely, but in my opinion shape animation is still the fastest, while staying affordable, way to do facial animation.

  14. Matthew Kapfhammer says:

    Steven,

    I probably should have chosen my words a little better in that post. Sorry about all that.

    Using the shapes gets you 90% of the way there very quickly and those ‘dorritos’ help polish that last 10%. Thanks for sharing the technique!

  15. Steven Caron says:

    no need to apologize, i just wanted my reason for posting to be clear :) i hope you have learned the important part about this posting, which is the use of the static kine state. facial animation is just one application for this, i hope others will experiment and post their findings.

  16. [...] Base Forum – facial animation (questions) und hier auch noch was in die richtung aufm xsi blog… XSIBlog » Blog Archive » Facial Animation, The Static KineState, and Dorritos? __________________ 3D Character Artist [...]

  17. I know, i’m really late here but i want to say thanks for this great tip, this really make my life a lot more easy :)

    Thank very much Steven

  18. Steven Caron says:

    i just realized this whole time i have been spelling doritos wrong!

    there is only one r in dorito

  19. gavin h says:

    is there anyone who can translate this into Jscript plz…
    im getting errors with python. its very fustrating, i have 0 experience with python environment.

  20. Steven Caron says:

    what errors are you getting with python?

  21. Scabyx says:

    Hi Steven,

    Many many thanks for sharing this technique. A bit late, but full of passion i have tried it out on my character.

    This technique is amazin, and if u semd me your mail on the adress above, i wiil gladly show you how i interpreted your nice setup onto my characters face.

    I hope i hear from you soon.

    Yours

    Scabyx

    “Blur” rulez

  22. Steven Caron says:

    this code will allow setupDorito() function to work without dispatch hack.

    https://gist.github.com/3896418