三维 BIM 编辑器的下一代架构:React 19 + Next.js 16 + WebGPU 渲染器与 Zustand 离线状态协同实战

三维 BIM 编辑器的下一代架构:React 19 + Next.js 16 + WebGPU 渲染器与 Zustand 离线状态协同实战
三维 BIM 编辑器的下一代架构:React 19 + Next.js 16 + WebGPU 渲染器与 Zustand 离线状态协同实战

Pascal Editor 封面

1. 浏览器端 BIM 编辑器的物理性跃迁

在传统的建筑信息模型(BIM)和 CAD 领域,重型客户端一直占据着绝对统治地位。以往,如果要在浏览器中运行一个三维建筑编辑器,开发者往往受限于 WebGL 渲染引擎的低效和 CPU 单线程几何运算的瓶颈。随着 Web 图形学和前端工程化的飞速发展,这一切正在发生物理性的跃迁。

React 19 的并发渲染(Concurrent Rendering)与即将到来的 Next.js 16 带来了极为优秀的 UI 线程调度能力。而最令人瞩目的图形硬件革新——WebGPU 渲染 API,更是直接打通了浏览器对现代显卡底层能力的访问渠道。通过更低的 CPU 开销、更强大的并行计算和原生的 Compute Shader 支持,复杂的 3D 场景与高精度的实时光影终于在 Web 端成为现实。

本文将以开源三维建筑编辑器 Pascal Editor 的架构设计为蓝本,深入剖析如何构建一套基于 React 19 + Next.js 16 + WebGPU 渲染器 + Zustand 离线状态协同 的次世代 Web BIM 编辑器架构。


2. Turborepo 单仓化多包架构:Editor, Core 与 Viewer 的解耦实践

大型 3D 复杂应用如果采用单体仓库结构,代码很快就会因为渲染逻辑、业务逻辑与 UI 状态的过度耦合而变得无法维护。为了解决这一痛点,Pascal Editor 采用了高度解耦的 Monorepo 结构,并使用高效的 Turborepo 对依赖包和构建流进行管理。

Pascal Editor 架构

整个系统的核心能力被拆分为以下三个主要部分,形成了极佳的高内聚、低耦合设计:

1. apps/editor (编辑器应用层):基于 Next.js 构建,作为编辑器的入口应用。它主要承载上层的用户交互界面(UI)、侧边工具栏、属性面板以及编辑器专有的业务控制系统,绝不涉及底层的 3D 渲染细节。

2. @pascal-app/core (核心业务逻辑层):作为编辑器的“大脑”,它是完全独立于图形框架的纯逻辑库。负责定义场景节点 Schema(如场地、楼层、墙体等拓扑结构)、管理编辑器的全局数据流状态、处理几何体底层解析和空间查询计算。

3. @pascal-app/viewer (渲染层):作为系统的“眼睛”,专门负责 3D 场景的高性能呈现。基于 React Three Fiber(R3F)和 Drei 封装,底层直接对接 Three.js 的 WebGPU 渲染器。它对 Core 包提供纯粹的渲染服务,接收数据节点树并将其转化为高效的 GPU 渲染流水线。

通过 Monorepo 的包级别拆分,我们能够将渲染引擎、业务逻辑和视图层彻底剥离。即使未来需要开发桌面客户端或轻量级 H5 预览端,也只需替换应用层或渲染层,而 @pascal-app/core 的业务大脑完全可以直接复用。


3. 次世代渲染矩阵:Three.js WebGPU Renderer + R3F + Drei

在传统的 WebGL 渲染下,每一次 3D 物体属性更新(例如修改墙体厚度、改变灯光位置)都需要频繁地在 CPU 和 GPU 之间进行上下文切换和数据搬运,这造成了极大的 Draw Call 开销。

Pascal Editor 的渲染核心 @pascal-app/viewer 原生拥抱了 Three.js WebGPU Renderer,并通过 React Three Fiber (R3F) 将 3D 节点无缝映射到 React 的组件声明式生命周期中。WebGPU 的核心优势在于将命令提交设计为非阻塞的,且引入了管线状态对象(Pipeline State Object),能让显卡在运行前就完成编译,从而大幅度降低了 CPU 的提交开销。

以下是 @pascal-app/viewer 中 WebGPU Canvas 组件的声明式初始化和渲染管道绑定的核心实战代码:

import React, { useRef } from 'react';
import { Canvas } from '@react-three/fiber';
import { OrbitControls, PerspectiveCamera } from '@react-three/drei';
import { useScene } from '@pascal-app/core';

// 强制指定 WebGPU 渲染器配置
const webGpuGLOptions = {
powerPreference: "high-performance",
antialias: true,
alpha: false,
};

export const PascalViewer: React.FC = () => {
const { rootNode } = useScene(); // 从 core 获取核心数据源
const canvasRef = useRef<HTMLCanvasElement>(null);

return (
<div className="w-full h-full relative">
<Canvas
ref={canvasRef}
gl={(canvas) => {
// 初始化 Three.js 的次世代 WebGPURenderer
// 注:在最新版 Three.js 中,WebGPURenderer 将作为未来的默认渲染引擎
const renderer = new (window as any).THREE.WebGPURenderer({
canvas,
...webGpuGLOptions
});
return renderer;
}}
>
<PerspectiveCamera makeDefault position={[10, 10, 10]} fov={50} />
<ambientLight intensity={0.5} />
<directionalLight position={[5, 10, 5]} intensity={1.0} castShadow />

{/* 动态场景树渲染 */}
<BIMSceneGraph node={rootNode} />

<OrbitControls enableDamping dampingFactor={0.05} />
</Canvas>
</div>
);
};

结合 R3F 与 Drei 提供的控制器和网格预设,开发者只需用纯声明式的方式管理 3D 组件的状态。一旦 React 状态发生变更,WebGPU 便会自动接收到增量数据并进行超高速光栅化渲染,带来极佳的实时视觉交互反馈。

三维 BIM 编辑器的下一代架构:React 19 + Next.js 16 + WebGPU 渲染器与 Zustand 离线状态协同实战


4. 硬核几何引擎:three-bvh-csg 赋能的“动态墙体切割”

在三维 BIM 编辑中,最频繁且耗费计算资源的操作当属“开窗打洞”。例如,在绘制一面墙体时,如果将门、窗组件拖入墙体中,墙体必须实时进行挖空裁切(CSG 运算,即构造实体几何布尔运算)。

在浏览器中,传统的 CSG 运算(如 three-csg)在进行大规模几何体相减时极其缓慢,容易导致主线程卡死,造成严重的交互掉帧。Pascal Editor 采用了极其硬核的解决方案——three-bvh-csg

three-bvh-csg 利用了层次包围盒(Bounding Volume Hierarchy,简称 BVH)算法。它在做几何体布尔运算前,会先为两个 Mesh 构建紧凑的二叉树空间包围盒,从而在计算时快速剔除绝对不相交的三角面片,仅对真正发生碰撞的局部三角形进行精准相减。这使得原本长达数百毫秒的运算被缩短到了 16ms 以内,实现了在 Web 视口中以 60FPS 流畅拖拽门窗并实时切割墙体的效果。

下面展示了通过 three-bvh-csg 在墙体中动态切割门洞的核心逻辑代码:

import * as THREE from 'three';
import { CSG, Evaluator } from 'three-bvh-csg';

export function cutWallOpening(wallMesh: THREE.Mesh, doorMesh: THREE.Mesh): THREE.Mesh {
// 1. 初始化 BVH-CSG 高效求值器
const evaluator = new Evaluator();
evaluator.useGraph = true; // 启用图连接结构优化面片生成

// 2. 将普通的几何体包装并生成 BVH 空间索引
const wallCSG = CSG.fromMesh(wallMesh);
const doorCSG = CSG.fromMesh(doorMesh);

// 3. 执行布尔求差(Difference)运算:Wall - Door
// BVH 会极大加速寻找相交面上三角片的过程
const resultCSG = evaluator.subtract(wallCSG, doorCSG);

// 4. 将 CSG 结果转换为高效率的 WebGL/WebGPU 物理 Mesh
const newWallMesh = CSG.toMesh(resultCSG, wallMesh.matrix, wallMesh.material);

// 5. 释放临时 CSG 显存,防止大场景下发生 OOM 内存泄露
wallCSG.geometry.dispose();
doorCSG.geometry.dispose();

return newWallMesh;
}

通过这一计算原理,BIM 编辑器能把任何复杂的窗洞、开孔动作转化为秒级无感知的流式运算,保证了三维编辑的极致流畅。


5. 离线状态协同:Zustand + Zundo + IndexedDB 空间状态机

对于一个工业级的 3D BIM 软件,如何优雅地处理大批量 3D 节点的状态变更、实时历史记录回溯(Undo/Redo)以及断电离线保存,是决定产品成败的关键。

Pascal Editor 摒弃了厚重的 Redux,在核心层 @pascal-app/core 中采用了轻量且高性能的 Zustand,并创造性地将其划分为三个职责单一的 Store 构成全局状态机:

Mermaid Diagram

5.1 场景数据状态 (useScene)

负责存放整个建筑场景的节点树(拓扑 Schema)。为了避免建筑项目在大数据量下内存溢出,它与本地高性能数据库 IndexedDB 建立了双向通道。每当数据变更,系统会做增量脏节点检测(Dirty Tracking),流式写入本地,防止数据丢失。 同时,利用 Zundo 中间件,自动对场景节点快照进行拦截,实现预设 50 步历史记录 的高效 Undo/Redo,且排除了 UI 等非关键状态的干扰。

5.2 视图状态 (useViewer)

管理用户如何与 3D 界面进行视觉交互,支持视图模式的算法切换: - solo (单层隔离):仅渲染当前工作楼层。 - stacked (正常堆叠):所有楼层正常显示。 - exploded (楼层爆炸图):在垂直方向(Y轴或Z轴)拉开各楼层距离,展现整体纵向架构。 同时它还接管当前视口中的多选状态(Selection)及相机投影参数。

5.3 编辑行为状态 (useEditor)

负责管理纯前端 UI 表现,如侧边面板激活的工具(绘制墙体、拉伸楼板等)以及控制辅助线、测量网格的可见度。

通过这一套状态拆分设计,任何一次轻微的交互都不会引起 3D 视口的全局重新渲染,极大地提升了大型项目的流畅度和工程可维护性。


6. 数据防线与拓扑关系:Zod 护航的 BIM 拓扑模型

在 3D 编辑器开发中,模型数据的序列化和反序列化很容易因为微小的格式错误导致 3D 场景渲染直接崩溃崩溃。为此,Pascal Editor 引入了 Zod 验证库,为全流程的数据传递建立了固若金汤的数据防线。

@pascal-app/core 中,编辑器将现实世界中的物理建筑抽象为标准的层级树状拓扑关系:

Site (场地) ──> Building (建筑) ──> Level (楼层) ──> Element (建筑构件,如 Wall, Slab, Ceiling, Roof)

我们使用 Zod 严格定义了每个层级的 Schema,无论是从 IndexedDB 读取缓存、解析用户上传的 JSON 文件,还是通过 API 获取后端数据,都必须通过 Zod 的门禁检验,确保类型的绝对安全。

下面是针对 BIM 基础构件(BIMElement)的 Zod 核心类型定义代码:

import { z } from 'zod';

// 定义三维坐标 Schema
export const Vector3Schema = z.object({
x: z.number(),
y: z.number(),
z: z.number(),
});

// 定义基础建筑构件的 Zod 校验 Schema
export const BIMElementSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1),
type: z.enum(['wall', 'slab', 'ceiling', 'roof', 'door', 'window']),
position: Vector3Schema,
rotation: Vector3Schema,
scale: Vector3Schema,
properties: z.object({
thickness: z.number().positive().default(200), // 墙厚/板厚 mm
height: z.number().positive().default(3000), // 高度 mm
material: z.string().default('concrete'), // 材质
castShadow: z.boolean().default(true), // 投射阴影
opacity: z.number().min(0).max(1).default(1.0), // 透明度
}),
});

// 基于 Zod Schema 自动导出 TypeScript 类型定义
export type BIMElement = z.infer<typeof BIMElementSchema>;

这种数据模型直接映射了经典的 BIM 数据规范,并在前端保证了强类型校验,是 3D 复杂工程走向高可用、零崩溃的必经之路。


7. 极致的本地开发与构建流

在大型 Monorepo 项目中,启动本地编译和生产构建往往是一场噩梦,等待时间可能高达数分钟。Pascal Editor 采用了 Bun 运行时和 Turborepo,实现了令人惊叹的极速反馈循环。

只需几个简单的命令,开发者即可秒级拉起开发工作流:

第一步:安装工作区依赖

bun install

基于 Bun 高效的缓存和零拷贝系统调用,整个 Monorepo 依赖安装能在数秒内完成。

第二步:一键拉起跨包热更新

bun dev

此命令将自动调用 Turborepo。它不仅会并行编译底层的 @pascal-app/core@pascal-app/viewer 包,开启监听文件变动(Watch Mode),同时拉起 Next.js 应用。当开发者修改 core 里的物理拓扑算法,或者修改 viewer 里的着色器,Next.js 编辑器应用能在浏览器端实现秒级跨包热更新(HMR),大大节约了调试时间。

第三步:生成生产环境构建

# 全量打包
turbo build

# 定向构建核心逻辑库
turbo build --filter=@pascal-app/core

借助 Turborepo 的缓存技术,如果源码未发生改动,构建将在几毫秒内瞬间完成,为 CI/CD 自动部署流程带来了卓越的体验。


8. 总结:下一代 Web BIM 的技术曙光

Pascal 3D 编辑器成功验证了底层硬核运算、顶层敏捷响应的技术路线。通过拥抱 React 19Next.js 16 作为应用骨架,联合 WebGPU 打破网页渲染的瓶颈,并利用 three-bvh-csg 将繁重的 3D 布尔运算在浏览器端做到 60FPS 实时响应,Web 端的 CAD/BIM 开发终于迎来了属于它的技术曙光。

这种模块化、解耦设计的单仓多包架构不仅是一个好用的建筑编辑器,更是所有希望进军智慧城市、机房监控、家装设计等 3D 可视化垂直领域的开发团队的优秀起步模板。未来已来,网页端的三维算力物理跃迁正悄然改变着每一个三维空间创作者的视界。


公众号二维码

长按二维码关注 “边学边练”

文章版权声明:除非注明,否则均为边学边练网络文章,版权归原作者所有

相关阅读