Я не могу заставить Перспективную камеру следить за игроком. Камера прилипла к мировому происхождению

#javascript #three.js

Вопрос:

Я новичок в THREE.js.

С целью изучения JavaScript и THREE.js Я сделал эту (своего рода) мини-игру, в которой игрок может исследовать космос и различные космические объекты (работа в процессе).

В любом случае, моя проблема в том, что когда сцена и объекты визуализируются, и вы начинаете перемещать свой кубоид, камера не перемещается вместе с ним (на самом деле она не удаляется от источника мира), а только вращается на месте, глядя на объект игрока.

Это и есть код:

 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 cameraObject, keys;
var temp = new THREE.Vector3;
var dir = new THREE.Vector3;
var a = new THREE.Vector3;
var b = new THREE.Vector3;
var distance = 0.3;
var velocity = 0.0;
var speed = 0.0;

// Camera object
const perspectiveCamera = new THREE.PerspectiveCamera( 25, window.innerWidth / window.innerHeight, 50, 1e7 )
perspectiveCamera.position.setZ(80);
cameraObject = new THREE.Object3D;
cameraObject.add(perspectiveCamera);
// perspectiveCamera.lookAt(scene.position)

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

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

// Light
// PointLight
const pointLight = new THREE.PointLight(0xffffff)
pointLight.position.set(20,20,20)
// AmbientLight
const ambientLight = new THREE.AmbientLight(0xffffff)
scene.add(pointLight, ambientLight)

// Helper classes
const lightHelper = new THREE.PointLightHelper(pointLight);
const axesHelper = new THREE.AxesHelper(5);
scene.add(lightHelper, axesHelper)

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

let cube = new THREE.Group();
const cubeGeometry = new THREE.BoxGeometry(3,10,3)
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0x238423 })
const cube1 = new THREE.Mesh( cubeGeometry, cubeMaterial );
cube.add(cube1)
scene.add(cube)

// Objects
// 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(1500).fill().forEach(addStar)

let keyState = {};
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;
});

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

  requestAnimationFrame( animate );
  speed = 0.0;

  if ( keys.w )
    cube.rotateX(-0.03);

  if ( keys.s )
  cube.rotateX(0.03);

  if ( keys.a )
  cube.rotateZ(0.03);

  if ( keys.d )
  cube.rotateZ(-0.03);

  if ( keys.q )
  cube.rotateY(-0.06);

  if ( keys.e )
  cube.rotateY(0.06);

  if ( keys.space )
    speed = 0.9;

  velocity  = ( speed - velocity ) * .3;
  cube.translateY( velocity );

  if ( keys.shiftleft )
    speed = 0.9*5;
    velocity  = ( speed - velocity ) * .3; 
    cube.translateY( velocity );

  perspectiveCamera.lookAt( cube.position ); 
  controls.update(delta);
  renderer.render( scene, perspectiveCamera );
}
animate();
 

На самом деле я пытаюсь сделать что-то вроде камеры от третьего лица. Для того, чтобы камера следовала за этим маленьким кубоидом и вращалась по мере вращения объекта на экране.

Первая попытка:

 const idealOffset = new THREE.Vector3(0, 0, -80);
function animate(){
  ...
  perspectiveCamera.position.set(0, 0, -80);
  perspectiveCamera.applyQuaternion(cube.rotation);
  perspectiveCamera.position.add(cube.position);
  perspectiveCamera.lookAt(idealOffset);
  ...
}
 

Камера движется вместе с кубом, но через несколько секунд поворачивается назад, чтобы посмотреть на происхождение мира.

Second attempt:

 // Animate objects
  requestAnimationFrame( function animate(milliseconds) {
  const delta = clock.getDelta();
  let moveDistance = 10*delta;
  let rotateAngle = Math.PI/2*delta;
  requestAnimationFrame( animate );
  speed = 0.0;

  if ( keys.w ){
    cube.rotateX(-0.03);
  }
  if ( keys.s ){
    cube.rotateX(0.03);
  }

  let rotation_matrix = new THREE.Matrix4().identity();
  if ( keys.a ){
    cube.rotateZ(rotateAngle);
  }
  if ( keys.d ){
    cube.rotateZ(-rotateAngle);
  }
  if ( keys.q ){
    cube.rotateY(-rotateAngle);
  }
  if ( keys.e ){
    cube.rotateY(rotateAngle);
  }
  if ( keys.space ){
    speed = 0.9;
    velocity  = ( speed - velocity ) * .3;
    cube.translateY( velocity );
  }
  if ( keys.shiftleft ){
    speed = 0.9*5;
    velocity  = ( speed - velocity ) * .3; 
    cube.translateY( velocity );
  }
  
  var relativeCameraOffset = new THREE.Vector3(0,-80,0);
  var cameraOffset = relativeCameraOffset.applyMatrix4(cube.matrixWorld);
  perspectiveCamera.position.x = cameraOffset.x;
  perspectiveCamera.position.y = cameraOffset.y;
  perspectiveCamera.position.z = cameraOffset.z;
  perspectiveCamera.lookAt(cube.position);
  renderer.render( scene, perspectiveCamera );
});
 

Камера действительно следует за моим кубом,но когда я поворачиваю ее на 180 градусов по оси x, она переворачивается вверх дном, она прикреплена к проигрывателю и движется не плавно, и она смотрит прямо на игрока (задняя сторона куба).

Это вдохновило меня прочитать больше о вращении/переводе в 3d-пространстве, об углах Эйлера, кватернионах, карданном замке. Я просто не совсем уверен, как применить эти страшные кватернионы к моему проекту…

Любая помощь, рекомендации, все, что угодно, было бы очень признательно.

Заранее спасибо.

Ответ №1:

Если вы используете OrbitControls, просто обновите .target свойство до положения объекта, на котором вы хотите его сфокусировать. Когда куб движется, камера будет двигаться вместе с ним. Смотрите здесь для получения дополнительной информации о документах:

 orbitControls.target = cube.position;
 

Я не совсем понимаю, зачем ты это делаешь: cameraObject.add(perspectiveCamera); . Это ничего не даст, если вы не внесете никаких изменений cameraObject .

Комментарии:

1. Спасибо за быстрый ответ. Это не дало мне желаемого результата. Камера по-прежнему приклеена к центру. Что касается «объекта камеры»… ну, я экспериментировал с перспективной камерой и кватернионами…и я забыл удалить эти две строки перед отправкой кода. Я отредактировал свой вопрос, чтобы показать вам, что я пытался.