【问题标题】:how to get vertical rotation in 3D space with OpenGL?如何使用 OpenGL 在 3D 空间中获得垂直旋转?
【发布时间】:2019-09-02 10:15:40
【问题描述】:

我在 OpenGL 中创建了一个多维数据集字段,并且按预期工作,并且旋转“相机”的一部分正在工作,直到我尝试向上或向下看。

我有一段可以运行的代码:

if pressed[pygame.K_UP] or pressed[pygame.K_DOWN]:
            rotx = cos(rot/radian)
            rotz = sin(rot/radian)
            if pressed[pygame.K_UP]:
                glRotatef(speed / 2, -rotx, 0, rotz)
            if pressed[pygame.K_DOWN]:
                glRotatef(speed / 2, rotx, 0, -rotz)

但它只在 rot 为 0 时有效。所以当我第一次运行程序时,如果我只左右移动,我可以上下查看,而不是左右看,或者前后移动。

verticies = (
    (1, -1, -1),
    (1, 1, -1),
    (-1, 1, -1),
    (-1, -1, -1),
    (1, -1, 1),
    (1, 1, 1),
    (-1, -1, 1),
    (-1, 1, 1)
    )

edges = (
    (0,1),
    (0,3),
    (0,4),
    (2,1),
    (2,3),
    (2,7),
    (6,3),
    (6,4),
    (6,7),
    (5,1),
    (5,4),
    (5,7)
    )


def Cube(tX, tY, tZ):
    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3f(verticies[vertex][0] + tX, verticies[vertex][1] + tY, verticies[vertex][2] + tZ)
    glEnd()


def main():
    pygame.init()
    screenSize = (1500, 800)
    pygame.display.set_mode(screenSize, DOUBLEBUF|OPENGL)

    gluPerspective(45, (screenSize[0]/screenSize[1]), 0.1, 50.0)

    rot = 0
    speed = 3
    radian = 57.2958
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        pressed = pygame.key.get_pressed()

        #==# Rotation with arrow keys #==#
        if pressed[pygame.K_LEFT]:
            glRotatef(speed / 2, 0, -1, 0)
            rot += 1
        if pressed[pygame.K_RIGHT]:
            glRotatef(speed / 2, 0, 1, 0)
            rot -= 1
        if pressed[pygame.K_UP] or pressed[pygame.K_DOWN]:
            rotx = cos(rot/radian)
            rotz = sin(rot/radian)
            if pressed[pygame.K_UP]:
                glRotatef(speed / 2, -rotx, 0, rotz)
            if pressed[pygame.K_DOWN]:
                glRotatef(speed / 2, rotx, 0, -rotz)

        #==# Walking with WASD #==#
        if pressed[pygame.K_w]:
            glTranslate(sin(rot/radian) / speed, 0, cos(rot/radian) / speed)
        if pressed[pygame.K_s]:
            glTranslate(-sin(rot/radian) / speed, 0, -cos(rot/radian) / speed)

        if pressed[pygame.K_a]:
            glTranslate(sin((rot + 90)/radian) / speed, 0, cos((rot + 90)/radian) / speed)
        if pressed[pygame.K_d]:
            glTranslate(-sin((rot + 90)/radian) / speed, 0, -cos((rot + 90)/radian) / speed)


        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

        for i in range(8):
            for j in range(8):
                Cube(-i*2.5, -4, -j*2.5)

        pygame.display.flip()
        pygame.time.wait(10)

main()

我认为这可以作为 FPS 游戏中的运动和摄像头,但事实并非如此。

【问题讨论】:

    标签: python opengl pygame trigonometry opengl-compat


    【解决方案1】:

    这完全是顺序问题。 OpenGL 是一个状态引擎。每个操作都会改变一个状态。当您执行glTranslatefglRotatef 之类的操作时,矩阵堆栈上的当前矩阵会更改。

    在 OpenGL 中有不同的矩阵,例如模型视图矩阵和投影矩阵。您要做的第一件事是将投影矩阵和模型 vie 矩阵分开。这可以通过设置矩阵模式来完成(参见glMatrixMode):

    glMatrixMode(GL_PROJECTION)
    gluPerspective(45, (screenSize[0]/screenSize[1]), 0.1, 50.0)
    glMatrixMode(GL_MODELVIEW)
    
    # [...]
    

    当a矩阵运算应用于矩阵堆栈时,当前矩阵乘以新的(附加)矩阵,该矩阵由该运算定义。这意味着 glRotatef 后跟 glTranslatef 死了:

    current_matrix = current_matrix * rotation_matrix * translation_matrix
    

    问题在于,如果您想在第一人称视图中应用新的平移或旋转,则必须在当前视图(当前模型视图矩阵)上应用新的变换。这意味着必须以与矩阵运算相反的顺序执行运算:

    current_matrix = rotation_matrix * translation_matrix * current_matrix
    

    您已尝试通过考虑当前视图方向来补偿这一点,该方向是您通过三角函数计算的。但有替代解决方案:

    current_mv_mat = (GLfloat * 16)() 
    glGetFloatv(GL_MODELVIEW_MATRIX, current_mv_mat)
    glLoadIdentity()
    
    # [...] glTranslatef, glRotatef
    
    glMultMatrixf(mv)
    

    更多的技巧是必须在当前视图上执行的上下旋转,但遗憾的是它不应该在当前矩阵中说明,因为移动和左右旋转不应该依赖于上下视图:

    current_matrix = rotation_matrix * translation_matrix * current_matrix
    mdel_view_matrix = roate_updown * current_matrix
    

    幸运的是,当前矩阵是在堆栈上管理的,可以由glPushMatrix / glPopMatrix 推送和弹出。向上广告向下旋转必须进行总结并最终应用于视图:

    glPushMatrix()
    
    current_mv_mat = (GLfloat * 16)()
    glGetFloatv(GL_MODELVIEW_MATRIX, current_mv_mat)
    glLoadIdentity()
    glRotatef(sum_rot_updown, 1, 0, 0)
    glMultMatrixf(mv)
    
    # [...] draw all the objects of the scene
    
    glPopMatrix()
    

    查看示例,我将建议应用于您的原始代码:

    def main():
        pygame.init()
        screenSize = (1500, 800)
        pygame.display.set_mode(screenSize, DOUBLEBUF|OPENGL)
    
        glMatrixMode(GL_PROJECTION)
        gluPerspective(45, (screenSize[0]/screenSize[1]), 0.1, 50.0)
        glMatrixMode(GL_MODELVIEW)
    
        rot = 0
        speed = 3
        radian = 57.2958
        sum_rot_updown = 0
        current_mv_mat = (GLfloat * 16)()
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()
    
            pressed = pygame.key.get_pressed()
    
            glGetFloatv(GL_MODELVIEW_MATRIX, current_mv_mat)
            glLoadIdentity()
    
            #==# Rotation left and right with arrow keys #==#
            if pressed[pygame.K_LEFT]:
                glRotatef(speed / 2, 0, -1, 0)
                rot += 1
            if pressed[pygame.K_RIGHT]:
                glRotatef(speed / 2, 0, 1, 0)
                rot -= 1
    
            #==# Walking with WASD #==#
            if pressed[pygame.K_w]:
                glTranslate(0, 0, 1/speed)
            if pressed[pygame.K_s]:
                glTranslate(0, 0, -1/speed)
            if pressed[pygame.K_a]:
                glTranslate(1/speed, 0, 0)
            if pressed[pygame.K_d]:
                glTranslate(-1/speed, 0, 0)
    
            glMultMatrixf(current_mv_mat)
    
            #==# Rotation up and down with arrow keys #==# 
            if pressed[pygame.K_UP]:
                sum_rot_updown -= speed / 2
            if pressed[pygame.K_DOWN]:
                sum_rot_updown += speed / 2
    
            glPushMatrix()
    
            glGetFloatv(GL_MODELVIEW_MATRIX, current_mv_mat)
            glLoadIdentity()
            glRotatef(sum_rot_updown, 1, 0, 0)
            glMultMatrixf(current_mv_mat)
    
            glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    
            for i in range(8):
                for j in range(8):
                    Cube(-i*2.5, -4, -j*2.5)
    
            glPopMatrix()
    
            pygame.display.flip()
            pygame.time.wait(10)
    
    main()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-06
      • 1970-01-01
      • 2015-10-19
      • 2021-04-23
      • 1970-01-01
      相关资源
      最近更新 更多