Enhancing a three.js project with point-and-click functionality while utilizing OrbitControls

I am currently experimenting with a point-and-click navigation feature in three.js for a project. The goal is to move the camera to the location where the user clicks on the screen using a raycaster along with a simple mechanic implemented with gsap:

const move_cam = () => {
    const new_pos = { ...marker.position };
    gsap.to(camera.position, {
      duration: 2,
      x: new_pos.x,
      z: new_pos.z,

      onComplete: () => {
      }
    });
  };

However, I encountered an issue when using OrbitControls alongside this mechanic, as the camera would always orient towards a specific target while moving:

The reason behind this behavior lies in how OrbitControls functions by assigning a fixed target for the camera.

Several strategies were attempted to address this challenge, including disabling and re-enabling OrbitControls during camera movement or preventing OrbitControls from affecting the camera's target. However, these solutions proved ineffective in maintaining the desired camera orientation throughout the animation.

As a final approach, I devised a method that involved storing the distance between the camera and its target in a variable named "offset", which was then used to set a new target at the end of the animation. This revised version of the move_cam() function aimed to resolve the issue:

const move_cam = () => {
    camera_is_moving = true;
    const offset = {
      x: controls.target.x - camera.position.x,
      y: controls.target.y - camera.position.y,
      z: controls.target.z - camera.position.z,
    };

    const new_pos = { ...marker.position };
    new_pos.y = CAMERA_HEIGHT;
    
    gsap.to(camera.position, {
      duration: 2,
      x: new_pos.x,
      y: new_pos.y,
      z: new_pos.z,

      onComplete: () => {
        controls.target.x = offset.x + camera.position.x;
        controls.target.z = offset.x + camera.position.z;

        offset.x = controls.target.x - camera.position.x;
        offset.y = controls.target.y - camera.position.y;
        offset.z = controls.target.z - camera.position.z;
        camera_is_moving = false;
      }

    });
  };

Despite implementing this solution, a slight twitch in the camera's movement was still observed at the end of the animation, indicating a discrepancy in setting the new target position. Further investigation is required to determine the root cause of this issue and ensure consistent camera rotation before and after the animation.

If anyone has insights or suggestions on how to improve this functionality, your assistance would be greatly appreciated. Feel free to explore the project on Github repo to gain a better understanding of the problem. The complete JavaScript file can be found here.

Thank you for your support and input in advance.

Answer №1

After some trial and error, I found a solution by incorporating separate animation for the camera target using gsap rather than directly setting its value in the onComplete() callback. As a result, the modified version of the move_cam() function now looks like this:

const move_cam = () => {
    camera_is_moving = true;
    controls.enabled = false;
    const offset = {
      x: controls.target.x - camera.position.x,
      y: controls.target.y - camera.position.y,
      z: controls.target.z - camera.position.z,
    };
    const new_pos = { ...marker.position };
    new_pos.y = camera.position.y;

    gsap.to(this.camera.position, {
      duration: this.camera_travel_duration,
      x: new_pos.x,
      y: new_pos.y,
      z: new_pos.z,

      onComplete: () => {
        offset.x = controls.target.x - camera.position.x;
        offset.y = controls.target.y - camera.position.y;
        offset.z = controls.target.z - camera.position.z;

        camera_is_moving = false;
        controls.enabled = true;
      },
    });
    gsap.to(controls.target, {
      duration: camera_travel_duration,
      x: offset.x + new_pos.x,
      z: offset.z + new_pos.z,
    });
  };

This revision completely resolved my issue, although I am still puzzled as to why the initial code failed to work.

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

Building a basic music player with the <audio> element and JavaScript / jQuery

I am new to Javascript and jQuery, and this is my first time posting a question here. I have been trying to create custom functions for the HTML5 audio tag by following tutorials online. Despite my efforts, I cannot seem to get it working. Although I can m ...

What could be the reason for my Express server returning a 404 error for all files other than index.html?

Currently, I am delving into Node.js with Express in order to set up a small server for educational purposes. Strangely, every request made to files linked within my index.html file, such as the .css, .js, and image files, results in a response code 404. ...

What is the best way to handle the resolution of multiple promises as they complete?

Suppose I have three different promises each taking a varying amount of time to resolve - 1000ms, 2000ms, and 3000ms respectively. How can I simultaneously start all the promises and handle them as they get resolved? For instance: let quickPromise = new ...

Error: Firebase encountered an issue (auth/invalid-api-key) while deploying on Netlify

I'm currently working on a Next.js application that utilizes Firebase Auth for client authentication and is hosted on Netlify. firebaseConfig.js import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth" ...

An error has occurred: Expected a string as the element type in React when attempting to update the state

I encountered an issue while trying to update the state after fetching data. Error: Element type is invalid - expected a string (for built-in components) or a class/function (for composite components), but received: undefined. This could be due to forgett ...

Utilizing loop variables in ng-class and ng-click directive

This piece of code generates a list consisting of seven thumbnails, with the currently active image designated by the active and thumb classes. <div ng-repeat="no in [1, 2, 3, 4, 5, 6, 7]"> <img ng-src="images/{{no}}t.jpg" class="thumb" ng ...

I'm encountering an issue in my server.js file where I am unable to read the property 'collection' as it is undefined

I have encountered an error in my code: /home/ubuntu/workspace/server.js:43 db.collection('quotes').find().toArray(function(err, results) { ^ TypeError: Cannot read property 'collection' of undefined at Object.<anonymous> ( ...

You can interact with our dropdown menu using the tab key, even when it is

We are looking to make our dropdown tabbable when expanded and non-tabbable when collapsed. We attempted using tabindex="-1" on the content inside the expandable div, but this resulted in it being non-tabbable even when expanded. Any suggestions on how t ...

I have a json file that I need to convert to a csv format

I am currently working with a json file, but I need to switch it out for a csv file. Do I have to use a specific library to accomplish this task, or can I simply modify the jQuery 'get' request from json to csv? I attempted the latter approach, b ...

Guide on adding pictures to an ExpressJS server

Working on this project has been quite a challenge for me as I delve deeper into web development. As a relatively new developer, creating a one-page application with image upload functionality has proven to be quite the task, especially considering this is ...

What are the steps to address the Invalid Hook Call issue while working with Material UI?

Having an issue with a MaterialUI Icon in my code as a newcomer to coding. Here is the snippet: import PersonIcon from '@mui/icons-material/Person'; function Header() { return ( <div> <PersonIcon /> <h2>Header file</h2 ...

Exploring Angular.js methods to capture values from check boxes and radio buttons simultaneously

Check out my demo at https://embed.plnkr.co/R4mdZr/ Just diving into the world of Angular, I'm looking to retrieve both true values from checkboxes and radio button selections. I have a condition where if the minimum value for ingredients is one, it ...

Header misalignment occurs when the user scrolls up too quickly causing it to display

One interesting feature on my website is that the header disappears as users scroll down the page, but reappears when they start scrolling back up, even if they are halfway down. However, if a user quickly scrolls up and down, there seems to be an issue wi ...

How to smoothly fade out content when hovering over a menu item in HTML<li> tags

Hi there, I have encountered a problem and could really use your assistance. I am attempting to create a menu that displays content when you hover over an li tag. The first content should always be visible when hovering over the first li option or if no l ...

Preventing navigation to non-existent routes in Vue by disabling the forward and backward buttons

Hello, I have developed an app that functions as a plugin within another application, requiring me to manually handle forward and backward navigation. My Question: How can I disable the forward and backward buttons using the .disabled class when there a ...

Updating a component with React JS setState() must be done on a mounted or mounting component

I encountered an issue where I am getting the error message setState(...): Can only update a mounted or mounting component., but I am struggling to find a solution. import React, { Component } from 'react'; import Loading1 from '../images/ ...

Develop a Vue.js component embedded within another component to manipulate data stored in the parent

After reviewing a few answers that partially address my question, I realized there is more to explain. In our Laravel project website layout, we utilize a global #app div. This means all pages share the same main Vue instance, prompting me to segregate ke ...

Exploring the Dev Tools Console feature in Excel for Windows

I have developed an Excel add-in using AngularJS. I utilize <div ng-show="isLoggedIn">...</div> and <div ng-show="!isLoggedIn">...</div> to manage different content based on the value of $scope.isLoggedIn. While it functions well i ...

Balancing asynchronous tasks - masteringlearnode - program that initially succeeded but eventually faltered

node version: v4.4.3 npm version: 3.8.9 Error output Your entered data does not match the expected values. ──────────────────────────────────────────────── ...

unable to transfer Vuex store information to the graph

Currently, I am facing an issue with passing my vuex store data into my apexcharts graph. Despite my efforts, it seems like the data is not being displayed correctly. Can anyone provide guidance on what I might be doing wrong? My main objective is to updat ...