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' />
解答
核心问题
报错的关键原因有两个:
- 仅设置顶点数据,未提供面信息:
Mesh需要三角化的面数据才能渲染填充多边形,setFromPoints仅传入顶点坐标,WebGL无法识别如何绘制填充区域。 - 版本兼容性(次要):如果使用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工具类对顶点进行三角化生成面索引:
- 先引入
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>
- 修改几何体创建逻辑:
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
相关产品推荐
相关产品推荐

