当前位置: 首页 > article >正文

学习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>

效果如下:
在这里插入图片描述


http://www.kler.cn/a/403031.html

相关文章:

  • AWTK fscript 中的 大端小端扩展函数
  • C++ STL - vector/list讲解及迭代器失效
  • 汽车加油行驶问题-动态规划算法(已在洛谷AC)
  • 14 go语言(golang) - 并发编程goroutine和channel
  • AWS CLI
  • DB-GPT V0.6.2 版本更新:牵手libro社区、GraphRAG图谱构建能力增强等
  • Matlab多输入单输出之倾斜手写数字识别
  • os库的常见使用
  • 星融元与焱融科技AI分布式存储软硬件完成兼容性互认证
  • 13.C++内存管理2(C++ new和delete的使用和原理详解,内存泄漏问题)
  • 数据结构(双向链表——c语言实现)
  • Restful API 规范详解
  • 单片机学习笔记 2. LED灯闪烁
  • c++--------《set 和 map》
  • C++手写PCD文件
  • 使用Kotlin写一个将字符串加密成short数组,然后可以解密还原成原始的字符串的功能
  • 前端页面自适应等比例缩放 Flexible+rem方案
  • 小程序-基于java+SpringBoot+Vue的超市购物系统设计与实现
  • 【React 进阶】掌握 React18 全部 Hooks
  • 鸿蒙原生应用开发元服务 元服务是什么?和App的关系?(保姆级步骤)
  • 详解八大排序(一)------(插入排序,选择排序,冒泡排序,希尔排序)
  • Linux驱动开发第2步_“物理内存”和“虚拟内存”的映射
  • EDA实验设计-led灯管动态显示;VHDL;Quartus编程
  • Ubuntu24.04LTS设置root用户可远程登录
  • Flutter踩坑记录(一)debug运行生成的项目,不能手动点击运行
  • Qt5-雷达项目