来源 :https://blog.csdn.net/qq_30100043/article/details/80087471
简介
上一节本想直接了结动画这一章。最后一想,没有做过模型动画切换的案例。就此,再加一章,关于模型多个动画之间如何切换的问题。
案例实现
案例查看地址:http://www.wjceo.com/blog/threejs/2018-04-25/153.html
首先,我们需要先将模型导入,之前案例已经讲过如何导入,这里就不赘述。
//加载模型var loader = new THREE.FBXLoader();loader.load("/lib/models/fbx/Naruto.fbx", function (mesh) { ???mesh.position.y += 100; ???scene.add(mesh);});导入模型以后,我们需要查看当前模型的动画的长度,也就是mesh.animations的长度,如果只有一个长度,代表只有一个动画,如果有多个,就是多个动画的模型。然后我们需要遍历mesh.animations数组,为每个动画创建一个action,作为后面调用:
mixer = mesh.mixer = new THREE.AnimationMixer(mesh);var actions = []; //所有的动画数组for(var i=0; i<mesh.animations.length; i++){ ???actions[i] = mixer.clipAction(mesh.animations[i]);}在切换动画的时候,我们需要做的就是,将当前的所有的action除去需要播放的那个action全部暂停动画播放,让需要播放的哪一个动画调用play()事件:
gui["action"+i] = function () { ???for(var j=0; j<actions.length; j++){ ???????if(j === i){ ???????????actions[j].play(); ???????} ???????else{ ???????????actions[j].stop(); ???????} ???}};animations.add(gui, "action"+i);这样,我们就实现了对模型的动画切换。
案例代码
<!DOCTYPE html><html lang="en"><head> ???<meta charset="UTF-8"> ???<title>Title</title> ???<style type="text/css"> ???????html, body { ???????????margin: 0; ???????????height: 100%; ???????} ???????canvas { ???????????display: block; ???????} ???</style></head><body onload="draw();"></body><script src="https://cdn.bootcss.com/three.js/91/three.min.js"></script><script src="/lib/js/libs/inflate.min.js"></script><script src="/lib/js/loaders/FBXLoader.js"></script><script src="/lib/js/controls/OrbitControls.js"></script><script src="https://cdn.bootcss.com/stats.js/r17/Stats.min.js"></script><script src="https://cdn.bootcss.com/dat-gui/0.7.1/dat.gui.min.js"></script><script src="/lib/js/Detector.js"></script><script> ???var renderer, camera, scene, gui, light, stats, controls, meshHelper, mixer, action,datGui; ???var clock = new THREE.Clock(); ???function initRender() { ???????renderer = new THREE.WebGLRenderer({antialias: true}); ???????renderer.setPixelRatio(window.devicePixelRatio); ???????renderer.setSize(window.innerWidth, window.innerHeight); ???????renderer.setClearColor(0xeeeeee); ???????renderer.shadowMap.enabled = true; ???????//告诉渲染器需要阴影效果 ???????document.body.appendChild(renderer.domElement); ???} ???function initCamera() { ???????camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000); ???????camera.position.set(100, 200, 300 ); ???} ???function initScene() { ???????scene = new THREE.Scene(); ???????scene.background = new THREE.Color( 0xa0a0a0 ); ???????scene.fog = new THREE.Fog( 0xa0a0a0, 200, 1000 ); ???} ???//初始化dat.GUI简化试验流程 ???function initGui() { ???????//声明一个保存需求修改的相关数据的对象 ???????gui = { ???????????helper:true //模型辅助线 ???????}; ???????datGui = new dat.GUI(); ???????//将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值) ???????datGui.add(gui, "helper").onChange(function (e) { ???????????meshHelper.visible = e; ???????}) ???} ???function 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; ???????//告诉平行光需要开启阴影投射 ???????light.castShadow = true; ???????scene.add(light); ???} ???function 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.rotation.x = - Math.PI / 2; ???????mesh.receiveShadow = true; ???????scene.add( mesh ); ???????//添加地板割线 ???????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("/lib/models/fbx/Naruto.fbx", function (mesh) { ???????????console.log(mesh); ???????????//添加骨骼辅助 ???????????meshHelper = new THREE.SkeletonHelper(mesh); ???????????scene.add(meshHelper); ???????????//设置模型的每个部位都可以投影 ???????????mesh.traverse( function ( child ) { ???????????????if ( child.isMesh ) { ???????????????????child.castShadow = true; ???????????????????child.receiveShadow = true; ???????????????} ???????????} ); ???????????//AnimationMixer是场景中特定对象的动画播放器。当场景中的多个对象独立动画时,可以为每个对象使用一个AnimationMixer ???????????mixer = mesh.mixer = new THREE.AnimationMixer(mesh); ???????????//mixer.clipAction 返回一个可以控制动画的AnimationAction对象 ?参数需要一个AnimationClip 对象 ???????????//AnimationAction.setDuration 设置一个循环所需要的时间,当前设置了一秒 ???????????//告诉AnimationAction启动该动作 ???????????//action = mixer.clipAction(mesh.animations[0]); ???????????//action.play(); ???????????var actions = []; //所有的动画数组 ???????????var animations = datGui.addFolder("animations"); ???????????for(var i=0; i<mesh.animations.length; i++){ ???????????????createAction(i); ???????????} ???????????function createAction(i){ ???????????????actions[i] = mixer.clipAction(mesh.animations[i]); ???????????????gui["action"+i] = function () { ???????????????????for(var j=0; j<actions.length; j++){ ???????????????????????if(j === i){ ???????????????????????????actions[j].play(); ???????????????????????} ???????????????????????else{ ???????????????????????????actions[j].stop(); ???????????????????????} ???????????????????} ???????????????}; ???????????????animations.add(gui, "action"+i); ???????????} ???????????//添加暂停所有动画的按键 ???????????gui.stop = function(){ ???????????????for(var i=0; i<actions.length; i++){ ???????????????????actions[i].stop(); ???????????????} ???????????}; ???????????datGui.add(gui, "stop"); ???????????mesh.position.y += 100; ???????????scene.add(mesh); ???????}); ???} ???//初始化性能插件 ???function initStats() { ???????stats = new Stats(); ???????document.body.appendChild(stats.dom); ???} ???function initControls() { ???????controls = new THREE.OrbitControls(camera, renderer.domElement); ???????//设置控制器的中心点 ???????//controls.target.set( 0, 100, 0 ); ???????// 如果使用animate方法时,将此函数删除 ???????//controls.addEventListener( ‘change‘, render ); ???????// 使动画循环使用时阻尼或自转 意思是否有惯性 ???????controls.enableDamping = true; ???????//动态阻尼系数 就是鼠标拖拽旋转灵敏度 ???????//controls.dampingFactor = 0.25; ???????//是否可以缩放 ???????controls.enableZoom = true; ???????//是否自动旋转 ???????controls.autoRotate = false; ???????controls.autoRotateSpeed = 0.5; ???????//设置相机距离原点的最远距离 ???????controls.minDistance = 1; ???????//设置相机距离原点的最远距离 ???????controls.maxDistance = 2000; ???????//是否开启右键拖拽 ???????controls.enablePan = true; ???} ???function render() { ???????var time = clock.getDelta(); ???????if (mixer) { ???????????mixer.update(time); ???????} ???????controls.update(); ???} ???//窗口变动触发的函数 ???function onWindowResize() { ???????camera.aspect = window.innerWidth / window.innerHeight; ???????camera.updateProjectionMatrix(); ???????renderer.setSize(window.innerWidth, window.innerHeight); ???} ???function animate() { ???????//更新控制器 ???????render(); ???????//更新性能插件 ???????stats.update(); ???????renderer.render(scene, camera); ???????requestAnimationFrame(animate); ???} ???function draw() { ???????//兼容性判断 ???????if (!Detector.webgl) Detector.addGetWebGLMessage(); ???????initGui(); ???????initRender(); ???????initScene(); ???????initCamera(); ???????initLight(); ???????initModel(); ???????initControls(); ???????initStats(); ???????animate(); ???????window.onresize = onWindowResize; ???}</script></html>Three.js 对模型多个动画切换展示(fbx)
原文地址:https://www.cnblogs.com/lst619247/p/9195028.html