小言_互联网的博客

使用vue学习three.js之创建动画-变形动画-通过设置morphTargetInfluences属性创建动画

396人阅读  评论(0)

1.demo效果

2. 实现要点

2.1 Geometry到BufferGeometry

最新的three.js中的 updateMorphTargets 方法不再支持Geometry几何体,需要使用 BufferGeometry 替代,而且原来Geometry对象中的morphTargets属性BufferGeometry中也没有,不过有替换方案。
查阅得知BufferGeometry有一个 morphAttributes 属性,用来存储了几何体的 morphTargets 信息,
这里可以存放顶点信息-position,也可以存放法线信息-normal

例如要存放两个目标形状的顶点信息:

geometry.morphAttributes.position = [
  new THREE.BufferAttribute(new Float32Array(array1), 3),
  new THREE.BufferAttribute(new Float32Array(array2), 3),
]

3.2 创建带有变形目标的网格对象

这里首先通过BoxBufferGeometry对象创建一个原几何体对象,两个目标几何体对象,然后将原几何体对象的morphAttributes属性的顶点信息使用两个目标几何体对象的顶点信息填充

// 创建立方体
var cubeGeometry = new THREE.BoxBufferGeometry(4, 4, 4)
var cubeMaterial = new THREE.MeshLambertMaterial({
   
  morphTargets: true,
  color: 0xff0000
})

// 创建morphtargets, 用来获取顶点信息
var cubeTarget1 = new THREE.BoxBufferGeometry(2, 10, 2)
var cubeTarget2 = new THREE.BoxBufferGeometry(8, 2, 8)

// 设置morphAttributes
cubeGeometry.morphAttributes.position = [
  new THREE.BufferAttribute(cubeTarget2.attributes.position.array, 3),
  new THREE.BufferAttribute(cubeTarget1.attributes.position.array, 3)
]

this.cube = new THREE.Mesh(cubeGeometry, cubeMaterial)

3.3 render中更新动画

render() {
   
  this.cube.morphTargetInfluences[0] = this.properties.influence1.value
  this.cube.morphTargetInfluences[1] = this.properties.influence2.value
  this.renderer.render(this.scene, this.camera)
  requestAnimationFrame(this.render)
}

4. demo代码

<template>
  <div>
    <div id="container" />
    <div class="controls-box">
      <section>
        <el-row>
          <div v-for="(item,key) in properties" :key="key">
            <div v-if="item&&item.name!=undefined">
              <el-col :span="8">
                <span class="vertice-span">{
   {
    item.name }}</span>
              </el-col>
              <el-col :span="12">
                <el-slider v-model="item.value" :min="item.min" :max="item.max" :step="item.step" :format-tooltip="formatTooltip" />
              </el-col>
              <el-col :span="3">
                <span class="vertice-span">{
   {
    item.value }}</span>
              </el-col>
            </div>
          </div>
        </el-row>
      </section>
    </div>
  </div>
</template>

<script>
import * as THREE from 'three'
import {
    OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
export default {
   
  data() {
   
    return {
   
      properties: {
   
        influence1: {
   
          name: 'influence1',
          value: 0.01,
          min: 0,
          max: 1,
          step: 0.001
        },
        influence2: {
   
          name: 'influence2',
          value: 0.01,
          min: 0,
          max: 1,
          step: 0.001
        }
      },
      cube: null,
      camera: null,
      scene: null,
      renderer: null,
      controls: null
    }
  },
  mounted() {
   
    this.init()
  },
  methods: {
   
    formatTooltip(val) {
   
      return val
    },

    // 初始化
    init() {
   
      this.createScene() // 创建场景

      this.createLight() // 创建光源
      this.createCamera() // 创建相机
      this.createRender() // 创建渲染器
      this.createModels() // 创建模型
      this.createControls() // 创建轨道控制器
      this.render() // 渲染
    },
    // 创建场景
    createScene() {
   
      this.scene = new THREE.Scene()
    },
    // 创建模型
    createModels() {
   
      // 创建一个平面
      var planeGeometry = new THREE.PlaneGeometry(20, 20, 1, 1)
      var planeMaterial = new THREE.MeshLambertMaterial({
    color: 0xffffff })
      var plane = new THREE.Mesh(planeGeometry, planeMaterial)
      plane.rotation.x = -0.5 * Math.PI
      this.scene.add(plane)

      this.createCube() // 创建立方体
    },
    createCube(e) {
   
      // 创建立方体
      var cubeGeometry = new THREE.BoxBufferGeometry(4, 4, 4)
      var cubeMaterial = new THREE.MeshLambertMaterial({
   
        morphTargets: true,
        color: 0xff0000
      })

      // 创建morphtargets, 用来获取顶点信息
      var cubeTarget1 = new THREE.BoxBufferGeometry(2, 10, 2)
      var cubeTarget2 = new THREE.BoxBufferGeometry(8, 2, 8)

      // 设置morphAttributes
      cubeGeometry.morphAttributes.position = [
        new THREE.BufferAttribute(cubeTarget2.attributes.position.array, 3),
        new THREE.BufferAttribute(cubeTarget1.attributes.position.array, 3)
      ]

      this.cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
      this.cube.position.set(0, 3, 0)
      this.scene.add(this.cube)
    },

    // 创建光源
    createLight() {
   
      // 环境光
      const ambientLight = new THREE.AmbientLight(0x0c0c0c) // 创建环境光
      this.scene.add(ambientLight) // 将环境光添加到场景

      const spotLight = new THREE.SpotLight(0xffffff)
      spotLight.position.set(-25, 25, 15)
      this.scene.add(spotLight)
    },
    // 创建相机
    createCamera() {
   
      const element = document.getElementById('container')
      const width = element.clientWidth // 窗口宽度
      const height = element.clientHeight // 窗口高度
      const k = width / height // 窗口宽高比
      // PerspectiveCamera( fov, aspect, near, far )
      this.camera = new THREE.PerspectiveCamera(45, k, 0.1, 1000)
      this.camera.position.set(-15, 15, 15) // 设置相机位置

      this.camera.lookAt(new THREE.Vector3(0, 0, 0)) // 设置相机方向
      this.scene.add(this.camera)
    },
    // 创建渲染器
    createRender() {
   
      const element = document.getElementById('container')
      this.renderer = new THREE.WebGLRenderer({
    antialias: true, alpha: true })
      this.renderer.setSize(element.clientWidth, element.clientHeight) // 设置渲染区域尺寸
      this.renderer.setClearColor(0xeeeeee, 1) // 设置背景颜色
      element.appendChild(this.renderer.domElement)
    },

    render() {
   
      this.cube.morphTargetInfluences[0] = this.properties.influence1.value
      this.cube.morphTargetInfluences[1] = this.properties.influence2.value
      this.renderer.render(this.scene, this.camera)
      requestAnimationFrame(this.render)
    },
    // 创建轨道控制器
    createControls() {
   
      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
    }
  }
}
</script>

<style>
#container {
   
  position: absolute;
  width: 100%;
  height: 100%;
}
.controls-box {
   
  position: absolute;
  right: 5px;
  top: 5px;
  width: 300px;
  padding: 10px;
  background-color: #fff;
  border: 1px solid #c3c3c3;
}
.vertice-span {
   
  line-height: 38px;
  padding: 0 8px 0 10px;
}
</style>


转载:https://blog.csdn.net/qw8704149/article/details/117380337
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场