【问题标题】:How do I move the camera independently of specific camera axes?如何独立于特定的相机轴移动相机?
【发布时间】:2019-12-19 06:59:34
【问题描述】:

所以我得到了https://threejs.org/examples/?q=lock#misc_controls_pointerlock 示例中的这段代码,但是非常精简和简化,没有飞行方块、跳跃和其他一些东西:

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 );
}

它工作得很好,但是这个例子有一个问题:你越往下看,你移动的越慢。如果你完全向下看,你就不能动。

原因是目前在代码中translateZtranslateX 用于移动。 translateZ/X 沿 z/x 轴平移,同时考虑相机角度。

所以为了解决这个问题,我希望运动几乎不受摄像机角度的影响。

一种方法是改变

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

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

一开始这似乎工作得很好,但现在唯一剩下的问题是,如果你旋转相机,那么你就不再朝着你所看的方向移动了。

我如何沿 z/x 轴移动相机,不受相机角度的影响,但我仍然朝着我在相机上看到的方向移动?这样当我向下(或向上)看时,我不会缓慢移动。

【问题讨论】:

    标签: javascript three.js 3d camera


    【解决方案1】:

    您可以使用controls.getDirection() 来获取相机在世界空间中的方向。然后你需要标准化它的xz 分量,这样垂直旋转就不会影响你的运动了。

    对于横向移动,您应该使用垂直于d 的其他向量(只需交换其组件并将y 乘以-1)。

    替换

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

    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));
    

    【讨论】:

    • 工作得很好,虽然它仍然存在当完全向下看时它不会移动的错误(或者在这种情况下它有时会向后移动一点),即当 dx 和/或 dy 为 0 .
    • @r00ster 我已经从零开始实现了几次类似的相机交互,解决方案是始终将垂直旋转限制在 -89.9 到 89.9 度之间。您可以尝试在PointerLockControls.js:euler.x = Math.max( - PI_2, Math.min( PI_2, euler.x ) ); 中编辑此行(当前范围为 [-PI_2, PI_2])。
    • 啊,是的,不能直视似乎是一个很好的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2016-12-14
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    相关资源
    最近更新 更多