I have a Mapbox map that has several animated 3D-arrows that have been added to a custom layer on the map.
However, whenever I zoom out too far on the map, the arrows disappear and the entire map goes white (as if a piece of white paper has been placed between the viewer and the map).
I wasn't able to embed a video to show this behaviour, but here is a link that will show an animation of what is happening: https://i.stack.imgur.com/hw4to.jpg
My assumption is that this has something to do with the gltf model, frustrum, culling, camera. Whenever I change the parameters of the Three.PersepectiveCamera it has no effect on the behaviour.
The following is the code used to implement the custom layer. There are a few other pieces (i.e., onRemove, render) that work alongside this configuration, but I can't see how any of it would be connected.
// configuration of the custom layer for a 3D model per the CustomLayerInterface
var customLayer = {
id: layer_id,
type: 'custom',
renderingMode: '3d',
onAdd: function (map, gl) {
camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 0.1, 10000);
// camera = new THREE.Camera();
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);
// use the three.js GLTF loader to add the 3D model to the three.js scene
const loader = new THREE.GLTFLoader();
loader.load(
arrow_type,
(gltf) => {
model = gltf.scene.children[0];
model.castShadow = true;
scene.add(model);
mixer = new THREE.AnimationMixer( model );
const clip = gltf.animations[0];
//console.log(gltf);
mixer.clipAction(clip).play();
delta = clock.getDelta();
mixer.tick = (delta) => mixer.update(delta);
animate();
}
);
this.map = map;
// use the Mapbox GL JS map canvas for three.js
renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl,
antialias: true
});
function animate() {
delta = clock.getDelta();
mixer.update(delta);
//model.tick = (delta) => mixer.update(delta);
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
renderer.autoClear = false;
},
onRemove: function (map, gl) {
// This function hasn't been tested and may cause problems when removing a 3D object
this.container.parentNode.removeChild(this.container);
this.map = undefined;
},
render: function (gl, matrix) {
const rotationX = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(1, 0, 0),
modelTransform.rotateX
);
const rotationY = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(0, 1, 0),
modelTransform.rotateY
);
const rotationZ = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(0, 0, 1),
modelTransform.rotateZ
);
const m = new THREE.Matrix4().fromArray(matrix);
const l = new THREE.Matrix4()
.makeTranslation(
modelTransform.translateX,
modelTransform.translateY,
modelTransform.translateZ
)
.scale(
new THREE.Vector3(
modelTransform.scale * length_arr[0],
modelTransform.scale * length_arr[1],
modelTransform.scale * length_arr[2]
)
)
.multiply(rotationX)
.multiply(rotationY)
.multiply(rotationZ);
camera.projectionMatrix = m.multiply(l);
renderer.resetState();
renderer.render(scene, camera);
map.triggerRepaint();
}
Any help would be greatly appreciated in solving this problem.