Configuring the build
Configuring the build to enable animation in your app involves modifying the
build.gradle
file and importing animations into your project.
Update your app's
build.gradle
to support an imported animation model renderable, by adding the Sceneform animation dependency:dependencies { … // Support for animated model renderables. implementation "com.google.ar.sceneform:animation:1.15.0" }
Import and preview your
*.fbx
animation files to obtain an*.sfb
file containing the imported model.
Using animations at runtime
Use runtime operations to:
(Optional) Add additional property animations
Creating an animation renderable
At runtime, use ModelRenderable.Builder
to load the *.sfb
and attach it to a node in the scene, as you would do
with any ModelRenderable
:
// Create the ModelRenderable.
ModelRenderable.builder()
.setSource(this, R.raw.andy)
.build()
.thenAccept(renderable -> andyRenderable = renderable)
.exceptionally(
throwable -> {
Log.e(TAG, "Unable to load Renderable.", throwable);
return null;
});
// Attach the ModelRenderable to the node in the scene.
Node andyNode = new Node();
andyNode.setParent(arFragment.getArSceneView().getScene());
andyNode.setRenderable(andyRenderable);
Get access to the animation data
// Get the animation data called "andy_dance" from the `andyRenderable`.
AnimationData danceData = andyRenderable.getAnimationData("andy_dance");
Accessing animations based on different metadata
// Get the animation name.
danceData.getName();
To retrieve an instance of animation data, use the ModelRenderable.getAnimationData()
methods:
// Access animations by index.
numAnimations = andyRenderable.getAnimationDataCount();
danceData = andyRenderable.getAnimationData(0);
Control playback
Create a ModelAnimator
to control playback.
ModelAnimator andyAnimator = new ModelAnimator(danceData, andyRenderable);
Use start()
to play back the animation. It will stop automatically at the end.
andyAnimator.start();
To loop the animation, use setRepeatCount()
andyAnimator.setRepeatCount(<number of repeats>)
(Optional) Add property animation operations
The ModelAnimator
extends the Android Animator
class, which allows more rich
interactions such as looping,
responding to events, and non-linear interpolators.
Using SkeletonNode
to identify and attach models to bones
When you’re working with a renderable containing bones, use the
SkeletonNode
class to get access to individual bones in the skeleton by
attaching nodes to the bones. This lets you “attach” objects to bones or control
their position.
While the animation is playing, The position, scale, and orientation of the
attached node is updated by the SkeletonNode
each frame. Setting the position,
scale, or rotation of the attached node will override the bone until the next
time the bone is updated by the animation.
In the Animation sample, this is done
by attaching a Node
containing a model of a hat to the bone for Andy’s “head.”
When Andy is animated, the hat stays on his head.
Accessing information about bones
To access information about bones in a ModelRenderable
,
use the getBoneCount()
, getBoneName()
, or getBoneParent()
methods:
// Get the number of bones in the model’s skeleton.
andyRenderable.getBoneCount();
// Get the names of the bones in the model’s skeleton.
andyRenderable.getBoneName();
// Get the hierarchy of the bones in the model’s skeleton.
andyRenderable.getBoneParent();
Working with SkeletonNode
s
The SkeletonNode
class exposes the skeleton of a model in order to attach nodes to
specific bones.
To use SkeletonNode
, create a new instantiation of it and set the renderable
to the renderable that contains a model with a skeleton.
andyWithSkeleton = new SkeletonNode();
andyWithSkeleton.setRenderable(andyRenderable);
andyWithSkeleton.setParent(scene);
To attach a renderable to a specific bone, first create a new node and attach it to the bone. Add the node containing the renderable as a child of the first node. To ensure that the scale and rotation of the bone isn't used to set the relative transform of the nodes, make sure to reset the scale and position of the second node.
hatNode = new Node();
Node boneNode = new Node();
boneNode.setParent(andy);
andy.setBoneAttachment(HAT_BONE_NAME, boneNode);
hatNode.setRenderable(hatRenderable);
hatNode.setParent(boneNode);
hatNode.setWorldScale(Vector3.one());
hatNode.setWorldRotation(Quaternion.identity());
Vector3 pos = hatNode.getWorldPosition();