vue3中引入Threejs,加载gltf模型,引入gsap(2.0版本叫tweenmax),实现相机运动动画

第一步:创建vue3.0的项目,使用npm引入threejs的安装包,编辑文章的时候使用的threejs是0.129.0版本的.
1.npm install three --save
2,引入gsap,2.0版本的叫tweenmax,升级为3.0版本后叫gsap,用法稍微做了点改变,
建议使用新版的gsap,
npm安装 npm install gsap
链接: gsap官网.
链接: tweenmax中文网.

// threejs部分
import * as THREE from "three/build/three.module.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; //控制器
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; // gltf加载器
import gsap from "gsap";
import { CSSRulePlugin } from "gsap/CSSRulePlugin"; 
gsap.registerPlugin(CSSRulePlugin); // 引入css插件,完成某些css动画

2.配置threejs的环境

 setup () {
    const Scene = new THREE.Scene();
    const Camera = new THREE.PerspectiveCamera(
      45,
      window.innerWidth / window.innerHeight,
      1,
      5000
    );
    const Renderer = new THREE.WebGLRenderer({
      antialias: true,
      alpha: true, //开启alpha
    });
    // 控制器
    const Controls = new OrbitControls(Camera, Renderer.domElement);
    //gltfLoader
    const Gltfloader = new GLTFLoader();
    // 注意:此处为threejs的DOM,需要将threejs的场景渲染进去
    const threeDom = ref(null);
  

3.设置相机的角度与朝向,同时设置轨道控制器的朝向

   // 首页进入相机的视角,这个视角可以在三维模型中建立一个摄像机获取摄像机的坐标,如C4D,非常准确.
    const cameraPosition = {
      x: -180,
      y: 430,
      z: 333,
    };
    const cameraLookat = {
      x: 0,
      y: 0,
      z: 0,
    };
   // 声明一个方法传入参数可以在不同的地方调用相机
   const cameraReset = (position, lookAt, time = 1) => {
    gsap.to(Camera.position, {
        x: position.x,
        y: position.y,
        z: position.z,
        duration: time,
        ease: "power4.out",
       // onComplete: function () {
         // 这是相机运动完成的回调,可以执行其他的方法.
       // }
    });
    gsap.to(Camera.lookAt, {
        x: lookAt.x,
        y: lookAt.y,
        z: lookAt.z,
        duration: time,
        ease: "power4.out",
    });
    gsap.to(Controls.target, {
        x: lookAt.x,
        y: lookAt.y,
        z: lookAt.z,
        duration: time,
        ease: "power4.out",
    });
};

4.初始化threejs场景;并设置相机,灯光,控制器,renderer的设置

    const initThreeScene = () => {
      // 点光源
      const point = new THREE.PointLight(0xffffff, 1);
      point.position.set(10, 600, -40); // 点光源位置
      // Scene.position.set(0, 15, 0); // 场景位置
      // Scene.add(point); // 点光源添加到场景中
      // 环境光
      const ambient = new THREE.AmbientLight(0x444444, 1);
      Scene.add(ambient);
      // 辅助坐标系
      // const axesHelper = new THREE.AxesHelper(500);
      // Scene.add(axesHelper);
      // 修改相机,场景的参数
      Camera.position.set(-180, 430, 333);
      Camera.lookAt(0, 0, 0);
      Controls.target = new THREE.Vector3(0, 0, 0);
      // 使动画循环使用时阻尼或自转 意思是否有惯性
      Controls.enableDamping = true;
      // 动态阻尼系数 就是鼠标拖拽旋转灵敏度
      Controls.dampingFactor = 0.04;
      // 是否可以旋转
      Controls.enableRotate = false;
      // 是否可以缩放与速度
      Controls.enableZoom = false;
      // 设置相机距离原点的最远距离
      Controls.minDistance = 1;
      // 设置相机距离原点的最远距离
      Controls.maxDistance = 2000;
      // 是否开启右键拖拽
      Controls.enablePan = false;
      //render的相关设置
      Renderer.setPixelRatio(window.devicePixelRatio);
      Renderer.setSize(window.innerWidth, window.innerHeight);
      Renderer.inputEncoding = true;
      Renderer.outputEncoding = THREE.sRGBEncoding;
      Renderer.setClearColor(0xd0d0d0, 1);
      // 将renderer渲染进DOM里面
      threeDom.value.appendChild(Renderer.domElement);
 
    }; 
    // 设置页面自适应
     const onWindowResize = () => {
      Camera.aspect = window.innerWidth / window.innerHeight;
      Camera.updateProjectionMatrix();
      Renderer.setSize(window.innerWidth, window.innerHeight);
    };
    window.addEventListener("resize", onWindowResize, false);
   //  完成以上步骤基本的场景已经配置完成

5.加载gltf/glb格式的模型,经过对比各种格式(如obj,fbx),推荐大家使用gltf/glb格式的;
优点:
第一体积小,相对于obj格式的可以减少一半的体积;相对于fbx体积也会更小
第二不用烘焙贴图,C4D的自带材质球很多threejs都是支持的;
第三就是可以继续压缩达到更小的体积,在相同的网速下压缩后的glb格式的模型可以更快下载;

  Gltfloader.load("model/road.glb", (gltf) => {
     Scene.add(gltf.scene);
     // 模型加载完,进行相机的初始化,传入设置的参数,模型加载为异步
     cameraReset(cameraPosition, cameraLookat);
    }, function (xhr) {
      // 控制台查看加载进度xhr
      console.log(Math.floor(xhr.loaded / xhr.total * 100)) 
    });

6 声明render函数进行循环渲染

	 const Render = () => {
      requestAnimationFrame(Render);
      Controls.update(); // 轨道控制器的更新
      Renderer.clear(); // 清除画布
      Renderer.render(Scene, Camera);
    };

7.在onMounted中调用方法初始化threejs场景,在onUnmounted 中释放内存,移除事件监听

  onMounted(() => {
      initThreeScene();
      Render();
    });
    onUnmounted(() => {
      Scene.traverse((e) => {
        if (e.BufferGeometry) e.BufferGeometry.dispose()
        if (e.material) {
          if (Array.isArray(e.material)) {
            e.material.forEach((m) => {
              m.dispose()
            })
          } else {
            e.material.dispose()
          }
        }
        if (e.isMesh) {
          e.remove();
        }
      })
      Scene.remove();
      Renderer.dispose();
      Renderer.content = null;
      window.removeEventListener("resize", onWindowResize, false);
    });
    // setup中将threejs的dom返回
    return {
      threeDom,
    };

8,最后在顶部引入refthreejsdom

   <div ref="threeDom"></div>

总结:vue3的引入方法基本上就是这样,不要把threejs的scene,camera,renderer等内部函数写入vue的响应式数据(如有错误请留言,我会及时修改)
最后附上VUE3引入的threejs做的项目,模型大概12兆左右.
附上链接: 智能控制器的3D场景

Logo

前往低代码交流专区

更多推荐