Behavior and Animation

Introduction

MVO provides a collection of classes that manage object "behaviors". Most commonly behaviors are those defined as keyframe-based animations that manipulate an object's position or orientation over time. By combining multiple "behaviors" for different objects and running them simultaneously, complex animations can be created. Furthermore, "actions" can be associated to objects or GUI events allowing for a high level of interactivity in the scene.

The resulting behavior data is represented as XML-Tags (see the AnimationXMLSpecification document for the complete specification) and is automatically stored with the HSF file.

Behavior Manager

All "behavior" information is stored and managed by the HBhvBehaviorManager class. There is one Behavior Manager for every HBaseModel instance. Here is an example of how to retrieve a pointer to the Behavior Manager for a particular model:


To start and stop an existing set of animations, the HBhvBehaviorManager class provides intuitive high level functions similar to a VCR like Play, Pause, Rewind and Stop. If an hsf file already contains behavior information, those functions are all that is needed to activate those animations.


The HBhvBehaviorManager contains a lists of all behavior related objects. There are functions that add new animations to the current animation list and to retrieve a particular animation and to delete animation data. This functionality will be discussed in the context of the other behavior related classes.

Defining Behaviors

To create an animation for your scene, use the HBhvBehaviorManager::AddAnimation method.
When you call this method, pass a unique name for your animation, the path of the target object and the coordinates for the object's pivot point. The method returns a pointer to the newly created animation object.

HPoint *pivot = new HPoint(0,0,0);
HBhvAnimation *driveCar = bm->AddAnimation("driveCar", "SPATH:car", pivot);

Once you have created your animation object, you can add a variety of keyframes that express the desired behavior for your animation. For instance, to maneuver our "car" through the scene, we can add several position keyframes to our "driveCar" animation using the HBhvBehaviorManager::AddPositionKeyframe method. It takes the name of your animation, the time in ticks, the position of the object and a flag indicating whether the movement is linear or spline-based.

HPoint posA(0,0,0), posB(10,10,10), posC(10,10,20);
bm->AddPositionKeyframe("driveCar", 0, posA, true);
bm->AddPositionKeyframe("driveCar", 20, posB, true);
bm->AddPositionKeyframe("driveCar", 60, posC, true);

The above sample code shows how to add three positional keyframes to our animation. The animation begins with the target object located at the origin at 0 ticks. Subsequently, two keyframes are added indicating a new position for the object at 20 and 60 ticks respectively.

In general, times are expressed as ticks per second where every tick represents an individual time-slice of the animation. The default tps value is 10. That value can be set either in the constructor of the HBhvBehaviorManager or by calling the function HBhvBehaviorManager::SetTicksPerSecond.

The Behavior Manager has a number of methods that allows you to add keyframes from rotating with HBhvBehaviorManager::AddAxisRotateKeyframe and scaling with HBhvBehaviorManager::AddScaleKeyframe to color morphing with HBhvBehaviorManager::AddColorMorphInterpolator.

Complex Animations

The methods provided by HBhvBehaviorManager are sufficient for creating most animations. However, in some cases, finer grain control is needed to author intricate and sophisticated behaviors. For these situations, MVO provides the ability to construct animations directly with HBhvAnimation, HBhvTimeline and a collection of
HBhvInterpolator classes.

To construct a keyframe based behavior, you will need a HBhvTimeline which provides a list of time values, one or more HBhvInterpolator objects that represent changing values over a time period(these can include positional values, rotation, color, etc...) and finally an HBhvAnimation object which connects the timeline, interpolators and applies various attributes to the animation(delay period, on/off, etc...). Once the animation object is assembled, you can add it to the Behavior Manager's active animation list via the HBhvBehaviorManager::AddAnimation method.

To illustrate this approach, we will create a simple animation that moves an object from position (0,0,0) to position (5,5,5) in 2 seconds:

First we instanciate the required interpolator object. For positional changes, the HBhvInterpolatorPosition class is appropriate (for a list of the various Interpolator types please refer to the MVO reference manual and/or the AnimationXMLSpecification Document).


The next step is to add two keyframe objects to this interpolator instance which represents the two positional values. The type of the keyframe objects determines the interpolation type (linear, spline based, discrete).

interpolator->Append(new HKeyframeChannelLinear(0,0,0));
interpolator->Append(new HKeyframeChannelLinear(5,5,5));

While we now have a list of keyframes, we still need to associate the correct time values (expressed in ticks) to every keyframe. (The "Ticks per Second" value can be set in the Behavior Manager and determines the absolute speed of the animation). To do that, we create a new timeline object and add the desired tick values to it:

HBhvTimeline *timeline = new HBhvTimeline();
timeline->AddKeyframe(0);
timeline->AddKeyframe(20); // 2 seconds if tps is set to 10

To associate the Interpolator with a timeline and to assign it a target (which is usually a segment identifier), an animation object is created (by passing a name for the animation and a pointer to the Behavior Manager this animation belongs to).

HBhvAnimation *animation = new HBhvAnimation("myanimation", bm);
animation->SetTimeline(timeline);
animation->AddInterpolator(interpolator);

Internally, each target of an animation is represented by an object of the HBhvTargetObject class which not only holds a target path and the associated HOOPS key (if applicable) but also defines the pivot point for the object (essentially the center of rotation). The function below either creates a new target object or uses an already existing one if the path is the same:

animation->SetTargetByPath("SPATH:car/wheel1");

Finally, we add the newly created animation to the animation list of the behaviour manager:

bm->AddAnimation(animation);

This approach works similar for all the other interpolator types.

Retrieving Animation Data

To allow manual iteration through the animation list, it is possible to retrieve a pointer to it from the Behavior Manager. It is not recommended though to use this pointer for anything but query purposes. In particular, deletion/creation of animations should always be done with the appropriate functions:

vlist_s *alist = pBehaviorManager->GetAnimationList();

It is also possible to search for a particular animation by target/interpolator type or name:

HBhvAnimation * animation = pBehaviorManager->FindAnimationByName("myanimation");
HBhvAnimation * animation = pBehaviorManager->FindAnimation("SPATH:car", "Pos");

To delete an existing animation object and to remove it from the animation list, the following sequence can be used:

HbhvAnimation * animation = pBehaviorManager->FindAnimationByName("myanimation");
pBehaviorManager->DeleteAnimation(animation);

Sensors

The HBhvSensor class provides a simple means of performing actions (like triggering animations) based on GUI events or other type of input. Commonly, a sensor is associated with visible geometry and set to respond to mouse events.

A HBhvSensor object contains pointers to one or more HBhvCondition object (which defines what kind of events activate the sensor) and one or more HbhvAction objects which performs the desired action (like triggering an animation or activating/deactivating another sensor).

To create a simple sensor that activates an animation when the user clicks on a particular object, the following steps need to be performed:

First, a new sensor object is created. The second parameter of the constructor determines if the sensor should be active by default:

HBhvSensor * sensor = new HBhvSensor("mysensor", true, pBehaviorManager);

The condition (left mouse click) is specified by creating the appropriate HBhvCondition object. The constructor takes the target for the condition (in this case the segment path to the target object), the condition identifier, a flag that indicates if the condition should be reversed and a pointer to the sensor that this condition is associated to:

HBhvCondition * condition = (HBhvCondition *)new HBhvConditionONLCLICK("SPATH:car/wheel", "ONLCLICK", false, sensor);

To perform the desired action (an animation gets activated) a HBhvAction object is created which also takes a target specifier (in this case the name of the animation to activate) the action type, an additional parameter which is type specific and the sensor that this action will be associated to:

HBhvAction * action = new HBhvAction("ANIM:myanimation", "ACTIVATE", "", sensor);

Finally to bring it all together the Conditions and Actions are added to the previously created sensor object and the sensor is in turn added to the Behavior Manager:

sensor->AddCondition(condition);
sensor->AddAction(action);
pBehaviorManager->AddSensor(sensor);

Exporting Animations

The AVI export support is provided by the HIO AVI plug-in component; its underlying 'playback' logic is tied into the MVO Behavior Manager. The user should already be familiar with the the Input/Output architecture of HOOPS/MVO as well as the Behavior Manager.

For a particular animation sequence to be saved to an AVI, an animation needs to first be setup using the Behavior Manager. Once the animation has been authored, the user can specify the output options and then export to an AVI file as described in the HOOPS HIO AVI Plug-in programming guide.

Animation Collisions

Objects can be instructed to automatically check for collisions between themselves and the environment during an animation, enabling an application to be aware of (and provide visual feedback about) colliding objects. This is achieved by calling HBhvTargetObject::SetCollision for the target object of an animation. If collisions are active for a particular object then any collision with the environment will trigger a HAnimationListener::ObjectCollisionEvent event which can be received by any class deriving from HAnimationListener.

top_level:2 prog_guide:1