【问题标题】:Determine if a rotation angle is in view of a camera inside a sphere确定旋转角度是否在球体内的相机视野中
【发布时间】:2016-05-02 08:16:30
【问题描述】:

我希望有人可以帮助我解决这个问题。在 three.js 中,我在位于 (0,0,0) 位置的 SphereGeometry 内创建了一个相机。我正在球体的墙上投射全景图像。

我正在尝试在 threejs 框架之外创建一些交互式 JS 元素,这些元素会根据相机所面对的方向进行触发。我得到了两个参数,theta & phi,它们分别是 x & z 和 y & z 沿图像的 360 度旋转角度。这个概念是,如果那个点(或向量)在相机的视野中,它会触发一些 JS 事件。请注意,该点不是一个对象,而是一组任意旋转角度。此外,使用鼠标或设备方向移动相机。换句话说,我对以编程方式将相机移动到这些点不感兴趣,而是只有在手动旋转相机并且这些点进入视野时才会执行 JS。

最初,我开始使用 Frustums.containsPoint 方法,但意识到我可能并不是真的在寻找空间中的特定点,而是在寻找相机角度。我想也许改用 camera.getWorldDirection() 或 camera.rotation 会提供正确的天使,但我似乎被困在这里。

任何帮助将不胜感激。

【问题讨论】:

标签: javascript three.js rotation panoramas


【解决方案1】:

将您想要交互的区域定义为一个圆锥(方向 vec3 + 角度),并且每当相机旋转时,检查相机前向 dir 是否在圆锥内。

【讨论】:

    【解决方案2】:

    显然,纬度/经度角已经被捕获并与每个 mousemove 事件一起存储,如下所示:

    function onDocumentMouseMove( event )
    {
        if ( isUserInteracting === true && !isControlInteraction )
        {
            lon = (( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon) % 360;
            lat = (( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat) % 360;
        }
    }
    

    然后我可以使用 lat/lon 变量来计算从某个点 p 开始的 theta/phi 偏移量。如果偏移量小于某个指定的半径,比如 30 度,则可以认为它在范围内。

        var v_theta = THREE.Math.degToRad(lat);
        var v_phi = THREE.Math.degToRad(lon);
        var p_theta = THREE.Math.degToRad(p[0]);
        var p_phi = THREE.Math.degToRad(p[1]);
    
        v_theta = Math.atan2(Math.sin(v_theta), Math.cos(v_theta));
        v_phi = Math.atan2(Math.sin(v_phi), Math.cos(v_phi));
        p_theta = Math.atan2(Math.sin(p_theta), Math.cos(p_theta));
        p_phi = Math.atan2(Math.sin(p_phi), Math.cos(p_phi));
    
        var theta_offset = Math.abs(v_theta - p_theta) * 180 / Math.PI;
        var phi_offset = Math.abs(v_phi - p_phi) * 180 / Math.PI;
        if ( theta_offset <= radius && phi_offset <= radius ) 
        {
           // execute some code here
        }
    

    但是,这不包括独立工作的设备方向控制事件。我想我现在卡住的地方是如何从设备方向计算纬度/经度。我能够获取相机旋转和位置,但不确定如何从相机旋转矢量中获取纬度/经度。

    【讨论】:

      【解决方案3】:

      啊,看来我知道三角法了。通过向设备方向添加事件侦听器,我现在可以根据世界方向更新纬度/经度。

      window.addEventListener( 'deviceorientation', function(e) {
          e.preventDefault();
      
          var angle = window.orientation;
          if ( angle == null ) return;
      
          var dir = camera.getWorldDirection();
          var d_phi = Math.acos( dir.y );
          var d_theta = Math.atan2( dir.x, dir.z );
          d_theta = Math.atan2(Math.sin(d_theta), Math.cos(d_theta));
      
          // update lat / lon
          lon = 90 - THREE.Math.radToDeg(d_phi);
          lat = THREE.Math.radToDeg(d_theta);
      });
      

      现在,唯一的问题是补偿相机的旋转,我一直遇到麻烦。在threejs中,似乎在iOS上,当您第一次加载页面时,世界方向矢量与相机的旋转对齐,然后只有window.orientation角度发生变化。所以看起来原始方向会影响位置/旋转。如果我希望图像的中心为 (0,0),以下似乎适用于 iOS,但我不确定这是否是正确的方法。

          var d_theta = Math.atan2( dir.x, dir.z );
          if ( init_orient === 0 ) d_theta = Math.PI - d_theta;
          else if ( init_orient == -90 ) d_theta = -Math.PI/2 - d_theta;
          else if ( init_orient == 90 ) d_theta = Math.PI/2 - d_theta;
          d_theta = Math.atan2(Math.sin(d_theta), Math.cos(d_theta));
      

      很遗憾,这在 Android 设备上似乎并不一致。也许有人可以评论如何最好地解决这个问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-27
        • 1970-01-01
        • 2020-01-02
        • 2017-11-20
        • 1970-01-01
        • 2019-07-12
        • 2015-01-08
        • 1970-01-01
        相关资源
        最近更新 更多