开发者

Trackball Rotation in OpenGL

开发者 https://www.devze.com 2023-01-22 21:51 出处:网络
I am having trouble implementing a trackball rotation on OpenGL. When I rotate my cube using the trackball rotation 90 degrees to the right along the X axis (dragging mouse left to right on screen) an

I am having trouble implementing a trackball rotation on OpenGL. When I rotate my cube using the trackball rotation 90 degrees to the right along the X axis (dragging mouse left to right on screen) and then try rotating it dragging my mouse from the top to the bottom of the screen, I expect the cube to rotate along my perspective's y-axis. Instead it rotates along ITS y-axis after rotation, rotating sideways from my perspec开发者_C百科tive.

Can someone show me what I may be doing wrong?


It sounds like you're not using quaternions to represent the rotation. If you Google for "Arcball Graphics Gems" you should be able to find code by Ken Shoemake’s in Graphic Gems IV.

Or, if you just want the code, go here.


+1 for Daniel's advice about quaternions and Arcball. You should always be using quaternions to represent orientations and rotations.

One additional tip: the extension of Arcball implemented by Gavin Bell makes it much more intuitive for mouse clicks outside the rotation sphere. It is distributed with in the examples of the Glut library, here and here.

It is similar to the NeHe implementation, but the transition between inside and outside the sphere is smooth. Bell's approach is used in a number of open source 3D libraries, including:

  • The Blender project
  • Meshlab / VCGlib.


This is a very old question, but I just came across the exact same problem, as I was trying to adapt the camera code from learnopengl.com to the Arcball model...

Importantly, I didn't want to move to quaternions, as anything done with them can also be done using standard Linear Algebra.

A solution I found was to transform the arcball's coordinates into the camera coordinates (as if the arcball were rotating along with the camera).

I also rotate the Postion, Front and Up vectors of my camera by using the Rodrigues' formula, and then resort to glm:LookAt to return the final ViewMatrix (the one that is fed into the Vertex shader).

For the moment I have a quick and dirty solution, which looks as follows:

// Processes input received from a mouse input system. 
void ProcessMouseMovement(glm::vec2 prevMouse, glm::vec2 curMouse)
{
    glm::vec3 p1 = screen_to_arcball( curMouse );
    glm::vec3 p2 = screen_to_arcball( prevMouse );
    
    // Rotate arcball to camera coordinates
    p1 = glm::vec3( glm::inverse(ViewMatrix) * glm::vec4(p1, 0.0));
    p2 = glm::vec3( glm::inverse(ViewMatrix) * glm::vec4(p2, 0.0));
    
    glm::vec3 axis = glm::cross(p1, p2);

    float angle = std::acos(glm::dot(p1,p2));

    if ( angle > 0.001f)
    {
        // Rotate
        Position = rotate_axis_angle(Position, axis, angle);
        Front = rotate_axis_angle(Front, axis, angle);
        Up = rotate_axis_angle(Up, axis, angle);

        ViewMatrix = glm::lookAt(Position, Position + Front, Up);
    }
}

// Get Arcball coordinates from screen
glm::vec3 screen_to_arcball(const glm::vec2 &p)
{
    const float dist = glm::dot(p, p);
    if (dist < 0.999f) 
    {
        // If we're on/in the sphere return the point on it
        return glm::vec3(p.x, p.y, std::sqrt(1.f - dist));
    } 
    else 
    {
        // otherwise we project the point onto the sphere
        const glm::vec2 proj = glm::normalize(p);
        return glm::vec3(proj.x, proj.y, 0.f);
    }
}

// Rotate vector given (angle,axis) using Rodrigues' formula
glm::vec3 rotate_axis_angle(glm:: vec3 &vec, glm:: vec3 axis, float angle)
{
    axis = glm::normalize(axis);
    glm::vec3 cross_axis = glm::cross(axis, vec);
    vec = vec * std::cos(angle) + axis * glm::dot(axis,vec) * (1.0f - std::cos(angle)) + cross_axis * std::sin(angle); 
    return vec;
}

By the way, I took the screen_to_arcball function from a previous version of ArcballCamera.cpp in Ospray's repository. They have a quaternion-based implementation now, that looks similar to arcball_camera.cpp from Twinklebear.


I found a really cheap and dirty way to do it. So the matrix in OpenGL is like this
0  1  2  3
4  5  6  7
8  9  10 11
12 13 14 15

if you take the 3 vertical numbers as your rotation vector, you're gonna get your desired effect. For example:

If you rotate around vector (0, 4, 8) you will rotate about the x axis.
Similarly (1, 5, 9) will be y, (3, 6, 10) will be z.
Why it works?.... well when you take the vertical numbers, you made a transposed copy of the original matrix and that gives you a some sort of origin matrix compared to the rotated matrix..... Sorry I'm no mathematician but it works. Trust me ;).

My example code on OpenGL ES:

        Matrix.rotateM(Settings.anchorMatrix, 0, rX, Settings.anchorMatrix[0], Settings.anchorMatrix[4], Settings.anchorMatrix[8]);
        Matrix.rotateM(Settings.anchorMatrix, 0, rY, Settings.anchorMatrix[1], Settings.anchorMatrix[5], Settings.anchorMatrix[9]);
        Matrix.rotateM(Settings.anchorMatrix, 0, rZ, Settings.anchorMatrix[2], Settings.anchorMatrix[6], Settings.anchorMatrix[10]);

anchorMatrix is technically the my main matrix I created on the side for track keeping. Android OpenGL ES doesn't let me grab the current matrix from the state machine.

0

精彩评论

暂无评论...
验证码 换一张
取 消