【前端进阶之旅】Vue3 + Three.js 实战:从零构建交互式 3D 立方体场景

文章目录

本文为Three.js系列文章,专注前端 3D 可视化领域,从基础原理到实战落地,带你从零掌握 Three.js,适配 Web 端 VR、数字孪生、3D 展厅、数据可视化等主流业务场景。

【前端进阶之旅】3D 引擎的基本理解 ------ 基于 Three.js,吃透 3D 场景六大核心要素
项目完整代码请看这里

前言

Three.js,作为目前业界最主流、生态最完善的 WebGL 开源框架,它封装了复杂的底层 WebGL API,让前端开发者无需深入学习图形学知识,就能快速在网页中构建出高性能、沉浸式的 3D 场景,是前端踏入 3D 世界的最佳入门选择。

一、前置准备:Three.js 环境搭建

npm + Vite 工程化引入(实际项目首选)

bash 复制代码
# 安装Three.js核心库
npm install three
# 安装可视化调试工具
pnpm add dat.gui 
pnpm add @types/dat.gui -D

在项目中引入使用:

bash 复制代码
<script setup lang="ts">
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/Addons.js";
import { onMounted, ref } from "vue";
import gsap from "gsap";
import * as dat from "dat.gui";
// ...
</script>

二、初始化 Three.js 核心三要素:场景、相机、渲染器

上一篇文章我们详细讲解了三大核心要素 ------ 场景 (Scene)、相机 (Camera)、渲染器 (Renderer),只有三者配合,才能完成一次完整的 3D 画面渲染,这也是所有 Three.js 项目的基础骨架。
核心 API 与基础用法

javascript 复制代码
// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000,
);
// fov: 视野角度, aspect: 长宽比, near: 近端, far: 远端

// 设置相机位置
camera.position.z = 30;

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染器大小
renderer.setSize(window.innerWidth, window.innerHeight);

const container = ref<HTMLDivElement | null>(null);

onMounted(() => {
  if (container.value) {
    container.value.appendChild(renderer.domElement);
    render();
  }
});

<template>
  <div ref="container" class="container" />
</template>

<style lang="scss" scoped>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.container {
  width: 100vw;
  height: 100vh;
}
</style>

到这里,我们已经完成了 Three.js 最基础的骨架搭建,接下来我们只需要往场景中添加物体、光源、交互逻辑,就能让这个 3D 世界丰富起来。

三、创建物体:几何体与材质

在 Three.js 中,我们想要创建一个可见的 3D 物体,必须由两部分组成:几何体 (Geometry)材质 (Material),再通过网格 (Mesh) 将两者结合,最终添加到场景中。

javascript 复制代码
   // 创建几何体
   const geometry = new THREE.BoxGeometry(10, 10, 10); // 宽, 高, 深度(Z轴)

  // 创建材质
   const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });

   // 创建网格
   const box = new THREE.Mesh(geometry, materials);
   // 设置摄像机位置,-1表示摄像机在物体内部
   box.geometry.scale(1, 1, -1);
   // 将网格添加到场景中
   scene.add(box);

代码中的彩蛋:你可能注意到了代码中有两段被注释掉的函数 useBox 和 useSphere。这是实现360 度全景图的两种常用方法(立方体全景和球体全景)。如果你有六张全景图或一张全景图,取消注释并加载正确的图片路径即可体验 VR 效果。

四、 响应式窗口适配

为了让 3D 场景在浏览器窗口大小改变时也能正常显示,我们需要监听 resize 事件。

javascript 复制代码
window.addEventListener("resize", () => {
  // 更新相机的宽高比
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新相机的投影矩阵
  camera.updateProjectionMatrix();
  // 更新渲染器的尺寸
  renderer.setSize(window.innerWidth, window.innerHeight);
});

五、集成 dat.GUI 实现可视化调试

dat.GUI 是一个非常棒的工具,它能让我们快速生成一个控制面板,实时修改参数而不用改代码。

typescript 复制代码
// 初始化 GUI
const gui = new dat.GUI();

// 创建一个文件夹来管理立方体相关属性
const boxFolder = gui.addFolder("立方体属性");

// 添加位置控制滑块
boxFolder.add(box.position, "x").name("移动X轴").min(-10).max(10).step(0.01);
boxFolder.add(box.position, "y").name("移动Y轴").min(-10).max(10).step(0.01);
boxFolder.add(box.position, "z").name("移动Z轴").min(-10).max(10).step(0.01);

// 添加颜色选择器
boxFolder
  .addColor({ color: 0x00ff00 }, "color")
  .name("修改颜色")
  .onChange((value) => {
    box.material.color = new THREE.Color(value);
  });

// 定义参数对象,用于控制显示隐藏和触发动画
const params = {
  visible: true,
  moveAnimation: () => {
    gsap.to(box.position, { x: 10, duration: 2, yoyo: true });
  }
}

// 添加复选框和按钮
boxFolder.add(params, "visible").name("显示/隐藏").onChange((value) => {
  box.visible = value;
})
boxFolder.add(params, "moveAnimation").name("移动动画");
boxFolder.open(); // 默认展开该文件夹

// 同理,添加相机属性控制文件夹
const cameraFolder = gui.addFolder("相机属性");
// ... (代码省略,与立方体类似)
cameraFolder.open();

六、轨道控制器 (OrbitControls)

这是让场景 "动" 起来的关键。它允许我们通过鼠标拖拽旋转视角、滚轮缩放。

typescript 复制代码
// 声明控制器变量
let controls: OrbitControls;

// 用于绑定DOM的 ref
const container = ref<HTMLDivElement | null>(null);

// 渲染循环函数
const render = () => {
  // 如果有控制器,需要在每一帧更新(特别是开启阻尼效果时)
  controls && controls.update();
  
  // 执行渲染
  renderer.render(scene, camera);
  
  // 请求下一帧,形成循环
  requestAnimationFrame(render);
};

onMounted(() => {
  if (container.value) {
    // 实例化控制器:需要相机和渲染器的DOM元素作为参数
    controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true; // 开启阻尼(惯性)效果,让交互更丝滑
    controls.update();
    
    // 将渲染器生成的 canvas 挂载到 Vue 模板中
    container.value.appendChild(renderer.domElement);
    
    // 开始渲染循环
    render();
  }
});

七、模板与样式

最后,我们需要一个容器来放置 Three.js 的画布。

html 复制代码
<template>
  <div ref="container" class="container" />
</template>

<style lang="scss" scoped>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.container {
  width: 100vw;
  height: 100vh;
}
</style>

总结

通过这段代码,我们已经掌握了在 Vue3 中使用 Three.js 的基本流程:

  1. 搭建基础: 引入库,创建 Scene、Camera、Renderer。
  2. 添加内容: 创建 Geometry 和 Material,合成 Mesh 并加入场景。
  3. 交互控制: 使用 OrbitControls 进行视角控制。
  4. 调试优化: 使用 dat.GUI 快速调参。
  5. 持续渲染: 使用 requestAnimationFrame 建立动画循环。
相关推荐
视觉人机器视觉2 小时前
海康机器人3D 机器人引导 —— 空间基础篇一
3d·机器人
岱宗夫up2 小时前
【前端基础】HTML + CSS + JavaScript 基础(二)
开发语言·前端·javascript·css·架构·前端框架·html
我是苏苏2 小时前
Web开发:使用Ocelot+Nacos+WebApi作简单网关鉴权
前端·javascript·ui
SuperEugene2 小时前
Day.js API 不包含插件API的速查表
前端·javascript·面试
Mr -老鬼2 小时前
RustSalvo框架上传文件接口(带参数)400错误解决方案
java·前端·python
前端 贾公子2 小时前
Vue3 组件库的设计和实现原理(上)
javascript·vue.js·ecmascript
zheshiyangyang2 小时前
前端面试基础知识整理【Day-9】
前端·面试·职场和发展