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

发布于:2025-05-08 ⋅ 阅读:(18) ⋅ 点赞:(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() 异步加载多个模型
模型动画播放 使用 AnimationMixerClock 控制动画
加载进度条 使用 LoadingManager 显示加载百分比
自定义材质 遍历模型子对象并修改材质颜色、透明度等属性
高亮选中部分 修改点击对象的材质颜色或使用 OutlinePass 后期高亮

网站公告

今日签到

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