驱动数字化 质变

从权威的技术洞察,到精准的软硬配置,为企业的每一次转型提供决策支持。

架构师笔记
渲染 5 万个货位不掉帧?基于 Three.js + WebGPU 的超大规模 3D 仓储孪生架构 (附 Instancing 代码)

2026-03-05 10:47:00

#数字孪生 #Three.js #WebGPU #InstancedMesh #R3F #ASRS


一、 场景痛点:浏览器里的“幻灯片”

在最近交付的一个 AS/RS 立体仓库数字孪生项目中,我们遇到了严重的性能墙:

  • 规模:仓库有 50 排货架,总计 52,000 个货位,每个货位上可能放着不同颜色的箱子。

  • 现状:开发团队使用 Three.js 传统的 new THREE.Mesh() 方法,循环创建了 5 万个 Cube 对象。

  • 灾难

  1. Draw Calls 爆炸:GPU 绘制调用次数超过 50,000 次,远超浏览器瓶颈(通常 3000 次就开始卡)。

  2. FPS 暴跌:在 i7 的开发机上只有 8 FPS,在现场的中控大屏(通常配的是集显 Mini PC)上直接浏览器崩溃(WebGL Context Lost)。

  3. 交互延迟:点击一个箱子查看详情,需要 2 秒才有反应。

架构师指令:停止使用独立 Mesh。


对于这种“形状相同、位置不同”的大规模物体,必须使用 InstancedMesh (实例化网格) 技术。将 5 万次绘制合并为 1 次绘制,利用 GPU 的并行计算能力更新位置和颜色。


二、 架构设计:数据驱动的实例化管道

我们采用 React Three Fiber (R3F) 作为胶水层,结合 WebGPU 计算着色器(可选)处理状态更新。

  1. 渲染层:使用单个 InstancedMesh 承载所有货箱。内存中只存一份 Geometry(几何体)和 Material(材质)。

  2. 数据层:不使用 React State 存储实时位置(太慢)。使用 Refs 直接操作 ArrayBuffer(类型化数组)。

  3. 通信层:WebSocket 接收 WMS 的库存变动指令(如 Slot_A1_02: { status: empty }),直接修改 Buffer 中的颜色矩阵。

渲染管线


WMS 数据流 -> [WebSocket Worker] -> [SharedArrayBuffer] -> [Three.js InstancedMesh] -> GPU


三、 核心实施步骤 (Copy & Paste)

这里演示如何用 React Three Fiber 实现 5 万个动态货箱的渲染。

1. 创建实例化网格组件 (InstancedBoxes.jsx)

核心在于 useLayoutEffect 中对 tempObject 的复用,以及 setColorAt / setMatrixAt 的调用。


Jsx
import React, { useRef, useLayoutEffect, useMemo } from 'react'
import * as THREE from 'three'
import { useFrame } from '@react-three/fiber'

const COUNT = 50000; // 5万个货位

export default function WarehouseBoxes({ dataStream }) {
  const meshRef = useRef();
  const colorArray = useMemo(() => new Float32Array(COUNT * 3), []);
  
  // 临时对象,用于计算矩阵,避免 GC
  const tempObject = new THREE.Object3D();
  const tempColor = new THREE.Color();

  useLayoutEffect(() => {
    // 1. 初始化位置 (只执行一次)
    let i = 0;
    for (let x = 0; x < 100; x++) {
      for (let y = 0; y < 50; y++) {
        for (let z = 0; z < 10; z++) {
          const id = i++;
          tempObject.position.set(x * 1.2, y * 1.2, z * 1.5);
          tempObject.updateMatrix();
          meshRef.current.setMatrixAt(id, tempObject.matrix);
          
          // 初始化颜色 (空位为灰色)
          meshRef.current.setColorAt(id, tempColor.setHex(0xaaaaaa));
        }
      }
    }
    meshRef.current.instanceMatrix.needsUpdate = true;
    meshRef.current.instanceColor.needsUpdate = true;
  }, []);

  // 2. 实时更新 (每帧调用,或者在 WebSocket 回调中调用)
  useFrame(() => {
    if (!dataStream.current.hasUpdate) return;
    
    // 假设 dataStream 包含需要变更的 ID 和颜色
    dataStream.current.updates.forEach(({ id, status }) => {
      const color = status === 'occupied' ? 0xffa500 : 0xaaaaaa;
      meshRef.current.setColorAt(id, tempColor.setHex(color));
    });
    
    // 关键:告诉 GPU 颜色数据变了,需要重绘
    if (dataStream.current.updates.length > 0) {
       meshRef.current.instanceColor.needsUpdate = true;
       dataStream.current.clear();
    }
  })

  return (
    <instancedMesh ref={meshRef} args={[null, null, COUNT]}>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial />
    </instancedMesh>
  )
}

2. WebGPU 优化 (进阶)

如果 2026 年你的目标浏览器支持 WebGPU(Chrome 130+),可以使用 WebGPURenderer 和 Compute Shader 来处理粒子的物理运动(如 AGV 的平滑移动),将 CPU 彻底解放。

注:Three.js TSL (Three Shading Language) 是 2026 年操作 WebGPU 的标准方式。


四、 踩坑复盘 (Red Flags)

1. 交互检测 (Raycasting) 的性能黑洞

  • 现象:渲染很快,但鼠标一移上去想看货位信息,画面就卡顿。

  • 原因:Three.js 默认的 Raycaster 会遍历所有 50,000 个实例进行碰撞检测,CPU 算不过来。

  • 对策

    • BVH 优化:引入 three-mesh-bvh 库,为 InstancedMesh 构建空间索引,将射线检测速度提升 1000 倍。

    • 节流:不要在 mousemove 里每帧都做检测,限制为 100ms 一次。

2. 视锥体剔除 (Frustum Culling) 失效

  • 现象:当摄像机只看仓库的一个角落时,GPU 依然在渲染背后的 4 万个箱子。

  • 原因:InstancedMesh 默认被视为一个整体对象。只要这个整体有一部分在屏幕内,整个对象都会被提交给 GPU。

  • 对策:如果仓库极大,需进行空间分块 (Spatial Partitioning)。将 5 万个箱子拆分成 10 个 InstancedMesh(每个 5000 个),分布在不同区域。这样 Three.js 就能自动剔除看不见的区域块。

3. 内存泄漏 (Geometries Not Disposed)

  • 风险:在 React 中频繁切换场景(如从“仓库视图”切到“产线视图”)导致内存暴涨。

  • 对策:确保在组件卸载(Unmount)时调用 geometry.dispose() 和 material.dispose()。使用 R3F 的 <Canvas> 通常会自动处理,但在手动管理纹理时要格外小心。


五、 关联资源与选型

跑得动 5 万个 3D 物体,对显卡和 CPU 还是有一定要求的。

  • 推荐工控机配置

    • Intel Core Ultra 5 / AMD Ryzen 8000:核显性能强劲,完全能胜任这种轻量级 3D 渲染,无需独显。


开发工具

  • React Three Fiber (R3F):工业 3D 开发首选,组件化管理极佳。

  • Drei:R3F 的生态库,提供了现成的 Instances 组件,比手写原生代码更简单。