学习threejs,通过SkinnedMesh来创建骨骼和蒙皮动画

👨‍⚕️ 主页: gis分享者

👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录


一、🍀前言

本文详细介绍如何基于threejs在三维场景中通过SkinnedMesh来创建骨骼和蒙皮动画,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️THREE.SkinnedMesh 蒙皮网格

THREE.SkinnedMesh具有Skeleton(骨架)和bones(骨骼)的网格,可用于给几何体上的顶点添加动画。 其材质必须支持蒙皮,并且已经启用了蒙皮
创建方法:

SkinnedMesh( geometry : BufferGeometry, material : Material )

geometry:一个BufferGeometry实例。

material:(可选)一个Material实例,默认值是一个新的MeshBasicMaterial。
属性:

bindMode:string "attached"(附加)或者"detached"(分离)。"attached"使用SkinnedMesh.matrixWorld 属性作为对骨骼的基本变换矩阵,"detached"则使用SkinnedMesh.bindMatrix。 默认值是"attached"。

bindMatrix:Matrix4 该基础矩阵用于绑定骨骼的变换。

bindMatrixInverse:Matrix4 该基础矩阵用于重置绑定骨骼的变换。

isSkinnedMesh:用于检查这个类或者其派生类是否为蒙皮网格,默认值为true。

skeleton:用于表示蒙皮网格中骨骼的层次结构的Skeleton(骨架)。
方法:

(1)bind ( skeleton : Skeleton, bindMatrix : Matrix4 ):null

skeleton ------ 由一棵Bones树创建的Skeleton。

bindMatrix ------ 表示骨架基本变换的Matrix4(4x4矩阵)。

将骨架绑定到一个蒙皮网格上。bindMatrix会被保存到.bindMatrix属性中,其逆矩阵.bindMatrixInverse也会被计算出来。

(2)clone () : SkinnedMesh

返回当前SkinnedMesh对象的一个克隆及其任何后代。

(3)normalizeSkinWeights () : null

标准化蒙皮的权重。

(4)pose ():null

这个方法设置了在"休息"状态下蒙皮网格的姿势(重置姿势)。

(5)updateMatrixWorld ( force : Boolean ) :null

更新MatrixWorld矩阵。

二、🍀通过SkinnedMesh来创建骨骼和蒙皮动画

1. ☘️实现思路

  • 1、初始化renderer渲染器
  • 2、初始化Scene三维场景
  • 3、初始化camera相机,定义相机位置 camera.position.set,设置相机方向camera.lookAt。
  • 4、初始化THREE.AmbientLight环境光源,scene场景加入环境光源,初始化THREE.PointLight点光源,设置点光源位置,设置点光源投影,scene添加点光源。
  • 5、加载几何模型:创建THREE.AxesHelper坐标辅助工具,创建THREE.JSONLoader加载器加载hand1.js json模型文件,生成geometry几何体,根据生成的几何体创建THREE.SkinnedMesh蒙皮网格,设置mesh的旋转角度和位置。传入参数mesh创建THREE.SkeletonHelper可视化骨骼结构对象skeletonHelper。场景scene中加入mesh和skeletonHelper。创建间隔动画initTween,定义mesh的骨骼和蒙皮动画。具体代码参考代码样例。
  • 6、加入controls、gui控制(控制skeletonHelper的显示、隐藏和动画的播放),加入stats监控器,监控帧数信息。

2. ☘️代码样例

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>learn49(通过SkinnedMesh来创建骨骼和蒙皮动画)</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/threejs/91/three.js"></script>
    <script src="https://johnson2heng.github.io/three.js-demo/lib/js/controls/OrbitControls.js"></script>
    <script src="https://cdn.bootcss.com/tween.js/r14/Tween.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.setSize(window.innerWidth, window.innerHeight)
    renderer.setClearColor(0xeeeeee)
    document.body.appendChild(renderer.domElement)
  }
  var scene
  var initScene = () => {
    scene = new THREE.Scene()
  }
  var camera
  var initCamera = () => {
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)
    camera.position.set(0, 40, 50)
  }
  var light
  var initLight = () => {
    scene.add(new THREE.AmbientLight(0x444444))
    light = new THREE.PointLight(0xffffff)
    light.position.set(0, 50, 0)
    light.castShadow = true
    scene.add(light)
  }
  var mesh, tween, skeletonHelper
  var initModel = () => {
    var helper = new THREE.AxesHelper(50)
    scene.add(helper)
    var loader = new THREE.JSONLoader()
    loader.load('data/model/hand1/hand1.js', geometry => {
      mesh = new THREE.SkinnedMesh(geometry, new THREE.MeshLambertMaterial({
        color: 0xf4b397,
        skinning: true
      }))
      mesh.rotation.x = 0.5 * Math.PI
      mesh.rotation.z = 0.7 * Math.PI
      mesh.scale.set(10, 10, 10)

      skeletonHelper = new THREE.SkeletonHelper(mesh)
      skeletonHelper.visible = false
      scene.add(skeletonHelper)

      scene.add(mesh)
      tween.start()
    })
  }
  var initTween = () => {
    tween = new TWEEN.Tween({pos: -1})
      .to({pos: 0}, 3000)
      .easing(TWEEN.Easing.Cubic.InOut)
      .yoyo(true)
      .repeat(Infinity) //一直循环
    tween.onUpdate(function () {
      var pos = this.pos
      // 旋转手指的方向
      mesh.skeleton.bones[5].rotation.set(0, 0, pos)
      mesh.skeleton.bones[6].rotation.set(0, 0, pos)
      mesh.skeleton.bones[10].rotation.set(0, 0, pos)
      mesh.skeleton.bones[11].rotation.set(0, 0, pos)
      mesh.skeleton.bones[15].rotation.set(0, 0, pos)
      mesh.skeleton.bones[16].rotation.set(0, 0, pos)
      mesh.skeleton.bones[20].rotation.set(0, 0, pos)
      mesh.skeleton.bones[21].rotation.set(0, 0, pos)

      // 旋转手腕
      mesh.skeleton.bones[1].rotation.set(pos, 0, 0)
    })
  }
  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 gui, animation = true
  var initGui = () => {
    gui = {
      animation: true,
      helper: false
    }
   var datGui = new dat.GUI()
    datGui.add(gui, 'animation').onChange(e => {
      animation = e
    })
    datGui.add(gui, 'helper').onChange(e => {
      skeletonHelper.visible = e
    })
  }
  var render = () => {
    animation && TWEEN.update()
    controls.update()
  }
  var onWindowResize = () => {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)
  }
  var animate = () => {
    render()
    stats.update()
    renderer.render(scene, camera)
    requestAnimationFrame(animate)
  }
  var draw = () => {
    if (!Detector.webgl) Detector.addGetWebGLMessage()

    initRender()
    initScene()
    initCamera()
    initLight()
    initModel()
    initControls()
    initStats()
    initGui()
    initTween()

    animate()

    window.onresize = onWindowResize
  }
</script>
</html>

效果如下:

相关推荐
gis分享者20 小时前
学习threejs,使用PointLight点光源
threejs·点光源·pointlight
gis分享者5 天前
学习threejs,使用HemisphereLight半球光
threejs·hemispherelight·半球光
gis分享者9 天前
学习threejs,使用Lensflare模拟镜头眩光
threejs·lensflare·眩光
gis分享者12 天前
学习threejs,tga格式图片文件贴图
threejs·贴图·tga·tgaloader
gis分享者13 天前
学习threejs,pvr格式图片文件贴图
threejs·贴图·pvr
gis分享者1 个月前
学习threejs,使用OrbitControls相机控制器
threejs·相机·相机控制器·orbitcontrols
不系舟1781 个月前
threejs 实现镜面反射,只反射指定物体,背景透明
threejs
gis分享者1 个月前
学习threejs,使用RollControls相机控制器
threejs·相机控制器·rollcontrols
gis分享者1 个月前
学习threejs,使用FlyControls相机控制器
threejs·相机控制器·flycontrols
gis分享者1 个月前
学习threejs,使用TrackballControls相机控制器
threejs·trackball·相机控制器