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

基于Three.js实现高度图地形等高线及相似高度区域选择咨询

实现基于Three.js的地形等高线与高度选中工具方案

一、核心概念解析

1. 等高线(Contour Line)

  • 定义:地形上海拔高度相同的点连接成的闭合曲线,直观展示地形起伏。
  • 用途:给地形Mesh叠加高度相同的线条,让地形层级更清晰,匹配你要的参考图效果。
  • 拓扑作用:能直观呈现地形的坡度、山谷、山脊等特征,但无法表达地形的层级嵌套关系(比如大坑里的小坑)。

2. 等高树(Contour Tree)

  • 定义:把等高线按海拔高低和拓扑嵌套关系组织成树状结构,每个节点代表一条等高线,边代表等高线之间的包含/相邻关系。
  • 用途:如果需要分析地形的拓扑结构(比如找出所有独立山谷、山峰,判断某条等高线所属地形单元)时会用到;但如果只是做可视化和点击选同高度区域,初期可以不用,先聚焦等高线实现。
  • 拓扑作用:解决等高线无法表达的层级依赖问题,适合复杂地形的拓扑分析,比如自动识别河流流域、地形分区。

二、可行实现方案

1. 基于高度图生成地形Mesh(已有基础优化)

确保高度图数据转为顶点高度数组,用THREE.PlaneGeometry创建平面后,遍历顶点设置z轴高度:

// heightData为高度图像素灰度数组(0-255),plane为PlaneGeometry实例
const vertices = plane.attributes.position.array;
const maxHeight = 50; // 自定义地形最大高度
for (let i = 0; i < vertices.length; i += 3) {
  const xIndex = Math.floor((i/3) % plane.parameters.widthSegments);
  const yIndex = Math.floor((i/3) / plane.parameters.widthSegments);
  const height = heightData[yIndex * plane.parameters.widthSegments + xIndex] / 255 * maxHeight;
  vertices[i + 2] = height;
}
plane.attributes.position.needsUpdate = true;
plane.computeVertexNormals();

2. 生成等高线(两种核心方式)

方式一:Shader实现(性能优先,实时渲染)

通过片元着色器判断顶点高度,直接渲染等高线,适合大尺寸地形:

// 片元着色器代码
uniform float contourInterval; // 等高线间距
uniform float contourWidth; // 等高线宽度
uniform vec3 contourColor; // 等高线颜色
varying vec3 vPosition; // 顶点位置传递到片元

void main() {
  float height = vPosition.z;
  float fractional = fract(height / contourInterval);
  // 计算等高线的透明度权重
  float lineWeight = smoothstep(0.0, contourWidth / contourInterval, fractional) 
                   - smoothstep(1.0 - contourWidth / contourInterval, 1.0, fractional);
  vec3 terrainColor = vec3(0.3, 0.6, 0.2); // 基础地形色
  vec3 finalColor = mix(terrainColor, contourColor, lineWeight);
  gl_FragColor = vec4(finalColor, 1.0);
}
  • 优点:GPU加速,实时流畅;缺点:无法获取等高线几何数据,不支持交互选中。

方式二:几何生成等高线(支持交互)

遍历地形三角面,计算与等高高度的交点,生成可交互的线条:

function generateContours(terrainGeometry, contourHeights) {
  const contours = {};
  const positions = terrainGeometry.attributes.position.array;
  const indices = terrainGeometry.index.array;

  // 遍历所有三角面
  for (let i = 0; i < indices.length; i += 3) {
    const getVertex = idx => ({
      x: positions[idx*3], y: positions[idx*3+1], z: positions[idx*3+2]
    });
    const v1 = getVertex(indices[i]);
    const v2 = getVertex(indices[i+1]);
    const v3 = getVertex(indices[i+2]);

    // 遍历每个等高高度
    for (const h of contourHeights) {
      const intersections = [];
      // 判断边是否与等高线相交,计算交点
      const checkEdge = (a, b) => {
        if ((a.z < h && b.z > h) || (a.z > h && b.z < h)) {
          const t = (h - a.z) / (b.z - a.z);
          intersections.push({
            x: a.x + t*(b.x - a.x),
            y: a.y + t*(b.y - a.y),
            z: h
          });
        }
      };
      checkEdge(v1, v2);
      checkEdge(v2, v3);
      checkEdge(v3, v1);

      // 两个交点形成线段,加入对应等高线集合
      if (intersections.length === 2) {
        if (!contours[h]) contours[h] = [];
        contours[h].push(...intersections);
      }
    }
  }

  // 转为Three.js Line对象
  const contourObjects = [];
  for (const h in contours) {
    const geometry = new THREE.BufferGeometry().setFromPoints(contours[h]);
    const material = new THREE.LineBasicMaterial({ color: 0xffffff });
    contourObjects.push(new THREE.LineSegments(geometry, material));
  }
  return contourObjects;
}
  • 优点:可获取几何数据,支持交互;缺点:CPU计算,大尺寸地形需分块优化。

3. 点击选中同高度区域/等高线

方案一:Raycaster检测匹配

通过射线检测获取点击的地形高度,高亮同高度元素:

const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const tolerance = 0.5; // 高度容差

window.addEventListener('click', (event) => {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  raycaster.setFromCamera(mouse, camera);
  
  const intersects = raycaster.intersectObject(terrainMesh);
  if (intersects.length === 0) return;
  
  const targetHeight = intersects[0].point.z;
  // 高亮同高度地形顶点(需提前给geometry添加color属性,开启vertexColors)
  const colors = terrainMesh.geometry.attributes.color.array;
  for (let i = 0; i < colors.length; i += 3) {
    const height = terrainMesh.geometry.attributes.position.array[i+2];
    if (Math.abs(height - targetHeight) < tolerance) {
      colors[i] = 1; colors[i+1] = 0; colors[i+2] = 0; // 红色高亮
    } else {
      colors[i] = 0.3; colors[i+1] = 0.6; colors[i+2] = 0.2; // 恢复原地形色
    }
  }
  terrainMesh.geometry.attributes.color.needsUpdate = true;

  // 高亮对应等高线(几何生成方式适用)
  contourObjects.forEach(line => {
    const lineHeight = line.geometry.attributes.position.array[2];
    line.material.color.set(Math.abs(lineHeight - targetHeight) < tolerance ? 0xff0000 : 0xffffff);
  });
});

方案二:高度图像素匹配(高效)

点击地形时通过UV坐标找到对应高度图像素,遍历像素匹配后映射到地形顶点,适合大尺寸地形,性能优于遍历顶点。

4. 完整工具流程

  • 上传高度图:用input[type="file"]获取图片,通过Canvas读取像素转为高度数组。
  • 生成地形Mesh:用高度数组创建带高度的PlaneGeometry。
  • 生成等高线:根据需求选择Shader或几何方式。
  • 交互功能:实现点击选中同高度区域/等高线,添加间距、容差调整UI控件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 00:35:32