javascript 陀螺仪加摄像头可以玩出AR效果

原文链接:https://blog.jijian.link/2020-09-08/js-ar/

重要事情说三遍

此文章中的API接口,必须放在 https 协议下测试!浏览器APP必须开启摄像头权限!此文章代码仅在 chrome 手机浏览器及微信中测试通过。

此处省略两遍。

示例

本文仅使用陀螺仪模拟 AR 效果,完整 AR 逃不掉一整套算法,本菜鸟还做不到啊。

DEMO 演示效果

代码如下:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>陀螺仪模拟AR效果</title>
  <style>
    #video {
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      width: 100%;
      height: 100vh;
      background-color: #141414;
    }
    #address {
      position: fixed;
      left: 50%;
      top: 50%;
      width: 40px;
      height: 60px;
      border-radius: 100%;
      background-color: #009900;
      z-index: 4;
      color: #fff;
    }
  </style>
</head>
<body>
  <div id="address"></div>
  <video id="video" autoplay="autoplay"></video>
  <script>
    var video = document.getElementById('video');
    //默认使用前摄像头,强制使用后置摄像头如下设置
    var constraints = {video: { facingMode: { exact: "environment" } }};
    // let constraints = { video: true };
    navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
      // 旧的浏览器可能没有srcObject
      window.stream = stream;
      if ("srcObject" in video) {
        video.srcObject = stream;
      } else {
        // 防止在新的浏览器里使用它,应为它已经不再支持了
        video.src = window.URL.createObjectURL(stream);
      }
      video.onloadedmetadata = function() {
        video.play();
      };
    }).catch(function(err) {
      console.error(err.name + ": " + err.message);
    });
    // http://stackoverflow.com/questions/18112729/calculate-compass-heading-from-deviceorientation-event-api/21829819#21829819
    // todo 算法来源 https://my.oschina.net/u/2324376/blog/790939
    function compassHeading(alpha, beta, gamma) {
      // Convert degrees to radians
      var alphaRad = alpha * (Math.PI / 180);
      var betaRad = beta * (Math.PI / 180);
      var gammaRad = gamma * (Math.PI / 180);

      // Calculate equation components
      var cA = Math.cos(alphaRad);
      var sA = Math.sin(alphaRad);
      // var cB = Math.cos(betaRad);
      var sB = Math.sin(betaRad);
      var cG = Math.cos(gammaRad);
      var sG = Math.sin(gammaRad);

      // Calculate A, B, C rotation components
      var rA = - cA * sG - sA * sB * cG;
      var rB = - sA * sG + cA * sB * cG;
      // var rC = - cB * cG;

      // Calculate compass heading
      var compassHeading = Math.atan(rA / rB);

      // Convert from half unit circle to whole unit circle
      if(rB < 0) {
        compassHeading += Math.PI;
      }else if(rA < 0) {
        compassHeading += 2 * Math.PI;
      }

      // Convert radians to degrees
      compassHeading *= 180 / Math.PI;

      return compassHeading;
    }
    function updateGravity (event) {
      const that = this;
      // !根据陀螺仪获取旋转角度,设置人物位置
      const winWidth = document.documentElement.clientWidth;
      const itemWidth = parseInt(window.getComputedStyle(address).width);
      const heading = 360 - compassHeading(event.alpha, event.beta, event.gamma);
      const angle = 0;

      address.style.transform = 'rotate('+(heading - 90 + angle)+'deg)';
      // `${(winWidth - itemWidth) * Math.min(180, Math.max(0, (heading + 360 - angle) % 360)) / 180}px`  移动区间 0 - 180
      address.style.left = `${(winWidth - itemWidth) * ((heading + 360 - angle) % 360) / 180}px`;
    }
    window.addEventListener('deviceorientation', updateGravity, false);
  </script>
</body>
</html>

 

posted @ 2020-09-08 17:16  极·简  Views(709)  Comments(0Edit  收藏  举报