Three.js在vue中的使用(二)-加载、控制

发布于:2025-05-08 ⋅ 阅读:(271) ⋅ 点赞:(0)

在 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, model

function init() {
  // 创建场景
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0xeeeeee)

  // 创建相机
  const width = viewerContainer.value.clientWidth
  const height = viewerContainer.value.clientHeight
  camera = 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.scene
      scene.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 - 1
  mouse.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) return
  camera.aspect = viewerContainer.value.clientWidth / viewerContainer.value.clientHeight
  camera.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 后期高亮

微信公众号

今日签到

点亮在社区的每一天
去签到