> 技术文档 > 一文万字详解three.js+vue3.js保姆级教程_vue3 three.js

一文万字详解three.js+vue3.js保姆级教程_vue3 three.js


Vue3结合Three.js开发Web3D项目详解

引言:Web3D技术的崛起

随着Web技术的快速发展,Web3D应用已经从简单的展示发展到复杂的交互体验,广泛应用于电商展示、游戏开发、数据可视化和教育培训等地方。Three.js作为最流行的WebGL库,让开发者能够轻松创建3D场景。而Vue3的响应式系统和组件化架构,为管理复杂3D场景提供了优雅的解决方案。

本文将详细介绍如何在Vue3项目中集成Three.js,从基础设置到高级功能实现,带你构建一个完整的3D场景。

🚀一、项目环境搭建

1. 创建Vue3项目

npm init vue@latest# 选择Vue3 + TypeScript + Vitecd your-project-namenpm install

2. 安装Three.js及相关库

npm install three @types/three three-stdlib

3. 项目结构

src/├── assets/├── components/│ ├── ThreeScene.vue # 3D场景组件│ ├── SceneControls.vue # 场景控制组件│ └── ModelLoader.vue # 模型加载组件├── composables/│ └── useThree.js # Three.js组合式函数├── views/│ └── HomeView.vue # 主视图└── main.js

🧩二、Three.js核心概念

在集成之前,先了解Three.js的核心概念:

  1. 场景(Scene) :所有3D对象的容器
  2. 相机(Camera) :定义用户可见的视角
  3. 渲染器(Renderer) :将场景渲染到canvas元素
  4. 几何体(Geometry) :物体的形状
  5. 材质(Material) :物体表面的视觉特性
  6. 网格(Mesh) :几何体+材质的组合
  7. 光源(Light) :照亮场景的光源
  8. 动画循环(Animation Loop) :实现动态效果

🔧三、在Vue3中创建基础3D场景

1. 创建ThreeScene组件

 
import { ref, onMounted, onUnmounted } from \'vue\';import * as THREE from \'three\';import { OrbitControls } from \'three-stdlib/controls/OrbitControls\';const sceneContainer = ref(null);// 核心Three.js对象let scene, camera, renderer, controls, cube;// 初始化场景function initScene() { // 1. 创建场景 scene = new THREE.Scene(); scene.background = new THREE.Color(0x1a1a2e); // 2. 创建相机 camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); camera.position.z = 5; // 3. 创建渲染器 renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // 4. 添加到DOM sceneContainer.value.appendChild(renderer.domElement); // 5. 添加轨道控制器 controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.05; // 6. 添加光源 const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(5, 5, 5); scene.add(directionalLight); // 7. 创建立方体 const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshStandardMaterial({ color: 0x00a8ff, metalness: 0.7, roughness: 0.2 }); cube = new THREE.Mesh(geometry, material); scene.add(cube); // 8. 添加网格地板 const floorGeometry = new THREE.PlaneGeometry(10, 10); const floorMaterial = new THREE.MeshStandardMaterial({ color: 0x393e46, side: THREE.DoubleSide }); const floor = new THREE.Mesh(floorGeometry, floorMaterial); floor.rotation.x = Math.PI / 2; floor.position.y = -1.5; scene.add(floor); // 9. 开始动画循环 animate();}// 动画循环function animate() { requestAnimationFrame(animate); // 立方体旋转 if (cube) { cube.rotation.x += 0.01; cube.rotation.y += 0.01; } // 更新控制器 if (controls) controls.update(); // 渲染场景 renderer.render(scene, camera);}// 响应式调整大小function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight);}onMounted(() => { initScene(); window.addEventListener(\'resize\', onWindowResize);});onUnmounted(() => { window.removeEventListener(\'resize\', onWindowResize); // 清理资源 if (renderer) renderer.dispose();});.scene-container { width: 100%; height: 100vh; position: relative; overflow: hidden;}

2. 在主页面中使用组件

 

Vue3 + Three.js 3D场景

旋转视角: 按住鼠标左键拖动

缩放场景: 使用鼠标滚轮

import ThreeScene from \'@/components/ThreeScene.vue\';.home-view { position: relative; height: 100vh;}.overlay { position: absolute; top: 20px; left: 20px; color: white; background: rgba(0, 0, 0, 0.5); padding: 15px; border-radius: 10px; max-width: 300px; z-index: 10;}

⚙️四、高级功能实现

1. 模型加载与展示

 
机器人 汽车
import { ref } from \'vue\';import { GLTFLoader } from \'three-stdlib/loaders/GLTFLoader\';const emit = defineEmits([\'model-loaded\']);const selectedModel = ref(\'robot\');async function loadModel() { const loader = new GLTFLoader(); try { const modelPath = selectedModel.value === \'robot\' ? \'/models/robot.glb\' : \'/models/car.glb\'; const gltf = await loader.loadAsync(modelPath); // 调整模型大小和位置 gltf.scene.scale.set(0.5, 0.5, 0.5); gltf.scene.position.y = -1; // 发送到父组件 emit(\'model-loaded\', gltf.scene); } catch (error) { console.error(\'模型加载失败:\', error); }}

2. 在ThreeScene组件中处理模型加载

// ThreeScene.vue 中添加import { onMounted } from \'vue\';// 添加模型状态const currentModel = ref(null);// 加载模型function handleModelLoaded(model) { // 移除旧模型 if (currentModel.value) { scene.remove(currentModel.value); } // 添加新模型 scene.add(model); currentModel.value = model;}

3. 添加点击交互

// 在initScene函数中添加function initRaycaster() { const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); function onMouseClick(event) { // 计算鼠标位置 mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; // 更新射线 raycaster.setFromCamera(mouse, camera); // 检测相交物体 const intersects = raycaster.intersectObjects(scene.children); if (intersects.length > 0) { const clickedObject = intersects[0].object; // 高亮显示被点击的物体 clickedObject.material.emissive = new THREE.Color(0xffff00); setTimeout(() => { clickedObject.material.emissive = new THREE.Color(0x000000); }, 1000); console.log(\'点击了物体:\', clickedObject); } } window.addEventListener(\'click\', onMouseClick); onUnmounted(() => { window.removeEventListener(\'click\', onMouseClick); });}// 在initScene中调用initRaycaster();

🌐五、性能优化技巧

1. 使用组合式函数复用逻辑

创建 src/composables/useThree.js:

import { ref, onUnmounted } from \'vue\';import * as THREE from \'three\';export function useThree(container) { const scene = new THREE.Scene(); const camera = ref(null); const renderer = ref(null); function initCamera() { camera.value = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); camera.value.position.z = 5; } function initRenderer() { renderer.value = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.value.setSize(window.innerWidth, window.innerHeight); renderer.value.setPixelRatio(Math.min(window.devicePixelRatio, 2)); container.value.appendChild(renderer.value.domElement); } function onWindowResize() { camera.value.aspect = window.innerWidth / window.innerHeight; camera.value.updateProjectionMatrix(); renderer.value.setSize(window.innerWidth, window.innerHeight); } function init() { initCamera(); initRenderer(); window.addEventListener(\'resize\', onWindowResize); } onUnmounted(() => { window.removeEventListener(\'resize\', onWindowResize); if (renderer.value) renderer.value.dispose(); }); return { scene, camera, renderer, init };}

2. 在组件中使用组合式函数

// ThreeScene.vue 中import { useThree } from \'@/composables/useThree\';const { scene, camera, renderer } = useThree(sceneContainer);onMounted(() => { init(); // 调用组合式函数中的初始化 // 其他初始化代码...});

3. 其他优化策略

  • 模型压缩:使用glTF格式并启用Draco压缩
  • 按需渲染:静态场景仅在变化时渲染
  • LOD管理:根据距离显示不同细节模型
  • 纹理优化:使用合适的分辨率和压缩格式
  • 内存管理:及时释放不再使用的几何体和材质

💡六、调试工具与实用资源

1. 调试工具

  • Three.js Inspector:浏览器扩展,实时检查场景
  • Stats.js:性能监控面板
  • dat.GUI:创建控制面板调整参数

2. 实用资源

  • Three.js 官方文档
  • glTF 模型库
  • VueThreejs - Vue3的Three.js封装

📚七、总结

将Vue3与Three.js结合开发Web3D应用,可以充分发挥两者的优势:

  1. Vue3的优势

    • 响应式状态管理
    • 组件化架构
    • 组合式API复用逻辑
    • 丰富的生态系统
  2. Three.js的优势

    • 强大的3D渲染能力
    • 丰富的几何体和材质
    • 物理效果支持
    • 模型加载器

这种技术组合非常适合开发复杂的3D可视化应用、产品展示、教育模拟和游戏等场景。随着WebGPU等新技术的发展,Web3D应用的性能和表现力将进一步提升。