我一直在学习如何使用this example将ThreeJS与Mapbox集成。奇怪的是,这种方法是将加载的模型保留在其自己的坐标系中,并在渲染时变换摄影机位置,这让我感到奇怪。因此,我尝试重写代码,以便在加载时转换GLTF模型,然后将ThreeJS相机与Mapbox相机同步,而无需进行进一步修改。
代码现在看起来像这样:
function newScene() {
const scene = new THREE.Scene();
// create two three.js lights to illuminate the model
const directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(0,-70,100).normalize();
scene.add(directionalLight);
const directionalLight2 = new THREE.DirectionalLight(0xffffff);
directionalLight2.position.set(0,70,100).normalize();
scene.add(directionalLight2);
return scene;
}
function newRenderer(map,gl) {
// use the Mapbox GL JS map canvas for three.js
const renderer = new THREE.WebGLRenderer({
canvas: map.getcanvas(),context: gl,antialias: true
});
renderer.autoClear = false;
return renderer;
}
// create a custom layer for a 3D model per the CustomLayerInterface
export function addmodel(modelPath,origin,altitude = 0,orientation = [Math.PI / 2,0]) {
const coords = mapboxgl.MercatorCoordinate.fromLngLat(origin,altitude);
// transformation parameters to position,rotate and scale the 3D model onto the map
const modelTransform = {
translateX: coords.x,translateY: coords.y,translateZ: coords.z,rotateX: orientation[0],rotateY: orientation[1],rotateZ: orientation[2],/* Since our 3D model is in real world meters,a scale transform needs to be
* applied since the CustomLayerInterface expects units in MercatorCoordinates.
*/
scale: coords.meterInmercatorCoordinateUnits()
};
const scaleVector = new THREE.Vector3(modelTransform.scale,-modelTransform.scale,modelTransform.scale)
return {
id: "3d-model",type: "custom",renderingMode: "3d",onAdd: function(map,gl) {
this.map = map;
this.camera = new THREE.Camera();
this.scene = newScene();
this.renderer = newRenderer(map,gl);
// use the three.js GLTF loader to add the 3D model to the three.js scene
new THREE.GLTFLoader()
.load(modelPath,gltf => {
gltf.scene.position.fromArray([coords.x,coords.y,coords.z]);
gltf.scene.setRotationFromEuler(new THREE.Euler().fromArray(orientation));
gltf.scene.scale.copy(scaleVector);
this.scene.add(gltf.scene);
const bbox = new THREE.Box3().setfromObject(gltf.scene);
console.log(bbox);
this.scene.add(new THREE.Box3Helper(bbox,'blue'));
});
},render: function(gl,matrix) {
this.camera.projectionmatrix = new THREE.Matrix4().fromArray(matrix);
this.renderer.state.reset();
this.renderer.render(this.scene,this.camera);
// this.map.triggerRepaint();
}
}
}
它的基本原理是,在Mapbox世界中的正确位置加载并绘制模型。但是,与其看起来像这样:
现在看起来像这样,一个混乱的混乱,随着摄像机的移动而混乱地抖动着:
我对ThreeJS不够熟悉,无法知道我做错了什么。
这是右侧旧功能代码与左侧新功能代码的并排比较。
进一步调查
我怀疑原因可能与将所有坐标缩小到投影坐标系的[0..1]范围之内以及可能失去数学精度有关。当我将模型放大100倍时,它会呈现出这样的样子-杂乱无章,但至少可以识别为某种东西。