OpenTK/ONGGL-用鼠标旋转相机

本文关键字:旋转 相机 鼠标 ONGGL- OpenTK | 更新日期: 2023-09-27 18:15:48

背景

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

Public Sub update_rotation()
    If cam.manual_lookat = True Then
        If camangley >= 360 Then
            camangley = camangley - 360
        End If
        If camanglex >= 360 Then
            camanglex = camanglex - 360
        End If
        If camangley < 0 Then
            camangley = 360 + camangley
        End If
        If camanglex < 0 Then
            camanglex = 360 + camanglex
        End If
        If camangley > 90 And camangley <= 270 Then
            cam.invert_y = True
        Else
            cam.invert_y = False
        End If

        camx = distance * -Sin(camanglex * (PI / 180)) * Cos((camangley) * (PI / 180))
        camy = distance * -Sin((camangley) * (PI / 180))
        camz = distance * Cos((camanglex) * (PI / 180)) * Cos((camangley) * (PI / 180))
        cam.Position.X = camx
        cam.Position.Y = camy
        cam.Position.Z = camz
        cam.lookat.X = 0
        cam.lookat.Y = 0
        cam.lookat.Z = 0
        ' Label2.Text = camanglex & "," & camangley
    End If
End Sub  

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

用这种方式,用键盘,一切都很好。

问题

我现在试着用鼠标代替键盘来处理旋转。我相信这只是一个数学问题,但我如何计算新的camanglex和camangley变量,或者直接计算新的camx、camy和camz变量,以确定我的相机的新位置?

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

OpenTK/ONGGL-用鼠标旋转相机

如果您想围绕对象进行动态观察,您可以跟踪鼠标在假球体上的路径(有时称为轨迹球(。有一个轨道控制的工作示例。

这里有一个类似的伪代码草图:

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;  
}

旋转数学可以用四元数来完成(如果你不想使用四元数,也可以只使用欧拉角的矩阵(:

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(中,通过对初始相机位置应用三个基本旋转来设置最终的X、Y、Z坐标。所以你的主要参数是resultAngles。你更新角度,然后设置位置。

也许这个工作示例可以更好地解释。