就像你说的那样,一个天真的解决方案是获取屏幕中心处的地形高度和你的模型的高度,然后相减。可以通过以下方式实现:
render(gl, matrix) {
const modelOrigin = new LngLat(11.53, 47.67);
const modelElevation = map.terrain ? map.terrain.getElevationForLngLatZoom(modelOrigin, map.getZoom()) : 0;
const modelOriginMercator = mlg.MercatorCoordinate.fromLngLat(modelOrigin, 0);
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);
this.camera.projectionMatrix = cameraProjectionMatrix;
this.renderer.resetState();
this.renderer.render(this.scene, this.camera);
map.triggerRepaint();
}
- maplibre似乎总是将threejs场景准确地定位在屏幕中心的高度...所以当使用
mlg.MercatorCoordinate.fromLngLat(modelOrigin, 0)
获取模型高度时,我们不需要提供实际的模型高度,只需传递0
deltaMercatorZ
被添加到模型的z轴平移中
关于maplibre在transform.ts中的命名约定,以下是一些注意事项:
elevation
[米]:中心点center
下方地形的高度
center
[经度,纬度]:屏幕中心在世界坐标系中的位置
centerPoint
[像素]:屏幕中心在屏幕上的位置
altitude
[米]:相机相对于海平面的高度
我认为可能有更优雅的解决方案,但现在这个可能能够胜任!