确定旋转角度是否在球体内的相机视野中

时间:2016-01-25 21:13:20

标签: javascript three.js rotation panoramas

我希望有人可以帮助我。在three.js中,我在位于(0,0,0)位置的SphereGeometry中创建了一个摄像头。我在球体的墙上投射出一幅全景图像。

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

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

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

显然,纬度/经度角已经被捕获并存储在每个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的θ/ 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
    }

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

答案 2 :(得分:0)

啊,好像我想出了三角学。通过向设备方向添加事件监听器,我现在可以根据世界方向更新lat / lon。

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设备上似乎并不一致。也许有人可以评论如何最好地解决这个问题。