0

I'm working on a Three.js mini-game where you can flying a rocket through space. I was able to get the camera follow the rocket but when I rotate it for 180° upwards, the camera turns upside down. Could you please help me with these Angle restrictions? (The point of the project and this question is to learn Three.js, please excuse my lack of experience.)

I've already experimented a little bit with quaternions but I couldn't get it to work. I've stumbled upon a post which stated that Spherical could be a part of the solution here. So, could you please help me with an example of how to implement any of those two (or maybe something else) in order to solve this problem?

This is my code:

import './style.css'
import * as THREE from 'three'; 
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

// Scene object
const scene = new THREE.Scene();
const clock = new THREE.Clock();

var keys;
var velocity = 0.0;
var speed;

// Camera object
let perspectiveCamera = new THREE.PerspectiveCamera( 25, window.innerWidth / window.innerHeight, 50, 1e7 )

// Renderer object
const renderer = new THREE.WebGLRenderer({
  antialias: true
});
document.body.appendChild( renderer.domElement );

// Renderer
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.render( scene, perspectiveCamera )

// PointLight
const pointLight = new THREE.PointLight(0xffffff)
pointLight.position.set(20,20,20)

// AmbientLight
const ambientLight = new THREE.AmbientLight(0xffffff)
scene.add(pointLight, ambientLight)

// Controls
const controls = new OrbitControls(perspectiveCamera, renderer.domElement);
controls.movementSpeed = 1000;
controls.domElement = renderer.domElement;
controls.rollSpeed = Math.PI / 24;
controls.autoForward = false;
controls.dragToLook = false;

// Rocket 
const geometry = new THREE.BoxGeometry( 1, 1, 3 );
const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
const rocket = new THREE.Mesh( geometry, material );
scene.add(rocket);

// Stars
function addStar() {
  const geometry = new THREE.SphereGeometry(0.25, 24, 24);
  const material = new THREE.MeshStandardMaterial( { color: 0xffffff })
  const star = new THREE.Mesh( geometry, material );
  const [x, y, z] = Array(3).fill().map(() => THREE.MathUtils.randFloatSpread( 500 ));
  star.position.set(x,y,z);
  scene.add(star)
}
Array(500).fill().forEach(addStar)

keys = {
  a: false,
  s: false,
  d: false,
  w: false,
  q: false,
  e: false,
  space: false,
  shiftleft: false,
};

document.addEventListener("keydown", function(e) {
  console.log(e.code);
  const key = e.code.replace('Key', '').toLowerCase();
    if ( keys[ key ] !== undefined )
      keys[ key ] = true;
});

document.body.addEventListener( 'keyup', function(e) {
    
  const key = e.code.replace('Key', '').toLowerCase();
  if ( keys[ key ] !== undefined )
    keys[ key ] = false;
});

// 
let goal = new THREE.Object3D;
goal.add(perspectiveCamera);


function followCamera()
{
    //Offset from camera to player
    var relativeCameraOffset = new THREE.Vector3(0,0,-80);

    //Updating player world matrix for perfect camera follow
    rocket.updateMatrixWorld()
    
    //Apply offset to player matrix
      var cameraOffset = relativeCameraOffset.applyMatrix4( rocket.matrixWorld );

    //Smooth camera movement
    perspectiveCamera.position.lerp(cameraOffset, 0.1);
    perspectiveCamera.lookAt( rocket.position );
}

// Animate method
function animate() {
  const delta = clock.getDelta();
  requestAnimationFrame( animate );

  speed = 0.0;
    
  if ( keys.w )
    rocket.rotateX(0.02);

  if ( keys.s )
    rocket.rotateX(-0.02);

  if ( keys.a )
    rocket.rotateY(0.02);

  if ( keys.d )
    rocket.rotateY(-0.02);

  if ( keys.q )
    rocket.rotateZ(-0.05);

  if ( keys.e )
    rocket.rotateZ(0.05);

  if ( keys.space )
    speed = 0.8;
    velocity += ( speed - velocity ) * .2;
    rocket.translateZ( velocity );

  if ( keys.shiftleft )
    speed = 0.8*5;
    velocity += ( speed - velocity ) * .2; 
    rocket.translateZ( velocity );
  
  followCamera()
  controls.update(delta);
  renderer.render( scene, perspectiveCamera );
}
animate();

Thank you all in advance!!!

I tried, although unsuccessfully, copying the rocket quaternion and applying it to my perspective camera and normalizing it, it didn't do much.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • What’s the desired behavior? If you rotate the camera vertically past the North pole, it would start coming back down on the opposite side, but upside down. What would you like the camera to do at that point? I think OrbitControls by default stops rotating at that point. – M - Apr 07 '23 at 05:01
  • @Marquizzo Exactly, when rotating over 180 degrees, the camera turns upside down. I was looking for a way to prevent it from doing that. It would be easier if you see it for yourself, this is my Pen for this project: [ https://codepen.io/js_thin_time/pen/ZEqYzmQ ] Go ahead and rotate the object pressing "w" or "s". – js_thin_time Apr 07 '23 at 15:52
  • I don't know, but maybe you'd like to try [ArcballControls](https://threejs.org/examples/?q=control#misc_controls_arcball) or [TrackballControls](https://threejs.org/examples/?q=control#misc_controls_trackball). They both keep spinning without regard to which way is "up". – M - Apr 07 '23 at 17:15

0 Answers0