学习threejs,对模型多个动画切换展示
👨⚕️ 主页: gis分享者
👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨⚕️ 收录于专栏:threejs gis工程师
文章目录
- 一、🍀前言
- 1.1 ☘️THREE.AnimationMixer 动画混合器
- 二、🍀对模型多个动画切换展示
- 1. ☘️实现思路
- 2. ☘️代码样例
一、🍀前言
本文详细介绍如何基于threejs在三维场景中对模型多个动画切换展示,亲测可用。希望能帮助到您。一起学习,加油!加油!
1.1 ☘️THREE.AnimationMixer 动画混合器
THREE.AnimationMixer动画混合器是用于场景中特定对象的动画的播放器。当场景中的多个对象独立动画时,每个对象都可以使用同一个动画混合器。
创建方法:
AnimationMixer( rootObject : Object3D )
rootObject 是 混合器播放的动画所属的对象
属性:
time:Number 全局的混合器时间(单位秒; 混合器创建的时刻记作0时刻)。
timeScale:全局时间(mixer time)的比例因子。
说明: 将混合器的时间比例设为0, 稍后再设置为1,可以暂停/取消暂停由该混合器控制的所有动作。
方法:
clipAction(clip : AnimationClip, optionalRoot : Object3D):AnimationAction 返回所传入的剪辑参数的AnimationAction, 根对象参数可选,默认值为混合器的默认根对象。第一个参数可以是动画剪辑(AnimationClip)对象或者动画剪辑的名称。
如果不存在符合传入的剪辑和根对象这两个参数的动作, 该方法将会创建一个。传入相同的参数多次调用将会返回同一个剪辑实例。
existingAction (clip : AnimationClip, optionalRoot : Object3D) : AnimationAction 返回传入剪辑的已有AnimationAction, 根对象参数可选,默认值为混合器的默认根对象。
第一个参数可以是动画剪辑(AnimationClip)对象或者动画剪辑的名称。
update (deltaTimeInSeconds : Number) : AnimationMixer 推进混合器时间并更新动画。
deltaTimeInSeconds 参数表示当前帧与前一帧之间的时间差(以秒为单位)。
二、🍀对模型多个动画切换展示
1. ☘️实现思路
- 1、初始化renderer渲染器
- 2、初始化Scene三维场景
- 3、初始化camera相机,定义相机位置 camera.position.set,设置相机方向camera.lookAt。
- 4、初始化THREE.AmbientLight环境光源,scene场景加入环境光源,初始化THREE.PointLight点光源,设置点光源位置,设置点光源投影,scene添加点光源。
- 5、加载几何模型:创建THREE.AxesHelper坐标辅助工具,创建THREE.PlaneBufferGeometry平面几何体、THREE.GridHelper地板割线,scene场景中加入创建的平面几何体和地板割线。创建gui控件datGui。通过THREE.FBXLoader类加载 ‘Naruto.fbx’ 模型文件mesh,在加载模型的回调函数中,定义mesh动画,datGui加入动画控制。具体实现参考代码样例。
- 6、加入controls控制,加入stats监控器,监控帧数信息。
2. ☘️代码样例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>learn50(对模型多个动画切换展示)</title>
<script src="lib/threejs/127/three.js-master/build/three.js"></script>
<script src="lib/threejs/127/three.js-master/examples/js/controls/OrbitControls.js"></script>
<!--<script src="lib/js/inflate.min.js"></script>-->
<script src="lib/threejs/127/three.js-master/examples/js/loaders/FBXLoader.js"></script>
<script src="lib/threejs/127/three.js-master/examples/js/libs/fflate.min.js"></script>
<script src="lib/threejs/127/three.js-master/examples/js/libs/stats.min.js"></script>
<script src="lib/threejs/127/three.js-master/examples/js/libs/dat.gui.min.js"></script>
<script src="lib/js/Detector.js"></script>
</head>
<style type="text/css">
html, body {
margin: 0;
height: 100%;
}
canvas {
display: block;
}
</style>
<body onload="draw()">
</body>
<script>
var renderer
var initRender = () => {
renderer = new THREE.WebGLRenderer({antialias: true})
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setClearColor(0xeeeeee)
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true
document.body.appendChild(renderer.domElement)
}
var scene
var initScene = () => {
scene = new THREE.Scene()
scene.backgroundColor = new THREE.Color(0xa0a0a0)
scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000)
}
var camera
var initCamera = () => {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000)
camera.position.set(100, 200, 300)
}
var light
var initLight = () => {
scene.add(new THREE.AmbientLight(0x444444))
light = new THREE.DirectionalLight(0xffffff)
light.position.set(0, 200, 100)
light.castShadow = true
light.shadow.camera.top = 180
light.shadow.camera.bottom = -100
light.shadow.camera.left = -120
light.shadow.camera.right = 120
scene.add(light)
}
var gui, datGui, meshHelper, mixer
var initGui = () => {
gui = {
helper: true
}
datGui = new dat.GUI()
datGui.add(gui, 'helper').onChange(e => {
meshHelper.visible = e
})
}
var initModel = () => {
var helper = new THREE.AxesHelper(50)
scene.add(helper)
var mesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(2000, 2000), new THREE.MeshPhongMaterial({
color: 0xffffff,
depthWrite: false
}))
mesh.receiveShadow = true
mesh.rotation.x = -0.5 * Math.PI
scene.add(mesh)
// var planeGeometry = new THREE.PlaneBufferGeometry(2000, 2000)
// var planeMatarial = new THREE.MeshPhongMaterial({
// color: 0xffffff,
// depthWrite: false
// })
// var plane = new THREE.Mesh(planeGeometry, planeMatarial)
// plane.rotation.x = -0.5 * Math.PI
// plane.position.y = -0
// plane.receiveShadow = true
// scene.add(plane)
// 添加地板割线
var grid = new THREE.GridHelper(2000, 20, 0x000000, 0x000000)
grid.material.opacity = 0.2
grid.material.transparent = true
scene.add(grid)
var loader = new THREE.FBXLoader()
loader.load('data/model/NarutoFbx/Naruto.fbx', mesh => {
meshHelper = new THREE.SkeletonHelper(mesh)
scene.add(meshHelper)
mesh.traverse(child => {
if (child.isMesh) {
child.castShadow = true
child.receiveShadow = true
}
})
mixer = mesh.mixer = new THREE.AnimationMixer(mesh)
var actions = []
var animations = datGui.addFolder('animations')
var createAction = (i) => {
actions[i] = mixer.clipAction(mesh.animations[i])
gui['action' + i] = () => {
for (var j = 0; j < actions.length; j++) {
if (j === i) {
actions[j].play()
} else {
actions[j].stop()
}
}
}
animations.add(gui, 'action' + i)
}
for (var i = 0; i < mesh.animations.length; i++) {
createAction(i)
}
gui.stop = () => {
for (var i = 0; i < actions.length; i++) {
actions[i].stop()
}
}
datGui.add(gui, 'stop')
mesh.position.y += 100
scene.add(mesh)
})
}
var stats
var initStats = () => {
stats = new Stats()
document.body.appendChild(stats.dom)
}
var controls
var initControls = () => {
controls = new THREE.OrbitControls(camera, renderer.domElement)
controls.enableDamping = true
}
var clock = new THREE.Clock()
var render = () => {
var time = clock.getDelta()
if (mixer) {
mixer.update(time)
}
controls.update()
}
var onWindowResize = () => {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
render.setSize(window.innerWidth, window.innerHeight)
}
var animate = () => {
render()
stats.update()
renderer.render(scene, camera)
requestAnimationFrame(animate)
}
var draw = () => {
initRender()
initScene()
initCamera()
initGui()
initLight()
initModel()
initStats()
initControls()
animate()
window.onresize = onWindowResize
}
</script>
</html>
效果如下: