I am actually making a rotating globe, with points of interest on it. The globe is rotating so it should show points of interest whenever the point is visible on the globe.
My problem is that I only see the points of interest when they are “behind” the globe when it rotates, like on the picture below (you can only see a thin red line on the right):

Here is the code:
<script setup>
import * as THREE from 'three';
const points = [
{
name: 'Paris',
latitude: 48.864716,
longitude: 2.349014,
},
{
name: 'New York',
latitude: 40.73061,
longitude: -73.935242,
},
{
name: 'Beijing',
latitude: 39.9042,
longitude: 116.407396,
},
];
const wrapper = ref(null);
let renderer = null;
let scene = null;
let camera = null;
let sphere = null;
let clouds = null;
const rotationSpeed = 0.005;
const markers = [];
let animationFrameId = null;
let isMounted = false;
function render() {
if (isMounted) {
sphere.rotation.y += rotationSpeed;
animationFrameId = requestAnimationFrame(render);
renderer.render(scene, camera);
}
}
function createSphere(radius, segments) {
return new THREE.Mesh(
new THREE.SphereGeometry(radius, segments, segments),
new THREE.MeshBasicMaterial({ color: 0x0000ff })
);
}
function initialize() {
const width = window.innerWidth;
const height = window.innerHeight;
// Earth params
const radius = 0.5;
const segments = 32;
const rotation = 6;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, width / height, 0.01, 1000);
camera.position.z = 1.5;
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
});
renderer.setSize(width, height);
scene.add(new THREE.AmbientLight(0x333333));
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 3, 5);
scene.add(light);
sphere = createSphere(radius, segments);
sphere.rotation.y = rotation;
scene.add(sphere);
for (const point of points) {
const marker = new THREE.Mesh(
new THREE.RingGeometry(0.01, 0.02, 32),
new THREE.MeshBasicMaterial({ color: 0xff0000 })
);
const phi = (90 - point.latitude) * (Math.PI / 180);
const theta = (point.longitude + 180) * (Math.PI / 180);
marker.position.x = -((radius + 0.001) * Math.sin(phi) * Math.cos(theta));
marker.position.y = (radius + 0.001) * Math.cos(phi);
marker.position.z = (radius + 0.001) * Math.sin(phi) * Math.sin(theta);
marker.lookAt(sphere.position);
sphere.add(marker);
}
wrapper.value.appendChild(renderer.domElement);
render();
}
function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
onMounted(() => {
isMounted = true;
initialize();
window.addEventListener('resize', onResize);
});
onUnmounted(() => {
isMounted = false;
cancelAnimationFrame(animationFrameId);
window.removeEventListener('resize', onResize);
});
</script>
<template>
<div ref="wrapper">
<!-- -->
</div>
</template>
Here is a reproduction of my problem on Stackblitz: https://stackblitz.com/edit/nuxt-starter-ewsydq?file=app.vue. I removed anything superfluous (textures for instance) so the reproduction is the lightest as possible.
Thanks for your help 🙂
What should I do so my points of interest are visible when they are on the visible side of the globe?