SmartBody characters are usually controlled via python scripts. These scripts are responsible for loading all of the features need for the character animation and then seting up the character in the environment and last functions to control the actions of the character(s).
This is a common exmaple, there are more advanced features than what is discussed in this post.
The first part of the python script to control a SmartBody character should be calls to add any assests that are need for the character animations that will be used later in the script.
smartBodyRelitivePath = "../../smartbody/data/"
# Add asset paths
scene.addAssetPath('script',smartBodyRelitivePath + 'sbm-common/scripts')
scene.addAssetPath('mesh', smartBodyRelitivePath + 'mesh')
scene.addAssetPath('mesh', smartBodyRelitivePath + 'retarget/mesh')
scene.addAssetPath('motion', smartBodyRelitivePath + 'ChrBrad')
scene.addAssetPath('motion', smartBodyRelitivePath + 'ChrRachel')
scene.addAssetPath('motion', smartBodyRelitivePath + 'retarget\motion')
scene.addAssetPath('motion', smartBodyRelitivePath + 'sbm-common/common-sk')
scene.loadAssets()
The above code first defines the relative path to the directory that contain all of the assest for character animation. These include meshes, skeletal meshes, joint maps, etc. These are usually stored in the data folder in SmartBody. As can bee seen assets for the mesh for a character is added as well as common script for that character and motion data that will be used to create the motion of the character.
The next section of the program Will configure the scene. This is much more OpenGL like and is to define the setting for the camera.
# Set scene parameters and camera
print 'Configuring scene parameters and camera'
scene.setScale(1.0)
scene.setBoolAttribute('internalAudio', True)
scene.run('default-viewer.py')
camera = getCamera()
camera.setEye(0, 2.87, 11.67)
camera.setCenter(0, 2.14, 9.81)
camera.setUpVector(SrVec(0, 1, 0))
camera.setScale(1)
camera.setFov(1.0472)
camera.setFarPlane(100)
camera.setNearPlane(0.1)
camera.setAspectRatio(0.966897)
scene.getPawn('camera').setPosition(SrVec(0, -5, 0))
The next section is a little less obvious. It first runs a script, this script loads a joint map. After a joint map is loaded it can be applied to a character in SmartBody.
# Set joint map for Brad
print 'Setting up joint map for Brad'
scene.run('zebra2-map.py')
zebra2Map = scene.getJointMapManager().getJointMap('zebra2')
bradSkeleton = scene.getSkeleton('ChrBrad.sk')
zebra2Map.applySkeleton(bradSkeleton)
zebra2Map.applyMotionRecurse('ChrBrad')
Next two more scripts are run to setup the motion animation that the character can do and next activates the parametric animation that is used for the characters.
# Retarget setup
scene.run('motion-retarget.py')
# Animation setup
scene.run('init-param-animation.py')
Now everything that needs to be done to be able to use animations is complete The last step that needs to be done so that a character can be used in the scene is described below.
# Set up Brads
print 'Adding characters into scene'
posX = -200
for i in range(1): # Only add one brad
baseName = 'ChrBrad%s' % i
brad = scene.createCharacter(baseName, '')
bradSkeleton = scene.createSkeleton('ChrBrad.sk')
brad.setSkeleton(bradSkeleton)
# Set position
bradPos = SrVec((posX + (i * 200))/100, 0, 0)
brad.setPosition(bradPos)
# Set up standard controllers
brad.createStandardControllers()
# Set deformable mesh
brad.setDoubleAttribute('deformableMeshScale', .01)
brad.setStringAttribute('deformableMesh', 'ChrBrad')
# Play idle animation
bml.execBML(baseName, '')
# Retarget character
retargetCharacter(baseName, 'ChrBrad.sk', False)
# Turn on GPU deformable geometry for all
for name in scene.getCharacterNames():
scene.command("char %s viewer deformableGPU" % name)
To add a character to the scene it needs to have a unique name ( will be seen later why ) and must be assigned a skeleton. THe rest of the code sets up the initial conditions for the character Brad: initial position, standard controllers, scale and turn on deformable geometry (by default a characters geometry is not displayed) and the initial posture for brad. A posture is the stance the character will take when no other animations are in effect.
The last part of the script is the part that you must write. After the characters have been initialized properly it is up to you to control the character as you want. For this example I wrote a simple controller that accepts information from a TCP connection so that I can control the character with another program.
class LocomotionDemo(SBScript):
def update(self, time):
# Select is a creative way of checking to see if a service has data ready to read,
# ready to write to or an exceptional condition.
r, w, e = select.select([service], [], [], 0.0)
if r: # There is something to read
data = service.recv(256)
character = 'ChrBrad0'
# The last 0 in the target is zero just so the character stays on the plane
bmlMessage = ''
print "BML Message for " + character + ": " + bmlMessage
bml.execBML(character, bmlMessage)
To add a controlling script you need to write a class and have a method called update in that class. This update method will be called every frame and you can check the characters and scene for events of interest to further animate your characters. THe code include some notes on some features of Python.
Last the script that you have created need to be given control. This is done by explicitely removing the script name if it already exsist and then creating an object that can be used to reference your update function.
NOTE: this script name is for the class that is created not the name of script file that is be used.
# Run the update script
scene.removeScript('locomotiondemo')
locomotiondemo = LocomotionDemo()
scene.addScript('locomotiondemo', locomotiondemo)
References
- http://smartbody.ict.usc.edu/forum
- http://smartbody.ict.usc.edu