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.