OpenTK / OpenGL - 带鼠标的旋转摄像头

时间:2015-10-02 15:25:10

标签: c# vb.net opengl math opentk

背景

我目前有一个我正在显示的对象,它始终位于原点。我有一个函数,它增加我的x和y角度,然后计算相机的新x,y,z坐标:

      +---+    
 arr: |'a'|  arr[0][0] <------------------+ before temp++
      +---+                               |
      |'b'|  arr[0][1]                    |
      +---+                               |
      |'c'|  arr[1][0] <--+ after temp++  |   
      +---+               |               |
      |'d'|  arr[1][1]    |               |
      +---+               |               |
       ...                |               |
      +---+               |               |
temp: |   |---------------+---------------+
      +---+

我将此设置为使用键盘事件..X按钮添加到camanglex变量,Y按钮添加到camangley变量,Z按钮添加到距离变量。

使用键盘以这种方式做得很好。

问题

我现在尝试使用鼠标来处理旋转而不是键盘。我相信这只是一个数学问题,但我如何计算新的camanglex和camangley变量,或者直接计算新的camx,camy,camz来建立我的相机的新位置?

我有一个鼠标功能,可以捕捉鼠标坐标,但是计算部分有问题。

1 个答案:

答案 0 :(得分:0)

如果你想围绕物体运行轨道,你可以追踪你的鼠标在假球体上的路径(有时称为轨迹球)。有a working example of orbit controls

这是一个伪代码草图,类似于:

mouseDownEventFunction(event) {
    computeDragPoint (event.mouseX, event.mouseY, &oldDragPoint);
    isMouseDown = true;
}
mouseUpEventFunction(event) {
    isMouseDown = false;
}
mouseMoveEventFunction(event) {
    if (isMouseDown) {
        computeDragPoint (event.mouseX, event.mouseY, &newDragPoint);
        rotateCamera (oldDragPoint, newDragPoint);
        oldDragPoint = newDragPoint;
    }
}

我们在轨迹球上找到了一点:

/* we want to ray trace a point on face side of fake sphere.
dragPoint* is our result*/

computeDragPoint(int x, int y, Vector3* dragPoint) {
    /* normalize x and y to [-1, 1] so they match flat circle position on screen.
    And assign this to dragPoint->x and dragPoint->y. 
    This part depends on what you want to achieve and input units of x, y. 
    Keep in mind aspect ratio */
    dragPoint->x = (2*x/screenWidth - 0.5) * (screenHeight/screenWidth);
    dragPoint->y = 2*y/screenHeight - 0.5;
    dragPoint->x /= sqrt(dragPoint->x*dragPoint->x + dragPoint->y*dragPoint->y);
    dragPoint->y /= sqrt(dragPoint->x*dragPoint->x + dragPoint->y*dragPoint->y);

    /* Then having two values in [-1,1] compute corresponding z */
    float tmp = dragPoint->x*dragPoint->x + dragPoint->y*dragPoint->y;
    if (tmp > 1) {
        dragPoint.x /= sqrt(tmp);
        dragPoint.y /= sqrt(tmp);
    }

    dragPoint->z = -sqrt (1 - dragPoint->x^2 - dragPoint->y^2) || 0;  
}

旋转数学可以使用四元数(或者如果你不想使用quats那样只使用Euler角度的矩阵):

rotateCamera(oldDragPoint, newDragPoint) {
    Quaternion quat = new Quaternion (Config.AngleX, Config.AngleY, Config.AngleZ);
    quat.normalize();

    Quaternion deltaQuat = new Quaternion();
    deltaQuat = deltaQuat.setFromUnitVectors(oldDragPoint, newDragPoint);

    quat = quat.multiply(deltaQuat);
    quat.normalize();

    Vector3 resultAngles = Vector3();
    resultAngles.setFromQuaternion(quat);

    setCameraPositionFromAngles(resultAngles);
}

setCameraPositionFromAngles(resultAngles)中,通过将three basic rotations应用到初始相机位置来设置最终的X,Y,Z坐标。所以你的主要参数是resultAngles。你更新角度,然后设置位置。

也许this working example会更好地解释。