Web Worker 可提升物理模拟性能,因其独立线程不阻塞主线程渲染。将刚体积分、碰撞检测、约束求解等计算卸载至 Worker,通过 postMessage 传递精简状态,结合 Transferable Objects 和双缓冲优化通信,保障 60fps 流畅性。

Web Worker 本身不能直接操作 DOM 或调用 WebGL API,因此不能在 Worker 中执行真正的 3D 渲染。但可以将计算密集型的物理碰撞检测、刚体运动积分、矩阵变换(如模型矩阵更新、AABB/OBB 碰撞判定、约束求解等)完全剥离到 Worker 中运行,再将结果(如位置、旋转、碰撞标志、力反馈数据)通过 postMessage 同步回主线程,由主线程负责渲染。
为什么用 Worker 做物理模拟而不是主线程
3D 场景中,尤其含多个动态物体、连续碰撞响应或软体/布料时,物理计算可能占用 10–30ms 甚至更高。若在主线程执行,会阻塞渲染帧(导致掉帧、卡顿、输入延迟),破坏交互体验。Worker 在独立线程运行,不干扰渲染循环和事件响应,保障 60fps 的视觉流畅性与 UI 响应性。
典型可卸载到 Worker 的物理计算任务
- 刚体位置/姿态的数值积分(如 Verlet 或显式欧拉,配合固定时间步长)
- 物体包围盒(AABB/OBB)的实时更新与两两相交检测
- 基于分离轴定理(SAT)或 GJK/EPA 的凸体精确碰撞判定与穿透深度/法向量计算
- 约束求解(如铰链、滑块、距离约束)的迭代收敛过程
- 局部坐标系下的相对变换矩阵(Model × World × InverseParent)批量预计算
如何高效通信与数据结构设计
避免频繁传递大对象(如完整 Float32Array 矩阵数组)。推荐做法:
- 使用 Transferable Objects:通过
postMessage(data, [arrayBuffer])零拷贝传递Float32Array.buffer,大幅提升大数据量同步效率 - 结构化消息协议:例如发送
{type: 'update', id: 5, pos: [x,y,z], rot: [qx,qy,qz,qw]},Worker 只处理 delta 更新而非全量状态 - 双缓冲状态数组:主线程与 Worker 各持一份共享内存视图(
SharedArrayBuffer+Float32Array),配合Atomics协调读写,适合高频小粒度同步(需 HTTPS 环境)
实际集成建议(以 Three.js 为例)
主线程中:
- 初始化 Web Worker,并监听
message获取物理状态 - 在
requestAnimationFrame循环中,仅调用mesh.position.copy(physState.pos)和mesh.quaternion.copy(physState.rot) - 用户交互(如拖拽、施加力)通过
postMessage发送指令给 Worker 处理
Worker 中:
- 使用
self.onmessage接收指令与初始状态,维护独立物理世界实例(如自研轻量引擎或 Ammo.js 的 Worker 封装版) - 采用固定时间步长(如 1/60s)做多子步积分,避免穿模;用
setInterval或requestIdleCallback控制计算节奏 - 输出精简后的关键状态(非每帧全量),减少通信开销
不复杂但容易忽略:务必在 Worker 中禁用任何依赖 DOM 或 Canvas 的代码;所有数学运算优先使用 Float32Array 和内联函数,避免创建临时对象;矩阵运算可复用 gl-matrix 的 mat4 工具函数(需手动移植或打包为 Worker 可用模块)。










