Sharing skeletons when the bone configuration is the same, and applying animations to shared skeletons can be very effecient. For details on sharing skeletons, see Sharing skeletons. After sharing, be sure to bind the animation to any one SkeletalModel.
Information on how to do this when bone configurations differ is scheduled as a future addition.
Using a cache can reduce the processing load when applying animation results to more than one model.
Use of a cache can be enabled by setting true for AllocCache using options available4 when creating AnimEvaluator.
If the cache is enabled, cached results can be returned by GetResult. To update the cache, call UpdateCache.
Note that some overhead occurs because memory copies increase if the cache is enabled.
Be sure to disable use of the cache if it is not required, such as when there is only one model or frame format data is being used.
Separate animations can be configured by registering multiple animations for a single model so that elements to be animated do not overlap.
For example, you can manage animations of the upper and lower body separately, or split the ambient color and diffuse color of a material into separate animations.
This can be implented using code like the following.
// You can configure several animations when creating models from resources.
nw::gfx::SceneBuilder builder;
nw::gfx::SkeletalModel* model =
builder.Resource(resource)
.MaxAnimObjectPerGroup(2) // This line sets the maximum number of animations per model.
.CreateObject(&allocator, &deviceAllocator)
// evaluator0 and evaluator1 represent the AnimEvaluator for the upper and lower body, respectively.
// Set two animations for the model.
model->SetSkeletalAnimObject(evaluator0, 0);
model->SetSkeletalAnimObject(evaluator1, 1);
For details, see PartialAnimationDemo.
Under AnimInterpolator version 1.0.1 and earlier, members that were not to be animated were skipped during the blending process. On the other hand, under the current implementation, OriginalValue (status when the model was loaded) is used in blend calculations for members without animations. Members without animations are also included when normalizing weights.
In the case of the implementation used in version 1.0.1 and earlier, weights are normalized for all members every frame. We hope for improved performance because now the operation is performed only when necessary.
Upper body animation: A, B (neither includes lower body animation) Lower body animation: C, D (neither includes upper body animation)
If we were to blend four animations of this type, under the method using in version 1.0.1 and earlier the ultimate result is the blending A and B for the upper body and the blending of C and D for the lower body. (Note that old behavior can be restored by enabling IsOldMethod or IgnoreNoAnimMember.) If you want to get results such as in the past using the current implementation, blend A and B using one interpolator and blend C and D with a different interpolator. The same results as previous versions can be obtained by registering two Interpolators for target models when performing partial animations.
The IsOldMethod option is scheduled for abolishment in 1.3.0. To perform equivalent blending, use the IgnoreNoAnimMember option.
// The following represents the above description expressed in code form.
AnimEvaluator* evaluator_lower_0; // Lower body animation:1
AnimEvaluator* evaluator_lower_1; // Lower body animation: 2
AnimEvaluator* evaluator_upper_0; // Upper body animation 1
AnimEvaluator* evaluator_upper_1; // Upper Body Animation 2
// Code in 1.0.1 and earlier
{
AnimInterpolator* blender = AnimIntrerpolator::Builder()
.MaxAnimObjects(4)
.Create(&allocator);
blender->Bind(animGroup);
// In the old code, membes that were not animated were skipped during blending, so
// Animations for the upper and lower body are blended separately.
blender->AddAnimObject(evaluator_lower_0);
blender->AddAnimObject(evaluator_lower_1);
blender->AddAnimObject(evaluator_upper_0);
blender->AddAnimObject(evaluator_upper_1);
blender->SetWeight(0, 0.5f);
blender->SetWeight(1, 0.5f);
blender->SetWeight(2, 0.1f);
blender->SetWeight(3, 0.9f);
// Register AnimObject with the model.
model->SetSkeletalAnimObject(blender);
}
// Current code
{
// Because members without animations are blended using OriginalValue in new code,
// provide separate blenders for the upper and lower bodies.
AnimInterpolator* blender_lower = AnimInterpolator::Builder()
.MaxAnimObject(2)
.Create(&allocator);
AnimInterpolator* blender_upper = AnimInterpolator::Builder()
.MaxAnimObject(2)
.Create(&allocator);
blender_lower->AddAnimObject(evaluator_lower_0);
blender_lower->AddAnimObject(evaluator_lower_1);
blender_upper->AddAnimObject(evaluator_upper_0);
blender_upper->AddAnimObject(evaluator_upper_1);
blender_lower->SetWeight(0, 0.5f);
blender_lower->SetWeight(1, 0.5f);
blender_upper->SetWeight(0, 0.1f);
blender_upper->SetWeight(1, 0.9f);
// Set so that multiple AnimObject instances can be reigstered per model.
// Apply the blend results for the upper and lower body to each model using partial animation.
model->SetAnimObject(blender_lower, 0);
model->SetAnimObject(blender_upper, 1);
}
CONFIDENTIAL