探索3D世界的无限可能,通过Vue3与Three.js结合程序化生成技术,告别传统建模方式,实现高效动态构建。本文将详细介绍如何从零打造可交互的3D资产系统。
不写模型文件,用代码「捏」出 3D 世界:Vue3 + Three.js 程序化资产生成实战
本文对应开源仓库:qdcxj/three.js-3d-assets
基于原项目:boytchev/3d-assets 的 Vue 3 二次开发版本
效果预览
Demo 展示页(/demo)呈现16种程序化生成的3D资产,每张卡片展示一个模型,支持点击"重新生成"按钮创建随机变体。
前言:为什么不用 .glb?
传统3D开发流程通常采用Blender建模后导出glTF格式,再由Three.js加载。虽然可行,但存在以下痛点:
问题
程序化生成的解法
尺寸修改需重新建模
调整数值即可实时重建几何体
变体数量与文件量成正比
一套参数数据配合generate()方法支持无限变体
下载体积庞大
纯JS计算实现,代码仅KB级别
UI控件难以联动
参数即API,天然支持表单对接
程序化生成(Procedural Generation)的核心思想在于:通过参数化设计实现动态建模。
本项目(three.js-3d-assets)基于boytchev/3d-assets进行了Vue化改造,已实现16种常见物体(如杯子、桌子、衣柜等),支持滑块实时调参、随机生成和场景组合展示功能。
下面将从架构设计到源码实现,完整解析实现方法。
一、整体架构
┌─────────────────────────────────────────────────────────┐
│ Vue 视图层 │
│ AllInOne.vue / Demo.vue │
│ · 下拉选择资产 · 参数面板 · 滑块实时刷新 │
└───────────────────────┬─────────────────────────────────┘
│
┌───────────────────────▼─────────────────────────────────┐
│ ThreeScene.vue + useThreeScene.js │
│ · Scene / Camera / Renderer / OrbitControls │
│ · addObject / removeObject / clearScene │
└───────────────────────┬─────────────────────────────────┘
│
┌───────────────────────▼─────────────────────────────────┐
│ src/assets/ 资产层 │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ mug.js │ │ table.js │ │ catalog.js │ │
│ │ plate.js │ │ wardrobe.js │ │ (分类注册表) │ │
│ └──────┬──────┘ └──────┬───────┘ └───────────────┘ │
│ └────────────────┴──────────────────────────────│
│ │ │
│ assets-utils.js (基类 + 自定义几何体) │
│ bin-packing.js (UV 图集打包) │
└─────────────────────────────────────────────────────────┘
数据流(调参时发生了什么):
二、项目目录说明
src/
├── assets/ # 程序化资产核心
│ ├── assets-utils.js # Asset 基类、LatheUVGeometry、RoundedBoxGeometry...
│ ├── bin-packing.js # UV 矩形打包算法
│ ├── mug.js / plate.js ... # 每个物体一个模块
│ ├── procedural-kit.js # 【扩展】工厂函数,快速批量造物体
│ ├── catalog.js # 【扩展】分类目录(家具/兵器/交通...)
│ └── index.js # 统一导出
├── components/
│ └── ThreeScene.vue # 3D 画布封装
├── composables/
│ └── useThreeScene.js # Three.js 生命周期管理
└── views/
├── AllInOne.vue # 全场景 / 单物体展示 + 参数面板
└── Demo.vue # 分卡片 Demo
三、核心设计:每个物体都是一个 Class
所有资产继承自Asset基类(本质是THREE.Group):
// assets-utils.js
class Asset extends Group { // 从 paramData 自动提取默认值
static get defaults() {
let result = {}
for (const [key, param] of Object.entries(this.paramData)) {
result[key] = param.default
}
return result
} // 按 min/max/chance 随机生成一套参数
static random() {
let result = {}
for (const [key, param] of Object.entries(this.paramData)) {
if (param.type != Boolean) {
result[key] = random(param.min, param.max, param.prec)
}
if (param.type == Boolean) {
result[key] = Math.random() < param.chance
}
}
return result
}
}
3.1 标准