Bramanta
Bramanta

Reputation: 441

Trackball doesn't turn correctly

i'm trying to implement trackball by referring to this source https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Arcball and https://www.khronos.org/opengl/wiki/Object_Mouse_Trackball

but after getting the rotation axis it doesn't seem to turn correctly

here's some snippet of my code

def compute_z(x, y):
    # compute z from sphere model
    # sphere size = 1
    z = math.sqrt(abs(1 - math.pow(x,2) - math.pow(y,2)))
    return z

def get_rotation_axis(vect_1, vect_2):
    # determine rotation direction
    axis = np.cross(vect_1, vect_2)
    return axis

here's the main

    while True:
        mouse_pos = pygame.mouse.get_pos()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.MOUSEMOTION:
                if arcball_on:
                    cur_mx = mouse_pos[0]
                    cur_my = mouse_pos[1]
                    last_conv = convert_range(last_mx, last_my)
                    cur_conv = convert_range(cur_mx, cur_my)
                    a = (last_conv[0], last_conv[1], compute_z(last_conv[0], last_conv[1]))
                    b = (cur_conv[0], cur_conv[1], compute_z(cur_conv[0], cur_conv[1]))
                    angle = compute_angle(a, b)
                    axis = get_rotation_axis(a, b)
                    print(axis)
                    glRotatef(angle, axis[0], axis[1], -axis[2])

Upvotes: 3

Views: 168

Answers (1)

Benjamin
Benjamin

Reputation: 3448

Generally your code works fine. Based on the references that you wrote, your compute_z function might look like this:

def compute_z(x, y):
    # compute z from sphere model
    op_squared = x ** 2 + y ** 2
    r_squared = SPHERE_R ** 2
    if op_squared > r_squared / 2:
        z = r_squared / 2 / math.sqrt (op_squared)
    else:
        z = math.sqrt(r_squared - op_squared)
    return z

or even simpler:

def compute_z(x, y):
    # compute z from sphere model
    op_squared = x ** 2 + y ** 2
    r_squared = SPHERE_R ** 2
    if op_squared > r_squared:
        return 0
    else:
        return math.sqrt(r_squared - op_squared)

where SPHERE_R is the radius of a hypothetical sphere (default 1), because when the mouse clicks outside of the sphere, strange things might happen, while the first code approximates the shape to the hyperbolic sheet (following this reference) and second following this reference.

The angle and axis values are calculated correctly as I checked.

Furthermore the rotation vector should be normalized:

def normalize(x):
    x = np.asarray(x)
    if np.linalg.norm(x):
        return x / np.linalg.norm(x)
    else:
        return x

# .....

a = (last_conv[0], last_conv[1], compute_z(last_conv[0], last_conv[1]))
b = (cur_conv[0], cur_conv[1], compute_z(cur_conv[0], cur_conv[1]))
a = normalize(a)
b = normalize(b)
axis = get_rotation_axis(a, b)
axis = normalize(axis)

the glRotatef function is working properly (you might also change the direction of the x axis, but it still works good.

When you perform a lot of rotations, you will see that the axis are not placed by the common sense, because of those rotations, but when you carefully and slowly move up/down of left/right using mouse - you will see that axis have rotated but the cube is still rotating as it should.

There is a trick that might change what you are rotating and it's used here. This way the rotation is made in object coordinates. I paste the description, but follow the details above.

An extra trick is converting the rotation axis from camera coordinates to object coordinates. It's useful when the camera and object are placed differently. For instance, if you rotate the object by 90° on the Y axis ("turn its head" to the right), then perform a vertical move with your mouse, you make a rotation on the camera X axis, but it should become a rotation on the Z axis (plane barrel roll) for the object. By converting the axis in object coordinates, the rotation will respect that the user work in camera coordinates (WYSIWYG). To transform from camera to object coordinates, we take the inverse of the MV matrix (from the MVP matrix triplet).

Upvotes: 1

Related Questions