Search code examples
pythonopenglrotationpyopengl

openGL trouble rotating squares around their own axis


I'm using the mouse to rotate the cube. The problem is that instead of rotating around its own center, the cube rotates around the origin and kind of just orbits it.

def mouseMovement(event):
    global lastPosX, lastPosY, xRot, yRot, zRot

    if event.type == pygame.MOUSEBUTTONDOWN and event.button == 4:  # scroll in
        glScaled(1.03, 1.03, 1.03)
    elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 5: # scroll out
        glScaled(0.97, 0.97, 0.97)
    
    if event.type == pygame.MOUSEMOTION:
        x, y = event.pos
        dx = x - lastPosX
        dy = y - lastPosY
        
        mouseState = pygame.mouse.get_pressed()
        if mouseState[0]:   # left click occured
            modelView = (GLfloat * 16)()
            mvm = glGetFloatv(GL_MODELVIEW_MATRIX, modelView)

            temp = (GLfloat * 3)()
            temp[0] = modelView[0]*dy + modelView[1]*dx
            temp[1] = modelView[4]*dy + modelView[5]*dx
            temp[2] = modelView[8]*dy + modelView[9]*dx
            norm_xy = math.sqrt(temp[0]*temp[0] + temp[1]*temp[1] + temp[2]*temp[2])
            glTranslatef(-CUBE_SIZE / 2.0, -2.0, -10.0)
            glRotatef(math.sqrt(dx*dx+dy*dy) / 2, temp[0]/norm_xy, temp[1]/norm_xy, temp[2]/norm_xy)
            glTranslatef(CUBE_SIZE / 2.0, 2.0, 10.0)

        lastPosX = x
        lastPosY = y

I believe the problem lies within the above block of code. From other questions I've read, I need to translate back and forth from origin to where I want the cube to go with a rotation in-between.

            glTranslatef(-CUBE_SIZE / 2.0, -2.0, -10.0)
            glRotatef(math.sqrt(dx*dx+dy*dy) / 2, temp[0]/norm_xy, temp[1]/norm_xy, temp[2]/norm_xy)
            glTranslatef(CUBE_SIZE / 2.0, 2.0, 10.0)

However it still is rotating around the origin. Any advice?


Solution

  • You need to transform the cube so that the center of the cube is at (0, 0, 0). Then rotate the cube and finally place the cube in its position in the world:

    v' = world_translate * rotate * origin0_translate * v
    

    If the left, bottom, near model coordinate of the cube is (0, 0, 0) and the right, top, far model coordinate is (CUBE_SIZE, CUBE_SIZE, CUBE_SIZE), this means:

    glTranslatef(0, 0, -10.0)
    glRotatef(math.sqrt(dx*dx+dy*dy) / 2, temp[0]/norm_xy, temp[1]/norm_xy, temp[2]/norm_xy)
    glTranslatef(-CUBE_SIZE/2, -CUBE_SIZE/2, -CUBE_SIZE/2)
    

    In general, you need to calculate the axis-aligned bounding box (minimum and maximum coordinates) of an object and move the center of the box to (0, 0, 0) before rotating the object:

    min_v # minimum x, y, z coordinate
    max_v # maximum x, y, z coordinate
    
    center_x = (min_v[0] + max_v[0]) / 2
    center_y = (min_v[1] + max_v[1]) / 2
    center_z = (min_v[2] + max_v[2]) / 2
    
    glTranslatef(world_pos_x, world_pos_y, world_pos_z)
    glRotatef(angle, axis_x, axis_y, axis_z)
    glTranslatef(-center_x, -center_y, -center_z)
    

    Note that when drawing a cube, with the left, bottom, near model coordinate (-s/2, -s/2, -s/2) and the right, top, far model coordinate (s/2, s/2), s/2), this would become easier since the center of the cube is (0, 0, 0).