Map error after adding new function

i updated a code i got from here to add an addMarker function, but the locations on the map is off, any reason why?

let scene = new THREE.Scene();
      let camera = new THREE.PerspectiveCamera(
        45,
        innerWidth / innerHeight,
        1,
        2000
      );
      camera.position.set(0.5, 0.5, 1).setLength(14);
      let renderer = new THREE.WebGLRenderer({
        antialias: true,
      });
      renderer.setSize(innerWidth, innerHeight);
      renderer.setClearColor(0xaaffaa); //bg
      document.body.appendChild(renderer.domElement);

      let labelRenderer = new CSS2DRenderer();
      labelRenderer.setSize(window.innerWidth, window.innerHeight);
      labelRenderer.domElement.style.position = "absolute";
      labelRenderer.domElement.style.top = "0px";
      document.body.appendChild(labelRenderer.domElement);

      window.addEventListener("resize", onWindowResize);

      let controls = new OrbitControls(camera, labelRenderer.domElement);
      controls.enablePan = false;
      controls.minDistance = 6;
      controls.maxDistance = 15;
      controls.enableDamping = true;
      controls.autoRotate = true;
      controls.autoRotateSpeed *= 0.25;

      let globalUniforms = {
        time: { value: 0 },
      };

      // <GLOBE>
      let counter = 200000;
      let rad = 5;
      let sph = new THREE.Spherical();

      let r = 0;
      let dlong = Math.PI * (3 - Math.sqrt(5));
      let dz = 2 / counter;
      let long = 0;
      let z = 1 - dz / 2;

      let pts = [];
      let clr = [];
      let c = new THREE.Color();
      let uvs = [];

      for (let i = 0; i < counter; i++) {
        r = Math.sqrt(1 - z * z);
        let p = new THREE.Vector3(
          Math.cos(long) * r,
          z,
          -Math.sin(long) * r
        ).multiplyScalar(rad);
        pts.push(p);
        z = z - dz;
        long = long + dlong;

        c.setHSL(0.45, 0.5, Math.random() * 0.25 + 0.25);
        c.toArray(clr, i * 3);

        sph.setFromVector3(p);
        uvs.push(
          (sph.theta + Math.PI) / (Math.PI * 2),
          1.0 - sph.phi / Math.PI
        );
      }

      let g = new THREE.BufferGeometry().setFromPoints(pts);
      g.setAttribute("color", new THREE.Float32BufferAttribute(clr, 3));
      g.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2));
      let m = new THREE.PointsMaterial({
        size: 0.1,
        vertexColors: true,
        onBeforeCompile: (shader) => {
          shader.uniforms.globeTexture = {
            value: new THREE.TextureLoader().load("texture.jpg"),
          };
          shader.vertexShader = `
      	uniform sampler2D globeTexture;
        varying float vVisibility;
        varying vec3 vNormal;
        varying vec3 vMvPosition;
        ${shader.vertexShader}
      `.replace(
            `gl_PointSize = size;`,
            `
        	vVisibility = texture(globeTexture, uv).g; // get value from texture
          gl_PointSize = size * (vVisibility < 0.5 ? 1. : 0.75); // size depends on the value
          vNormal = normalMatrix * normalize(position);
          vMvPosition = -mvPosition.xyz;
          gl_PointSize *= 0.4 + (dot(normalize(vMvPosition), vNormal) * 0.6); // size depends position in camera space
        `
          );
          //console.log(shader.vertexShader);
          shader.fragmentShader = `
      	varying float vVisibility;
        varying vec3 vNormal;
        varying vec3 vMvPosition;
        ${shader.fragmentShader}
      `.replace(
            `vec4 diffuseColor = vec4( diffuse, opacity );`,
            `
        	bool circ = length(gl_PointCoord - 0.5) > 0.5; // make points round
          bool vis = dot(vMvPosition, vNormal) < 0.; // visible only on the front side of the sphere
        	if (circ || vis) discard;

          vec3 col = diffuse + (vVisibility > 0.5 ? 0.5 : 0.); // make oceans brighter

          vec4 diffuseColor = vec4( col, opacity );
        `
          );
          //console.log(shader.fragmentShader);
        },
      });
      let globe = new THREE.Points(g, m);
      scene.add(globe);

      // <Markers>
      const markerCount = 30;
      let markerInfo = []; // information on markers
      let gMarker = new THREE.PlaneGeometry();
      let mMarker = new THREE.MeshBasicMaterial({
        color: 0xff3232,
        onBeforeCompile: (shader) => {
          shader.uniforms.time = globalUniforms.time;
          shader.vertexShader = `
      	attribute float phase;
        varying float vPhase;
        ${shader.vertexShader}
      `.replace(
            `#include <begin_vertex>`,
            `#include <begin_vertex>
        	vPhase = phase; // de-synch of ripples
        `
          );
          //console.log(shader.vertexShader);
          shader.fragmentShader = `
      	uniform float time;
        varying float vPhase;
      	${shader.fragmentShader}
      `.replace(
            `vec4 diffuseColor = vec4( diffuse, opacity );`,
            `
        vec2 lUv = (vUv - 0.5) * 2.;
        float val = 0.;
        float lenUv = length(lUv);
        val = max(val, 1. - step(0.25, lenUv)); // central circle
        val = max(val, step(0.4, lenUv) - step(0.5, lenUv)); // outer circle

        float tShift = fract(time * 0.5 + vPhase);
        val = max(val, step(0.4 + (tShift * 0.6), lenUv) - step(0.5 + (tShift * 0.5), lenUv)); // ripple

        if (val < 0.5) discard;

        vec4 diffuseColor = vec4( diffuse, opacity );`
          );
          //console.log(shader.fragmentShader)
        },
      });
      mMarker.defines = { USE_UV: " " }; // needed to be set to be able to work with UVs
      let markers = new THREE.InstancedMesh(gMarker, mMarker, markerCount);

      let dummy = new THREE.Object3D();
      let phase = [];

      // Function to convert latitude and longitude to 3D coordinates
      function latLngToVector3(lat, lng, radius) {
        const phi = (90 - lat) * (Math.PI / 180);
        const theta = (lng + 180) * (Math.PI / 180);

        const x = -(radius * Math.sin(phi) * Math.cos(theta));
        const y = radius * Math.cos(phi);
        const z = radius * Math.sin(phi) * Math.sin(theta);

        return new THREE.Vector3(x, y, z);
      }

      // Function to add a marker
      function addMarker(lat, lng, magnitude, countryName, flagURL) {
        const dummy = new THREE.Object3D(); // Ensure dummy is defined locally

        // Calculate position similar to the for loop
        dummy.position.copy(latLngToVector3(lat, lng, rad + 0.1));
        dummy.position.setLength(rad + 0.1); // Ensure position length matches the for loop

        // Orient marker
        dummy.lookAt(dummy.position.clone().setLength(rad + 1)); // Match lookAt logic in the for loop
        dummy.updateMatrix();

        // Add marker to instance
        const markerIndex = markerInfo.length;
        markers.setMatrixAt(markerIndex, dummy.matrix);
        markers.instanceMatrix.needsUpdate = true;

        // Store marker information
        markerInfo.push({
          id: markerIndex + 1,
          mag: magnitude || THREE.MathUtils.randInt(1, 10), // Default to random if not provided
          crd: dummy.position.clone(),
          country: countryName,
          flag: flagURL,
        });
      }

      // Example usage: Add markers for specific countries
      const locations = [
        {
          name: "Nigeria",
          flag: "https://www.worldometers.info/img/flags/small/tn_ni-flag.gif",
          lat: 9.081999,
          lng: 8.675277,
        },
        {
          name: "Mexico",
          flag: "https://www.worldometers.info/img/flags/small/tn_mx-flag.gif",
          lat: 23.634501,
          lng: -102.552788,
        },
        {
          name: "Brazil",
          flag: "https://www.worldometers.info/img/flags/small/tn_br-flag.gif",
          lat: -14.235,
          lng: -51.9253,
        },
        {
          name: "Colombia",
          flag: "https://www.worldometers.info/img/flags/small/tn_co-flag.gif",
          lat: 4.5709,
          lng: -74.2973,
        },
        {
          name: "Paraguay",
          flag: "https://www.worldometers.info/img/flags/small/tn_pa-flag.gif",
          lat: -23.4425,
          lng: -58.4438,
        },
        {
          name: "Costa Rica",
          flag: "https://www.worldometers.info/img/flags/small/tn_cs-flag.gif",
          lat: 9.7489,
          lng: -83.7534,
        },
        {
          name: "Spain",
          flag: "https://www.worldometers.info/img/flags/small/tn_sp-flag.gif",
          lat: 40.4637,
          lng: -3.7492,
        },
        {
          name: "France",
          flag: "https://www.worldometers.info/img/flags/small/tn_fr-flag.gif",
          lat: 46.6034,
          lng: 1.8883,
        },
        {
          name: "Germany",
          flag: "https://www.worldometers.info/img/flags/small/tn_gm-flag.gif",
          lat: 51.1657,
          lng: 10.4515,
        },
        {
          name: "Lithuania",
          flag: "https://www.worldometers.info/img/flags/small/tn_lh-flag.gif",
          lat: 55.1694,
          lng: 23.8813,
        },
        {
          name: "Indonesia",
          flag: "https://www.worldometers.info/img/flags/small/tn_id-flag.gif",
          lat: -0.7893,
          lng: 113.9213,
        },
      ];

      locations.forEach((place) => {
        addMarker(place.lat, place.lng, 0, place.name, place.flag);
      });
      // addMarker(37.7749, -122.4194, 5); // San Francisco
      // addMarker(51.5074, -0.1278, 7); // London
      // addMarker(35.6895, 139.6917, 8); // Tokyo

      gMarker.setAttribute(
        "phase",
        new THREE.InstancedBufferAttribute(new Float32Array(phase), 1)
      );

      scene.add(markers);
      // </Markers>

      // <Label>
      let labelDiv = document.getElementById("markerLabel");
      let closeBtn = document.getElementById("closeButton");
      closeBtn.addEventListener("pointerdown", (event) => {
        labelDiv.classList.add("hidden");
      });
      let label = new CSS2DObject(labelDiv);
      label.userData = {
        cNormal: new THREE.Vector3(),
        cPosition: new THREE.Vector3(),
        mat4: new THREE.Matrix4(),
        trackVisibility: () => {
          // the closer to the edge, the less opacity
          let ud = label.userData;
          ud.cNormal
            .copy(label.position)
            .normalize()
            .applyMatrix3(globe.normalMatrix);
          ud.cPosition
            .copy(label.position)
            .applyMatrix4(
              ud.mat4.multiplyMatrices(
                camera.matrixWorldInverse,
                globe.matrixWorld
              )
            );
          let d = ud.cPosition.negate().normalize().dot(ud.cNormal);
          d = smoothstep(0.2, 0.7, d);
          label.element.style.opacity = d;

          // https://github.com/gre/smoothstep/blob/aa5b60a10fd7c1c6e3a62d5efad4b086369f4232/index.js
          function smoothstep(min, max, value) {
            var x = Math.max(0, Math.min(1, (value - min) / (max - min)));
            return x * x * (3 - 2 * x);
          }
        },
      };
      scene.add(label);
      // </Label>

      // <Interaction>
      let pointer = new THREE.Vector2();
      let raycaster = new THREE.Raycaster();
      let intersections;
      let divID = document.getElementById("idNum");
      let divMag = document.getElementById("magnitude");
      let divCrd = document.getElementById("coordinates");

      let divCountry = document.getElementById("country");
      let divFlag = document.getElementById("flag");
      window.addEventListener("pointerdown", (event) => {
        pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
        pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
        raycaster.setFromCamera(pointer, camera);
        intersections = raycaster.intersectObject(markers).filter((m) => {
          return m.uv.subScalar(0.5).length() * 2 < 0.25; // check, if we're in the central circle only
        });
        //console.log(intersections);
        if (intersections.length > 0) {
          let iid = intersections[0].instanceId;
          let mi = markerInfo[iid];
          //   divID.innerHTML = `ID: <b>${mi.id}</b>`;
          //   divMag.innerHTML = `Mag: <b>${mi.mag}</b>`;
          //   divCrd.innerHTML = `X: <b>${mi.crd.x.toFixed(
          //     2
          //   )}</b>; Y: <b>${mi.crd.y.toFixed(2)}</b>; Z: <b>${mi.crd.z.toFixed(
          //     2
          //   )}</b>`;

          // Display Country Name and Flag
          divCountry.innerHTML = `<b>${mi.country}</b>`;
          divFlag.innerHTML = `<img src="${mi.flag}" alt="${mi.country} flag" style="width: 50px; height: 50px;object-fit:contain;">`;
          label.position.copy(mi.crd);
          label.element.animate(
            [
              {
                width: "0px",
                height: "0px",
                marginTop: "0px",
                marginLeft: "0px",
              },
              {
                width: "230px",
                height: "50px",
                marginTop: "-25px",
                maginLeft: "120px",
              },
            ],
            {
              duration: 250,
            }
          );
          label.element.classList.remove("hidden");
        }
      });
      // </Interaction>

      let clock = new THREE.Clock();

      renderer.setAnimationLoop(() => {
        let t = clock.getElapsedTime();
        globalUniforms.time.value = t;
        label.userData.trackVisibility();
        controls.update();
        renderer.render(scene, camera);
        labelRenderer.render(scene, camera);
      });

      function onWindowResize() {
        camera.aspect = innerWidth / innerHeight;
        camera.updateProjectionMatrix();

        renderer.setSize(innerWidth, innerHeight);
        labelRenderer.setSize(innerWidth, innerHeight);
      }

Please provide a minimum code example of your running code, preferrably as a codepen or jsfiddle.
Example of what this would look like.

Nobody will go through your 440 lines of code as long as you neither specify what you expected nor what was the actual result.

sorry about that,

i uploaded it here

so i got a codepen link from a post made a couple of months ago for a globe with markers, so i updated it adding a new function to add specific markers by providing their longitude and latitude (mostly chatgpt since i’m still very new to threejs), and it worked, but the locations are wrong
i confimed from chatgpt that the latLngToVector3 function is accurate, so i have no idea why it shows a different location on the globe.

Thanks in advance

You are referring to this codeben by @prisoner849 . It would have been good style to give credits to the author of the code you copied, in the current case: @prisoner849 .

The only suggestion I can give you here is, to clone said codepen and try to understand what’s happening inside. Only then apply a small change and see if the code is still working properly, including you change. If not, tweak your change until the code is running again. Repeat as necessary.

2 Likes