Scripted Operator Shoulder by Josh Murtack, certified instructor from Vancouver Film School In this tutorial you will learn how to apply and edit scripted operators to create a shoulder rig that is both automatic and animatable. When you move the implicit sphere that controls the arm, scripted operators will control the rotation of the shoulder. You will: Create a null to set the local transformation of the control objects to zero values Apply a scripted operator to one of the control objects Create a script to drive the shoulder movement Create variables to control the script without editing it. 1 of 12
Section I: Methodology An important part of 3d animation is character rigging. Without a flexible and functional level of control that provides visual feedback, the animator s job would be much more difficult. A good rig will allow the animator to quickly reproduce good poses and yet still make the inner workings accessible for finer control. To achieve the complex and natural motion of human characters, the rigger can use scripting to automate some of the movements and help speed up the animation process. With SOFTIMAGE XSI, we have the ability to apply scripted operators to almost any node. A scripted operator functions similarly to a basic expression but allows for much more functionality. Scripted operators can work with both JavaScript and VBScript, for this tutorial I have used VBScript for an easy-to-follow syntax. Scripted operators allow for Input and Output connections. Variables can also be applied, and they work through the use of custom parameters applied locally to the output connection. With this shoulder rig I am trying to reproduce the natural movement of the clavicle and scapula when the arm is rotated in all directions. While the shoulder movement has been scripted, the shoulder itself can still be animated separately. 2 of 12
Section II: Beginning the Scene Start by opening the script_op_start.scn file. Looking in the camera view, you will see some geometry approximating the shoulder skeleton of a human. There are two control spheres, shldr_ctrl_keyable and arm_ctrl respectively. The scripted operator will be applied to the local Z and Y rotation of the shldr_ctrl null which is at the top of the arm hierarchy. The local position values of the arm_ctrl sphere will drive the shldr_ctrl null rotation using this scripted op. This scene has the objects divided up into layers. The XSI skeleton (bones, chain roots, and effectors) has been hidden, and the geometry has been made unselectable. Use the layers window (6 hotkey) to make any changes to these objects. Before we begin applying the scripted operator, we need to set the arm_ctrl null positional values to 0, 0, and 0. This will make the math in our expression easier to handle. The easiest method to reset the local kinematic values of an object is to make it the child of a null located in the exact same position as itself. Bring a new null into the scene (Get > Primitive > Null) and name it arm_ctrl_zero_top. Match the position of the new null with the arm_ctrl by selecting it, using Transform > Match Translation and picking the arm_ctrl object. This will place the null in the correct position. All that s left is to make the null the parent of the implicit sphere and simply hide it to ensure it is not selected by accident (you could even add it to a layer that is unselectable). See figure 2.1. Figure 2.1: proper parenting of the arm_ctrl implicit 3 of 12
We are now going to apply the scripted operator to the local kinematics of the shldr_ctrl null object. Select the shldr_ctrl null and use the CTRL + K shortcut to open its local kinematics properties. (If you branch-select shldr_ctrl and rotate it, you can see that it is the Y and Z axes that will control the shoulder movement. X rotation of the clavicle is not really physiologically possible but it can still be keyed however.) We will start with the Y axis rotation, which will be matched with the Z axis translation of the arm_ctrl sphere. Right click on the green animation button beside the Y rotation and select Set Scripted Operator. See Figure 2.2. Figure 2.2: setting a scripted operator There is a second method to apply a scripted operator: you can simply mark the parameters which you want to control, select the object that it will be applied to and select Set Scripted Operator from the Animation menu on the bottom toolbar. A scripted operator will be created for the marked parameter. Note - even if multiple parameters are marked only the first one will be put in the Connections panel, the other parameters will still need to be added manually. When you have done this, a new window will pop up called Scripted Operator Editor. See Figure 2.3. The scripted operator editor is divided into four sections: the menu, the connections, the local code and the global code. The menu section is very similar to the Animation editor window and when you open a parameter that has a scripted operator applied to it, the animation editor changes into the scripted operator editor. Contained in the menu sections are the export options (preset, SPDL, and FCurve) and the Edit > Inspect Variables tool. Figure 2.3: Scripted Operator Editor Window 4 of 12
The connections section is where all the input and output connections are shown. It is also where the variables are displayed when you switch from Connections to Variables. A scripted operator can have many input and output connections so careful naming of the connections is important. The bottom two sections deal with the actual code of the script, the first section is enclosed in Sub Update ( ) and End Sub. This is the local code section also called the Main Editing Pane. The bottom section is known as the auxiliary editing pane. This section can be used to hold extra code such as global variables or procedures and can also be used to show a graph of the output connection with the hotkey CTRL-G or View > Show Graph. First, we need to add our input connection. We need to add the local Z axis position of the arm_ctrl sphere to our connections. Click on the New icon and browse to find the arm_ctrl node. (See Figure 2.4). Next select the kinematic > local > posz node which will add the arm_ctrl Z position to the list of Connections. Rename the Out1 node to yout and the In2 node to zin this is so we can remember which axis is coming in and which we are controlling. Figure 2.4: arm_ctrl.kine.local.posz 5 of 12
Now we need to create some variables to allow us finer control of the shoulder movement and to limit its range of motion. Change the Connections dropdown menu to Variables and then click on New. The familiar custom parameter window pops up allowing us to define the variable we are creating. (See Figure 2.5). Create one Variable of type Floating Point, give it a range from 0 to 25, set the Default Value to 10 and name it ymax. Create a second floating point variable called ymin, give it range from -25 to 0 and a Default Value of -10. These two variables will define the maximum and minimum rotation of the Y axis on our shoulder rig. Lastly we need to create a scale variable, yscl, to control how fast the shoulder will react with the arm movement. Give it a range from 0.001 to 10 to prevent zero values which could cause problems with the rotation. Set the Default Value of yscl to 2.5. See Figure 2.6. Click Apply in the scripted operator editor window. If you look at the local kinematics property editor of the shldr_ctrl null (refresh if locked) you will see the variables we created are represented as sliders at the bottom of the page. These parameters are also listed in the explorer underneath shldr_ctrl > Kinematics > Local Transform > Ori > Euler > Y > Scripted Op. Using these sliders we will be able to control our script without directly editing it and we can also animate the values if necessary. Figure 2.5: Scripted Operator Variable Figure 2.6: Final Variables 6 of 12
Section III: Scripting Now we need to write a little code. Basically we need to create a mathematical relation between the Z movement of the arm_ctrl and the Y rotation of the shldr_ctrl null. This relation can be made more complex using the variables we created earlier to give us more control of the output values. All of the script commands we add will be put in the main scripted operator window, (the middle one, not the global script pane at the bottom). First we need to define all the variables we created. By defining the variables we create shorter names to access the variables with. The VBScript command to define a variable is dim. Once the names have been defined we need to tell the scripted operator to link these to the variables we created earlier and to recalculate if we change the values. We can retrieve the values using the command: locvar = In_UpdateContext.Parameters("MyParam").Value Or the shorter version: locvar = In_UpdateContext.MyParam.Value We now have new names for the variables we created: yscl is now yscale, ymax and ymin are ymaxi and ymini respectively. Our final variable code will look like the following. 7 of 12
Code: dim yscale yscale = In_UpdateContext.yScl.value dim ymaxi ymaxi = In_UpdateContext.yMax.value dim ymini ymini = In_UpdateContext.yMin.value dim zinput zinput = zin.value (The last line is a shorter name for our input connection, we could still use the full zin.value name but zinput is a little easier to understand.) Next, we need to check if the zinput value is larger than our maximum and minimum for the movement. If the value is below the ymini or above the ymaxi then we simply return the appropriate maximum or minimum value again. If our input value is within our defined range, we need to simply apply our input value as our output value and the shoulder will move. Lastly, to ensure that we can control the movement, we will multiply our Output value by our scaling variable. To check how a variable s value relates to something else, we use if then statements. In VBScript if then statements are given in the following structure: If (input value) (comparison operation, i.e. <, >, =) (comparison value) then else (do this) (do something else) end if (this is required at the end) 8 of 12
Code: if zinput > ymaxi then Out.Value = -(ymaxi*yscale) else if zinput < ymini then Out.Value = -(ymini*yscale) else Out.Value = -(zinput*yscale) end if end if Our code is as above. The output values are made negative to correct the null s rotation in the other direction. Your final scripted operator should look like Figure 3.1: Figure 3.1: Final Code for Y Axis 9 of 12
When you finished writing this script click Apply at the top of the pane. (If you have made any errors in the script these will be reported in the Command History section of the Script Editor.) Click on Inspect at the top of the Scripted Operator pane. Three sliders appear which correspond to the three variables set for the scripted operator. Adjust the ymax slider to 25, ymin to -25 and yscl to 3. Select the arm_ctrl object and translate it around in space. You will be able to see the scripted op in action on one axis of the shoulder movement. To apply a scripted operator on the other shoulder axis, rightclick on shldr_ctrl > Kinematics > Local Transform > Ori > Euler > Z and select Set Scripted Operator. Rename Out1 to zout in the Connections page. Click on New and select arm_ctrl_zero_top > arm_ctrl > kine > local > posy to create another connection. Change the name from In2 to yin. Click on the Connections pull-down menu and select Variables. Create new variables as described previously and allocate these ranges for these variables: zmax 0 to 25, default 10 zmin -25 to 0, default -10 zscl 0.001 to 10, default 2.5 10 of 12
Next, enter the script as follows (Figure 3.2) to reflect the final code for the Z axis rotation: Figure 3.2: Final Z-axis shldr_ctrl rotation Click on Apply to apply the scripted operator and click on Inspect to open the page with the sliders for the scripted operator variables. Play around with the slider values and move the arm_ctrl object around. We now have a completed shoulder rig using the power of XSI scripted operators. Scripted operators can easily be applied to many complex rigs, but it is important to maintain the ability to key the movement also. While this rig has both 11 of 12
effectors constrained to control spheres, it is still possible to key the forward kinematics by blending the weight of these constraints to 0. I hope this tutorial was a good introduction to the power of scripted operators. Since 1987, Vancouver Film School (VFS) has offered a unique program focus with sole concentration on production of the moving image. Years ahead of the industry curve, the 3d animation and visual effects division of VFS is a 12-month, highly-intensive, hands-on program. The instructors at VFS have in-depth practical experience in the industry. As a result, the fundamental classes taught at VFS provide the skill sets and knowledge graduates need of the most widely adopted technologies in order to succeed in the highly competitive world of visual media. Josh is a Vancouver Film School grad, and brings his technical knowledge and a love of animation to the School. With a more technical background in computer programming, Josh is a useful resource for students. Recently certified by Softimage to teach XSI, he is one of the most knowledgeable XSI users at Vancouver Film School. Josh Murtack Visual Effects Assistant Instructor Vancouver Film School josh@vfs.com http://www.vfs.com Vancouver Film School. Creative. Disciplined. Focused. 2003 Avid Technology, Inc. All rights reserved. Avid, SOFTIMAGE, XSI and the XSI Logo are registered trademarks or trademarks of Avid Technology, Inc. in the United States and/or other countries. All other trademarks contained herein are the property of their respective owners. 12 of 12