Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best way to render 3D markers #90

Closed
danman335 opened this issue Feb 27, 2022 · 9 comments
Closed

Best way to render 3D markers #90

danman335 opened this issue Feb 27, 2022 · 9 comments

Comments

@danman335
Copy link

Hi,

I've setup a globe and styled etc - looking now at the best way to render 3D map markers that rise off the earth perpendicular to its surface. Is there anyway to change the column that is generated by the pointsData or would I better adding custom objects with objectsData in the objects later.

Example of below of what I'm trying to emulate:
Screenshot 2022-02-27 at 08 34 10

@vasturiano
Copy link
Owner

@danman335 thanks for reaching out.

I'd recommend using the Objects Layer for this. That will give you maximum flexibility on how to customize those pin objects.

@danman335
Copy link
Author

danman335 commented Feb 28, 2022

Thanks @vasturiano I got it mostly working, only thing I've hit a blocker on is that if I have multiple locations in my objectsData but only one object is rendered onto the globe, I think its to do with me misunderstanding how gtlf loaders and scenes work but is there anything obvious to be done differently here:

initGlobe() {
      const globeHolder = document.querySelector("#globe");
      const myGlobe = Globe({
        animateIn: true,
      });
      myGlobe(globeHolder)
        .globeImageUrl(require("../assets/full-map.jpg"))
        .backgroundColor("#000000")
        .atmosphereColor("#FFFFFF")
        .objectLat("lat")
        .objectLng("lng")
        .objectAltitude("alt")
        .objectLabel("name");

      const loader = new GLTFLoader();
      const self = this;

      loader.load(
        "/mappin.glb",
        function (gltf) {
          self.locations.forEach(() => {
            let scene = new THREE.Scene();
            gltf.scene.scale.set(30, 30, 30);
            scene.add(gltf.scene)
            myGlobe.objectThreeObject(() => scene);
          });
        },
        undefined,
        function (error) {
          console.error(error);
        }
      );

      myGlobe.objectsData(this.locations);
    },

This is my data and the result:

locations: [ { lat: 57.47753490825867, lng: -4.224291359173809, name: "Scotland", alt: 0, }, { lat: 46.227638, lng: 2.213749, name: "France", alt: 0, }, ],

Screenshot 2022-02-28 at 07 06 22

@vasturiano
Copy link
Owner

@danman335 it should suffice to do myGlobe.objectThreeObject(gltf.scene).

If you use the accessor function (() => scene) you're essentially using the exact same gltf object3d instance for every item in your data, which is what's happening I believe. You see a single object that gets moved around between all the coordinates.

Leaving out the accessor function cause the module to clone the object for each item.

@danman335
Copy link
Author

@vasturiano thanks, I got that - working now thanks. Final question (I promise) - trying to alter the individual rotations of the objectThreeObjects, at the moment they all share the same rotation properties.

If I log myGlobe.objectsData() I can see my individual objects with a reference to the underlying __threeObj but I can't see how to update the rotation of each point individually. Any pointers would be amazing thanks.

@vasturiano
Copy link
Owner

@danman335 glad you got the markers to work.

In order to rotate the objects you need to manipulate the rotation attribute in each of them: https://threejs.org/docs/#api/en/core/Object3D.rotation

In principle you should be able to use each object's lat,lng coordinates to calculate what the rotation angle of each object should be.

@danman335
Copy link
Author

danman335 commented Feb 28, 2022

Hey @vasturiano yeah I found the docs on rotation - what I'm not understanding is how to manipulate the rotate for each individually. I can't access the __threeObj on each individual object, and updating within my loader applies the properties to each object

loader.load(
        "/mappin.glb",
        function (marker) {
          marker.scene.scale.set(30, 30, 30);
          myGlobe.objectThreeObject(marker.scene);
        },
        function (xhr) {
          console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
        },
        function (error) {
          console.log("An error happened", error);
        }

i.e. whats the best way to access the Object3D properties/methods for the objects created passed in via objectsData?

Thanks

@vasturiano
Copy link
Owner

You can use the objectThreeObject in function accessor mode (like you had originally, but cloning the objects each time). Something like this:

myGlobe.objectThreeObject(item => {
  const obj = marker.scene.clone();
  obj.rotation = /* compute based on item */;
  return obj;
})

@danman335
Copy link
Author

Thanks thats exactly what I was trying to do amazing @vasturiano!

Last question (promise) as each object is a child of a group I cannot get them to lookAt the centre of the globe. Setting lookAt to 0, 0, 0 for each child just looks at the origin of the group that its within. The origin of the globe is 0, 0, 0 so thats why it isn't working, can we move the meshes out of the groups into the scene to do this or would that not work? I'm trying to get the objects to stand perpendicular to the surface of the sphere similar to how the columns do in the points layer.

@vasturiano
Copy link
Owner

@danman335 that's more of a question on the scope of ThreeJS itself, but I'm guessing you need to the rotation of the object in the world context, not local.

Perhaps you can get the current object rotation in world units and propagate that to your own, via getWorldQuaternion.
Actually lookAt should already be doing that in world context, hmmm.

Maybe you need to convert the globe center to local coordinates before using it, like:

const globeCenter = myGlobe.scene().localToWorld(new THREE.Vector3(0, 0, 0));
...
obj.lookAt(globeCenter);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants