用鼠标旋转地球仪

时间:2013-02-19 19:51:57

标签: javascript math opengl-es geometry webgl

我可以确定用户在地球上的位置clicked

当用户第一次点击鼠标按钮时,我可以存储他们点击的位置;我们称之为pin

然后,当他们拖动鼠标时,我想将pin放在鼠标光标下。

enter image description here

以下是一些代码似乎大致将pin保留在鼠标指针下,但未正确维护地球;它随机地闪烁和旋转。有时它会完全翻转轴线,因此地球仪会暂时从前到后。

function evtPos(evt) {
    if(!scene.ortho) return null;
    var x = lerp(scene.ortho[0],scene.ortho[1],evt.clientX/canvas.width),
        y = lerp(scene.ortho[3],scene.ortho[2],evt.clientY/canvas.height), // flipped
        sqrd = x*x+y*y;
    return (sqrd > 1)?
        null:
        mat4_vec3_multiply(mat4_inverse(scene.mvMatrix),[x,y,Math.sqrt(1-sqrd)]);
}

function onMouseDown(evt) {
    pin = evtPos(evt);
}

function onMouseMove(evt,keys,isMouseDown) {
    if(!isMouseDown) return;
    var pt = evtPos(evt);
    if(pin == null) pin = pt;
    if(pt == null) return;
    var d = vec3_sub(pt,pin),
        rotx = Math.atan2(d[1],d[2]),
        roty = (d[2] >= 0)?
            -Math.atan2(d[0] * Math.cos(rotx),d[2]):
            Math.atan2(d[0] * Math.cos(rotx),-d[2]),
        rotz = Math.atan2(Math.cos(rotx),Math.sin(rotx)*Math.sin(roty));
    scene.mvMatrix = mat4_multiply(scene.mvMatrix,mat4_rotation(rotx,[1,0,0]));
    scene.mvMatrix = mat4_multiply(scene.mvMatrix,mat4_rotation(roty,[0,1,0]));
    scene.mvMatrix = mat4_multiply(scene.mvMatrix,mat4_rotation(rotz,[0,0,1]));
}

function onMouseUp(evt) {
    pin = null;
}

此外,随着时间的推移,似乎会出现错误并且pin越来越远离鼠标指针。我认为我应该以某种方式完全计算mvMatrix,而不是每个事件都有很多小的增量?

我希望用户能够拖动地球以自然导航。我发现的旋转球体的所有代码都使用固定速度,例如:箭头键,而不是在鼠标指针下“固定”地球仪。 Unity有一个函数Quaternion.FromToRotation(fromPos,toPos),看起来非常有前途,但源代码不可用。

1 个答案:

答案 0 :(得分:1)

执行此操作的方法之一是arcBall algorithm。甚至有JavaScript implementations可用,因此您无需自己动手。