如何使用Three.js渲染由输入顶点定义的直边多边形?
嘿,完全不用碰贝塞尔曲线哦!Three.js渲染直边多边形其实很直接,毕竟WebGL底层是靠三角形绘制图形的,咱只要把多边形拆成合适的三角形(或者直接画边框)就行,给你一步步说:
1. 整理顶点数据
首先把你的(x,y,z)顶点转换成扁平化的数组,比如你有四个顶点(0,0,0)、(1,0,0)、(1,1,0)、(0,1,0),就转成:
const vertices = [0,0,0, 1,0,0, 1,1,0, 0,1,0];
这样Three.js能直接用Float32BufferAttribute来处理。
2. 创建几何体
用BufferGeometry(性能比旧的Geometry好太多),把顶点数据设置进去。如果要渲染填充的多边形,关键是要给几何体加索引(indices)——因为WebGL只能画三角形,所以得把多边形拆成多个三角形:
const geometry = new THREE.BufferGeometry(); // 传入顶点数组,第二个参数3表示每3个元素对应一个顶点的x/y/z geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); // 举个四边形的索引:拆成两个三角形 const indices = [ 0, 1, 2, // 第一个三角形:顶点0→1→2 0, 2, 3 // 第二个三角形:顶点0→2→3 ]; geometry.setIndex(indices);
如果是复杂的凹多边形,手动拆三角太麻烦,可以用Three.js自带的THREE.TriangulationUtils.triangulateShape()来自动生成索引,省不少事。
3. 选合适的材质
- 要填充的多边形:用
MeshBasicMaterial(不受光照影响)或者MeshLambertMaterial/MeshPhongMaterial(受光照影响),记得加side: THREE.DoubleSide,不然多边形背面可能看不见:const fillMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00, side: THREE.DoubleSide }); - 只要边框:用
LineBasicMaterial,然后配合LineLoop(自动把最后一个顶点连回第一个):const lineMaterial = new THREE.LineBasicMaterial({ color: 0x0000ff });
4. 创建网格/线条并加入场景
- 填充多边形:用
Mesh把几何体和材质组合起来,加到场景:const polygonMesh = new THREE.Mesh(geometry, fillMaterial); scene.add(polygonMesh); - 边框:用
LineLoop:const polygonBorder = new THREE.LineLoop(geometry, lineMaterial); scene.add(polygonBorder);
完整示例代码
// 初始化基础场景、相机、渲染器(这部分是Three.js基础操作) const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 你的多边形顶点 const vertices = [ 0, 0, 0, 2, 0, 0, 2, 1, 0, 1, 2, 0, 0, 1, 0 ]; // 创建几何体 const geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); // 自动三角化(适合复杂多边形) const shapePoints = vertices.reduce((acc, val, idx) => { if (idx % 3 === 0) acc.push(new THREE.Vector2(val, vertices[idx+1])); return acc; }, []); const indices = THREE.TriangulationUtils.triangulateShape(shapePoints, []); geometry.setIndex(indices); // 填充材质+网格 const fillMaterial = new THREE.MeshBasicMaterial({ color: 0xff9900, side: THREE.DoubleSide }); const polygon = new THREE.Mesh(geometry, fillMaterial); scene.add(polygon); // 边框材质+线条 const lineMaterial = new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 2 }); const border = new THREE.LineLoop(geometry, lineMaterial); scene.add(border); // 调整相机位置 camera.position.z = 5; // 渲染循环 function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate();
注意哈:如果你的多边形是3D空间里的(不是平面),只要顶点坐标是对的,上面的方法同样适用——Three.js会自动处理3D空间的面渲染。
内容的提问来源于stack exchange,提问作者Mandroid
相关产品推荐
相关产品推荐

