How to manipulate Three.js camera to follow an object closely

Trying to figure out how to make a camera follow an object controlled by physics within a Three.js scene.

I'm currently working on a Three.js scene where the W,A,S,D keys move a sphere along a plane. However, I can't seem to get the camera to follow behind the sphere as it moves.

In the code example below, the camera follows the sphere perfectly when only the W key is pressed. But when A or D are pressed, causing the sphere to turn, the camera loses track of the sphere. My goal is to have the camera always positioned just behind the sphere at a constant distance, even when the sphere turns. As the user continues pressing W, the sphere should keep rolling forward relative to the camera.

In a previous scene demo, I achieved this behavior by creating the sphere, adding it to a group, and using the following code snippet each frame:

var relativeCameraOffset = new THREE.Vector3(0,50,200);
var cameraOffset = relativeCameraOffset.applyMatrix4(sphereGroup.matrixWorld);
camera.position.x = cameraOffset.x;
camera.position.y = cameraOffset.y;
camera.position.z = cameraOffset.z;
camera.lookAt(sphereGroup.position);

The key in the previous demo was to rotate the sphere while keeping the sphereGroup unrotated, allowing me to calculate the camera offset based on the un-rotated sphereGroup.

In the current demo, the sphere's position is influenced by the Cannon.js physics library, which handles translations and rotations based on applied forces. Any ideas on how to make the camera follow the sphere in this setup?

// Code snippets will go here
// CSS snippets will go here
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.js'></script>

Answers to comment questions

@jparimaa Is there a way to implement controls where W adds forward momentum, S adds backward momentum, and A and D control camera rotation around the ball?

@HariV Are there methods to integrate camera logic with physics in Three.js for this scenario?

Answer №1

My suggestion for user-friendly controls is to have the W key consistently move the ball "forward" in relation to the camera.

To achieve this, one approach could be to determine the direction between the ball and the camera, then apply velocity in that direction. This method would allow you to adjust the camera angle without affecting the ball's momentum when moving it forward. Changing the direction would occur only after pressing W/S following a camera rotation. While I'm not certain if this aligns with your objectives, perhaps it can provide some inspiration.

I experimented with the code below (rotation serves as a global variable set to 0):

function moveSphere() {
    var delta = clock.getDelta(); // seconds
    var moveDistance = 500 * delta; // n pixels per second
    var dir = new THREE.Vector3(sphereBody.position.x, sphereBody.position.y, sphereBody.position.z);
    dir.sub(camera.position).normalize(); // directional vector between camera and ball
    if (pressed['W'] || pressed['ARROWUP']) {
        sphereBody.velocity.x += moveDistance * dir.x;
        sphereBody.velocity.z += moveDistance * dir.z;
    }
    if (pressed['S'] || pressed['ARROWDOWN']) {
        sphereBody.velocity.x -= moveDistance * dir.x;
        sphereBody.velocity.z -= moveDistance * dir.z;
    }
}

function moveCamera() {
    var delta = clock.getDelta();
    var sensitivity = 150;
    var rotateAngle = Math.PI / 2 * delta * sensitivity;
    if (pressed['A'] || pressed['ARROWLEFT']) {
        rotation -= rotateAngle;
    }
    if (pressed['D'] || pressed['ARROWRIGHT']) {
        rotation += rotateAngle;
    }
    var rotZ = Math.cos(rotation)
    var rotX = Math.sin(rotation)
    var distance = 200;
    camera.position.x = sphereBody.position.x - (distance * rotX);
    camera.position.y = sphereBody.position.y + 50;
    camera.position.z = sphereBody.position.z - (distance * rotZ);
    camera.lookAt(sphereGroup.position);
}

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

Creating a typewriter effect with Vue Js

Hey there, I'm having some trouble with the code below while working on my Vue project. It seems to be functioning correctly, but for some reason it's not working in my Vue environment. const text = document.getElementById("text"); const phrase ...

Guide on sending a message to a specific channel using Discord.js version 13 with TypeScript

After recently diving into TypeScript and seeing that Discord.js has made the move to v13, I have encountered an issue with sending messages to a specific channel using a Channel ID. Below is the code snippet I am currently using: // Define Channel ID cons ...

I don't understand why I keep receiving the error message "Cannot read property 0 of undefined" even though the object clearly exists and I am attempting to access it within the correct scope

Here is a function example: (function iterate(index) { var obj = { 0:{name:"John Doe"}, 1:{age: 30}, 2:{years: 5} }; setTimeout(function() { //code ... }, (obj[0][years]*1000) ); )(0); Encountering an error in the second last line myscript. ...

changing the css transformation into zoom and positioning

My goal is to incorporate pinch zoom and panning using hardware-accelerated CSS properties like transform: translate3d() scale3d(). After completing the gesture, I reset the transform and switch to CSS zoom along with absolute positioning. This method ensu ...

Do not execute the script if the window's width is below a certain threshold

I have a unique website layout that adjusts to different screen sizes, and I've incorporated some jQuery functionality. Here is a snippet of the code: <script> $(document).ready(function(){ $("#D1000C36LPB3").click(function(){$("#D ...

Encasing the window global variable within an AngularJS framework

Currently, I am encapsulating a global variable within a factory in order to make it injectable. Here is an example of how it's done: angular.module('Analytics').factory('woopra', [ '$window', function ($window) ...

Looking for assistance with creating a D3 bar chart that involves selecting a specific year and crime category? Let me help

I am still learning D3 and I'm facing a challenge while trying to create a bar chart. My idea is to first select the YEAR radio button, then choose the CRIMEHEAD option, and finally the bar chart should be displayed. Here's my thought process: I ...

What sets apart .create from .save in mongoose?

A while ago, I completed a bootcamp course on Express and Mongoose on Udemy. In the course, we learned how to add new fields to data by writing code like this: var playground = require("../models/playground.js"); route.post("/", middleware.isLoggedIn,fun ...

Unable to retrieve file on Linux system through PHP

<?php // Ensuring that an ID is provided include('include/function.php'); if(isset($_GET['id'])) { // Retrieving the ID $id = intval($_GET['id']); // Validating the ID if($id <= 0) { die('Th ...

How can I modify the ngx-datatable pager component to display text instead of icons and include a totalVisible property?

I am currently customizing the datatable-pager in ngx-dataTable and have been successful in adding footers and pagers. However, I am facing two issues that need resolution: How can I display text instead of icons for the prev/Next/First and Last buttons? ...

What is the process for a developer to utilize Ajax in order to send and receive numerous requests across multiple div elements simultaneously?

I have created a page where I implement an Ajax post request to a PHP file and receive a response as shown below. <input type="hidden" id="qid" value ="2" /> <div id="scores"></div> <sc ...

When resetting the function, make sure to move the class to the closest sibling element

I am currently utilizing a slider that employs the .prev and .next jQuery functions to toggle the active class, indicating which slide is being displayed. Here is the code responsible for this functionality. It identifies the current sibling with the acti ...

Encountered an issue with parsing the source map while working on my personal computer

WARNING: failed to parse source map from specified file location due to a missing file or directory. I encountered this error message while trying to launch my React application, and I'm unsure of the cause. ...

The buttons in the Bootstrap modal are unresponsive

I'm attempting to create a modal navigation bar for mobile view but encountering an issue. When I click on the icon bar or menu bar in mobile view, none of the buttons inside the modal are responding. I'm quite stuck on this and would appreciate ...

Discovering the regex pattern to locate any existing code and substitute it with nothing

How do I remove possible code from strings and replace it with blank? For example: Input = 9eac83a4-80f4-4a2e-b0fe-7a4a9329ff62Manual Handling.pdf Desired Output = Manual Handling.pdf Input = 14a19827-8f33-4666-a3cc-ea257875f1f7Fire&Evac.pdf Desir ...

Is there a way to execute the identical promise once more based on the outcome of the previous execution?

My dilemma involves a block of code enclosed within a promise. This particular code is responsible for modifying records in a remote database and reporting the number of records edited. In case the count of edited records exceeds 0 (indicating work done), ...

Having trouble getting an element by id in Vue/Nuxt on initial load? You're not alone. It seems like the element

I am currently utilizing VueScroll as a container for a carousel. However, I have observed that when a user hovers their mouse over the VueScroll element and scrolls using the wheel, it zooms in/out on the elements inside VueScroll. I am looking to target ...

Navigate to a specific section of the page by scrolling when linked to an id

Just getting started with web development and using Bootstrap to build this site. I'm working on a single-page site where the top navbar directs users to specific IDs. The issue I'm facing is that I want the page to scroll to the ID when clicked ...

Incorporating data retrieved through AJAX requests into a Python function

The Flask application described below continuously makes Ajax calls to a backend index function that queries a database and injects the results into a template. However, the injected data is not being refreshed after the Ajax calls are completed, leading ...

The method to retrieve post data from Angular / Ionic to PHP

I'm having some issues accessing the JSON data that I'm posting from Angular / Ionic to PHP. Below is the PHP code that I'm using: $jsonData = file_get_contents('php://input'); $data = json_decode($jsonData, true); When I saved ...