带有地形层的 MapLibre GL JS:如何将水平面固定到特定高度?

Dan*_*l F 7 terrain three.js mapbox-gl-js maplibre-gl

我基于“添加 3D 模型”示例的一些代码来仅在地图上绘制水平面,用于setTerrain添加地形图层。我的目的是在海拔高度绘制半透明图层,并使它们与山脉相交,有点类似于等高线。

我在海拔 0 处创建了一个 1 公里宽的正方形。海拔 0 是可见地图区域中心地形的高度。当我拖动地图并释放鼠标时,高度 0 会重置为中心地形的新高度 0,从而使飞机改变其相对高度:

问题飞机搬迁

为了更好地说明问题,夸大了海拔。

如何指定飞机的高度(以米为单位)并在拖动地图时将其固定在该高度?我想我需要获取中心地形的高度,然后从平面的 z 位置添加/减去它,但是如何在自定义图层的渲染函数中执行此操作?

Mic*_*ein 0

正如您所说,一个简单的解决方案是获取屏幕中心地形的高度和模型的高度,然后将它们相减。这可以像这样实现:

// edited version of https://maplibre.org/maplibre-gl-js/docs/examples/add-3d-model/

  render(gl, matrix) {
    
    const modelOrigin = new LngLat(11.53, 47.67);  // just an example
    const modelElevation = map.terrain ? map.terrain.getElevationForLngLatZoom(modelOrigin, map.getZoom()) : 0;
    const modelOriginMercator = mlg.MercatorCoordinate.fromLngLat(modelOrigin, 0);
  
    // calculating the difference between center-elevation and model-elevation
    const terrainCenterElevation = map.transform.elevation;
    const deltaMetersZ = modelElevation - terrainCenterElevation;
    const mercatorPerMeter = modelOriginMercator.meterInMercatorCoordinateUnits();
    const deltaMercatorZ = deltaMetersZ * mercatorPerMeter;

    const modelTransform = {
      translateX: modelOriginMercator.x,
      translateY: modelOriginMercator.y,
      translateZ: modelOriginMercator.z + deltaMercatorZ,
      rotateX: Math.PI / 2,
      rotateY: 0,
      rotateZ: 0,
      scale: modelOriginMercator.meterInMercatorCoordinateUnits()
    };

    const rotationX = new Matrix4().makeRotationAxis(new Vector3(1, 0, 0), modelTransform.rotateX);
    const rotationY = new Matrix4().makeRotationAxis(new Vector3(1, 0, 0), modelTransform.rotateY);
    const rotationZ = new Matrix4().makeRotationAxis(new Vector3(0, 0, 1), modelTransform.rotateZ);

    const m = new Matrix4().fromArray(matrix);
    const l = new Matrix4()
      .makeTranslation(modelTransform.translateX, modelTransform.translateY, modelTransform.translateZ)
      .scale(new Vector3(modelTransform.scale, modelTransform.scale, modelTransform.scale))
      .multiply(rotationX).multiply(rotationY).multiply(rotationZ);
    const cameraProjectionMatrix = m.multiply(l);

    // @ts-ignore
    this.camera.projectionMatrix = cameraProjectionMatrix;
    // @ts-ignore
    this.renderer.resetState();
    // @ts-ignore
    this.renderer.render(this.scene, this.camera);
    map.triggerRepaint();


}
Run Code Online (Sandbox Code Playgroud)
  • maplibre 似乎总是将 Threejs 场景精确定位在屏幕中心的高度...因此,当使用 获取模型高度时mlg.MercatorCoordinate.fromLngLat(modelOrigin, 0),我们不需要提供实际的模型高度,只需通过0
  • deltaMercatorZ正在被添加到模型的 z 平移中

关于transform.ts中maplibre命名法的一些注释:

  • elevation[米]:下方地形的高度center
  • center[lng, lat]: 屏幕中心在世界中的位置
  • centerPoint[pixel]:屏幕中心在屏幕上的位置
  • altitude[m]:相机相对于海平面的高度

我认为可能有一个更优雅的解决方案,但这可能暂时可以完成工作!