threejs对obj模型实现爆炸效果

效果

在这里插入图片描述
说明:实现模型加载完成后,对其进行爆炸分解,然后延迟还原。

思路:
1.获取到obj模型后,初始化爆炸数据保存到每个mesh的userdata上;
在这里插入图片描述
代码:

// 初始化爆炸数据保存到每个mesh的userdata上
 initExplodeModel (modelObject) {
    
    
   let _this = this;
   if (!modelObject) return;
   // 计算模型中心
   const explodeBox = new THREE.Box3();
   explodeBox.setFromObject(modelObject);
   const explodeCenter = this.getWorldCenterPosition(explodeBox);
   const meshBox = new THREE.Box3();
   // 遍历整个模型,保存数据到userData上,以便爆炸函数使用
   modelObject.traverse(function (value) {
    
    
     if (value.isMark || value.isMarkChild || value.isLine || value.isSprite) return;
     if (value.isMesh) {
    
    
       meshBox.setFromObject(value);
       const meshCenter = _this.getWorldCenterPosition(meshBox);
       // 爆炸方向
       value.userData.worldDir = new THREE.Vector3()
         .subVectors(meshCenter, explodeCenter)
         .normalize();
       // 爆炸距离 mesh中心点到爆炸中心点的距离
       value.userData.worldDistance = new THREE.Vector3().subVectors(meshCenter, explodeCenter);
       // 原始坐标
       value.userData.originPosition = value.getWorldPosition(new THREE.Vector3());
       // mesh中心点
       value.userData.meshCenter = meshCenter.clone();
       value.userData.explodeCenter = explodeCenter.clone();
     }
   });
 },

2.获取模型的中心坐标(很重要,不然分解出来很奇怪)

// 获取模型中心点
    getWorldCenterPosition (box, scalar = 0.5) {
    
    
      return new THREE.Vector3().addVectors(box.max, box.min).multiplyScalar(scalar);
    },

3.设置爆炸值与方向

// 设置爆炸值,scalar=1为初始值
 explodeModel (model, scalar) {
    
    
   model.traverse(function (value) {
    
    
     // @ts-ignore
     if (!value.isMesh || !value.userData.originPosition) return;
     const distance = value.userData.worldDir
       .clone()
       .multiplyScalar(value.userData.worldDistance.length() * scalar);
     const offset = new THREE.Vector3().subVectors(
       value.userData.meshCenter,
       value.userData.originPosition
     );
     const center = value.userData.explodeCenter;
     const newPos = new THREE.Vector3().copy(center).add(distance).sub(offset);
     const localPosition = value.parent?.worldToLocal(newPos.clone());
     localPosition && value.position.copy(localPosition);
   });
 },

1.点击调用:单单实现爆炸效果

this.explodeModel(scene, 1);
默认1为初始值,就是模型未爆炸的样子,数值越大,爆炸分解的越狠

2.模型加载完成后旋转并过渡爆炸,延迟两秒后再逐步还原,停止旋转;

//调用
this.sceneRange(1)
//爆炸动画
sceneRange (num) {
    
    
  //开启模型自动旋转
  this.controls.autoRotate = true;
  //禁止对模型的操作
  this.controls.enabled = false;
  let time = setInterval(() => {
    
    
    if (num >= 1.7) {
    
    
      setTimeout(() => {
    
    
        let time2 = setInterval(() => {
    
    
          if (num <= 1) {
    
    
            window.clearInterval(time2)
            // 关闭旋转,可操作
            this.controls.autoRotate = false;
            this.controls.enabled = true;
            this.explodeModel(scene, 1);
            // 初始化相机视角
            // this.initPoint();
            return
          }
          num -= 0.005;
          this.explodeModel(scene, num)
        }, 10)
      }, 1500)
      window.clearInterval(time)
      return
    }
    num += 0.01;
    this.explodeModel(scene, num)
  }, 1)
},

模型开启自旋转:

// 控制器操作
    initOrbitControls () {
    
    
      // let allControls = new OrbitControls(camera, HTMLDOMElement);
      let allControls = new OrbitControls(camera, renderer.domElement);
      allControls.enableDamping = true;
      allControls.enableZoom = true;// 是否可以缩放 默认是true
      allControls.autoRotate = true;//是否旋转
      allControls.autoRotateSpeed = 7;//开启旋转时的旋转速度
      allControls.enablePan = true;// 是否开启右键拖拽
      allControls.enableKeys = true;
      allControls.keyPanSpeed = 7;//使用键盘控制模型位置的相机平移像素
      allControls.dampingFactor = 0.5;// 动态阻尼系数 就是鼠标拖拽旋转灵敏度,阻尼越小越灵敏
      allControls.keys = {
    
    
        LEFT: 37,
        UP: 38,
        RIGHT: 39,
        BOTTOM: 40
      }
      this.controls = allControls;
   },

这一步很重要,要开启控制器方法
在这里插入图片描述

总结:在处理爆炸的定时器方法中,还没想到更好的处理方式,欢迎补充。还有这个封装的爆炸方法,不只是obj模型可用,基本上都能通用。

猜你喜欢

转载自blog.csdn.net/hzqzzz/article/details/126780087