Search code examples
c++openglopengl-compat

OpenGL Rotation in Viewing Space


I want to make an object defined in the modeling space to translate in viewing space. The amount of translation is controlled by clicking and dragging the mouse (varying deltaX and deltaY). And here's the code that works well: (reference https://gist.github.com/ptbrowne/2048812)

glPushMatrix();
glLoadMatrixd(cam2wld[cameraIndex].matrix());
glTranslated(deltaX, deltaY, 0);
glMultMatrixd(wld2cam[cameraIndex].matrix());
glMultMatrixd(obj2wld.matrix());
glGetDoublev(GL_MODELVIEW_MATRIX, obj2wld.matrix());
glPopMatrix();

I also want to rotate the object with respect to the camera(screen)'s x-axis, which the amount of rotation is dependent on the mouse dragging again. However, by changing from

glTranslated(deltaX, deltaY, 0);

to

glRotated(deltaX + deltaY, 1, 0, 0);

The object is translated instead. Any idea how to solve the problem? Thanks.


Solution

  • I assume that wld2cam[cameraIndex] is the view matrix and cam2wld[cameraIndex] is the inverse view matrix:

    glLoadMatrixd(cam2wld[cameraIndex].matrix());
    glRotated(deltaY, 1, 0, 0);
    glMultMatrixd(wld2cam[cameraIndex].matrix());
    

    What you actually do is to rotate the the model around the point of view. The rotation axis (1, 0, 0) is the view space x-axis. If the distance of the camera to the model is large and the angle is small, this rotation appears to be a translation:

    You have to define a pivot for the rotation. For instance the origin of the world. In view space the origin of the world:

    const GLdouble *viewMat = cam2wld[cameraIndex].matrix();
    GLdouble pivotX = viewMat[12];
    GLdouble pivotY = viewMat[13];
    GLdouble pivotZ = viewMat[14];
    
    glLoadMatrixd(cam2wld[cameraIndex].matrix());
    
    glTranslated(pivotX, pivotY, pivotZ);
    glRotated(deltaY, 1, 0, 0);
    glTranslated(-pivotX, -pivotY, -pivotZ);
    
    glMultMatrixd(wld2cam[cameraIndex].matrix());
    

    If you want to do complex matrix operations, then I recommend to use a library like OpenGL Mathematics (GLM):

    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    
    glm::dmat4 c2w = glm::make_mat4<double>(cam2wld[cameraIndex].matrix());
    glm::dmat4 t   = glm::translate(glm::dmat4(1.0), glm::dvec3( deltaX, deltaY, 0.0));
    glm::dmat4 w2c = glm::make_mat4<double>(wld2cam[cameraIndex].matrix());
    glm::dmat4 o2w = glm::make_mat4<double>(obj2wld.matrix());
    
    glm::dmat final = c2w * t * w2c * o2w;
    glLoadMatrixd(glm::value_ptr(final));