文章目录
摘要:最近「Vue 3D 正式引入 WebGPU」的说法在社区传得很广,不少人顺势得出结论:「那它是不是和 Three.js 差不多了?」这个判断对了一半,也错了一半。本文分三层讲清楚:① 「Vue 3D」到底是什么,它和 Three.js 是替代关系还是上下游关系;② TresJS v5 的 WebGPU 支持到底是不是「正式」,能力边界在哪;③ 站在技术选型视角,给出 Vue3 项目做 3D 的正面对比、性能真相与决策树。全文含最小可跑代码、TSL 迁移的真实坑,以及一个「不站队」的混合结论。读完你应该能回答两个问题:这次更新我该不该动?动的话,该动哪一层?
关键词:TresJS、Vue 3、Three.js、WebGPU、TSL、WebGL、声明式渲染、技术选型
适合人群:有 Vue3 项目经验、正在评估或已经上手 Web 3D 的前端开发者与架构师;对 WebGPU 听说过但没系统了解的同学。

一、先破除三个误会(这是本文最重要的部分)
社区里关于这次更新的三个流行说法,几乎每一个都需要修正。先把结论摆出来,后面再逐个拆。
| 流行说法 | 真相 | 性质 |
|---|---|---|
| 「Vue 3D 正式引入 WebGPU」 | TresJS v5 引入的是实验性(experimental) WebGPU 支持,官方公告原文就是 experimental | 措辞夸大 |
| 「它和 Three.js 差不多」 | TresJS 底层就是 Three.js,两者不是同层竞品,是上下游 | 概念混淆 |
| 「WebGPU 就是更快,换就完了」 | 对简单场景是真·一行切换;对任何手写 Shader 的项目,是材料层重写 | 严重低估成本 |
一句话总结这三个误会:「Vue 3D」不是一个新引擎,它是套在 Three.js 外面的声明式外壳;它这次的 WebGPU 能力,是借用 Three.js 的 WebGPURenderer 实现的,而不是自己造了一套 WebGPU 管线。 所以「和 Three.js 差不多」这句直觉——在引擎层是对的(因为就是同一个引擎),在生态位是错的。
想明白这一点,后面所有对比都会变得顺理成章。
二、概念扫盲:四个人一台戏
在讨论之前,必须先把四个经常被混为一谈的名字摆正位置。很多「Vue2 还是 Vue3 做 3D 好」的争论,本质是把不同层的东西放在一起比。
| 名词 | 是什么 | 属于哪一层 | 类比 |
|---|---|---|---|
| WebGL | 2010 年代的浏览器图形 API | 底层图形接口 | 老式手动挡变速箱 |
| WebGPU | 新一代浏览器图形 + 计算 API,支持计算着色器 | 底层图形接口 | 新一代自研变速箱 |
| Three.js | 跨浏览器的 3D 渲染库(场景图 / 相机 / 材质 / 加载器) | 中间渲染层 | 整车平台 |
| TresJS(俗称 Vue 3D) | 给 Vue3 用的声明式 Three.js 框架,把场景拆成组件 | 上层框架层 | 针对某发动机定制的车身与内饰 |
关键关系只有一句:TresJS 依赖 Three.js,而不是取代 Three.js。
看懂这张图,你就能理解为什么「TresJS 支持 WebGPU」这句话,本质上等于「TresJS 允许你把内部的渲染器换成 Three.js 的 WebGPURenderer」。能力上限由 Three.js 决定,TresJS 决定的是你写起来爽不爽。
2.1 声明式 vs 命令式:差在哪
这不是风格问题,是心智模型问题。
| 维度 | Three.js(命令式) | TresJS(声明式) |
|---|---|---|
| 场景构建 | 手动 new Scene()、scene.add() | 写组件树,自动挂载/卸载 |
| 状态同步 | 自己监听数据变化改对象属性 | 模板里绑定响应式数据即可 |
| 生命周期 | 手动 dispose 几何体、材质、纹理 | 组件卸载自动清理 |
| 复用 | 靠函数与类封装 | 靠 Vue 组件与 composable,天然可复用 |
| 与本项目状态管理 | 需要桥接层 | 直接吃 ref / computed / Pinia |
| 学习成本 | 学 Three.js 一套 API | 学 Three.js + Vue 组件约定 |
一句话:Three.js 让你「操作对象」,TresJS 让你「描述状态」。 这与 React 生态里 React Three Fiber(R3F)之于 Three.js 的关系完全同构——TresJS 就是 Vue 版的 R3F。
三、WebGPU 这次为什么不一样:把时间线捋直
要判断这次更新值不值得动,得先知道 WebGPU 这条线走到哪了。下面这条时间线是本文所有选型建议的事实底座(含第三方 2026 年的追踪报道,具体版本号请以官方 release 为准)。
| 时间 | 事件 | 对开发者的意义 |
|---|---|---|
| 2025-09 | Three.js r171 把 WebGPURenderer 作为可用方案推出 | 换渲染器≈改一行 import,并自动回退 WebGL2 |
| 2025-09-22 | TresJS v5 发布,引入实验性 WebGPU 支持 | Vue 侧第一次能吃到 WebGPURenderer |
| 2026-01 | WebGPU 在主流浏览器达到「Baseline」级可用(Chrome / Edge / Firefox / Safari 26) | WebGL 十五年统治期正式进入尾声 |
| 2026-04-16 | Three.js r184 | 修掉每帧数十万次的多余对象分配,减少卡顿 |
| 2026-07-01 | Three.js r185 | 移除废弃代码;计算着色器光栅化、WebGPU 蒙皮实例化 |
| 2026-09-08 | Three.js r186 | SunLight、级联阴影、compileComputeAsync();WebGPU 成为默认预期路径 |
3.1 WebGPU 到底强在哪
官方文档的说法很克制,翻译成人话是四条:
- 更低的 CPU 开销:驱动提交命令的成本大幅下降,复杂场景的 draw call 不再先卡在 CPU 上。
- 计算着色器:真正能拿 GPU 做通用计算,粒子、模拟、GPU 拾取这类以前只能凑合做的事变得可行。
- 统一 API:图形与计算一套 API,还有
GPURenderBundles、间接绘制等现代特性。 - 为未来设计:面向现代 GPU 架构,而不是兼容十年前的设计。
社区里流传的一组行业参考值(非厂商基准,实测差异很大,仅作量级感知):WebGL 下 GPU 粒子上限大致在 5 万级,WebGPU 计算着色器可推到百万级;有团队报告某些数据密集场景提速数十倍。这类数字请当成「量级参考」而非承诺,你的真实收益取决于场景是 CPU 瓶颈还是 GPU 瓶颈。
3.2 浏览器支持:别被「全平台可用」带偏
这是最容易被自媒体简化的一句话。准确状态是:
| 浏览器 | 状态(2026) |
|---|---|
| Chrome / Edge | 自 113 起稳定支持 |
| Safari(macOS 26+ / iOS 26) | 已支持 |
| Firefox | 默认仍可能关闭 / 需实验开关 |
只要 Firefox 还存在默认关闭的情况,WebGL2 回退路径就不是「可选项」,而是一条你必须测试的一等公民路径。 换句话说:WebGPU 准备好了,但你的双后端维护成本并没有归零。
3.3 为什么 WebGPU 能更快:架构差异
很多人把 WebGPU 理解成「WebGL 的加速版」,这是误读。两者的差别是架构级的:
| 对比项 | WebGL | WebGPU |
|---|---|---|
| 设计年代 | 2011 年左右,脱胎于 OpenGL ES | 面向现代 GPU 架构重新设计 |
| API 模型 | 全局状态机,逐条设置状态 | 显式对象(Pipeline / BindGroup) |
| 命令生成 | 单线程,每帧在 JS 主线程拼装 | 支持多线程录制命令 |
| 计算能力 | 基本没有通用的计算着色器 | 原生计算着色器 |
| CPU 提交开销 | 高(状态切换昂贵) | 低(预录制 + 复用) |
| 绘制批量 | 逐个 draw call | GPURenderBundles / 间接绘制可预录制 |
| 着色语言 | GLSL ES | WGSL(配合 TSL 可跨编译) |
用人话解释最关键的一条:WebGL 时代,你其实是在 JS 主线程里「指挥」GPU,每一个 draw call 都要走一遍昂贵的状态校验和驱动调用。 当场景里有上万个对象时,CPU 先被拖垮,GPU 反而空转。WebGPU 的 GPURenderBundles 允许你把一批绘制命令预先录制好,运行时一次提交——这就是为什么它能在「对象特别多」的场景里拉开差距。
这解释了一个反直觉的现象:WebGPU 对「几十个对象的小场景」可能毫无提升,对「上万对象的大场景」却可能是数倍差距。 选型时先问自己:我的瓶颈是 CPU 提交,还是 GPU 填充?前者才吃 WebGPU 的红利。
四、TresJS v5 的 WebGPU 到底怎么用(最小可跑)
下面这段是官方推荐的做法,我在官方示例的基础上补全了被省略的 import,让它真正能跑起来(官方文档片段漏了 toValue 的来源,直接抄会报错)。
4.1 起项目
# 官方 CLI,一条命令配好 Vue+Vite/Nuxt 模板、TS、ESLint 与生态包
npx create-tres my-tres-project
v5 是 ESM-only:UMD 构建被移除。老项目升级前,先确认构建链支持 ESM,否则会在打包阶段直接炸。
4.2 挂上 WebGPU 渲染器
<script setup lang="ts">
import { toValue } from 'vue' // 官方片段漏了这行,补上
import { TresCanvas } from '@tresjs/core'
import { WebGPURenderer } from 'three/webgpu' // 关键:从 three/webgpu 引入
import type { TresRendererSetupContext } from '@tresjs/core'
// 渲染器工厂:TresJS 会把 canvas 交给你,由你决定实例化哪种渲染器
const createWebGPURenderer = (ctx: TresRendererSetupContext) => {
const renderer = new WebGPURenderer({
canvas: toValue(ctx.canvas),
alpha: true,
antialias: true,
})
return renderer
}
</script>
<template>
<TresCanvas :renderer="createWebGPURenderer">
<TresPerspectiveCamera :position="[3, 3, 3]" :look-at="[0, 0, 0]" />
<TresMesh>
<TresBoxGeometry :args="[1, 1, 1]" />
<TresMeshBasicMaterial color="hotpink" />
</TresMesh>
<TresAmbientLight :intensity="1.5" />
</TresCanvas>
</template>
三个必须知道的细节:
WebGPURenderer来自three/webgpu,不是three。这是最常见的踩坑点。- 回退是自动的。浏览器不支持 WebGPU 时,
WebGPURenderer内部会退回 WebGL2 后端,所以这段代码不需要你写兼容分支。 - init 是异步的。TresJS 内部(
useRendererManager)已经帮你处理了初始化与首次渲染时序。但如果你是绕过 TresJS 手动new WebGPURenderer(),请务必先await renderer.init()再渲染——否则纹理转码会在后端确定之前发生,典型症状是模型贴图发黑(这是今年论坛上最高频的 bug)。
4.3 同一个需求,两种写法
「一个自转的立方体」最能说明抽象差异:
// ❌ Three.js 命令式:零件级组装
import * as THREE from 'three'
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, w / h, 0.1, 100)
camera.position.z = 2
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(w, h)
document.body.appendChild(renderer.domElement)
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshBasicMaterial({ color: 'hotpink' })
)
scene.add(cube)
renderer.setAnimationLoop(() => {
cube.rotation.x += 0.01
cube.rotation.y += 0.01
renderer.render(scene, camera)
})
<!-- ✅ TresJS 声明式:描述状态 -->
<script setup>
import { ref, onBeforeUnmount } from 'vue'
import { TresCanvas, useLoop } from '@tresjs/core'
const cubeRef = ref()
const { onBeforeRender } = useLoop()
onBeforeRender(() => {
if (!cubeRef.value) return
cubeRef.value.rotation.x += 0.01
cubeRef.value.rotation.y += 0.01
})
</script>
<template>
<TresCanvas>
<TresPerspectiveCamera :position="[0, 0, 2]" />
<TresMesh ref="cubeRef">
<TresBoxGeometry />
<TresMeshBasicMaterial color="hotpink" />
</TresMesh>
</TresCanvas>
</template>
注意 useLoop(v5 里取代了旧的 useRenderLoop),以及组件卸载时的清理由 TresJS 接管——在 Three.js 里,忘 dispose() 就是内存泄漏;在 TresJS 里,这层负担被框架吃了。
4.4 v5 的破坏性变更清单(升级前必看)
v5 是一次大版本跃迁,除了 WebGPU,还有一批会「静默出错」的变更。官方公告里列得很清楚,我整理成一张对照表:
| 变更项 | v4 写法 | v5 写法 | 风险 |
|---|---|---|---|
| 打包格式 | 支持 UMD | 仅 ESM | 老构建链直接失败 |
| 指针事件名 | @pointer-down | @pointerdown(标准 DOM) | 事件静默失效 |
| 事件触发范围 | 多个重叠对象都可能触发 | 只触发首个被拾取对象 | 交互逻辑需改用父级处理 |
| 就绪回调 | useTresReady() | TresCanvas 的 @ready | 组合式调用的老代码失效 |
| 渲染循环 | useRenderLoop() | useLoop() | —— |
| 节点查找 | useSeek() | useGraph() | —— |
| 事件管理器 | useTresEventManager() | 已移除,用原生事件 | —— |
| 纹理工具 | useTexture(core) | 迁移到 @tresjs/cientos | import 路径变更 |
| 加载器 | useLoader 返回 Promise | 返回响应式状态对象 | 调用方式重写 |
其中最需要留意的是 useLoader 的语义变化:它从「返回一个 Promise 的工具函数」变成了「真正返回响应式状态的真 composable」。这不是改名,是调用契约的改变:
<script setup>
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
// ❌ v4:await 一个 Promise
// const gltf = await useLoader(GLTFLoader, '/models/duck.gltf')
// ✅ v5:解构响应式状态,加载进度天然可响应
const { state: model, isLoading, error, progress } = useLoader(
GLTFLoader,
'/models/duck.gltf'
)
</script>
这次重构的动机值得一提:官方坦承,v4 里很多所谓的「composable」其实只是包了 Three.js API 的普通工具函数,并不具备 Vue composable 应有的响应式与生命周期语义。v5 把它们改成真 composable 后,带来三个实际收益:加载状态响应式、资源自动清理、加载路径可动态切换。
五、TresJS vs Three.js 正面对比
这是本文的核心对比表。再次强调:它们不是竞品,这张表的正确读法是「在不同的工程约束下,我该选哪一层」。
| 维度 | Three.js(直用) | TresJS(Vue 封装) |
|---|---|---|
| 定位 | 通用 3D 渲染库 | Vue3 声明式 3D 框架 |
| 渲染内核 | Three.js | 同一套 Three.js |
| 编程范式 | 命令式 | 声明式组件树 |
| 状态同步 | 手动 | 响应式自动同步 |
| 资源清理 | 手动 dispose | 组件卸载自动 |
| 复用单位 | 函数 / 类 | Vue 组件 / composable |
| 与 Pinia / Composition API | 需桥接 | 原生 |
| WebGPU 接入 | 换 renderer,一行 import | 传入 renderer 工厂函数 |
| 生态 | 极其庞大,任何问题都有答案 | 较新,有 Cientos / 后处理等配套 |
| 学习成本 | 学一套 Three API | 学 Three API + Vue 约定 |
| 迁移风险 | —— | v5 有多个破坏性变更 |
| 适用团队 | 任意技术栈 / 多框架 | 已深度使用 Vue3 的项目 |
| 性能 | 基准 | 与 Three.js 同源,无本质差异 |
5.1 性能真相:为什么「差不多」既对也错
对的部分:TresJS 底层就是 Three.js,渲染管线、draw call、GPU 负载完全一致。任何声称「TresJS 性能碾压 Three.js」的说法都站不住——它们是同一台发动机。声明式外壳会带来极小的响应式开销,但在正常场景里可以忽略。
错的部分:性能的真正分水岭不在「TresJS 还是 Three.js」,而在「WebGL 还是 WebGPU」,以及更隐蔽的一层——你的材质是不是手写 GLSL。
六、真正的坑:ShaderMaterial 在 WebGPU 下跑不了
这是本次升级中最被低估、也最容易翻车的地方,值得单独拉出来讲。
在 WebGPURenderer 的原生路径下,手写的 ShaderMaterial / RawShaderMaterial(也就是字符串形式的 GLSL)是不被支持的。 Three.js 新推的是 TSL(Three Shading Language)——一套节点式着色语言,写一遍,编译到 WGSL(WebGPU)与 GLSL(WebGL)两个目标。
对 GLB / glTF 这种标准管线,这件事无感:MeshStandardMaterial、PBR 贴图会自动转成节点材质图,Draco、KTX2 解码路径不变。但只要你手写过自定义 shader(水面、描边、顶点位移的草、溶解特效……),就得整体改写成 TSL 节点图,这不是「一行切换」。
// ❌ 旧:字符串 GLSL,WebGPURenderer 原生路径不支持
const mat = new THREE.ShaderMaterial({
vertexShader: `
uniform float uTime;
void main() {
vec3 p = position;
p.y += sin(p.x * 4.0 + uTime) * 0.2;
gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 1.0);
}`,
fragmentShader: `void main() { gl_FragColor = vec4(1.0, 0.3, 0.0, 1.0); }`,
})
// ✅ 新:TSL 节点图,一套源码同时编译到 WGSL / GLSL
import * as THREE from 'three/webgpu'
import { positionLocal, sin, time, vec4 } from 'three/tsl'
const mat = new THREE.MeshBasicNodeMaterial()
const displaced = positionLocal.toVar()
displaced.y.addAssign(sin(displaced.x.mul(4).add(time)).mul(0.2))
mat.positionNode = displaced // 顶点位移
mat.colorNode = vec4(1.0, 0.3, 0.0, 1.0)
结论:你的迁移成本,与你项目里手写 shader 的数量成正比。 纯标准材质项目几乎零成本,特效密集项目请老实排期。
顺带一提,后处理系统在 r183 把
PostProcessing改名为RenderPipeline,从 WebGL 教程里抄来的EffectComposer写法在 WebGPU 路径下会静默失效(不报错,就是没效果)。这也是 TSL 化的一部分。
七、选型决策树与混合方案
把所有信息压缩成一张图:
7.1 我的建议(不站队版)
- 已有 Vue3 项目 + 场景与界面状态强耦合(配置器、数据看板里的 3D、可视化):上 TresJS。声明式带来的可维护性收益,远大于那一层抽象的成本。
- 纯 3D 展示页 / 独立渲染模块:Three.js 直用反而更轻,少一层就少一个要跟的版本。
- WebGPU 的引入节奏:把它当成渐进增强,而不是一次性切换。先用
WebGPURenderer拿到自动回退,跑通业务,再逐步把热点的自定义 shader 迁到 TSL。 - 混合方案(最务实):Three.js 内核 + TresJS 外壳,是天然的混合——你随时可以在 TresJS 里用
<primitive>直接塞原生 Three.js 对象,也可以在需要极致控制的地方脱离组件约定写命令式代码。不必二选一。
| 场景 | 推荐组合 |
|---|---|
| Vue3 配置器 / 数据看板 | TresJS + WebGPURenderer,标准材质 |
| 特效密集型项目 | TresJS + WebGLRenderer,等 TSL 版本成熟再切 |
| 独立 3D 展示 | Three.js,按需选 WebGPU |
| 需要极致性能/自定义管线 | 原生 WebGPU(脱离 Three.js) |
7.2 如果你决定上,按这个顺序走
不要一上来就 WebGPURenderer 全量切换。建议分四步,每一步都可回退:
- 先升 TresJS v5,但渲染器仍用默认(WebGL)。把 4.4 表里的破坏性变更先消化掉——事件名、
useLoader、被移除的 composable。这一步与 WebGPU 无关,风险最低。 - 盘点自定义 shader。全项目搜
ShaderMaterial/RawShaderMaterial/EffectComposer。数量为 0,可以大胆进第 3 步;数量不为 0,先给它们排 TSL 重写的工作量。 - 切换到
WebGPURenderer,验证回退路径。重点测三件事:GLB 贴图是否发黑(KTX2 转码)、后处理是否还有效果(旧的EffectComposer会被静默忽略)、移动端是否走了 WebGL2 回退且表现正常。 - 逐块做 TSL 迁移,每迁一个就 A/B 对比帧率与视觉一致性,同时保留 WebGL 回退分支直到稳定。
一个容易被忽略的验证点:你必须在「禁用 WebGPU 的浏览器」上也跑一遍。因为回退路径是真实存在的代码分支,不是理论上的兜底。目前最省事的做法是在 Chrome 里用 chrome://flags 关掉 WebGPU 模拟老环境,或在 Firefox 默认配置下直接测。
八、常见误区 FAQ
Q1:TresJS 会取代 Three.js 吗?
不会,也不可能——它建在 Three.js 之上。Three.js 停止维护的那天,TresJS 才是真的要完。它们是一荣俱荣的关系。
Q2:TresJS v5 的 WebGPU 是「正式版」吗?
不是。官方原文是 experimental(实验性),明确提示「规范仍在演进,可能有破坏性变更」。宣传里说「正式引入」是措辞夸大。
Q3:换了 WebGPU 就一定会更快吗?
不一定。如果瓶颈在业务逻辑或 JS,WebGPU 帮不上忙。真正的增益来自 CPU 提交开销与计算着色器,GPU 瓶颈场景才明显。简单场景提升可能微乎其微。
Q4:老项目升级 v5 要注意什么?
v5 是一大版本,破坏性变更不少:UMD 被移除(ESM-only)、事件名改为标准 DOM 格式(@pointerdown 而非 @pointer-down)、多个 composable 被移除或迁移(useTresReady → @ready、useRenderLoop → useLoop、useSeek → useGraph、useTexture 移到 @tresjs/cientos),useLoader 也从「返回 Promise 的工具函数」变成「返回响应式状态的真 composable」。
Q5:只为了 WebGPU,值得升级吗?
如果你的项目没有自定义 shader且已有性能痛点,值得。否则建议按 v5 的其它收益(CLI、真 composable、Devtools、Nuxt4 支持)来评估升级价值,WebGPU 当赠品。
九、总结
- 「Vue 3D = TresJS」,它是 Three.js 的 Vue 声明式外壳,不是新引擎。 「和 Three.js 差不多」在引擎层是对的——因为就是同一个引擎。
- 这次的 WebGPU 支持是借用 Three.js 的
WebGPURenderer实现的,且状态是「实验性」。 「正式引入」的说法需要打折。 - 性能的分水岭不在 TresJS vs Three.js,而在 WebGL vs WebGPU,以及你的材质是不是手写 GLSL。 手写
ShaderMaterial在 WebGPU 原生路径下不工作,是本次最大的迁移成本。 - 选型的核心问题是「你是 Vue3 项目吗,场景和界面状态耦合深不深」,而不是「哪个更快」。
- 最务实的策略是渐进增强 + 混合:TresJS 外壳 + Three.js 内核,先拿自动回退,再逐块把热点 shader 迁到 TSL。不必二选一。
Web 3D 的技术栈从来不是「选一个赢家」,而是「在哪一层停下」。Three.js 管你到渲染器,TresJS 再往上帮你管到组件,WebGPU 换掉的是最底下那块发动机。想清楚你的团队愿意维护到哪一层,答案就清楚了。
参考与延伸阅读
- TresJS 官方公告 Announcing Tres 5.0(tresjs.org,2025-09-22)
- TresJS 官方文档 WebGPU(docs.tresjs.org/api/advanced/web-gpu)
- Three.js 官方文档与 release notes(r171 / r183 / r184 / r185 / r186 相关条目)
- MDN WebGPU API 与 caniuse 的 WebGPU 支持矩阵
- 社区对 WebGPU 迁移真实成本的实测讨论(含
ShaderMaterial不支持、KTX2 贴图发黑等具体问题) - 相关延伸:TSL(Three Shading Language)、
RenderPipeline节点式后处理、React Three Fiber(对照 Vue 侧生态)
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/mss359681091/article/details/166995802




