# 简介
在 three.js
中动画也是很重要的一环。在使用软件创建模型时,一般都会创建模型的骨骼动画用于在开发中使用。下面我们加载 .fbx
格式的文件模型(它除了包含几何、材质信息,可以存储骨骼动画等数据)来实现动画。
# AnimationMixer
- 动画混合器是用于场景中特定对象的动画的播放器。当场景中的多个对象独立动画时,每个对象都可以使用同一个动画混合器。
- 参数:
rootObject
混合器播放的动画所属的对象。就是包含动画模型的场景对象。 - 常用参数和属性:
.time
全局的混合器时间。.clipAction(AnimationClip)
返回所传入的剪辑参数的AnimationAction
对象。AnimationAction
用来调度存储在AnimationClip
中的动画。
AnimationClip
动画剪辑,是一个可重用的关键帧轨道集,它代表动画。
.getRoot()
返回混合器的根对象。.update()
推进混合器时间并更新动画。在渲染函数中调用更新动画。
# 开始使用
# 基础场景
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8" /> | |
<title>学习</title> | |
</head> | |
<body> | |
<canvas id="c2d" class="c2d" width="1000" height="500"></canvas> | |
<script type="module"> | |
import * as THREE from './file/three.js-dev/build/three.module.js' | |
import { OrbitControls } from './file/three.js-dev/examples/jsm/controls/OrbitControls.js' | |
import { FBXLoader } from './file/three.js-dev/examples/jsm/loaders/FBXLoader.js' | |
const canvas = document.querySelector('#c2d') | |
// 渲染器 | |
const renderer = new THREE.WebGLRenderer({ canvas }) | |
const fov = 40 // 视野范围 | |
const aspect = 2 // 相机默认值 画布的宽高比 | |
const near = 0.1 // 近平面 | |
const far = 10000 // 远平面 | |
// 透视投影相机 | |
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far) | |
camera.position.set(1000, 500, 1500) | |
camera.lookAt(0, 0, 0) | |
// 控制相机 | |
const controls = new OrbitControls(camera, canvas) | |
controls.update() | |
// 场景 | |
const scene = new THREE.Scene() | |
// 背景 | |
scene.background = new THREE.Color(0x87ceeb) | |
// 雾 | |
scene.fog = new THREE.Fog(0x87ceeb, 200, 10000) | |
// 辅助 | |
const axes = new THREE.AxisHelper(700) | |
scene.add(axes) | |
{ | |
// 灯光 | |
const skyColor = 0xffffff // 天空 白色 | |
const groundColor = 0x000000 // 地面 黑色 | |
const intensity = 1 | |
const light = new THREE.HemisphereLight(skyColor, groundColor, intensity) | |
scene.add(light) | |
} | |
{ | |
// 地面 | |
const loader = new THREE.TextureLoader() | |
const texture = loader.load('./file/23/1.jpg') | |
texture.wrapS = THREE.RepeatWrapping | |
texture.wrapT = THREE.RepeatWrapping | |
texture.magFilter = THREE.NearestFilter | |
// 纹理 重复 | |
texture.repeat.set(100, 100) | |
const planeGeo = new THREE.PlaneGeometry(10000, 10000) | |
const planeMat = new THREE.MeshPhongMaterial({ | |
map: texture, | |
side: THREE.DoubleSide | |
}) | |
const mesh = new THREE.Mesh(planeGeo, planeMat) | |
mesh.rotation.x = Math.PI * -0.5 | |
scene.add(mesh) | |
} | |
// 渲染 | |
function render() { | |
renderer.render(scene, camera) | |
requestAnimationFrame(render) | |
} | |
requestAnimationFrame(render) | |
</script> | |
</body> | |
</html> |
# 加载.fbx 模型
const loader = new FBXLoader() | |
loader.load('./file/Naruto.fbx', function (mesh) { | |
console.log(' AnimationMixer 动画混合器(二十四).html ~ line 73 ~ mesh', mesh) | |
mesh.position.y = 110 | |
scene.add(mesh) | |
}) |
- 可以看见解析出来的对象中,存在
animations
属性并且有 27 条数据,代表有 27 个动画。
# 使用 AnimationMixer 控制动画
# 1. 创建全局参数获取动画相关对象。
let actions = [] // 所有的动画数组 | |
let gui = {} // 动画控制 | |
let mixer = null // AnimationMixer 对象 |
# 2. 解析动画,并执行第 24 个动画。
mixer = new THREE.AnimationMixer(mesh) | |
for (var i = 0; i < mesh.animations.length; i++) { | |
actions[i] = mixer.clipAction(mesh.animations[i]) | |
} | |
gui['action'] = function (s) { | |
for (var j = 0; j < actions.length; j++) { | |
if (j === s) { | |
actions[j].play() | |
} else { | |
actions[j].stop() | |
} | |
} | |
} | |
// 第 24 个动作是鸣人站立的动作 | |
gui['action'](24) |
- 在渲染函数中执行
.update()
函数,推进动画进行。
.Clock()
该对象用于跟踪时间。
const clock = new THREE.Clock() | |
// 渲染 | |
function render() { | |
const time = clock.getDelta() | |
if (mixer) { | |
mixer.update(time) | |
} | |
renderer.render(scene, camera) | |
requestAnimationFrame(render) | |
} |
# 通过键盘空格切换动画
- 监听键盘事件,调用
gui
对象执行新的动画。
let keyNum = 24 // 动作 | |
document.onkeydown = function (e) { | |
if (e && e.keyCode == 32) { | |
if (keyNum === 27) { | |
keyNum = 1 | |
} | |
keyNum += 1 | |
gui['action'](keyNum) | |
} | |
} |