I have this scene as the landing page of a website. The idea is that a user can click on the name of a continent and then some Javascript runs that creates a popup related to that continent. When it all loads properly (I’d say 50 percent of the time, but this may be more or less), then everything is great, the raycaster intersects with the proper continent label on clicking, and the JS runs as expected. However, the other times, it seems that the textures are loaded offset from the object meshes. I’ve discovered that when this happens, I must click up and to the left of the actual label in order to achieve the expected result… sometimes so far up and left that the click is entirely off of the texture. I am at a total loss of why this is occurring. I’ve console logged the renderers bounding rect, and it seems that it is inconsistent, perhaps this is why? If so, why would it be so inconsistent when using the same device (I’ve seen this issue occur more often on mobile, I’m using a Samsung S24+)? My init() function and internal init functions are pasted below, and I’ll post some screenshots of the inconsistent behavior as an example (The first being what is expected, and the second being the offset loading). The landing page can be found at https://www.planet.pizza, perhaps you can recreate the issue yourself… the weird thing is that it is inconsistent and not certainly always reproducible.
Init function:
async function init() {
//set content
setPopupContent();
//camera
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set(1.5, 1, -2.5);
prevTime = performance.now();
earth = new THREE.Object3D();
ufo = new THREE.Object3D();
flag = new THREE.Object3D();
pizzaPlane = new THREE.Object3D();
northAmericaLabel = new THREE.Object3D();
southAmericaLabel = new THREE.Object3D();
europeLabel = new THREE.Object3D();
africaLabel = new THREE.Object3D();
asiaLabel = new THREE.Object3D();
australiaLabel = new THREE.Object3D();
antarcticaLabel = new THREE.Object3D();
stars = new THREE.Object3D();
scene = new THREE.Scene();
loader = new GLTFLoader();
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize( window.innerWidth, window.innerHeight - document.getElementsByTagName("nav-bar")[0].offsetHeight);
document.getElementById("map").appendChild( renderer.domElement );
controls = new OrbitControls( camera, renderer.domElement );
controls.saveState();
origin = new THREE.Vector3(0,0,0);
rotationAxis = new THREE.Vector3(0,1,0);
//click listener
renderer.domElement.addEventListener("mousedown", clickStart);
renderer.domElement.addEventListener("mouseup", clickEnd);
earthClick = false;
//light
light = new THREE.AmbientLight( 0x404040, 50 ); // soft white light
scene.add( light );
//load System
await loadSystem();
texts = [northAmericaLabel, southAmericaLabel, europeLabel, africaLabel, asiaLabel, australiaLabel, antarcticaLabel];
northAmericaLabel.scene.position.setFromSphericalCoords(1.1, -Math.PI * 1/4, -Math.PI * 1/3);
southAmericaLabel.scene.position.setFromSphericalCoords(1.1, -Math.PI * 7/13, -Math.PI * 1/8);
europeLabel.scene.position.setFromSphericalCoords(1.1, -Math.PI * 1/4, Math.PI * 3/10);
africaLabel.scene.position.setFromSphericalCoords(1.1, -Math.PI * 3/7, Math.PI * 1/3);
asiaLabel.scene.position.setFromSphericalCoords(1.1, -Math.PI * 1/4, Math.PI * 2/3);
australiaLabel.scene.position.setFromSphericalCoords(1.1, Math.PI * 5/8, 0);
antarcticaLabel.scene.position.setFromSphericalCoords(1.1, Math.PI, 0);
//interactions
bounds = renderer.domElement.getBoundingClientRect();
pointer = new THREE.Vector2();
clickStartV = new THREE.Vector2();
clickEndV = new THREE.Vector2();
raycaster = new THREE.Raycaster();
//event listeners
document.getElementById("resetPivot").addEventListener("click", resetCamera);
//stop loading animation
document.getElementById("loading").style.display = "none";
console.log(camera.position);
console.log(earth.scene.position);
console.log(renderer.domElement.getBoundingClientRect());
}
Load System Function:
async function loadSystem() {
//load objects asynchronously
let [...system] = await Promise.all([
loadObject("Earth"),
loadObject("UFO"),
loadObject("Flag"),
loadObject("PizzaPlane"),
loadObject("NorthAmericaLabel"),
loadObject("SouthAmericaLabel"),
loadObject("EuropeLabel"),
loadObject("AfricaLabel"),
loadObject("AsiaLabel"),
loadObject("AustraliaLabel"),
loadObject("AntarcticaLabel"),
loadObject("Stars")
])
earth = system[0];
ufo = system[1];
flag = system[2];
pizzaPlane = system[3];
northAmericaLabel = system[4];
southAmericaLabel = system[5];
europeLabel = system[6];
africaLabel = system[7];
asiaLabel = system[8];
australiaLabel = system[9];
antarcticaLabel = system[10];
stars = system[11];
//positioning and adding
scene.add(earth.scene);
earth.scene.rotation.y = Math.PI * 3/4;
scene.add(ufo.scene);
ufo.scene.position.set(1.5, 1.5, 1.5);
scene.add(flag.scene);
flag.scene.position.y = 0.98;
flag.scene.rotation.y = Math.PI/2;
scene.add(pizzaPlane.scene);
pizzaPlane.scene.rotation.z = -Math.PI/2;
pizzaPlane.scene.rotation.y = Math.PI/4;
pizzaPlane.scene.position.x = -400;
pizzaPlane.scene.position.z = 400;
scene.add(northAmericaLabel.scene);
scene.add(southAmericaLabel.scene);
scene.add(europeLabel.scene);
scene.add(africaLabel.scene);
scene.add(asiaLabel.scene);
scene.add(australiaLabel.scene);
scene.add(antarcticaLabel.scene);
scene.add(stars.scene);
}
Load Object Function:
function loadObject(id) {
let result = loader.loadAsync(`./static/objects/${id}.glb`);
return result;
}