Three.js: rotate camera with both touch and device orientation

后端 未结 1 1276
野趣味
野趣味 2021-02-04 17:31

I am making a 3D project with threejs which allows control of the camera with mouse for computer devices, and also allows control with touch events and deviceorientation event f

1条回答
  •  心在旅途
    2021-02-04 17:59

    I found a solution using a function to convert quaternions to radians, so I wanted to share it if someone wants to do a click/touch+device orientation control using OrbitControls.

    I take the initial orientation (x1,y1,z1) and calculate the new one (x2,y2,z3) and the difference between them is the variation of the rotation done by the camera. I add these line to the initial update function

    this.update = function () {
      // Z
      const alpha = scope.deviceOrientation.alpha 
        ? THREE.Math.degToRad(scope.deviceOrientation.alpha)
        : 0;
    
      // X'
      const beta = scope.deviceOrientation.beta
        ? THREE.Math.degToRad(scope.deviceOrientation.beta)
        : 0;
    
      // Y''
      const gamma = scope.deviceOrientation.gamma 
        ? THREE.Math.degToRad(scope.deviceOrientation.gamma)
        : 0;
    
      // O
      const orient = scope.screenOrientation
        ? THREE.Math.degToRad(scope.screenOrientation) 
        : 0;
    
      const currentQ = new THREE.Quaternion().copy(scope.object.quaternion);
    
      setObjectQuaternion(currentQ, alpha, beta, gamma, orient);
      const currentAngle = Quat2Angle(currentQ.x, currentQ.y, currentQ.z, currentQ.w);
    
      // currentAngle.z = left - right
      this.rotateLeft((lastGamma - currentAngle.z) / 2);
      lastGamma = currentAngle.z;
    
      // currentAngle.y = up - down
      this.rotateUp(lastBeta - currentAngle.y);
      lastBeta = currentAngle.y;
    }
    

    Listeners

    function onDeviceOrientationChangeEvent(event) {
      scope.deviceOrientation = event;
    }
    
    window.addEventListener('deviceorientation', onDeviceOrientationChangeEvent, false);
    


    function onScreenOrientationChangeEvent(event) {
      scope.screenOrientation = window.orientation || 0;
    }
    
    window.addEventListener('orientationchange', onScreenOrientationChangeEvent, false);
    

    Functions

    var setObjectQuaternion = function () {
      const zee = new THREE.Vector3(0, 0, 1);
      const euler = new THREE.Euler();
      const q0 = new THREE.Quaternion();
      const q1 = new THREE.Quaternion(-Math.sqrt(0.5), 0, 0,  Math.sqrt(0.5));
    
      return function (quaternion, alpha, beta, gamma, orient) {
        // 'ZXY' for the device, but 'YXZ' for us
        euler.set(beta, alpha, -gamma, 'YXZ');
    
        // Orient the device
        quaternion.setFromEuler(euler);
    
        // camera looks out the back of the device, not the top
        quaternion.multiply(q1);
    
        // adjust for screen orientation
        quaternion.multiply(q0.setFromAxisAngle(zee, -orient));
      }
    } ();
    


    function Quat2Angle(x, y, z, w) {
      let pitch, roll, yaw;
    
      const test = x * y + z * w;
      // singularity at north pole
      if (test > 0.499) {
        yaw = Math.atan2(x, w) * 2;
        pitch = Math.PI / 2;
        roll = 0;
    
        return new THREE.Vector3(pitch, roll, yaw);
      }
    
      // singularity at south pole
      if (test < -0.499) {
        yaw = -2 * Math.atan2(x, w);
        pitch = -Math.PI / 2;
        roll = 0;
        return new THREE.Vector3(pitch, roll, yaw);
      }
    
      const sqx = x * x;
      const sqy = y * y;
      const sqz = z * z;
    
      yaw = Math.atan2((2 * y * w) - (2 * x * z), 1 - (2 * sqy) - (2 * sqz));
      pitch = Math.asin(2 * test);
      roll = Math.atan2((2 * x * w) - (2 * y * z), 1 - (2 * sqx) - (2 * sqz));
    
      return new THREE.Vector3(pitch, roll, yaw);
    }
    

    0 讨论(0)
提交回复
热议问题