经纬志
首页 / three.js / API 文档

BufferGeometry

先看结论

顶点数据的容器:位置、法线、纹理坐标、颜色与索引都存在这里,最终上传为 GPU 缓冲区。

最后验证 2026-11-03 · three.js 0.160.0 · 更新 2026-10-27 · 引用本文
new THREE.BufferGeometry() → BufferGeometry

属性

属性说明
attributes属性字典,键名即着色器里的 attribute 名,如 position、normal、uv
index索引缓冲区,复用顶点、减少重复;为 null 时按顺序取顶点
groups面片分组,配合多材质使用
drawRange实际绘制的顶点或索引区间,可用于只画一部分
boundingBox / boundingSphere包围体,参与视锥裁剪与拾取,未计算时可能为 null
morphAttributes变形目标属性

核心方法

方法说明
setAttribute(name, attribute)写入属性,值为 BufferAttribute 实例
setIndex(index)设置索引,可传数组或 BufferAttribute
setFromPoints(points)用点数组生成 position 属性,适合线与点云
computeVertexNormals()按三角面重算法线,顶点位置改动后必须调用
computeBoundingBox() / computeBoundingSphere()重算包围体,位置整体变化后要更新
applyMatrix4(matrix)把所有顶点乘上一个变换矩阵
toNonIndexed()返回展开后的非索引几何体,便于逐面操作
setDrawRange(start, count)限定绘制区间,常用于逐步显示轨迹
dispose()释放 GPU 缓冲区

手动构造一份几何体

const geometry = new THREE.BufferGeometry();

// 每个顶点三个分量,共三个顶点
const positions = new Float32Array([
  -0.5, -0.5, 0,
   0.5, -0.5, 0,
   0.0,  0.5, 0
]);

geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.computeVertexNormals();
geometry.computeBoundingSphere();

BufferAttribute 的第二个参数是每个顶点占几个分量: 位置与法线是 3,纹理坐标是 2,颜色是 3 或 4。写错会导致着色器读到的数据整体错位, 表现是模型扭曲或纹理乱飞。

索引与顶点复用

索引让多个三角面共享同一批顶点。一个由 8 个顶点构成的立方体,非索引写法需要 36 个顶点, 索引写法只要 8 个顶点加 36 个索引。顶点属性越多,索引带来的节省越明显。

const box = new THREE.BoxGeometry(1, 1, 1);
console.log(box.index !== null);        // true
console.log(box.attributes.position.count); // 24

const flat = box.toNonIndexed();
console.log(flat.attributes.position.count); // 36

动态更新顶点

const positions = geometry.attributes.position;

// 标记为动态用途,驱动层会采用适合频繁写入的缓冲策略
positions.setUsage(THREE.DynamicDrawUsage);

renderer.setAnimationLoop(function () {
  for (let i = 0; i < positions.count; i++) {
    const x = positions.getX(i);
    positions.setY(i, Math.sin(x * 4 + clock.elapsedTime * 2) * 0.4);
  }

  positions.needsUpdate = true; // 关键:否则 GPU 侧不会重新上传
  renderer.render(scene, camera);
});

只改了数据却没有置 needsUpdate,画面不会变化。这是动态几何最常见的疏漏。 如果整体替换成新的 Float32Array,还需要重新 setAttribute, 仅置标志位不够。

用 drawRange 做逐步显示

轨迹动画不一定要每帧重建几何体。预先写入整条路径,再用 setDrawRange(0, n) 逐步增加绘制数量,就能得到生长效果, 数据只上传一次。点数超过十万时,这种做法的收益非常明显。

释放

geometry.dispose() 会释放显存中的顶点与索引缓冲。 从场景移除网格并不会自动调用它。切换图层、重建几何体之前, 先销毁旧的那份,否则显存会持续累积。

熟悉的几何体优先用内置的。BoxGeometry、PlaneGeometry、 SphereGeometry 已经处理好索引、法线与 UV。 只有表达非规则数据(点云、地形、自定义网格)时才需要手写 BufferGeometry。

引用本文

经纬志(2026)。《BufferGeometry》。https://www.jingweizhi.com/three/api/buffer-geometry.html(访问日期 2026-11-03)。