title: Three.js: rotate camera with both touch and device orientation
body: <p>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 for smartphones. 
  As an example, <a href="http://lacostewinter.seeourwork.cn/en/intro" rel="nofollow noreferrer">this site</a> works the same way as what I want to do.</p>
  
  <p>As I am using OrbitControls to move camera on the PC version, I bound the touchstart/move/end events to mousedown/move/up and <em>it works perfectly</em>.<br>
  The problem is when I try to add the device orientation event's values. Here is what I tried to add in OrbitControls.js :</p>
  
  <pre class="lang-js prettyprint-override"><code>THREE.OrbitControls = function (object, domElement) {
    const scope = this;
    let lastBeta = 0;
    let lastGamma = 0;
    this.deviceOrientation = {};
  
    function onDeviceOrientationChangeEvent(event) {
      scope.deviceOrientation = event;
      // Z
      var alpha = scope.deviceOrientation.alpha
        ? THREE.Math.degToRad(scope.deviceOrientation.alpha) 
        : 0;
  
      // X'
      var beta = scope.deviceOrientation.beta
        ? THREE.Math.degToRad(scope.deviceOrientation.beta)
        : 0;
  
      // Y''
      var gamma = scope.deviceOrientation.gamma 
        ? THREE.Math.degToRad(scope.deviceOrientation.gamma) 
        : 0;
  
      // O
      var orient = scope.screenOrientation 
        ? THREE.Math.degToRad(scope.screenOrientation) 
        : 0;
  
      rotateLeft(lastGamma - gamma);
      rotateUp(lastBeta - beta);
  
      lastBeta = beta; //is working
      lastGamma = gamma; //doesn't work properly
    }
  
    window.addEventListener('deviceorientation', onDeviceOrientationChangeEvent, false);
  };
  </code></pre>
  
  <p>As beta's values are within a [-180,180] degree range the vertical rotation encounters no problem, whereas gamma's range is [-90,90] and values are also changing suddenly when orientating device' screen up and down (even if, I think, it should return horizontal rotation).
  And even when converting gamma's range to make it takes values from -180 to 180, the sudden shifts make everything goes wrong.</p>
  
  <p>I guess that I have to use quaternions as in deviceOrientationControls.js, but I really don't know how it works and every attempt I've made so far was a fail. Can someone help me please?</p>
  
  <p>PS: Here is a link to <a href="http://w3c.github.io/deviceorientation/spec-source-orientation.html#deviceorientation" rel="nofollow noreferrer">the description on the deviceorientation event</a> to have a better comprehension of what really are alpha beta and gamma.</p>
  
  <p><strong>EDIT</strong><br>
  I added a snippet bellow to show the beta and gamma variations.</p>
  
  <p><div class="snippet" data-lang="js" data-hide="true" data-console="false" data-babel="false">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>let deltaBeta = 0;
  let deltaGamma = 0;
  
  if (window.DeviceOrientationEvent) {
    window.addEventListener('deviceorientation', function (e) {
      const beta = (e.beta != null) ? Math.round(e.beta) : 0;
      const gamma = (e.gamma != null) ? Math.round(e.gamma) : 0;
  
      deltaBeta = Math.abs(beta - deltaBeta);
      deltaGamma = Math.abs(gamma - deltaGamma);
  
      $("#beta").html("Beta: " + beta);
      $("#gamma").html("Gamma: " + gamma);
      
      if (Math.abs(deltaBeta) &gt; Math.abs(Number($("#deltaBeta").html()))) {
        $("#deltaBeta").html(deltaBeta);
        if (Number($("#deltaBeta").html()) &gt;= 30) {
          $("#deltaBeta").removeAttr("class", "blue").addClass("red");
        }
      }
      if (Math.abs(deltaGamma) &gt; Math.abs(Number($("#deltaGamma").html()))) {
        $("#deltaGamma").html(deltaGamma);
        if (Number($("#deltaGamma").html()) &gt;= 30) {
          $("#deltaGamma").removeAttr("class", "blue").addClass("red");
        }
      }
    }, true);
  
  } else {
    $("#gamma").html("deviceorientation not supported");
  }</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>.red {
    color: red;
    font-weight: bold;
  }
  .blue {
    color: blue;
    font-weight: bold;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;
  
  &lt;body&gt;
    &lt;div&gt;
      &lt;span id="beta"&gt;&lt;/span&gt;
      &lt;span&gt; [-180; 180]&lt;/span&gt;
    &lt;/div&gt;
    &lt;div&gt;
      &lt;span&gt;DeltaMax&lt;/span&gt;
      &lt;span id="deltaBeta" class="blue"&gt;0&lt;/span&gt;
    &lt;/div&gt;
    &lt;div&gt;
      &lt;span id="gamma"&gt;&lt;/span&gt;
      &lt;span&gt; [-90; 90]&lt;/span&gt;
    &lt;/div&gt;
    &lt;div&gt;
      &lt;span&gt;DeltaMax&lt;/span&gt;
      &lt;span id="deltaGamma" class="blue"&gt;0&lt;/span&gt;
    &lt;/div&gt;
  &lt;/body&gt;</code></pre>
  </div>
  </div>
  </p>