Using Three.js to move the camera to a specific point on a sphere's surface and adjusting the camera's orientation to align with the surface

Within my project, I have integrated https://github.com/vasturiano/react-globe.gl to showcase a visually appealing 3D globe. The current configuration of the globe is as follows:

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

The camera operates with OrbitControls and its target point is set at:

OrbitControls.target = (0, 0, 0)

This positioning ensures that by default, the sphere remains centered within the canvas. Additionally, there are markers strategically positioned on the globe's surface.

Objective

The desired behavior involves adjusting the camera position dynamically when a user clicks on a marker. Instead of focusing on the center of the globe, the camera should move closer to the surface, aligning itself with the marker's position. This action would result in only a portion of the globe being visible at the lower section of the canvas. I discovered a functional demo illustrating this concept here: (try clicking on a green marker). Could someone provide guidance on how to achieve this effect?

Current Approach

The current method involves gradually updating the OrbitControl target to match the marker's 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()

Similarly, the camera is also moved gradually to a specific position:

// 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()

To further enhance the visual effect, the globe is shifted slightly downwards on the canvas:

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()

Issue

The manual process of identifying positions for each marker is not practical. Moreover, the visibility of the globe varies significantly depending on the marker location, whereas consistency is maintained on the website reference provided earlier. Is there a more efficient approach to achieving this animation? Any guidance would be greatly appreciated.


Edit (jscastro's answer)

Thank you for the prompt response — it seems we are making progress! However, I am encountering difficulties in generating the appropriate curve. Currently, the curve is created based on camera.position (starting point) and marker.position (ending point):

// 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 setup results in a straight line. When the camera reaches the end of the curve, the globe's positioning within the canvas is incorrect, as shown in this screenshot for a specific marker:

https://i.sstatic.net/n0wuL.jpg

However, I aim to represent the globe consistently for all markers, similar to the display illustrated in this screenshot:

https://i.sstatic.net/geQ0C.jpg

Is there a method to generate dynamic curves so that upon reaching the end, the globe appears as intended in the second screenshot (regardless of the marker's position)? Your insights on this matter would be greatly valued. Thank you.

Answer №1

If you're looking to achieve a similar effect, I suggest taking a look at this particular example where they use the "animationView" option. It seems to fit your requirements perfectly. You can experiment with creating a ring or curve around your sphere using the provided code.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Combining jQuery's UI widget with my topNav disrupts horizontal alignment

Within my web application, I have integrated jQuery and jQuery UI (specifically versions 1.10.2 and 1.10.4). To style the components, I utilize the CSS found in /js/jquery-ui-1.10.4/css/ui-lightness/jquery-ui-1.10.4.min.css from the jQuery site. Prior to i ...

Using Javascript to dynamically change the data type to align with a specific keyword

I need to create an input box for a promo code that triggers the appearance of additional radio input options when a specific promo code is entered. For example, if the user enters "springchicken" in the input box, I want a set of radio inputs to show up ...

Is there a way to invert my array by utilizing just a single array instead of resorting to using two arrays

While I am still learning JavaScript and programming as a whole, I decided to test out some code for reversing an array using push and pop methods. Even though I am aware that I could easily utilize Array.prototype.reverse(), I wanted to have some fun expe ...

Error message: The md-autocomplete function is throwing a TypeError because it cannot read the property 'then' of an undefined object

I am encountering an issue with the md-autocomplete component from angular material. Here is my code snippet: <md-autocomplete required md-search-text="searchTxt" md-selected-item-change="setModelValue(item.name)&q ...

Struggling for hours with a nested React component that refuses to render

I'm new to the world of react and javascript development and currently encountering an issue with nesting a component. While the Home component is displaying correctly, the testComp is not appearing as expected. I'm feeling quite stuck and would ...

Is it possible to enable auto play on HTML5 Video for iPad similar to BBC iPlayer?

Can HTML5 Videos automatically play on iPads? I used to believe that it wasn't possible because of iOS restrictions, but after trying BBC iPlayer on my iPad, I noticed that the videos did autoplay upon loading. Could this indicate that it is indeed ...

Error code 10062 occurred on the Discord Bot while verifying the channel name during the processing of a user-sent slash command

I've been developing a Discord bot using JavaScript for a study server with my friends. Currently, I'm working on a feature that allows users to add phone numbers but only in specific channels. Everything was functioning properly until I implemen ...

What is the best way to transmit information using the POST method in JavaScript?

When using javascript, the typical way to redirect a page with a parameter is the following: window.location = "add-new-cos.jsp?id="+id; However, the id value is sent to the next page using the GET method. I am interested in sending it using the POST met ...

Uncovering the secrets: accessing hidden folder files in react-native-fs

I am encountering a problem when trying to access files from a hidden folder /WhatsApp/Media/.Statuses in react-native-fs. Despite granting the READ_EXTERNAL_STORAGE permission on Android, I only receive an empty array when attempting to access it using th ...

A guide on updating div IDs using jQuery sortable when an element is moved by the user

My goal is to use jQuery sortable to allow users to rearrange elements on a page by dragging and dropping them. Each div element has a unique ID, and when the user swaps elements, I want to update the IDs accordingly and alert the new order so it can be sa ...

Create a dynamic animation effect for the placeholder in an input field that triggers when the user starts typing

Have you ever come across interactive demos like this one? I've noticed that most examples involve creating a new element. parent().append("<span>" + $input.attr('placeholder') + "</span>"); Is there a way to make the placehol ...

Can Javascript work together with HTML?

Can 'this' be utilized in this specific scenario? var td = document.getElementsByTagName("td"); for (var i = 0; i<td.length; i++){ td[i].id = 'abc' + i; }; for (var i = 0; i<td.length; i++){ td[i].onclick = c ...

Improving Vue.js CLI Performance and Enhancing Webpack Build Optimization

For a tutorial project that I've created, the code consists of no more than 100-200 lines. However, when I use webpack to build this project, the resulting bundle.js file is flagged as being larger than the recommended size. It's concerning to me ...

Javascript - The preflight request response fails the access control check

I followed the instructions in the documentation to create a checkout session for stripe, but I encountered the following error: Access to fetch at 'https://subdomain' from origin 'https://main-domain' has been blocked by CORS policy: ...

Connecting MySql database with Firefox Addon

Is there a way to connect a MySql database that is hosted on an online hosting service using JavaScript and WebExtensions APIs? If so, how can I go about programming this? Any advice or suggestions would be greatly appreciated! Thank you in advance for yo ...

In Vue JS, ensure that each item is loaded only after the previous item has finished loading

Is there a way to optimize the loading of around 1000 static images, .gifs, and videos for an online slideshow presentation? Currently, all items are loading simultaneously causing viewers to wait to see the first item. How can each item be loaded after th ...

Create a distinct variable name for opening a modal within an *ngFor loop

I need help creating a unique variable called share within the *ngFor loop so that I can open a single modal. <li *ngFor="let gallery of galleries; let i = index"> <div class="gallery card" > <div class="sh ...

Upon successfully authenticating with Firebase, the data refuses to appear in the console

I'm currently working on a React app that utilizes Firebase for authentication. Here is the code snippet: function signIn(){ firebase.auth().signInWithPopup(provider).then(function(result)=>{ console.log(result.user); setUserInfo(result.u ...

Tips on creating a required field for file type in AngularJS

Greetings! Currently, I am in the process of developing a web application using AngularJS. One of the modules I am working on involves file uploads, which are being handled dynamically. The list of files to be uploaded is retrieved through an API call, and ...

JS/Electron Insert items individually

Apologies if my explanation is unclear. I have a function (shown below) that parses a JSON file and creates a grid of 1550 items. How can I add them one by one instead of all at once? Loading all 1500 items together is taking too long. function addItem () ...