使用设备方向移动 Three.js 相机 - 设备垂直放置时出现奇怪的行为

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

我正在使用 Three.js 创建一个小项目,其中相机位于有纹理的毛衣内。旋转相机是利用手机在空间中的方向来完成的。乍一看,我的解决方案工作正常,但当设备接近垂直位置(角度 Beta 接近 90 度)时,图像会变得疯狂并意外旋转。看起来设备已绕其中一个轴(对应于 alpha 角)旋转了 360 度。

createScene() {
    const scene = new THREE.Scene();
    console.log('scene', scene);

    // create a new Three.js perspective camera
    const camera = new THREE.PerspectiveCamera(
      75, // field of view
      window.innerWidth / window.innerHeight, // aspect ratio
      0.1, // near plane
      1000 // far plane
    );

    // create a new Three.js renderer
    const renderer = new THREE.WebGLRenderer();

    // set the renderer size to the window dimensions
    renderer.setSize(window.innerWidth, window.innerHeight);

    // get the container element for the background
    const backgroundContainer = document.querySelector('.vr-sphere');

    if (backgroundContainer == null) return;

    backgroundContainer.appendChild(renderer.domElement);

    const loader = new THREE.TextureLoader();

    const texture = loader.load(
      '../../assets/images/oil_painting_van_gogh_starry_night.jfif'
    );

    const geometry = new THREE.SphereGeometry(500, 60, 40);

    // invert the geometry to render it inside out
    geometry.scale(-1, 1, 1);

    const material = new THREE.MeshBasicMaterial({
      map: texture,
    });

    const sphere = new THREE.Mesh(geometry, material);

    scene.add(sphere);

    // set the camera's position in the scene
    camera.position.set(0, 0, 0);

    // enable VR mode based on DeviceOrientation API
    if (window.DeviceOrientationEvent) {
      window.addEventListener('deviceorientation', (event) => {
        let alpha = event.alpha ? THREE.MathUtils.degToRad(event.alpha) : 0; // Z
        let beta = event.beta ? THREE.MathUtils.degToRad(event.beta) : 0; // X'

        if (alpha && beta) {
          if (beta >= 0 && beta <= 180) {
            // up/down rotation
            camera.rotation.set(-Math.PI / 2 + beta, 0, 0);
            // left/right rotation
            sphere.rotation.y = -alpha;
        }
      });
    }

    function animate() {
      // request the next frame of the animation
      requestAnimationFrame(animate);

      renderer.render(scene, camera);
    }

    animate();

  }

我读到这个问题的解决方案可以是使用四元数或旋转矩阵。我尝试使用 Three.js 内置函数来实现它们,但效果是相同的。有没有人遇到过类似的问题并且知道如何解决?

three.js virtual-reality device-orientation
1个回答
0
投票

你发现问题了:使用四元数。

我编写了这个类,您可以自由地重用或修改(欢迎引用),以将设备方向控件添加到 Three.js 项目中。

我使用 AbsoluteOrientationSensor 来代替 DeviceOrientationEvent

关键部分在这里:

// Retrieve device absolute rotation quaternion
const q1 = new THREE.Quaternion().fromArray(this.sensor.quaternion)

// Ispired by https://gist.github.com/kopiro/86aac4eb19ac29ae62c950ad2106a10e
// Apply rotation around x axis (camera points toward the back of the phone, not up)
// and then update camera quaternion
const q2 = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3(1, 0, 0), -Math.PI/2 )
this.camera.quaternion.multiplyQuaternions(q2, q1)
© www.soinside.com 2019 - 2024. All rights reserved.