r00ster
r00ster

Reputation: 85

How do I move the camera independently of specific camera axes?

So I have this code from the https://threejs.org/examples/?q=lock#misc_controls_pointerlock example, but very minimized and simplified, without the flying cubes and the jumping and some other stuff:

var camera, scene, renderer, controls;
var objects = [];
var raycaster;
var moveForward = false;
var moveBackward = false;
var moveLeft = false;
var moveRight = false;
var canJump = false;
var prevTime = performance.now();
var velocity = new THREE.Vector3();
var direction = new THREE.Vector3();
var vertex = new THREE.Vector3();
var color = new THREE.Color();

init();
animate();

function init() {
  camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 );
  camera.position.y = 10;
  scene = new THREE.Scene();
  scene.background = new THREE.Color( 0xffffff );
  scene.fog = new THREE.Fog( 0xffffff, 0, 750 );
  var light = new THREE.HemisphereLight( 0xeeeeff, 0x777788, 0.75 );
  light.position.set( 0.5, 1, 0.75 );
  scene.add( light );
  controls = new THREE.PointerLockControls( camera );

  document.body.addEventListener( 'click', function () {
    controls.lock();
  }, false );

  scene.add( controls.getObject() );
  var onKeyDown = function ( event ) {
    switch ( event.keyCode ) {
      case 38: // up
      case 87: // w
        moveForward = true;
        break;
      case 37: // left
      case 65: // a
        moveLeft = true;
        break;
      case 40: // down
      case 83: // s
        moveBackward = true;
        break;
      case 39: // right
      case 68: // d
        moveRight = true;
        break;
      case 32: // space
        if ( canJump === true ) velocity.y += 350;
        canJump = false;
        break;
    }
  };
  var onKeyUp = function ( event ) {
    switch ( event.keyCode ) {
      case 38: // up
      case 87: // w
        moveForward = false;
        break;
      case 37: // left
      case 65: // a
        moveLeft = false;
        break;
      case 40: // down
      case 83: // s
        moveBackward = false;
        break;
      case 39: // right
      case 68: // d
        moveRight = false;
        break;
    }
  };
  document.addEventListener( 'keydown', onKeyDown, false );
  document.addEventListener( 'keyup', onKeyUp, false );
  raycaster = new THREE.Raycaster( new THREE.Vector3(), new THREE.Vector3( 0, - 1, 0 ), 0, 10 );

  // floor
  var floorGeometry = new THREE.PlaneBufferGeometry( 2000, 2000, 100, 100 );
  floorGeometry.rotateX( - Math.PI / 2 );
  floorGeometry = floorGeometry.toNonIndexed(); // ensure each face has unique vertices
  position = floorGeometry.attributes.position;
  var colors = [];
  for ( var i = 0, l = position.count; i < l; i ++ ) {
    color.setHSL( Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75 );
    colors.push( color.r, color.g, color.b );
  }
  floorGeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
  var floorMaterial = new THREE.MeshBasicMaterial( { vertexColors: THREE.VertexColors } );
  var floor = new THREE.Mesh( floorGeometry, floorMaterial );
  scene.add( floor );

  renderer = new THREE.WebGLRenderer( { antialias: true } );
  renderer.setPixelRatio( window.devicePixelRatio );
  renderer.setSize( window.innerWidth, window.innerHeight );
  document.body.appendChild( renderer.domElement );

  window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
  requestAnimationFrame( animate );
  if ( controls.isLocked === true ) {
    var time = performance.now();
    var delta = ( time - prevTime ) / 1000;

    controls.getObject().translateZ(Number( moveBackward ) - Number( moveForward ));
    controls.getObject().translateX(Number( moveRight ) - Number( moveLeft ));

    if ( controls.getObject().position.y < 10 || controls.getObject().position.y > 10 ) {
      controls.getObject().position.y = 10;
    }

    prevTime = time;
  }
  renderer.render( scene, camera );
}

It works pretty well, however there's a problem with this example: the further you look down, the slower you move. If you look completely down, you cannot move.

The reason for that is that currently in the code translateZ and translateX is used for movement. translateZ/X translate along the z/x axis, taking the camera angle into account.

So to solve this, I want the movement to be almost independent of the camera angle.

One approach would be to change

controls.getObject().translateZ(Number( moveBackward ) - Number( moveForward ));
controls.getObject().translateX(Number( moveRight ) - Number( moveLeft ));

to

controls.getObject().position.z += Number( moveBackward ) - Number( moveForward );
controls.getObject().position.x += Number( moveRight ) - Number( moveLeft );

This seems to work pretty good at first, but here the only problem that is left now is that if you rotate the camera, then you no longer move in the direction you look at.

How do I move the camera along the z/x axis, independently of the camera angle, but so that I still go towards that what I'm looking at on the camera? So that I don't move slowly if I look down (or up).

Upvotes: 0

Views: 68

Answers (1)

StrandedKitty
StrandedKitty

Reputation: 302

You can use controls.getDirection() to get direction of camera in world space. Then you need to normalize its x and z components so that vertical rotation doesn't affect your movement.

For side movement you should use other vector which is perpendicular to d (just swap its components and multiply y by -1).

Replace

controls.getObject().translateZ(Number( moveBackward ) - Number( moveForward ));
controls.getObject().translateX(Number( moveRight ) - Number( moveLeft ));

with

var cameraDirection = new THREE.Vector3();
controls.getDirection(cameraDirection);

var d = new THREE.Vector2(
    cameraDirection.x,
    cameraDirection.z
);

d.normalize();

controls.getObject().position.x -= d.x * (Number(moveBackward) - Number(moveForward));
controls.getObject().position.z -= d.y * (Number(moveBackward) - Number(moveForward));

controls.getObject().position.x -= d.y * (Number(moveRight) - Number(moveLeft));
controls.getObject().position.z += d.x * (Number(moveRight) - Number(moveLeft));

Upvotes: 1

Related Questions