如何用JavaScript基于三维坐标数组渲染正确的3D多边形?
问题:Three.js渲染L形3D多边形出现异常闪烁三角形
我有格式固定的GeoJSON数据,需要用JavaScript渲染出和Python的Poly3DCollection示例一致的3D多边形,且不能修改数据。目前用Three.js尝试实现时,ID为5的L形墙体出现额外闪烁三角形,无法得到理想效果,求功能性修复方案,后续还有更多同类数据需要处理。
提供的GeoJSON数据
{ "type": "FeatureCollection", "features": [ { "id": "2", "type": "Feature", "properties": { "type": "wall", "sf_tilt": 90.0, "sf_orient": -32.0 }, "geometry": { "type": "Polygon", "coordinates": [ [ [2683852.4747061506,1252231.906523199,432.63800066187565], [2683852.4747061506,1252231.906523199,439.65200066187566], [2683852.200003838,1252232.076997624,439.39600066187137], [2683852.200003838,1252232.076997624,435.1080006618714], [2683850.956000865,1252232.8489994688,435.10800066185215], [2683850.956000865,1252232.8489994688,433.2940106618521], [2683852.4747061506,1252231.906523199,432.63800066187565] ] ] } }, { "id": "5", "type": "Feature", "properties": { "type": "wall", "sf_tilt": 90.0, "sf_orient": 146.0 }, "geometry": { "type": "Polygon", "coordinates": [ [ [2683853.20506449,1252236.2645763762,435.108], [2683854.3609999996,1252235.484,435.108], [2683854.3609999996,1252235.4839999997,439.3960000002033], [2683854.6319999998,1252235.301,439.6550000030672], [2683854.632,1252235.3009999997,433.7652148642271], [2683853.2050644904,1252236.264576376,433.74104702266015], [2683853.20506449,1252236.2645763762,435.108] ] ] } } ] }
尝试的Three.js代码
function createBufferGeometry(feature) { const coordinates = feature.geometry.coordinates[0]; const coords = coordinates.map((coord) => [coord[0] - offsets.x, coord[1] - offsets.y, coord[2] - offsets.z]); const geometry = new THREE.BufferGeometry(); const vertices = []; for (const coord of coords) { vertices.push(coord[0], coord[1], coord[2]); } const positionAttribute = new THREE.Float32BufferAttribute(vertices, 3); geometry.setAttribute("position", positionAttribute); const indices = []; for (let i = 0; i < coords.length - 2; i++) { indices.push(0, i + 1, i + 2); } geometry.setIndex(indices); geometry.computeVertexNormals(); return geometry; } for (let feature of data.features) { const meshMaterial = new THREE.MeshPhongMaterial({ color: collors[feature.properties.type], side: THREE.DoubleSide, opacity: 0.5, transparent: true, }); const meshGeometry = createBufferGeometry(feature); const mesh = new THREE.Mesh(meshGeometry, meshMaterial); scene.add(mesh); }
修复方案
问题原因
当前代码用扇形三角化(以第一个顶点为中心连接所有后续顶点)生成索引,这种方式只适用于凸多边形。但ID为5的L形是凹多边形,会生成错误的三角面,导致闪烁和异常显示。Python的Poly3DCollection会自动处理凹多边形的三角化,Three.js需要手动引入三角化库来实现相同效果。
具体解决步骤
使用earcut库(轻量、专门处理多边形三角化,支持凸/凹多边形)来生成正确的索引:
1. 安装/引入earcut
- 通过npm安装:
npm install earcut - 或引入CDN:
<script src="https://unpkg.com/earcut@2.2.4/dist/earcut.min.js"></script>
2. 修改后的代码
// 如果是模块化项目,导入earcut;CDN引入则直接使用全局earcut对象 import earcut from 'earcut'; function createBufferGeometry(feature) { const coordinates = feature.geometry.coordinates[0]; // 移除GeoJSON中重复的闭合顶点(首尾重合) const coords = coordinates.slice(0, -1).map(coord => [ coord[0] - offsets.x, coord[1] - offsets.y, coord[2] - offsets.z ]); const geometry = new THREE.BufferGeometry(); const vertices = []; // 提取二维坐标用于三角化(墙体为平面多边形,z坐标在同一平面) const flatCoords = []; for (const coord of coords) { vertices.push(coord[0], coord[1], coord[2]); flatCoords.push(coord[0], coord[1]); } // 用earcut生成正确的三角化索引 const indices = earcut(flatCoords); const positionAttribute = new THREE.Float32BufferAttribute(vertices, 3); geometry.setAttribute("position", positionAttribute); geometry.setIndex(indices); geometry.computeVertexNormals(); return geometry; } // 网格创建代码保持不变 for (let feature of data.features) { const meshMaterial = new THREE.MeshPhongMaterial({ color: collors[feature.properties.type], side: THREE.DoubleSide, opacity: 0.5, transparent: true, }); const meshGeometry = createBufferGeometry(feature); const mesh = new THREE.Mesh(meshGeometry, meshMaterial); scene.add(mesh); }
关键说明
- 移除闭合顶点:GeoJSON多边形首尾顶点重合,需先移除最后一个顶点,避免earcut处理重复点出错
- 二维三角化:墙体是倾斜90度的平面多边形,所有顶点在同一平面,用x/y坐标做三角化即可,生成的索引可直接对应3D顶点
- 批量处理适配:earcut支持任意简单多边形,完美适配后续同类数据的批量处理需求
内容的提问来源于stack exchange,提问作者Mohsin Uddin Abir
相关产品推荐
相关产品推荐

