不用装 Blender,有人用 Three.js 实现了多边形建模
Kokraf (opens in a new tab) 是一个跑在浏览器里的多边形建模工具,基于 Three.js 构建,开源免费。它做的事情有点出乎意料——在浏览器里支持挤出、环切、刀具、倒角这类通常只有 Blender、Maya 才有的操作,不需要安装任何东西,打开网页就能用。

项目功能
Kokraf 分两个操作模式,和 Blender 的交互逻辑一致。
Object Mode(对象模式) 操作整个物体:移动(G)、旋转(R)、缩放(S),支持多对象管理,可以合并、分离、复制。
Edit Mode(编辑模式) 进入顶点、边、面三个层级做多边形操作,核心工具包括:
- 挤出(Extrude):选中面沿法线方向生长出新几何体,是建模最核心的操作
- 环切(Loop Cut):沿一圈四边面插入新的循环边,给模型增加细节控制线
- 刀具(Knife):自由绘制切割路径,在模型表面生成新的边
- 倒角(Bevel):将尖锐的边转为斜面或圆角
- 内插面(Inset):在选中面内部嵌入一个缩小的新面
- 边滑移(Edge Slide):沿相邻面滑动边的位置,不改变拓扑
选择层级支持框选、点选,并提供循环边选择(Select Loops)、边环选择(Select Rings)、关联元素选择(Select Linked)等进阶选择方式。
视口操作:鼠标中键旋转、Shift+中键平移、滚轮缩放,视口角落有坐标轴助手可快速切换到标准视图。辅助功能包括 X 光透视模式、变换方向切换(局部/全局坐标系)、贴靠设置。
值得学习的技术点
Kokraf 的功能覆盖不算多,但要在浏览器里把这些操作做通,有几个工程问题必须解决,处理方式都有参考价值。
1. 为什么不能直接在 Three.js 上做建模
做这个项目之前,有一个底层问题必须想清楚:Three.js 的 BufferGeometry 是面向渲染优化的数据格式,顶点坐标、法线、UV 被打包进连续的 Float32Array,结构对 GPU 友好,但它不记录拓扑关系——你没法问它"这条边连着哪些面"或者"这个顶点的相邻顶点是谁"。
而挤出、环切这类操作的本质是拓扑操作,需要频繁查询和修改邻接关系。在 BufferGeometry 上直接做建模,等于在连续数组里维护图结构,几乎不可行。
Kokraf 的解法是在 Three.js 之上另起一层,把建模数据和渲染数据彻底分开。
2. 自研邻接网格数据结构(MeshData)
MeshData 是 Kokraf 建模层的核心,维护三类元素:顶点、边、面,每类用 Map<id, element> 管理。
关键设计是双向引用:每个顶点持有它关联的所有边 ID 和面 ID,每条边持有它属于的面 ID,每个面持有顶点列表和边列表。这样任意拓扑查询都能在常数或 O(degree) 时间内完成,不需要遍历整个网格。
面支持四边面和任意多边面,不强制三角化。这一点很重要——环切操作依赖四边面的循环结构,如果强制三角面,环切在拓扑层就失去了意义。
addEdge 在插入时会自动检查是否已有重复边,有则复用,保证拓扑一致性;deleteVertex 会级联删除关联的边和面,不需要调用方手动清理。
3. 渲染桥接层(MeshData → BufferGeometry)
建模层修改完之后,需要把 MeshData 转成 Three.js 能渲染的 BufferGeometry。MeshRendererAdapter 负责这件事,每次操作结束后调用一次,重新生成几何体。
这一步有两个子问题要处理:
多边面三角化:GPU 只能渲染三角形,但建模层保留了四边面和多边面。Kokraf 用 earcut 库做三角剖分——计算面的法线,将顶点投影到二维平面,由 earcut 切成三角形,索引填入 index buffer。着色模式支持 Flat(硬边,每个面独立顶点)、Smooth(共享顶点,边缘平滑)、Auto(按二面角阈值自动判断)三种。
鼠标拾取的对应问题:用户在视口里点击选择元素时,Three.js 射线检测返回的是 buffer 下标,而建模操作需要的是 MeshData 里的逻辑 ID。MeshRendererAdapter 在转换时同时维护两张映射表——逻辑 ID 到 buffer 下标、buffer 下标到逻辑 ID。点击命中后反查逻辑 ID,再通过邻接关系扩展到边和面。three-mesh-bvh 做 BVH 加速,避免射线检测逐三角形遍历。
这两个问题都集中在 MeshRendererAdapter 这一层,建模层和 Three.js 各自不需要感知对方。
4. 命令模式实现撤销重做
每个建模操作封装成一个 Command 对象。执行时,先用 structuredClone 深拷贝当前 MeshData 存为前快照,操作完成后再存一份后快照,两份快照一起推入历史栈。撤销切回前快照,重做切回后快照,然后重新生成 BufferGeometry。
这个方案实现直接,不需要维护 diff 逻辑,代价是每次操作都有一次深拷贝的开销。对于中等复杂度的模型,structuredClone 足够快;极复杂的模型可能需要考虑增量 diff,但对当前阶段够用。
每个 Command 实现了 toJSON / fromJSON,历史栈可以序列化,支持跨会话恢复。
UI 和操作逻辑通过信号(Signal)系统解耦:工具层 dispatch 信号,EditActions 层统一监听执行,两侧互不直接依赖。
技术栈
| 模块 | 技术 |
|---|---|
| 三维渲染 | Three.js |
| 射线检测加速 | three-mesh-bvh |
| 路径追踪渲染 | three-gpu-pathtracer |
| 多边面三角化 | earcut |
| 建模数据结构 | 自研 MeshData(VEF 邻接网格) |
| 前端 | 原生 HTML / CSS / JavaScript |
| 后端/存储 | Supabase |
前端没有构建步骤,本地运行只需要 clone 仓库后用 VS Code Live Server 打开 index.html 即可。
写在最后
Kokraf 目前还在持续迭代中。从技术角度看,它解决的核心问题是:如何在 Three.js 渲染体系之上,搭一套完整的多边形建模数据层。MeshData + MeshRendererAdapter + Command 三层分离的设计,对做类似方向(场景编辑器、在线建模工具、空间设计应用)的项目有直接的参考价值,源码结构也比较清晰,适合阅读学习。
GitHub:https://github.com/sengchor/kokraf (opens in a new tab) 在线体验:https://kokraf.com (opens in a new tab) 用户手册:https://kokraf.com/manual (opens in a new tab)