Tutorial: Creating blend shapes and controllers in XSI


 

 

 

 

 

 

 

 

Part One: Asymmetrical blend shapes in XSI

 

This tutorial will help you to create shapes for a character's face and use weightmaps to create multiple shapes from just a few base shapes. The method I'm going to use works best when the head is a separate mesh to the body, otherwise cluster shapes is probably a better way to go as duplicating the entire mesh would be rather heavy. I am assuming you already have a basic knowledge of XSI before starting. You will need to build your own head to start with, and place it under a model null. You will also need to download Helge Mathee's Image to Weightmap script from http://rray.de/xsi/. Search for ImageToWM and download from the local backup, or take a look at the shapetools addon on the same site from Mohammad Abdulfatah. Very useful!

 

1. Start with a symmetrical head. A good model is essential to help form the shapes so be very careful with your edge loops and make sure they follow the lines of the mouth. Create a good UV map that is also symmetrical, or if you don't plan to texture it a straightforward xy projection will do the job. Also create a symmetry map to use when modelling the shapes.

 

2. In photoshop create a horizontal black and white gradient that blends just through the middle of the image - see example. It doesn't have to be very large, maybe 600x400. Call this l_weight_map. Flip it horizontally and save again as r_weight_map. Make sure you load these images into your scene clips memory by dragging and dropping them onto XSI.

 

3. Back in XSI create a weightmap for your head, then select the mesh and run the ImagetoWeightmap script and select the l_weight_map image. Freeze off the Imagetoweightmap module in the weightmap operator stack, and re-name the weightmap l_weight_map. Repeat the procedure for the r_weight_map.

 

4. Duplicate the head and create the shapes you need. For this example I'm using happy and sad. The symmetry map created on the base mesh is copied over also so you can use that to make the shapes symmetrical. When you're happy with the shapes freeze them to clear the operator stack.

 

5. Change to shape modelling mode, select your base mesh and choose Deform\Shape\Select shape key, and again choose your base mesh. Then choose Deform\Shape\Save shape key and select your first shape, and call it l_shape*, and repeat again selecting the same shape and call it r_shape*. This creates two shape sources of the same shape in your model's mixer.

* = the appropriate shape name

6. In the explorer navigate to the clusters underneath the main mesh and locate the shape clusters. With the l_shape cluster selected choose Deform\Shape\Connect with weightmap and scroll down to the weightmapcls cluster in your base mesh, expand it and select the l_weight_map. Repeat for the r_shape.

 

7. Open the mixer for the model and create 2 new shape tracks, and import both l_shape and r_shape. If you play with the shape slider you should see that each slider affects one side but they join together to create the full shape, so you effectively get 3 shapes out of one - bargain!

 


 

 

 

 

 

Part 2: Building a controller for the shapes

Although you could set up a set of sliders using a Custom Parameter Set very easily it can get very confusing with long lists of parameters and no visual differences between them. I prefer a more graphic approach as found in the excellent 'Stop Staring' by Jason Osipa. If you haven't read this book it is a must for facial modelling, rigging and animation, and the principles cross over easily to XSI.

1. Create an implicit square, and make it 2 units big (this is very important for the expressions).

2. Create an implicit circle (I've found 0.2 to be a good size) and parent it to the square without moving either of them.

3. Open the local kinematics page for the circle (ctrl k) and select the Pos. limit tab. Enable pos. limits for x, y and z, and set them up as in the example opposite. You should find that the circle is now limited to movement within the square.

4. Now we need to write the expressions that will link the shapes to the slider, for this example I will use happy/sad shapes. For the top half of the square we want the happy shape to take effect and the sad shape on the bottom. We also want to create falloff so that on the left side the right side shapes have no effect, and if the circle is on the right side the left side shapes have no effect.

 

5. This is where it gets tricky. I'll tackle the l_smile first, which effects the left of the character's face, or the right as we look at it. Open the model mixer and right-click on the animation divot for the shape, and choose 'set expression'.

So for this shape we want it to be full when the controller is at the top of the square, and fall off as the slider moves further left or down to the middle of the square. So we need to combine two conditional expressions.

cond( circle.kine.local.posy > 0, circle.kine.local.posy, 0 )

This states that if the circle is greater than 0 in the y axis, the value will equal the value of the circle, and if less than 0, the value will be 0.

cond( circle.kine.local.posx > 0, 1, 1 + circle.kine.local.posx )

This states that if the circle is greater than 0 in the x axis, the value will equal 1, if it is less than 0 then the value will equal 1 + the posx value, which is 0 at the centre of the square and -1 at the left.

To combine the 2 expressions we simply multiply them together, because if they are both at max it is still only 1*1=1 so we are effectively normalising the values.

cond( circle.kine.local.posy > 0, circle.kine.local.posy, 0 ) * cond( circle.kine.local.posx > 0, 1, 1 + circle.kine.local.posx )

Something I should mention is that the 'circle' part of the above expression is obviously a variable and will change depending on what you name the implicit circle in your scene.

6. The expression for the r_smile next, which is slightly different:

cond( circle.kine.local.posy > 0, circle.kine.local.posy, 0 )

This part is the same as above as you want the same effect on the y axis as the other smile.

cond( circle.kine.local.posx < 0, 1, 1 - circle.kine.local.posx )

On the x axis if the circle is less than 0, the value returned is 1, if it is greater than 0, the value is 1 - the posx value which is 0 in the centre and 1 at the right, so it gradually cancels itself out the further right it gets.

Again you combine the 2 expressions to get the following:

cond( circle.kine.local.posy > 0, circle.kine.local.posy, 0 ) * cond( circle.kine.local.posx < 0, 1, 1 - circle.kine.local.posx )

 

I could give you the other expressions for the l_sad and r_sad expressions but where would be the fun in that ;) You should be able to use the logic above to work out what the other conditional expressions are, and it will give you a greater understanding of the process.

 

The final part of the process is to connect the sliders to either the head or a camera. I find it easy to simply parent the sliders to a camera underneath the model itself, and animate the visibility of the sliders as and when Ineed them. To control the visibility you can put them all in a group, and simply toggle the visibility on and off. This can also be scripted or controlled through a synoptic to make things easier.

 

 

 

 


 

A quick shout out to those who I have learnt most of this from - Jason Osipa and Michal Doniec who kindly posted his method for blending faces with weightmaps on xsibase, and not forgetting Helge Mathee for his brilliant tools.

tutorial by matt morris 2005