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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 15:08:13