Three.js地球和相机转动问题

时间:2017-03-08 05:24:49

标签: javascript three.js

喜欢这个网站http://www.gsmlondon.ac.uk/global-oil-map/

我想点击此标记,让此标记转到屏幕中心。 现在知道标记纬度和经度,点击后如何转动?我不明白。

1 个答案:

答案 0 :(得分:0)

有趣的问题,我尝试了Matrix以获得正确的方向,但结果有点奇怪。我选择使用球面坐标系统的另一种方法,它现在可以使用。

我们需要得到两个点坐标,一个是球面上最接近相机的点我们注意到它是 P (从相机到球体中心的线与球体相交)。另一点是我们点击球体表面,我们注意到它是 Q

我们使用raycaster获取 P Q 笛卡尔坐标。并将笛卡尔坐标转换为球面坐标(总是描述为(r,θ,φ))。

然后,我们计算从 Q P 的角位移。并将位移作为球体旋转的补充。

这是我的代码:

    //get the point coordinates which a line from camera to sphere center intersect with the sphere 
    var vector = new THREE.Vector3().copy(sphere.position);
    vector = vector.unproject(camera);
    var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
    var intersects = raycaster.intersectObjects([sphere],true);
    var intersected_point = new THREE.Vector3().copy(intersects[0].point);

    //calculate the intersected point spherical coordinates
    var radius = sphere.children[0].geometry.parameters.radius;
    var heading = Math.atan2(intersects[0].point.x,intersects[0].point.z);
    var pitch = Math.asin(-(intersects[0].point.y)/radius);

    document.addEventListener("click",OnDocumentClick,false);

    function OnDocumentClick(event)
    {
        //get the point coordinates which you click on the sphere surface
        var vector = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
        vector = vector.unproject(camera);
        var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
        var intersects = raycaster.intersectObjects([sphere],true);
        if(intersects.length > 0)
        {
            //get click point spherical coordinates
            var heading1 = Math.atan2(intersects[0].point.x,intersects[0].point.z);
            var pitch1 = Math.asin(-(intersects[0].point.y)/radius);
            //calculate displacement of click point to intersected point
            var delta_heading = heading - heading1;
            var delta_pitch = pitch - pitch1;
            var target_pitch = parseFloat(sphere.rotation.x) +delta_pitch;
            var target_heading = parseFloat(sphere.rotation.y) + delta_heading;

            //using an animation to rotate the sphere
            anime({
                targets:sphere.rotation,
                x:target_pitch,
                y:target_heading,
                elasticity: 0
            });
        }
    }

最后,我使用动画库来使旋转平滑。

以下是我的演示:rotate the earth

我取得了一些进展,之前的版本有点偏差。当我在地球上下来时,我得到了一个糟糕的结果。我认为代码sphere.rotation.x += delta_pitch使球体在对象轴上旋转。但我们需要的是让球体在世界空间轴上旋转。我们知道世界轴坐标总是x_axis = (1,0,0) ; y_axis = (0,1,0) ; z_axis = (0,0,1);然后,我将世界坐标转换为对象坐标,球体矩阵解释球体从缩进旋转到当前旋转。并且逆矩阵解释后缀。所以我们可以将逆矩阵应用于基本轴以获得对象空间坐标。使球体在新轴上旋转。我只是对OnDcoumentClick函数做了一点改动:

            var heading1 = Math.atan2(intersects[0].point.x,intersects[0].point.z);
            var pitch1 = Math.asin(-(intersects[0].point.y)/radius);
            //get the sphere inverse matrix;
            var sphere_matrix = new THREE.Matrix4().copy(sphere.matrix);
            var inverse_sphere_matrix = new THREE.Matrix4();
            inverse_sphere_matrix.getInverse(sphere_matrix);
            //convert world space x and y axises to sphere object space coordinates.
            var x_axis = new THREE.Vector3(1,0,0);
            var y_axis = new THREE.Vector3(0,1,0);
            x_axis.applyMatrix4(inverse_sphere_matrix);
            y_axis.applyMatrix4(inverse_sphere_matrix);

            //calculate displacement of click point to intersected point
            var delta_heading = heading - heading1;
            var delta_pitch = pitch - pitch1;
            //make sphere rotate around whith world x and y axises.
            sphere.rotateOnAxis(x_axis,delta_pitch);
            sphere.rotateOnAxis(y_axis,delta_heading);

以下是我的新演示:rotate earth new version