在 Vue 中使用 Three.js 渲染 GLB 格式模型

发布于:2025-05-16 ⋅ 阅读:(14) ⋅ 点赞:(0)

在 Vue 项目中渲染 GLB 格式的 3D 模型需要结合 Three.js 和 GLTFLoader。以下是完整的实现步骤:

  1. 安装必要的依赖
    首先安装 Three.js 和 GLTFLoader:
npm install three @types/three
  1. 页面中加载和渲染 GLB 模型
    (glb模型放入本地/assets/public文件夹下了)
<template>
  <div ref="container" style="width: 100%; height: 100vh;"></div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import url from '@/assets/public/jizu.glb'

const container = ref(null);

let scene, camera, renderer, controls, animationId;

onMounted(() => {
  // 1. 初始化场景
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xaaaaaa);

  // 2. 初始化相机
  const width = container.value.clientWidth;
  const height = container.value.clientHeight;
  camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
  camera.position.set(0, 2, 5);

  // 3. 初始化渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(width, height);
  container.value.appendChild(renderer.domElement);

  // 4. 添加光源
  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);
  scene.add(directionalLight);

  // 5. 添加轨道控制器
  controls = new OrbitControls(camera, renderer.domElement);
  controls.target.set(0, 1, 0);
  controls.update();

  // 6. 加载 GLB 模型
  const loader = new GLTFLoader();
  console.log(loader,'111')
  loader.load(
    url, // 替换成你的模型路径
    (gltf) => {
      console.log(gltf,'222')
      scene.add(gltf.scene);
    },
    undefined,
    (error) => {
      console.error('加载模型失败:', error);
    }
  );

  // 7. 动画循环
  function animate() {
    animationId = requestAnimationFrame(animate);
    controls.update();
    renderer.render(scene, camera);
  }
  animate();

  // 8. 监听窗口大小变化
  window.addEventListener('resize', onWindowResize);
});

function onWindowResize() {
  if (!container.value) return;
  const width = container.value.clientWidth;
  const height = container.value.clientHeight;
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
}

onBeforeUnmount(() => {
  window.removeEventListener('resize', onWindowResize);
  cancelAnimationFrame(animationId);
  controls.dispose();
  renderer.dispose();
  // 清理场景中的所有对象,防止内存泄漏
  scene.traverse((obj) => {
    if (obj.geometry) obj.geometry.dispose();
    if (obj.material) {
      if (Array.isArray(obj.material)) {
        obj.material.forEach((m) => m.dispose());
      } else {
        obj.material.dispose();
      }
    }
  });
  scene.clear();
});
</script>

如果使用的是vite可能会报错,在vite.config.js文件下加入:assetsInclude: ['**/*.glb'], // 明确包含GLB文件

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  assetsInclude: ['**/*.glb'], // 明确包含GLB文件
  server: {
    https: false,
    // host: "0.0.0.0",
    port: 9001,
    open: true,
    cors: true,
    strictPort: false,
    proxy: {
      '/api': {
        target: 'http://1.117.236.127',
        changeOrigin: true,
        rewrite: (path) => path.replace("/api", "")
      },
    }
  },
})

网站公告

今日签到

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