Rotating a camera in ThreeJS for a quick orbit

I am using an orbital camera that orbits around a globe with markers for users to interact with. When a user clicks on a marker, the camera moves to that specific point.

To animate this movement, I am utilizing TweenMax as shown below:

 TweenMax.to(currentPos, 3, {
     theta:targetPos.theta, 
     phi:targetPos.phi, 
     radius:targetPos.radius, 
     ease:Circ.easeIn, 
     onComplete:btnZoomComplete,
     onUpdateParams:["{self}"], 
     onComplete:SataliteTweenComplete, 
     onUpdate: function(tween) {
       controls.setThetaPhi(tween.target.theta, tween.target.phi, tween.target.radius);
     }
});

While this method works well, it does not always take the shortest route to reach the destination, often resulting in the camera going 'round the back' of the globe.

I have encountered difficulties with ThreeJS's angle measurement system which jumps from 0 to 1.57 (equivalent to 90 degrees), then to 3.14 (180 degrees), and abruptly shifts to negative values starting at -3.14 and so on. This has made it challenging for me to calculate the optimal path.

For instance, if the camera is at 2.6 and needs to move across to -2.61, the animation currently goes counter-clockwise (from 2.6 to -2.16) instead of clockwise (from 2.6 to 3.14, -3.14, and finally -2.61).

I would greatly appreciate any guidance on how to determine the correct direction to traverse and seamlessly animate from one point to another.

The two main challenges I face are figuring out the direction of rotation and smoothly transitioning from one angle to another, such as moving from 2.6 to 3.14, transitioning to -3.14, and arriving at -2.61

Answer №1

That "unusual unit-system" mentioned is simply measured in radians, a common practice to represent theta/phi values within a range of -180° to 180° and -90° to 90° (similar to latitude/longitude). The conversion between radians and degrees is straightforward:

angleDegrees = radians / Math.PI * 180;
radians = angleDegrees / 180 * Math.PI;

When using the tweening-library for interpolation, it operates on numerical values without contextual understanding. The challenge arises when determining the shortest path for rotations. However, this can be addressed prior to initiating the tween.

For instance, let's consider animating from 2.6 to -2.6 (equivalent to 149° to -149°).

var from = 2.6, to = -2.6;

The direction and angular distance for the animation can be calculated as

var distance = to - from; 
// === -5.2

A negative value indicates counterclockwise rotation, with 5.2 (~298°) being the total distance covered by the camera. It's important to note that any angle plus or minus 360° (2 * Math.PI) will bring you back to the same position. Let's adjust for this scenario:

var distance = (to + 2 * Math.PI) - from; 
// === 1.083185307179586 (~62°)

Hence, rotating from 2.6 to -2.6 + 2 * Math.PI (i.e., from 149° to 211°) results in a clockwise animation along a shorter path.

To ensure all values remain within their defined ranges, slight modifications are made in the onUpdate-function for proper wrapping:

controls.setThetaPhi(
    tween.target.theta % Math.PI, 
    tween.target.phi % Math.PI, 
    tween.target.radius);

Prior to starting the animation, updating the currentPos value with accurate data is recommended.

The final step involves finding a solution for a generalized case to determine the appropriate rotation direction based on whether the distance exceeds 180°:

if (Math.abs(to - from) > Math.PI) {
  if (to > 0) { // subtract a full circle if 'to' is positive, add otherwise
    to = to - 2 * Math.PI;
  } else {
    to = to + 2 * Math.PI;
  }
}

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

Transform form data from square notation to dot notation using jQuery

During my ajax operations, I noticed that the data being sent is in JSON format. However, when checking Chrome tools -> network XHR, I observed that the form parameters are displayed within square brackets. Example: source[title]:xxxxxxxxxxxx source[th ...

Steps for adding multiple images to a page in a React application:1. Create a

Having trouble displaying images on a React page. I have a directory with 30 images that I want to display on the page (.jsx file). Instead of exporting each image individually, is there a faster way to accomplish this task? Any ideas or suggestions would ...

Animation spinning on a different axis

I'm experimenting with rotating objects on a different axis instead of the default one using animation. Currently, I have implemented it this way. You can interact with the L and Li buttons successfully. However, when you click on the R button, the a ...

Puppeteer: Locating elements using HTML attributes

I'm currently working on getting Puppeteer to locate an element on this webpage using its attribute data-form-field-value, which needs to match 244103310504090. Here is the HTML code for the button in question: <section class="fl-accordion-tab--c ...

Adding Numerous Elements to a Container

In my HTML code, there is a div element with the id of controls. I am attempting to add a div containing 2 input fields using this method: this.controls = controlBtns .append('div') .classed({'time-container': true}) .appe ...

Steps for appending a string to a variable

Currently working on creating a price configurator for a new lighting system within homes using Angular 7. Instead of using TypeScript and sass, I'm coding it in plain JavaScript. Page 1: The user will choose between a new building or an existing one ...

Instructions on how to modify a document's content by its unique identifier using Firebase Modular SDK (V9)

I am trying to figure out how to update an existing document for the same user ID in V9 Firebase whenever they log in, rather than creating a new one each time. Any suggestions on how to achieve this? Current Code setDoc( query(collectionRef), // ...

Can Mongoose handle document arrays editing and version control efficiently?

Currently working on a web application using Node.js and MongoDB/Mongoose, the main model in our project is Record which contains numerous subdocument arrays such as "Comment", "Bookings", and "Subscribers". However, when users click the delete button in ...

Retrieving data from a <div> element within an HTML string using jQuery and AJAX

Having trouble extracting a value from a div within an HTML string. Seeking assistance in identifying the issue. I've attempted various methods to retrieve the data, but none seem to work for me. It appears I may be overlooking something crucial. $( ...

Guidelines for creating an auto-scrolling React Native FlatList similar to a Marquee

I currently have a FlatList component set up in my project. <FlatList horizontal data={data} key={(item, index) => index.toString()} ListHeaderComponent={listHeader} renderItem={ // renderin ...

Is there a way to import a module generated by typescript using its name directly in JavaScript?

I am trying to bring a function from a typescript-generated module into the global namespace of JavaScript. The typescript module I have is called foo.ts: export const fooFn = (): string => { return "hello"; }; Below is the structure of my HTML file ...

What are effective methods for testing HTML5 websites?

I'm currently working on a project to create a dynamic website using HTML5. The first page will prompt the user for specific inputs, and the following page will adjust accordingly based on these inputs. My main concern now is how to effectively test ...

Using jQuery ajax in PHP, the ability to remove retrieved information from a different page is a

I'm currently working on a jQuery AJAX PHP application that allows for adding, deleting, and displaying records using switch case statements to streamline the code. Everything seems to be functioning correctly with inserting and displaying records, bu ...

Retrieving information from Firebase using React

Is there a way to retrieve data from Firestore? import firebase from 'firebase/compat/app'; import 'firebase/compat/auth'; import 'firebase/compat/firestore'; const firebaseConfig = { apiKey: "AIzaSyCNBAxjeKNoAPPjBV0 ...

Tips on downloading an image using the URL in nestjs

I'm trying to retrieve a link and save the associated image in the static folder, but I seem to be encountering some issues with my code. Here's what I have so far: @Injectable() export class FilesService { createFileFromUrl(url: string) { t ...

Several mistakes occurred involving auth0, react, apollo, babel, and webpack

I seem to be facing some challenges while trying to integrate auth0 into my project. Every time I fix one issue, another one pops up and it's always the same trio of errors: -require is not a function -window is not defined -missing class properties ...

Asynchronously retrieving results in MongoDB

My task involves fetching all users from the users collection. app.post('/login', function(req,res,next){ users = self._db.get('users', {}) }) Below is the function in my database class: this.get = function( col, opt ) { ...

Challenges faced when attempting to launch a React-powered application on Railway platform

When I transferred my fullstack app (React + Express) from Heroku, I encountered an issue. React apps need to be built to run and require necessary dependencies installed, but typically only raw source code is stored on Git. A typical structure for fullst ...

What steps can be taken to verify if the user has transmitted a JSON Web Token?

Recently started using Express and been struggling with this particular error for quite a while. const token=req.header("jwt") console.log(token) if(!token ){ return res.json('no jwt') console.log('nojw ...

Resolving Problems with setInterval in jQuery Ajax Calls on Chrome

Seeking assistance in returning the value of a specific URL periodically using jQuery and setInterval. Below is my current code snippet: $("form").submit(function() { setInterval(function(){ $('#upload_progress').load(&ap ...