vue中使用three.js

本文介绍了如何在Vue 3项目中使用Three.js创建3D模型,并处理页面跳转时的WebGL渲染器管理和内存清理。作者详细讲解了如何在组件卸载时正确销毁渲染器,以避免资源泄漏,并展示了两种不同的方法来确保动画在路由切换时暂停。
摘要由CSDN通过智能技术生成
<template>
  <div id="container"></div>
</template>

<script>
import * as THREE from 'three';
let scene, mesh;
export default {
  name: 'test',
  data() {
    return {
      camera: '', //创建相机
      renderer: '', //创建渲染器
      geometry: '', //创建展示对象
      material: '', //创建材质
      selectObject: {}, //与射线相交的数组
      requestID: '',// 作为启用动画时返回得id,用于路由跳转离开页面得时候停止动画
    };
  },
  mounted() {
    this.init();
    window.addEventListener('resize', this.onWindowResize, false);
    window.addEventListener('click', this.onMouseDblclick, false);
  },
  beforeUnmount() {
    window.removeEventListener('resize', this.onWindowResize);
    window.removeEventListener('click', this.onMouseDblclick);
    // 页面离开时停止动画
    window.cancelAnimationFrame(this.requestID);
  },
  methods: {
    init() {
      // 创建场景
      scene = new THREE.Scene();
      // 创建相机
      this.camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000,
      );
      this.camera.position.z = 5;
      this.camera.position.x = 0;
      this.createGeometry();
      this.createRender();
      this.animate();
    },
    // 创建展示对象和材质
    createGeometry() {
      this.geometry = new THREE.BoxGeometry(1.5, 1.5, 1.5);
      this.material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
      mesh = new THREE.Mesh(this.geometry, this.material);
      scene.add(mesh);
    },
    //创建渲染器
    createRender() {
      this.renderer = new THREE.WebGLRenderer();
      this.renderer.setSize(window.innerWidth, window.innerHeight);
      this.renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
      // 这里和官网不同,是因为我想在canvas内部添加元素 ,用position:absolute  就可以 是的元素和     three.js得模型对象共存一个画布了
      let container = document.getElementById('container');
      container.appendChild(this.renderer.domElement);
    },
    // 渲染场景
    animate() {
      this.requestID = requestAnimationFrame(this.animate);
      this.render();
    },
    // 设置物体行为
    render() {
      mesh.rotation.x += 0.01;
      mesh.rotation.y += 0.01;
      this.renderer.render(scene, this.camera);
    },
    // 窗口变动触发的方法
    onWindowResize() {
      this.camera.aspect = window.innerWidth / window.innerHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(window.innerWidth, window.innerHeight);
    },
    // 鼠标双击触发的方法
    onMouseDblclick(event) {
      // 获取 raycaster 和所有模型相交的数组,其中的元素按照距离排序,越近的越靠前
      var intersects = this.getIntersects(event);
      // 获取选中最近的 Mesh 对象
      if (
        intersects.length != 0 &&
        intersects[0].object instanceof THREE.Mesh
      ) {
        this.$router.push({ name: 'test' });
      }
    },
    // 获取与射线相交的对象数组
    getIntersects(event) {
      event.preventDefault();
      // 声明 raycaster 和 mouse 变量
      var raycaster = new THREE.Raycaster();
      var mouse = new THREE.Vector2();

      // 通过鼠标点击位置,计算出 raycaster 所需点的位置,以屏幕为中心点,范围 -1 到 1
      mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

      //通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
      raycaster.setFromCamera(mouse, this.camera);

      // 获取与射线相交的对象数组,其中的元素按照距离排序,越近的越靠前
      var intersects = raycaster.intersectObjects(scene.children);

      //返回选中的对象
      return intersects;
    },
  },
};
</script>

<style lang="less" scoped>
#container {
  width: 100vw;
  height: 100vh;
}
</style>

  • 问题1

页面跳转的时候,根据官网的例子,canvas元素和app的元素并存一个页面

这个时候路由跳转时这个样子 document.body.appendChild(this.renderer.domElement);
在这里插入图片描述
在这里插入图片描述
解决

<template>
  <div id="container"></div>
</template>

<style lang="less" scoped>
#container {
  width: 100vw;
  height: 100vh;
}
</style>
	const renderer = new THREE.WebGLRenderer();
	renderer.setSize( window.innerWidth, window.innerHeight );
	document.body.appendChild( renderer.domElement );

这个时候 页面的结构时这样的:
在这里插入图片描述
在这里插入图片描述

  • 问题2
路由跳转的时候,webgl的实例对象一直存在,想法自然时清除

方法1

 beforeUnmount() {
    window.removeEventListener('resize', this.onWindowResize);
    window.removeEventListener('click', this.onMouseDblclick);
    
     this.renderer = null
  },

    // 设置物体行为
    render() {
      if (!this.renderer) {
        return;
      }
      mesh.rotation.x += 0.01;
      mesh.rotation.y += 0.01;
      this.renderer.render(scene, this.camera);
    },

方法2 (推荐)

  beforeUnmount() {
    window.removeEventListener('resize', this.onWindowResize);
    window.removeEventListener('click', this.onMouseDblclick);
    window.cancelAnimationFrame(this.requestID);
  },
   // 渲染场景
    animate() {
      this.requestID = requestAnimationFrame(this.animate);
      this.render();
    },
  • 问题3
在vue3中 如果在data中声明scene,mesh,vue3的底层代理proxy会报错,因为three.js的一个module对象时read-only

解决:

// 在export default外定义全局变量
let scene, mesh;
export default {
Vue使用Three.js VR全景图,你可以按照以下步骤进行: 1. 首先,确保你已经安装了VueThree.js的依赖包。你可以使用npm或yarn来安装它们。 2. 在Vue的组件,导入Three.js所需的库和组件: ```javascript import * as THREE from 'three'; import { VRButton } from 'three/examples/jsm/webxr/VRButton.js'; ``` 3. 创建一个Vue组件,并在其定义一个方法来初始化Three.js场景: ```javascript export default { mounted() { this.initScene(); }, methods: { initScene() { // 创建场景 const scene = new THREE.Scene(); // 创建相机 const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); // 创建渲染器 const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 添加VR按钮 document.body.appendChild(VRButton.createButton(renderer)); // 创建全景图 const textureLoader = new THREE.TextureLoader(); const texture = textureLoader.load('path/to/your/panorama-image.jpg'); const sphereGeometry = new THREE.SphereGeometry(500, 60, 40); const sphereMaterial = new THREE.MeshBasicMaterial({ map: texture }); const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); sphere.position.set(0, 0, 0); scene.add(sphere); // 更新相机和场景 const animate = () => { requestAnimationFrame(animate); sphere.rotation.y += 0.01; renderer.render(scene, camera); }; animate(); }, }, }; ``` 4. 在Vue模板使用这个组件: ```html <template> <div id="app"> <canvas id="vr-canvas"></canvas> </div> </template> ``` 这样,你就可以在Vue使用Three.js VR全景图了。当用户点击VR按钮时,全屏显示全景图,并支持通过移动设备或VR眼镜进行交互。你可以适配不同的全景图、修改相机参数等来满足你的需求。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值