roybro
roybro

Reputation: 21

Three.js: Move camera to a point on the surface of a sphere and make the camera look along the surface

In my project I use https://github.com/vasturiano/react-globe.gl to render a 3D globe. The globe is a sphere where:

radius   = 100
position = (0, 0, 0)

The camera uses OrbitControls with:

OrbitControls.target = (0, 0, 0)

This means that at default, the sphere is in the center of the canvas. There are markers present on the surface of the globe.

Goal

When the user clicks on a marker the camera should get closer to the surface of the globe, looking at the marker's position (instead of the center of the globe). This would make only a small bit of the globe visible at the bottom of the canvas. I found a working demo that exactly shows this concept here https://www.fonterra.com/nz/en/campaign/from-here-to-everywhere.html#/home (if you click on a green marker). Can someone please point me in a direction as in how I could achieve this?

Current implementation

Gradually set OrbitControl.target to marker.position

 new TWEEN.Tween({ x: controls.target.x, y: controls.target.y, z: controls.target.z })
  .to({ x: c1.x, y: c1.y, z: c1.z}, duration)
  .onUpdate(d => {
    controls.target.set(d.x, d.y, d.z)
  })
  .start()

Gradually move the camera to a specific position I found myself

// TODO: Find a way to calculate this position? 
new TWEEN.Tween({ x: camera.position.x, y: camera.position.y, z: camera.position.z })
  .to(pointIFoundMyself, duration)
  .onUpdate(d => {
    camera.position.set(d.x, d.y, d.z)
  })
  .start()

Move the globe a bit more to the bottom of the canvas (-y)

new TWEEN.Tween({ x: world.position.x, y: world.position.y, z: world.pos})
  .to({x: world.position.x, y: -25, z: world.position.z}, duration)
  .onUpdate(d => {
    world.position.set(d.x, d.y, d.z)
  })
  .start()

Problem

Finding a point for every marker on the map by myself is not really feasible. The portion of the globe that is visible also differs highly per marker (location), while it's very consistent on the website I linked above. I would like to know if there's a better way to achieve this animation. A push in the right direction would be highly appreciated.


Edit (jscastro's answer)

First off thanks for your quick reply -- it seems like we're getting closer! I have some trouble generating the correct curve though. Currently the curve is generated with camera.position (start) and marker.position (end), like so:

// converts (lat, lng) to world position
const coords = curr.getCoords(marker.node.location.lat, marker.node.location.lng, 0.20)

const curve = new THREE.CatmullRomCurve3( [
  new THREE.Vector3( camera.position.x, camera.position.y, camera.position.z ),
  new THREE.Vector3( coords.x, coords.y, coords.z ),
]);

This (obviously) generates a straight line. When the camera is at the end of the curve, the globe is incorrectly positioned in the canvas. Like this screenshot for a marker:

enter image description here

But I'd like the globe to be positioned like this for all markers:

enter image description here

Do you perhaps know how I can dynamically create such curves so that at the end of the curve, the globe displays in the same way as in the screenshot above (for any marker on the globe)? Thank you.

Upvotes: 2

Views: 1764

Answers (1)

jscastro
jscastro

Reputation: 3780

I’d recommend you to check this example selecting the option “animationView”, I think it’s exactly what you need.enter image description here You can test in that code just creating a ring or a curve based on those points around your sphere

Upvotes: 1

Related Questions