Three.js渲染3D柱状图时旋转卡顿怎么办?

Mr.瑞雪 阅读 96

最近在用Three.js做3D柱状图,当数据量超过500个柱子后,鼠标旋转视角时特别卡顿。我尝试过把材质改成BasicMaterial,合并所有柱子的几何体,但帧率还是掉到20多,控制台还偶尔报GL_OUT_OF_MEMORY的警告。这是不是模型优化没做好?


const geometry = new THREE.BufferGeometry();
const positions = [];
for(let i=0; i<500; i++) {
  // 生成柱子顶点坐标
  positions.push(i, Math.random()*10, 0);
}
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
const mesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial());
scene.add(mesh);

这样合并网格后内存占用反而更高了,是不是应该用WebGL的Instancing方式?或者数据量太大必须用其他库?

我来解答 赞 10 收藏
二维码
手机扫码查看
2 条解答
红彦
红彦 Lv1
直接用 InstancedMesh,你那个合并几何体的方式对大量相同模型其实更吃内存,尤其是每个柱子还要独立变换的时候。BufferGeometry 合并适合静态模型,但500个可变的柱子得换实例化渲染。

下面这个写法能跑60帧以上:

const geometry = new THREE.BoxGeometry(0.2, 1, 0.2); // 柱子尺寸
const material = new THREE.MeshBasicMaterial();

// 创建500个实例
const instancedMesh = new THREE.InstancedMesh(geometry, material, 500);
instancedMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // 允许动态更新
scene.add(instancedMesh);

// 设置每个柱子的位置和高度
const matrix = new THREE.Matrix4();
for (let i = 0; i < 500; i++) {
const scale = Math.random() * 0.8 + 0.2; // 高度随机
matrix.identity();
matrix.makeTranslation(i * 0.3 - 75, scale / 2, 0); // X偏移居中,Y按高度半高
matrix.scale(new THREE.Vector3(0.2, scale, 0.2));
instancedMesh.setMatrixAt(i, matrix);
}
instancedMesh.instanceMatrix.needsUpdate = true;


这样 GPU 只画一次模型,复制500次实例,内存占用小很多,也不会触发 GL_OUT_OF_MEMORY。你之前报内存警告是因为每个柱子都没复用,就算合并也还是生成了超大顶点缓冲。

如果还要再优化,可以把数据更新逻辑节流,或者用 web worker 预计算矩阵。不过先用 InstancedMesh 跑起来再说,这一步改完帧率基本就能稳住。
点赞 6
2026-02-09 15:09
Dev · 尚萍
你应该用InstancedMesh,500个柱子直接实例化渲染,性能会好很多。下面是改写后的代码:

const count = 500;
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial();
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);

const positions = new Float32Array(count * 3);
for (let i = 0; i < count; i++) {
positions[i * 3 + 0] = i;
positions[i * 3 + 1] = Math.random() * 10;
positions[i * 3 + 2] = 0;
}
const positionAttribute = new THREE.InstancedBufferAttribute(positions, 3);
instancedMesh.setAttribute('offset', positionAttribute);

scene.add(instancedMesh);


记得在着色器里处理实例属性,这样能大幅提升性能。
点赞 6
2026-02-02 11:19