在 Vue 中使用 Three.js 加載模型、控制視角、添加點擊事件是構建 3D 場景的常見需求。下面是一個完整的示例,演示如何在 Vue 單文件組件中實現以下功能:
- 使用
GLTFLoader
加載.glb/.gltf
模型 - 添加
OrbitControls
控制視角(旋轉、縮放、平移) - 給模型添加點擊事件
使用的技術棧
- Vue 3 + Composition API(或 Vue 2)
- Three.js 核心庫
three/examples/js/loaders/GLTFLoader
three/examples/js/controls/OrbitControls
📦 安裝依賴(如未安裝)
npm install three
npm install three-gltf-loader # 或直接引入 GLTFLoader
示例代碼:Vue 單文件組件
<template><div class="model-viewer-container" ref="viewerContainer"></div>
</template><script setup>
import { ref, onMounted } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'const viewerContainer = ref(null)let scene, camera, renderer, controls, modelfunction init() {// 創建場景scene = new THREE.Scene()scene.background = new THREE.Color(0xeeeeee)// 創建相機const width = viewerContainer.value.clientWidthconst height = viewerContainer.value.clientHeightcamera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000)camera.position.set(0, 2, 5)// 創建渲染器renderer = new THREE.WebGLRenderer({ antialias: true })renderer.setSize(width, height)renderer.setPixelRatio(window.devicePixelRatio)viewerContainer.value.appendChild(renderer.domElement)// 添加光源const ambientLight = new THREE.AmbientLight(0xffffff, 0.6)scene.add(ambientLight)const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)directionalLight.position.set(5, 10, 7.5)scene.add(directionalLight)// 添加控制器controls = new OrbitControls(camera, renderer.domElement)controls.enableDamping = true// 加載模型const loader = new GLTFLoader()loader.load('/models/test.glb', // 替換為你的模型路徑(gltf) => {model = gltf.scenescene.add(model)// 添加點擊事件監聽window.addEventListener('click', onClick)},undefined,(error) => {console.error('An error occurred while loading the model:', error)})// 渲染循環function animate() {requestAnimationFrame(animate)controls.update()renderer.render(scene, camera)}animate()
}// 點擊事件處理函數
function onClick(event) {if (!model) return// 計算鼠標歸一化坐標const mouse = new THREE.Vector2()mouse.x = (event.clientX / window.innerWidth) * 2 - 1mouse.y = -(event.clientY / window.innerHeight) * 2 + 1// 創建射線const raycaster = new THREE.Raycaster()raycaster.setFromCamera(mouse, camera)// 獲取模型中的所有可交互對象const intersects = raycaster.intersectObject(model, true)if (intersects.length > 0) {console.log('點擊了模型!', intersects[0].object)alert('你點擊了模型上的一個部件')}
}// 響應窗口變化
window.addEventListener('resize', () => {if (!camera || !renderer) returncamera.aspect = viewerContainer.value.clientWidth / viewerContainer.value.clientHeightcamera.updateProjectionMatrix()renderer.setSize(viewerContainer.value.clientWidth, viewerContainer.value.clientHeight)
})onMounted(() => {init()
})
</script><style scoped>
.model-viewer-container {width: 100%;height: 100vh;
}
</style>
文件結構建議
your-project/
├── public/
│ └── models/
│ └── test.glb <-- 放置你的模型文件
├── src/
│ └── components/
│ └── ModelViewer.vue
注意:模型放在
public/models/
目錄下,通過/models/test.glb
路徑訪問。
🔧 功能說明
功能 | 實現方式 |
---|---|
加載模型 | 使用 GLTFLoader 加載 .glb 或 .gltf 模型 |
控制視角 | 使用 OrbitControls 實現自由旋轉、縮放、平移 |
點擊事件 | 使用 Raycaster 進行射線檢測,判斷是否點擊到模型 |
響應式布局 | 監聽 resize 事件并更新相機和渲染器尺寸 |
擴展建議
需求 | 推薦做法 |
---|---|
多個模型加載 | 使用 Promise.all() 異步加載多個模型 |
模型動畫播放 | 使用 AnimationMixer 和 Clock 控制動畫 |
加載進度條 | 使用 LoadingManager 顯示加載百分比 |
自定義材質 | 遍歷模型子對象并修改材質顏色、透明度等屬性 |
高亮選中部分 | 修改點擊對象的材質顏色或使用 OutlinePass 后期高亮 |