动画(animation):3D场景中重要的资源类型,用于控制场景中各种元素的运动。例如,要让场景中的人物完成走路动作,逐帧计算并设置人物每个关节的旋转角是难以实现的。因此,针对这类复杂的动画需求,3D场景资源的制作者会预先制作好动画,在模型文件中保存动画的关键帧数据以及关键帧之间的插值器类型。
ArkGraphics 3D提供播放并控制场景动画的能力,支持开发者灵活地控制动画的状态,达到预期的渲染效果。
导入相关模块。
在页面脚本中导入ArkGraphics 3D提供的核心类型,用于创建和控制3D场景、相机以及动画资源。
import { Animation, Camera, Scene, SceneResourceFactory } from '@kit.ArkGraphics3D'; 加载场景资源。
调用Scene.load()方法从应用的resources/rawfile/目录加载.glb(或.gltf)模型,并在加载完成后获取Scene对象。
Scene.load($rawfile('gltf/BrainStem/glTF/BrainStem.glb'))
.then(async (result: Scene) => {
this.scene = result;
let rf: SceneResourceFactory = this.scene.getResourceFactory();
// ...
}).catch((err: string) => {
console.error(err);
}); 获取动画并注册回调。
从scene.animations[0]获取动画资源,启用并注册onStarted()、onFinished()回调,用于监听动画播放状态或触发逻辑。
ArkGraphics 3D提供以下动画回调接口:
this.anim = this.scene.animations[0];
if (this.anim) {
this.anim.enabled = true;
// 注册回调函数
this.anim.onStarted(() => {
// ...
this.animationCallbackInvoked = 'animation on start';
});
this.anim.onFinished(() => {
// ...
this.animationCallbackInvoked = 'animation on finish';
});
// ...
} else {
console.error('No animation found in scene.');
} 创建相机与设置场景渲染参数。
通过SceneResourceFactory.createCamera()创建相机并调整观察位置。随后将加载完成的Scene封装为SceneOptions,并指定渲染类型为ModelType.SURFACE,以便通过Component3D在界面上进行渲染。
// 创建一个新相机。
this.cam = await rf.createCamera({ name: 'Camera' });
// 设置相机。
this.cam.enabled = true;
this.cam.position.z = 5;
this.sceneOpt = { scene: this.scene, modelType: ModelType.SURFACE } as SceneOptions; 构建界面与动画控制。
通过Component3D渲染3D场景,并在界面中添加按钮以控制动画播放状态。
ArkGraphics 3D提供的动画状态控制操作主要包含如下几种:
Button('start')
// ...
.onClick(async () => {
if (!this.scene || !this.scene.animations[0]) {
return;
}
this.anim = this.scene.animations[0];
this.anim.start();
});
Button('pause')
// ...
.onClick(async () => {
if (!this.scene || !this.scene.animations[0]) {
return;
}
this.anim = this.scene.animations[0];
this.anim.pause();
});
Button('stop')
// ...
.onClick(async () => {
if (!this.scene || !this.scene.animations[0]) {
return;
}
this.anim = this.scene.animations[0];
this.anim.stop();
});
Button('finish')
// ...
.onClick(async () => {
if (!this.scene || !this.scene.animations[0]) {
return;
}
this.anim = this.scene.animations[0];
this.anim.finish();
});
Button('restart')
// ...
.onClick(async () => {
if (!this.scene || !this.scene.animations[0]) {
return;
}
this.anim = this.scene.animations[0];
this.anim.restart();
});
Button('seek to 30% progress')
// ...
.onClick(async () => {
if (!this.scene || !this.scene.animations[0]) {
return;
}
this.anim = this.scene.animations[0];
// 定位到 30% 处
this.anim.seek(0.3);
});