Three.js OrbitControls绕圆环旋转

问题描述 投票:0回答:1

我有一个OrbitControls摄像头,它围绕点旋转:target = player.position.x,y和z。没关系,但是播放器位于屏幕中央。我需要一台相机绕环旋转...first picture: target is in the centre, second: target is always placed to the left of the centre

让我解释一下:这是我的代码:

controls.target.x = player.position.x;
controls.target.y = player.position.y+3;
controls.target.z = player.position.z;

因此,我们绕固定点旋转。

但是我需要一个可以根据controls.getAzimuthalAngle()或其他方式更改其位置的点。相机必须像在GTA V或其他游戏中一样,其中玩家不在屏幕中央,而是在屏幕左侧偏左,因此例如在瞄准时,玩家更方便,不会干扰瞄准中心。

帮助...

javascript three.js 3d
1个回答
0
投票

通常,对于第三人称相机,您经常将相机对准播放器(或与播放器有一定偏移量,或连接到播放器的某些物体)

然后您可以让摄像机随时间跟随播放器。

在下面的代码中,播放器后面有一个cameraRig。摄像机装备在那里,因此我们无需进行任何数学运算即可将摄像机保持在地面上方。同样,有一个camTarget附在播放器上。这样相机就可以看到肩膀的高度。

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const keys = {};
  const scene = new THREE.Scene();

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 500;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  
  // put the camera 5 units above the rig
  const cameraRig = new THREE.Object3D();
  cameraRig.add(camera);
  camera.position.y = 5;
  scene.add(cameraRig);
  cameraRig.position.z = 5;

  {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(-1, 2, 4);
    scene.add(light);
  }
  
  {
    const size = 200;
    const divisions = 100;
    const gridHelper = new THREE.GridHelper(size, divisions);
    scene.add(gridHelper);
  }

  const boxWidth = 0.5;
  const boxHeight = 2;
  const boxDepth = 0.5;
  const geometry = new THREE.CylinderGeometry(boxWidth, boxDepth, boxHeight);

  const material = new THREE.MeshPhongMaterial({color:'red'});
  const cube = new THREE.Mesh(geometry, material);
  const player = new THREE.Object3D();
  const camTarget = new THREE.Object3D();

  cube.position.y = boxHeight / 2;  // move cube above ground
  player.add(cube);
  camTarget.position.y = boxHeight * 3 / 2;  // target 2/3ds up the player
  player.add(camTarget);
  scene.add(player);
  
  

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }
  
  const moveDir = new THREE.Vector3();
  const camTargetPos = new THREE.Vector3();
  
  let then = 0;
  function render(now) {
    now *= 0.001;
    deltaTime = now - then;
    then = now;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }
    
    // left, right, a, d
    const dx = ((keys[37] || keys[65]) ?  1 : 0) + 
               ((keys[39] || keys[68]) ? -1 : 0);
    // up, down, w, s
    const dy = ((keys[38] || keys[87]) ?  1 : 0) + 
               ((keys[40] || keys[83]) ? -1 : 0);
    const playerMoveSpeed = 10; // units per second
    camera.getWorldDirection(moveDir);
    moveDir.y = 0; // no up down movement
    moveDir.normalize();
    // move player forward/back
    player.position.addScaledVector(moveDir, dy * playerMoveSpeed * deltaTime);
    // rotate direction 90 degrees
    const t = moveDir.x;
    moveDir.x = moveDir.z;
    moveDir.z = -t;
    // move player left/right
    player.position.addScaledVector(moveDir, dx * playerMoveSpeed * deltaTime);
    
    // if the cameraRig is too far from
    // player then move it
    const maxDistance = 6;
    const maxCamMoveSpeed = 0.015;
    const distance = cameraRig.position.distanceTo(player.position);
    if (distance > maxDistance) {
      const amount = maxCamMoveSpeed;
      cameraRig.position.lerp(player.position, amount);
    }

    camTarget.getWorldPosition(camTargetPos);
    camera.lookAt(camTargetPos);
     

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
  
  window.addEventListener('keydown', (e) => {
    e.preventDefault();
    keys[e.keyCode] = true;
  });
  window.addEventListener('keyup', (e) => {
    e.preventDefault();
    keys[e.keyCode] = false;
  });
}



main();
body {
  margin: 0;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r113/build/three.min.js"></script>
<canvas id="c" tabindex="0"></canvas>

第三人称摄影机可能很难。上面的一个太简单了。您可以将其想像成是将cameraRig拖到播放器后面的字符串上。如果备份,相机不会移动。仅在摄像机离开maxDistance时才移动。

通常将照相机放在摇杆上,所以如果您向后走,摇杆会将照相机推回原位。

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const keys = {};
  const scene = new THREE.Scene();

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 500;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  
  // put the camera 5 units above the rig
  const cameraRig = new THREE.Object3D();
  cameraRig.add(camera);
  camera.position.y = 5;
  scene.add(cameraRig);
  cameraRig.position.z = 5;

  {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(-1, 2, 4);
    scene.add(light);
  }
  
  {
    const size = 200;
    const divisions = 100;
    const gridHelper = new THREE.GridHelper(size, divisions);
    scene.add(gridHelper);
  }

  const boxWidth = 0.5;
  const boxHeight = 2;
  const boxDepth = 0.5;
  const geometry = new THREE.CylinderGeometry(boxWidth, boxDepth, boxHeight);

  const material = new THREE.MeshPhongMaterial({color:'red'});
  const cube = new THREE.Mesh(geometry, material);
  const player = new THREE.Object3D();
  const camTarget = new THREE.Object3D();

  cube.position.y = boxHeight / 2;  // move cube above ground
  player.add(cube);
  camTarget.position.y = boxHeight * 3 / 2;  // target 2/3ds up the player
  player.add(camTarget);
  scene.add(player);
  
  

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }
  
  const moveDir = new THREE.Vector3();
  const camTargetPos = new THREE.Vector3();
  const rigTargetPos = new THREE.Vector3();
  
  function moveCameraToDistance(desiredDistance) {
    const maxCamMoveSpeed = 0.02;
    
    // delta from player to rig
    rigTargetPos.subVectors(cameraRig.position, player.position);
    // remove up/down
    rigTargetPos.y = 0; // no up/down
    // make unit vector
    rigTargetPos.normalize();
    // make desiredDistance long
    rigTargetPos.multiplyScalar(desiredDistance);
    // add player position
    rigTargetPos.add(player.position);
    // move rig toward that position
    const curDistance = cameraRig.position.distanceTo(player.position);
    cameraRig.position.lerp(
        rigTargetPos,
        THREE.MathUtils.lerp(
            maxCamMoveSpeed,
            1, 
            THREE.MathUtils.clamp(1 - curDistance / desiredDistance, 0, 1)));
  }
  
  let then = 0;
  function render(now) {
    now *= 0.001;
    deltaTime = now - then;
    then = now;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }
    
    // left, right, a, d
    const dx = ((keys[37] || keys[65]) ?  1 : 0) + 
               ((keys[39] || keys[68]) ? -1 : 0);
    // up, down, w, s
    const dy = ((keys[38] || keys[87]) ?  1 : 0) + 
               ((keys[40] || keys[83]) ? -1 : 0);
    const playerMoveSpeed = 10; // units per second
    camera.getWorldDirection(moveDir);
    moveDir.y = 0; // no up down movement
    moveDir.normalize();
    // move player forward/back
    player.position.addScaledVector(moveDir, dy * playerMoveSpeed * deltaTime);
    // rotate direction 90 degrees
    const t = moveDir.x;
    moveDir.x = moveDir.z;
    moveDir.z = -t;
    // move player left/right
    player.position.addScaledVector(moveDir, dx * playerMoveSpeed * deltaTime);
    
    // keep camera at distance
    const minDistance = 4;
    const maxDistance = 6;
    const distance = cameraRig.position.distanceTo(player.position);
    if (distance > maxDistance) {
      moveCameraToDistance(maxDistance);
    } else if (distance < minDistance) {
      moveCameraToDistance(minDistance);
    }

   // compute point from player in direction of rig 
    // at desired distance

    camTarget.getWorldPosition(camTargetPos);
    camera.lookAt(camTargetPos);
     

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }
  
  requestAnimationFrame(render);
  
  window.addEventListener('keydown', (e) => {
    e.preventDefault();
    keys[e.keyCode] = true;
  });
  window.addEventListener('keyup', (e) => {
    e.preventDefault();
    keys[e.keyCode] = false;
  });
}



main();
body {
  margin: 0;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r113/build/three.js"></script>
<canvas id="c" tabindex="0"></canvas>

然后,您需要处理诸如照相机和播放器之间的东西之类的事情。 (某些游戏会将这些内容淡出)。您还需要处理说走进一扇门的问题。有一会儿,玩家将在门的一侧,而摄像机则在门的另一侧(或者恰好在门口的相对侧),所以摄像机会掉下来,以便可以透过门看到它吗?墙壁会褪色吗?摄像机会跳吗?穿过门,从其他位置开始看。谣言是在《马里奥64》中,一个程序员整年都在照像机上工作,没别的。)

[请注意,上面的某些代码仅在以下特殊情况下有效:someObject.position是世界空间位置(该对象没有父对象,或者如果所有父对象都具有position = 0,0,0 rotation = 0 ,0,0,比例尺= 1,1,1)。如果对象确实有父母,那么您需要使用

来获得世界位置
const wp = new THREE.Vector3();
someObject.getWorldPosition(wp);

并且,如果您想应用世界位置,则需要做更多的工作才能使该位置成为父母的相对位置。现在,为了简单起见,我只使用世界位置就是其位置的对象。

© www.soinside.com 2019 - 2024. All rights reserved.