Is it possible to use Three.js camera lookAt function without any rolling?

In my game, there is a square level where a ball can roll around. I am trying to adjust the camera position so that it follows the ball but always looks at 0, 0, 0. Moving the camera x and z towards the ball's position gets me close, but as seen in the animation below (apologies for any motion sickness):

https://i.sstatic.net/6hdEQ.gif

When I use

camera.lookAt( new THREE.Vector3( 0, 0, 0 ) )
, the camera seems to rotate around its y axis, giving the illusion of the level rotating.

My goal is to move the camera to focus on 0, 0, 0 without the camera roll effect. I want the bottom edge of the level to remain parallel with the bottom edge of the screen as the camera moves. Is this achievable? I find it challenging to visualize.

I have created a CodePen demo to demonstrate the issue. I have extracted the lookAt function into a separate function so that I can modify the quaternion after it is returned:

function lookAtVector( sourcePoint, destPoint ) {

Basically, I manually rotate and position the camera as follows:

var cameraPosition = new THREE.Vector3(
    radius * Math.sin( Date.now() * speed ),
    radius * Math.cos( Date.now() * speed ),
    5
);

var lookAtQuaternion = lookAtVector(
    cameraPosition,
    new THREE.Vector3( 0, 0 ,0 )
);
camera.position.copy( cameraPosition );
camera.quaternion.copy( lookAtQuaternion );

How can I adjust the camera quaternion to eliminate this rolling effect while still looking at 0, 0, 0? I have attempted:

  • I have tried setting the x, y, z, and w fields of the quaternion to different values to prevent rotation, but the outcome is unexpected and I haven't found a combination that works.

  • I have also tried setting the camera up vector manually (

    camera.up = new THREE.Vector3(0,0,1);
    ) as suggested in this question, but results remain the same.

Edit: Essentially, I aim to remove the camera roll similar to traditional 3D software cameras and Three.js OrbitControls. The perspective from the bottom left and bottom right edges should resemble:

https://i.sstatic.net/NVJj3.png https://i.sstatic.net/CLRr4.png

Observe how the camera remains unrolled in these images.

Answer №1

The issue was resolved by adjusting the up vector in the code. Although the code snippet provided in the CodePen did not match my local game's axis system, I found that by replacing THREE.Object3D.DefaultUp with new THREE.Vector3( 0, 0, -1 ), I was able to achieve the desired outcome:

https://i.sstatic.net/VYYAt.gif

Here is the revised lookAt function with the corrected up vector:

function lookAtVector( sourcePoint, destPoint ) {

    return new THREE.Quaternion().setFromRotationMatrix(
        new THREE.Matrix4()
            .lookAt( sourcePoint, destPoint, new THREE.Vector3( 0, 0, -1 ) )
    );

}

Answer №2

To achieve the desired effect of moving the camera to 0,0,0 without rotation, you should only adjust its position (panning) and not its rotation. Keep the original Y and Z values for the camera position while copying the X value from the ball (assuming X axis is oriented left-right).

Here's a diagram to illustrate:

|   |
|   |
|O  |
+---+
  C

|   |
|   |
| O |
+---+
  C

|   |
|   |
|  O|
+---+
  C

O - ball
C - camera

The goal is to move the camera to look at 0,0,0 without any rotation.

To accomplish this, the camera can only move along its direction axis (Y).

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

Various <a> elements adjust the HTML code based on the selected option

I am working with the following code snippet: <!-- LANGUAGE --> <div class="languages_box"> <span class="red">Languages:</span> <a href="#" class="selected"><img src="../images/au.gif" alt="" title="" border="0" he ...

Looking to migrate my current firebase/react project to typescript. Any tips on how to batch.update?

Having difficulty resolving a typescript error related to batch.update in my code. const batch = db.batch(); const listingDoc = await db.collection("listings").doc(listingID).get(); const listingData = listingDoc.data( ...

Personalize the start and end dates of Fullcalendar

While working with fullcalendar, I have a unique requirement. I want my days to start at 5:00 and end at 5:00 the next day. Is it feasible to achieve this customization? ...

Steps to transform identical or duplicate "identifiers" containing distinct values within a construct into a structured array

I am facing a challenge with objects that have similar ids. [{ "_id": "603", "name": 'innova', "type": 'suv', "brand": 'toyota' }, { "_id": "902", "name": 'i20', "type": 'hashback', "brand": 'hyundai& ...

AppleScript: Check if the value of document.getElementById is empty, then fill in the value

Hello everyone, it's my first time asking a question here. I have an AppleScript that takes values from a Numbers document and fills them into different fields of a webform using document.getElementById. Everything is working perfectly so far, but now ...

Steps for achieving a seamless delay fade-in effect

Can anyone provide a solution to my issue? I'm a CSS beginner and need some help. My landing page has a background Youtube video with buttons that appear after 8 seconds. I want these buttons to smoothly fade in, but I can't figure out how to do ...

What could be causing the failure of loading CSS images or JS in my Laravel project?

This is a continuation of my previous question where I managed to get the site up and running. Initially, all files including css, js, and images were loading properly. However, now I am encountering issues as the files are not loading and the console disp ...

Utilizing Javascript or XUL windows without the use of iframes offer

I'm in the process of creating a multitab website for my bookmarks, but I've run into some issues. Here is the JavaScript version of what I'm trying to achieve: Unfortunately, there are obstacles with this method. The websites in the tabs ...

history.push() function is ineffective within a JavaScript file that does not contain a class

I've been delving into React and encountering an issue with the history.push("/dashboard") method, it's not functioning as expected. import axios from "axios"; import { GET_ERRORS, GET_PROJECT, GET_PROJECTS } from "./types"; export const createP ...

Calculate the average color of the outer pixels in an image

I am looking to dynamically set the background color of a div using the average color of the outer pixels in an image. This way, I can avoid manually setting the background color for each image. For example, if the image is 100px x 100px, I would check th ...

Creating intricate mazes using canvas drawing techniques

I recently developed a maze generator as a personal project utilizing a graph. While the generation logic works perfectly, I am facing challenges when it comes to rendering the maze. In my approach, each cell is represented by an array of 4 edges where the ...

I have successfully implemented ngCordova local notifications, but now I am looking for a way to make it trigger for each individual

Is there a way to trigger a notification on every logged-in user's mobile device when a value is changed and saved in Firebase? Currently, I am able to send a local notification using ngCordova when a user enters text in an ionicPopup with textarea. H ...

`Getting the full URL using a route name in Angular 2 - a step-by-step guide`

Within my Angular 2 (final) project, there is a recurring need to generate full absolute URLs based on route names (such as '/products'). This requirement arises for tasks like providing permalinks to specific pages or opening a page in a new tab ...

Removing the animation from a Material-UI Select component in React

Currently, I am utilizing the React Material UI's Select Component and I am looking to either remove or quicken the animation that occurs when opening the menu. I attempted the following approach: <Select ... TransitionComponent={({child ...

Why is it that $_GET consistently returns null despite successfully transmitting data via AJAX?

I'm currently developing a PHP script that dynamically generates tables in MySQL based on user input for the number of rows and columns. The data is being sent to the server using AJAX, but even though the transmission is successful, the server is rec ...

Modifying search criteria using JavaScript

Yesterday, I posted a topic on Stack Overflow about how to change the search value in Wordpress using a drop-down selector. Initially, I implemented it with the help of Fredrik, but later I changed my approach. Instead of having a select input, I decided t ...

Guide to accessing JSON APIs by utilizing a link within another API that contains JSON data linking to yet another JSON file

Searching for a Solution to Fetch Data from a Specific URL and Display it on a New Screen I have successfully called the API using the following link: - Completed After receiving JSON data, I was able to populate my DataTable. - Completed Upon clicking a ...

Show an alternative option in the dropdown menu

Currently working with the Select component from Material UI, and here's what I'm trying to achieve:https://codesandbox.io/s/divine-water-zh16n?file=/src/App.js Situation: With an account object like {id:1, name:'name'}, I want to sel ...

When the Json payload is lengthy, an Ajax request to an ASP.NET MVC Controller results in a 404 error

I am facing an issue with my ajax call that involves passing a json string to a controller action. When the content portion of the json is too long, or when the json string in general exceeds a certain length, the server returns a 404 error. However, if I ...

Converting JSON data from ASP.NET MVC to a Canvas.js chart

Despite my efforts to find a solution by looking through similar posts, I am unable to resolve the issue. Within my asp.net MVC controller, I have a method called public object OfferChart() List<Det> obj = new List<Det>(); foreach ...