第一人称视角相机旋转无效

时间:2018-09-08 12:11:30

标签: javascript three.js

相机无法正常旋转。当我在 x轴 y轴中移动鼠标时,相机似乎会翻转。我是three.js的新手,对界面一无所知。

Camera rotation

我看过 mrdoob 的点锁控件,但我不了解如何使用两个单独的对象进行偏航和俯仰。我认为他为此使用了两个对象。还有其他方法吗?

<!DOCTYPE html>
<html>

<head>
  <title>THREEJS</title>
  <style>
    body {
      margin: 0;
    }
  </style>
</head>

<body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.js"></script>
  <script type="text/javascript">
    let width = innerWidth
    let height = innerHeight

    let scene = new THREE.Scene()
    let camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000)

    let renderer = new THREE.WebGLRenderer()
    renderer.setSize(width, height)
    document.body.appendChild(renderer.domElement)

    let cube = new THREE.Mesh(
      new THREE.BoxGeometry(1, 1, 1),
      new THREE.MeshLambertMaterial({
        color: 0xFFFFFF,
        wireframe: false
      }))
    let plane = new THREE.Mesh(
      new THREE.PlaneGeometry(10, 10, 10, 10),
      new THREE.MeshLambertMaterial({
        color: 0x00FF00,
        wireframe: false
      }))
    let light = new THREE.PointLight(0xFFFFFF, 1.5, 15)

    plane.rotation.set(-Math.PI / 2, 0, 0)
    cube.position.set(0, 1, 0)
    light.position.set(0, 10, 0)

    scene.add(cube)
    scene.add(plane)
    scene.add(light)

    addEventListener("resize", () => {
      width = innerWidth
      height = innerHeight
      renderer.setSize(width, height)
      camera.aspect = width / height
      camera.updateProjectionMatrix()
    })

    camera.position.set(0, 1, 2)

    renderer.domElement.onclick = () =>
      renderer.domElement.requestPointerLock()
    document.addEventListener('pointerlockchange', lockChangeAlert, false);
    document.addEventListener('mozpointerlockchange', lockChangeAlert, false);

    function updatePosition(event) {
      let {
        movementX,
        movementY
      } = event
      let rotateSpeed = 0.002
      camera.rotation.y -= movementX * rotateSpeed
      camera.rotation.x -= movementY * rotateSpeed

      camera.rotation.x = Math.max(-Math.PI / 2, Math.min(camera.rotation.x, Math.PI / 2))
    }

    function lockChangeAlert() {

      if (document.pointerLockElement == renderer.domElement) {
        document.addEventListener("mousemove", updatePosition, false)
      } else {
        document.removeEventListener("mousemove", updatePosition, false)
      }
    }

    let keys = {}

    function keyDown(event) {
      keys[event.key] = true
    }

    function keyUp(event) {
      delete keys[event.key]
    }

    document.onkeydown = keyDown
    document.onkeyup = keyUp

    function update() {
      let moveSpeed = 0.05

      cube.rotation.x += 0.01
      cube.rotation.y += 0.01

      if (keys["w"]) {
        camera.position.x -= Math.sin(camera.rotation.y) * moveSpeed
        camera.position.z -= Math.cos(camera.rotation.y) * moveSpeed
      }
      if (keys["s"]) {
        camera.position.x += Math.sin(camera.rotation.y) * moveSpeed
        camera.position.z += Math.cos(camera.rotation.y) * moveSpeed
      }

      if (keys["d"]) {

      }
      if (keys["a"]) {

      }


    }

    function draw() {
      renderer.render(scene, camera)
    }

    function loop() {
      update()
      draw()

      requestAnimationFrame(loop)
    }

    loop()
  </script>
</body>

</html>

1 个答案:

答案 0 :(得分:1)

它使用2个对象的原因是由于您要描述的问题(称为“万能锁”)。

对于一个对象,根据旋转的级联顺序,您将在一个轴上获得一个旋转,从而锁定在另一个轴上的旋转或导致另一个轴翻转。

有一个rotation.order参数,您可以使用它来解决此问题(例如,rotation.order ='YZX'或'ZYX'而不是标准的'XYZ',但这会使您的旋转角度有所不同与管道的其余部分相比,“顺序”是更好的选择,因此有时更优雅但效率稍低的方法是只使用2个单独的对象,一个用于音高,一个用于偏航,另一种解决方案是使用不继承问题的四元数。万向节锁。

万向节锁是一个有趣的问题,它具有有趣的历史。

https://en.wikipedia.org/wiki/Gimbal_lock