You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js中BufferGeometry.setFromPoints报错:函数不存在问题咨询

问题:Three.js中BufferGeometry.setFromPoints报错"is not a function"

我尝试在Three.js中用BufferGeometry渲染2D多边形(相比Shape性能更优),基于Svelte开发,写了原生HTML/CSS/JS示例,运行时控制台报错:
Uncaught TypeError: geometry.setFromPoints is not a function
官方文档显示该方法存在,请问哪里使用有误?

相关代码

JavaScript

const imageWidth = 30000;
const imageHeight = 60000;

const CANVAS_WIDTH = 10000;
const CANVAS_HEIGHT = CANVAS_WIDTH * (imageHeight / imageWidth);

const layer = {
  fill: '#32a852',
  stroke: '#000000',
  opacity: 0.5,
  annotations: [
    [
        [0, 0],
        [0, 10000.23],
        [10000.012, 10000.3894],
        [10000.783, 0]
    ]
  ]
};

function draw() {
  const canvas = document.getElementById('canvas');
  if (!canvas) return;

  canvas.width = CANVAS_WIDTH;
  canvas.height = CANVAS_HEIGHT;

  const scene = new THREE.Scene();

  const camera = new THREE.OrthographicCamera(0, imageWidth, 0, -1 * imageHeight, 0.1, 10);
  camera.position.z = 1;

  // 创建带透明画布的渲染器
  const renderer = new THREE.WebGLRenderer({ canvas, alpha: true });

  // 当前图层的材质
  const fill_material = new THREE.MeshBasicMaterial({
    color: layer.fill,
    transparent: true,
    opacity: layer.opacity
  });

  for (const annotation of layer.annotations) {
    const points = annotation.map((point) => new THREE.Vector2(point[0], -1 * point[1]));
    // 复制第一个点以闭合形状
    points.push(new THREE.Vector2(annotation[0][0], -1 * annotation[0][1]));

    const geometry = new THREE.BufferGeometry();
    geometry.setFromPoints(points);

    // 创建网格并添加到场景
    const mesh = new THREE.Mesh(geometry, fill_material);
    scene.add(mesh);
  }

  // 清空标注
  layer.annotations = [];

  // 渲染场景
  renderer.render(scene, camera);
}

draw()

CSS

canvas {
  position: absolute;
  z-index: 1;
  width: 100%;
}

HTML

<canvas id='canvas' />

解答

核心问题

报错的关键原因有两个:

  1. 仅设置顶点数据,未提供面信息:Mesh需要三角化的面数据才能渲染填充多边形,setFromPoints仅传入顶点坐标,WebGL无法识别如何绘制填充区域。
  2. 版本兼容性(次要):如果使用Three.js r102及更早版本,BufferGeometry.setFromPoints方法确实不存在,该方法在r103版本才被加入。

修复方案

方案1:基于Shape生成BufferGeometry(兼顾性能与易用性)

虽然你想避开Shape,但可以用Shape定义多边形后转为BufferGeometry,性能接近原生BufferGeometry的同时无需手动处理三角化:

for (const annotation of layer.annotations) {
  const points = annotation.map((point) => new THREE.Vector2(point[0], -1 * point[1]));
  // 用Shape定义多边形
  const shape = new THREE.Shape(points);
  // 生成ShapeGeometry并转为BufferGeometry
  const geometry = new THREE.ShapeGeometry(shape).toBufferGeometry();

  const mesh = new THREE.Mesh(geometry, fill_material);
  scene.add(mesh);
}

方案2:手动三角化顶点(纯BufferGeometry方案)

如果坚持完全手动用BufferGeometry,需要用Three.js工具类对顶点进行三角化生成面索引:

  1. 先引入BufferGeometryUtils工具(需使用ES模块引入Three.js):
<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three@0.160.0/build/three.module.js",
      "three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
    }
  }
</script>
  1. 修改几何体创建逻辑:
import { BufferGeometryUtils } from 'three/addons/utils/BufferGeometryUtils.js';

// ...

for (const annotation of layer.annotations) {
  const points = annotation.map((point) => new THREE.Vector2(point[0], -1 * point[1]));
  // 无需手动重复第一个点,triangulateShape会自动闭合形状

  const geometry = new THREE.BufferGeometry();
  geometry.setFromPoints(points);
  // 生成三角面索引
  const indices = BufferGeometryUtils.triangulateShape(points, []);
  geometry.setIndex(indices);

  const mesh = new THREE.Mesh(geometry, fill_material);
  scene.add(mesh);
}

额外注意事项

  • 确保使用的Three.js版本≥r103,若版本过低建议升级到最新稳定版。
  • 若只需渲染线框多边形,可改用LineLoop代替Mesh,此时仅需顶点数据即可:
const line = new THREE.LineLoop(geometry, new THREE.LineBasicMaterial({ color: layer.stroke }));
scene.add(line);

内容的提问来源于stack exchange,提问作者Orcadeum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 20:55:57