spinning camera around a globe with javascript and three.js

In my project, I am working on enabling a player to navigate in a first-person view on a planet using three.js and JavaScript. There are two key aspects I am focusing on:

a) Implementing player movement around the planet, which involves two types of movement: rotation around the player's axis (using left-right or A/D buttons) and forward/backward movement (using W/S buttons). I was able to achieve this with the help of resources like this thread .

b) Attaching a camera to the player that rotates horizontally (perpendicular to the player's plane) as the player rotates around themselves (using A/D buttons), and the camera should be able to move from 0 (looking at the ground) to 180 degrees (looking upwards) using the Arrow Up/Arrow Down buttons (potentially with mouse interaction in the future).

While I have been successful with a), I am facing a challenge with b) where the camera rotation initially works but jumps to an incorrect position as the player moves. To help troubleshoot the issue, I have created an ArrowHelper object to represent the camera.

Here is the HTML code snippet:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">

        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <meta http-equiv="Cache-Control" content="no-cache"/>
        <meta http-equiv="Expires" content="-1"/>
        <meta http-equiv="Pragma" content="no-cache"/>
        <title>Planet</title>
        <link href="planet.css" rel="stylesheet" type="text/css"/>
        <script src="../three.js/build/three.js"></script>
        <script src="../three.js/examples/js/libs/stats.min.js"></script>
        <script src="planet.js"></script>
    </head>
    <body>
        <div id="divScreen">
        </div>
    </body>
</html>

And here is a snippet of the JavaScript code:


// JavaScript code snippet
// ...

I have attempted different rotations with quaternions, but none of them have provided the desired outcome. You can refer to the commented section in the code for my various attempts at solving the issue. Any assistance in resolving this problem would be greatly appreciated.

For a detailed example and to interact with the code, you can access the JSFiddle link: https://jsfiddle.net/z18ctvme/3/

Thank you in advance for your help.

Answer №1

Your question holds the key to the solution:

Consider attaching a camera to the player [...]

To simplify things, link arrowHelper to g_Game.cubePlayer. This implies that arrowHelper should be a child of g_Game.cubePlayer rather than the default THREE.Scene():

arrowHelper = new THREE.ArrowHelper( dir, new THREE.Vector3( 0, 0, 0 ), length, color );
g_Game.cubePlayer.add(arrowHelper);

This setup ensures that arrowHelper always maintains the same relative position to the g_Game.cubePlayer. Specifically, the relative position is indicated as THREE.Vector3( 0, 0, 0 ).

The arrowHelper.quaternion exclusively encapsulates the relative orientation of arrowHelper.
It's essential to update the arrowHelper.quaternion when dealing with this.keyarrowup or this.keyarrowdown:

this.update = function(seconds) {
    var rlud = false;

    if (this.keyup) {
        g_Game.cubePlayer.quaternion.multiply(this.QuatKeyU);
        g_Game.cameraPerspective.quaternion.multiply(this.QuatKeyU);
        rlud = true;
    } else if (this.keydown) {
        g_Game.cubePlayer.quaternion.multiply(this.QuatKeyD);
        g_Game.cameraPerspective.quaternion.multiply(this.QuatKeyD);
        rlud = true;
    };
    if (this.keyleft) {
        g_Game.cubePlayer.quaternion.multiply(this.QuatKeyL);
        g_Game.cameraPerspective.quaternion.multiply(this.QuatKeyL);
        rlud = true;
    } else if (this.keyright) {
        g_Game.cubePlayer.quaternion.multiply(this.QuatKeyR);
        g_Game.cameraPerspective.quaternion.multiply(this.QuatKeyR);
        rlud = true;
    };

    if (rlud == true) {
        qx = g_Game.cubePlayer.quaternion.x;
        qy = g_Game.cubePlayer.quaternion.y;
        qz = g_Game.cubePlayer.quaternion.z;
        qw = g_Game.cubePlayer.quaternion.w;
        g_Game.cubePlayer.position.x = 2 * (qy * qw + qz * qx) * 105;
        g_Game.cubePlayer.position.y = 2 * (qz * qy - qw * qx) * 105;
        g_Game.cubePlayer.position.z = ((qz * qz + qw * qw) - (qx * qx + qy * qy)) * 105;

        qx = g_Game.cameraPerspective.quaternion.x;
        qy = g_Game.cameraPerspective.quaternion.y;
        qz = g_Game.cameraPerspective.quaternion.z;
        qw = g_Game.cameraPerspective.quaternion.w;
        g_Game.cameraPerspective.position.x = 2 * (qy * qw + qz * qx) * g_Game.cameraDistance;
        g_Game.cameraPerspective.position.y = 2 * (qz * qy - qw * qx) * g_Game.cameraDistance;
        g_Game.cameraPerspective.position.z = ((qz * qz + qw * qw) - (qx * qx + qy * qy)) * g_Game.cameraDistance;
    }

    if (this.keyarrowup) {
        var q = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), -(this.ANGULAR_SPEED_MOVEMENT*Math.PI*10) / 180);
        arrowHelper.quaternion.multiply(q);
    }
    if (this.keyarrowdown) {
        var q = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), (this.ANGULAR_SPEED_MOVEMENT*Math.PI*10) / 180);
        arrowHelper.quaternion.multiply(q);
    }
}

Check out the example where the modifications have been implemented into your original code:

var g_Game;
var g_Player;

window.onload = function () {
initGame();
}

function initGame() {
...
#divScreen {
...
<script src="https://threejs.org/build/three.min.js"></script>
<div id="divScreen"></div>

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

In React, components will consistently render the initial code

I have a chat application that requires authentication and uses cookies. Here's what I've been attempting: class AppHeader extends React.Component { constructor(props) { super(props) } render() { if (cookies.get(' ...

Retrieve the DOM variable before it undergoes changes upon clicking the redirect button

I have been struggling for a long time to figure out how to maintain variables between page refreshes and different pages within a single browser session opened using Selenium in Python. Unfortunately, I have tried storing variables in localStorage, sessio ...

At times, the Kendo UI Tooltip may linger on screen longer than expected, failing to disappear as

I've been experimenting with this issue for quite some time now, but I'm stumped. Whenever I quickly move my mouse cursor over a series of links, occasionally a tooltip will linger on the screen even after the cursor has moved away from the link. ...

JavaScript - Retrieve all properties and methods of an object

Can an object created through a constructor function have its keys listed using the Object.keys() method? Let's consider an example with the following code: function Foo () {} Foo.prototype.bar = 'bar'; Foo.prototype.baz = 'baz'; ...

Reverse the color of H1 text within a vertical div

Is it feasible to reverse the coloring of a segment within an h1 element using a div, horizontally? Refer to the illustration shown in the image below. https://i.sstatic.net/QAKwD.jpg ...

Prop validation error: The property "title" must be a string with a value of **, but a number with a value of ** was provided

My Vue js code displays data from a JSON API in a modal. The issue is that the title should be dynamic, but it only works when clicked twice. On the first click, I get an error and the cancel button, which triggers the hidemodal() function, crashes. Can an ...

Challenge with Expect.js validation in a lesson on Codeacademy

I am currently developing a lesson on Codecademy to teach users about the construction of HTML forms. This project is mainly for my own enjoyment, just to keep everyone in the loop. After reviewing the submission test guidelines and API, I made the decisio ...

Acquire a numerical value from a text source and increment it by one using Jquery

I have a simple task of extracting a single number from a particular div. Once obtained, I intend to increment the number by one. However, despite successfully retrieving the number, my attempts to add one to it are not working as expected. For example: ...

Prevent side menu from automatically hiding when clicking on the heading

My menu is set up with headings and subheadings. When I click on the headings, it expands to display the corresponding subheadings, but it automatically collapses when clicking on the headings. I want it to stay expanded when clicking on the headings. He ...

Node.js - Hitting maximum call stack size limit despite using process.nextTick()

I am currently developing a module for creating "chainable" validation in Express.js: const validatePost = (req, res, next) => { validator.validate(req.body) .expect('name.first') .present('This parameter is required') ...

jQuery DataTable error: Attempted to set property 'destroy' on an undefined object

<script> $('#archiveTable').DataTable({}); </script> <table id="archiveTable" datatable="ng" class="table table-sm" style="color:black"> <!--some code--> </table> This is a snippet of HTML code Upon checking t ...

Navigating from a view to a controller in MVC to reach a different view: a step-by-step guide

I implement the MVC model using PHP, JS, HTML, and CSS. Additionally, I utilize CodeIgniter as my framework. I am looking to understand how to redirect to another controller. While on the Home page of my project, when clicking on "details" (div = prod_det ...

How to retrieve document.getElementsByName from a separate webpage using PHP and javascript

Hey there, I've been searching for a solution to this issue but haven't had any luck so far. I'm attempting to retrieve the value of the name test from an external website. <input type="hidden" name="test" value="ThisIsAValue" /> Up ...

How can I manipulate JSON animation using Three.js?

I utilized this code to import a JSON animation from Blender: var loader = new THREE.JSONLoader(); loader.load( 'monster2.json', function ( geometry, materials ) { var material = materials[ 0 ]; material.morphTargets = true; ...

How to access an element through the router-outlet in Angular 6?

<side-navigation [navigationTitle]="navTitle"></side-navigation> <router-outlet> </router-outlet> Within my project, I have a navigation bar located in the root component. I have set up [navigationTitle] as an @Input Decorator wit ...

Unlocking the power of python with web2py by tapping into html form values

I'm working on a project using web2py and need to incorporate ajax/javascript with a form. Currently, when a user selects an option in the departure box, the arrival box appears. However, I'm unsure of how to filter the list of arrival options ba ...

mongodb cannot locate the schema method within the nested container

Trying to access a method of a schema stored inside a mixed container has presented a challenge. The scenario is as follows: var CaseSchema = mongoose.Schema({ caseContent : {}, object : {type:String, default : "null"}, collision : {type : Boo ...

Utilize a JavaScript function on an element that is generated dynamically

I am encountering an issue with my autocomplete function. It works perfectly fine for the input field with the id "field10" that is already created. However, when I dynamically generate new input fields, the function does not seem to work on them. I have ...

Customize variable values on-the-fly in Laravel

I am trying to create a navbar in Laravel with Vue.js as a blade.php file. I want to include a variable like {{xyz}} in the navbar, and when I navigate to another page, be able to set text using Vue.js or something similar. Can someone assist me with this? ...

The subsequent middleware in express next() is failing to trigger the next middleware within the .catch() block

I'm facing a puzzling issue with my POST route. It's responsible for creating transactions through Stripe using the Node package provided by Stripe. Everything works smoothly until an error occurs, such as when a card has insufficient funds. Whe ...