Eric F
Eric F

Reputation: 948

OpenTK / OpenGL - Rotating camera with mouse

Background

I currently have an object that I am displaying that will always be at the origin. I have a function which increments my x and y angles and then calculates the new x,y,z coordinate for the camera:

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  

I have this set up to use keyboard events.. the X button adds to the camanglex variable, the Y button adds to the camangley variable, and the Z button adds to the distance variable.

Everything works well doing it this way, using the keyboard.

Problem

I am trying to now use the mouse to handle the rotation instead of the keyboard. I believe this is simply a math question but how do I go about calculating either the new camanglex and camangley variables or directly calculating the new camx,camy,camz ones to establish my cameras new location?

I have a mouse function which will capture the mouse coordinates but am having trouble with the calculation part.

Upvotes: 0

Views: 4478

Answers (1)

Ramil Kudashev
Ramil Kudashev

Reputation: 1175

If you want to orbit around object you could trace the path your mouse goes on fake sphere (which is called trackball sometimes). There is a working example of orbit controls.

And here is a pseudocode sketch for something similiar:

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

Here we find a point on trackball:

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

And rotation math can be done with quaternions (or just matrices from Euler angles if you don't want to use quats):

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

And in setCameraPositionFromAngles(resultAngles) set your final X, Y, Z coordinates by applying three basic rotations to your initial camera position. So your main parameters are resultAngles. You renew angles and then set position.

Maybe this working example will explain better.

Upvotes: 1

Related Questions