一种最为直接的方法是为每个动画剪辑(Animatin Clip)指定开始时间,最终形成一个卡通动画(Cartoon)。
1. 设计
1.1 概述
动画的脚本如下:
- 摄像机显示了一栋带门的建筑物。
- 摄像机靠近门并停止。
- 门打开,摄像机进入房间。
- 当摄像机进入房间时,房间里的灯亮起。
- 门关上,摄像机在房间里扫了一圈。
本次目的是展示电影剪辑的制作方式,因此房间和门将简单地用没有纹理的网格制成作为例子。
1.2 执行者
- 相机(Camera) - Universal Camera
- 门(Door) - 向内打开, 铰链在右侧(旋转轴)
- 聚光灯(Lights) - 带有球体以显示位置
1.3 时间排序
以下为各个执行者在不同时间段的执行动作:
对于每个执行者,可以创建一个动画,其中包含每个定时事件的关键点。
1.4 动画
对于相机
移动相机会更改相机的位置,相机绕 y 轴旋转。
由于动画只能更改一个属性,因此相机需要两个动画。
移动摄像机,关键点将在时间 0 处,摄像机将从建筑物开始,朝向和向下移动,直到时间 3 秒刚好在门外。
当门打开时,摄像机将保持其位置 2 秒钟,然后在时间 5 秒以远离门的角度向前移动到房间,在时间 8 秒停止。
相机不会旋转 9 秒,然后相机需要 14 秒才能旋转 180 度以面向门。
相机的key frame将是它在帧 0、3、5 和 8 秒的位置以及它在 0、9 和 14 秒的旋转。
TypeScript
//for camera move forward
const movein = new BABYLON.Animation("movein", "position", frameRate, BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
const movein_keys = [];
movein_keys.push({
frame: 0,
value: new BABYLON.Vector3(0, 5, -30),
});
movein_keys.push({
frame: 3 * frameRate,
value: new BABYLON.Vector3(0, 2, -10),
});
movein_keys.push({
frame: 5 * frameRate,
value: new BABYLON.Vector3(0, 2, -10),
});
movein_keys.push({
frame: 8 * frameRate,
value: new BABYLON.Vector3(-2, 2, 3),
});
movein.setKeys(movein_keys);
//for camera to sweep round
const rotate = new BABYLON.Animation("rotate", "rotation.y", frameRate, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
const rotate_keys = [];
rotate_keys.push({
frame: 0,
value: 0,
});
rotate_keys.push({
frame: 9 * frameRate,
value: 0,
});
rotate_keys.push({
frame: 14 * frameRate,
value: Math.PI,
});
rotate.setKeys(rotate_keys);
对于门
门将围绕一个铰链旋转(y 轴)。打开和关闭旋转各需要 2 秒。
Key frame将是 0、3、5 、13 和 15 秒。
扫描的关键值将是它在帧处绕 y 轴的旋转。
TypeScript
//for door to open and close
const sweep = new BABYLON.Animation("sweep", "rotation.y", frameRate, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
const sweep_keys = [];
sweep_keys.push({
frame: 0,
value: 0,
});
sweep_keys.push({
frame: 3 * frameRate,
value: 0,
});
sweep_keys.push({
frame: 5 * frameRate,
value: Math.PI / 3,
});
sweep_keys.push({
frame: 13 * frameRate,
value: Math.PI / 3,
});
sweep_keys.push({
frame: 15 * frameRate,
value: 0,
});
sweep.setKeys(sweep_keys);
对于灯光
不同灯光的强度会有所不同,它是一组灯光。
灯的关键点是保持关闭 7 秒,在 10 秒时达到最强,直到 14 秒熄灭。
TypeScript
//for light to brighten and dim
const lightDimmer = new BABYLON.Animation("dimmer", "intensity", frameRate, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
const light_keys = [];
light_keys.push({
frame: 0,
value: 0,
});
light_keys.push({
frame: 7 * frameRate,
value: 0,
});
light_keys.push({
frame: 10 * frameRate,
value: 1,
});
light_keys.push({
frame: 14 * frameRate,
value: 1,
});
light_keys.push({
frame: 15 * frameRate,
value: 0,
});
lightDimmer.setKeys(light_keys);
2. 卡通动画
现在只需同时运行所有的动画剪辑:
TypeScript
scene.beginDirectAnimation(camera, [movein, rotate], 0, 25 * frameRate, false);
scene.beginDirectAnimation(hinge, [sweep], 0, 25 * frameRate, false);
scene.beginDirectAnimation(spotLights[0], [lightDimmer], 0, 25 * frameRate, false);
scene.beginDirectAnimation(spotLights[1], [lightDimmer.clone()], 0, 25 * frameRate, false);