轨迹球转动不正确

Trackball doesn't turn correctly

我正在尝试通过参考此来源来实现轨迹球 https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Arcball and https://www.khronos.org/opengl/wiki/Object_Mouse_Trackball

但是得到旋转轴后好像没有正确转动

这是我的代码片段

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

这是主要内容

    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])

通常您的代码工作正常。根据您编写的参考资料,您的 compute_z 函数可能如下所示:

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

或更简单:

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)

其中SPHERE_R是一个假想球体的半径(默认为1),因为当鼠标在球体外部点击时,可能会发生奇怪的事情,而第一个代码将形状近似为双曲线sheet(继this reference) and second following this reference.

angleaxis 值在我检查时计算正确。

此外旋转向量应该是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)

glRotatef函数运行正常(你也可以改变x轴的方向,但它仍然运行良好。

当你执行很多旋转时,你会发现轴不是按常理放置的,因为那些旋转,但是当你小心地慢慢移动 up/down of left/right使用鼠标 - 你会看到轴已经旋转但立方体仍在旋转。

有一个技巧可能会改变您正在旋转的内容并已使用 here。这样旋转是在对象坐标中进行的。我粘贴了描述,但请遵循上面的详细信息。

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).