在 glClear 之后 PyOpenGL 不会多次重绘三角形条

Posted

技术标签:

【中文标题】在 glClear 之后 PyOpenGL 不会多次重绘三角形条【英文标题】:PyOpenGL does not redraw triangle strip more than once after glClear 【发布时间】:2021-03-06 02:37:36 【问题描述】:

在使用 PyOpenGL 和 pygame 编写一个非常简单的介绍性代码时,我偶然发现了一个逻辑错误。立方体(用三角带和glDrawArray 渲染)会在第一帧出现一次,然后在之后的所有帧中消失。

MRE

import pygame
pygame.init()
from OpenGL import GL
from OpenGL import GLU

def solidCube():
    vertices = (-1.0, 1.0, 1.0,
    1.0, 1.0, 1.0,
    -1.0, -1.0, 1.0,
    1.0, -1.0, 1.0,
    1.0, -1.0, -1.0,
    1.0, 1.0, 1.0,
    1.0, 1.0, -1.0,
    -1.0, 1.0, 1.0,
    -1.0, 1.0, -1.0,
    -1.0, -1.0, 1.0,
    -1.0, -1.0, -1.0,
    1.0, -1.0, -1.0,
    -1.0, 1.0, -1.0,
    1.0, 1.0, -1.0)

    GL.glColor3f(255, 255, 255)

    GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
    data = (GL.GLfloat * len(vertices))(*vertices)
    GL.glVertexPointer(3, GL.GL_FLOAT, 0, data)

    GL.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 14)
    GL.glDisableClientState(GL.GL_VERTEX_ARRAY)

display = (600, 500)

screen = pygame.display.set_mode(display, pygame.DOUBLEBUF|pygame.OPENGL)

GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()

GLU.gluPerspective(90, (display[0]/display[1]), 0.1, 100.0)
GLU.gluLookAt(0, 0, 0, -1.0, 0, 0, 0, 1, 0)

game = 1
clock = pygame.time.Clock()
while game:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            game = 0

    GL.glMatrixMode(GL.GL_MODELVIEW)
    GL.glLoadIdentity()

    GL.glClearColor(0, 0, 0, 1)
    GL.glClear(GL.GL_COLOR_BUFFER_BIT|GL.GL_DEPTH_BUFFER_BIT)

    GL.glTranslatef(-10, 0, 0)

    solidCube()

    GL.glMatrixMode(GL.GL_PROJECTION)
    GL.glLoadIdentity()

    GLU.gluLookAt(0, 0, 0, -1.0, 0, 0, 0, 1, 0)
    
    pygame.display.flip()
    clock.tick(50)
    
pygame.quit()

此代码未引发任何错误,但显示立方体的时间不超过一帧,而是闪烁一次,然后不再显示。然后我开始调试。

我的gluLookAtgluPerspective 是静态值,它们没有改变。因此,不可能是我没有看到立方体(它在第一帧正确渲染,这些是正确的值)。我的立方体的位置也是静态的,它没有移动到任何地方,也没有超出我的 FOV。所以,它归结为立方体没有被绘制。我从代码中删除了glClear 语句,立方体忽隐忽现。过去我也遇到过类似的问题,因为该对象仅在两个视频缓冲区之一中,所以pygame.display.flip() 会很快在两者之间切换,将其引入或不存在。

因此,我能够找到我的问题:立方体被绘制一次,然后被渲染(正确)。在此之后,它会清除两个缓冲区并且立方体不会被重绘,所以我只剩下一个空白屏幕。

总而言之,我的问题是:为什么我的三角形条形立方体没有被多次绘制,我该如何解决这个问题并让它重新绘制?

【问题讨论】:

你为什么不在抽奖循环中重新gluPerspective()ing? 还有,你为什么是putting a modelview transform onto the projection stack? 【参考方案1】:

你只是混淆了矩阵。投影矩阵应设置为当前GL_PROJECTION 矩阵,模式视图矩阵应设置为当前GL_MODELVIEW

GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
GLU.gluPerspective(90, (display[0]/display[1]), 0.1, 100.0)

game = 1
clock = pygame.time.Clock()
while game:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            game = 0

    GL.glMatrixMode(GL.GL_MODELVIEW)
    GL.glLoadIdentity()
    GLU.gluLookAt(0, 0, 0, -1.0, 0, 0, 0, 1, 0)

    GL.glClearColor(0, 0, 0, 1)
    GL.glClear(GL.GL_COLOR_BUFFER_BIT|GL.GL_DEPTH_BUFFER_BIT)

    GL.glTranslatef(-10, 0, 0)

    solidCube()

    pygame.display.flip()

请注意,OpenGL 是一个状态引擎。设置状态后,它会一直保留到再次更改,甚至超出帧。 受矩阵运算影响的矩阵由glMatrixMode 指定。矩阵运算,如gluPerspectivegluLookAtglRotateglScaleglTranslatef,不仅设置了一个矩阵,还定义了一个新矩阵并将当前矩阵乘以新矩阵。因此,您可以使用glLoadIdentity“重置”当前矩阵。 glLoadIdentity 将 Identity matrix 分配给当前矩阵。


完整示例:

import numpy as np
import pygame
pygame.init()
from OpenGL import GL
from OpenGL import GLU

def solidCube():
    vertices = (-1.0, 1.0, 1.0,
    1.0, 1.0, 1.0,
    -1.0, -1.0, 1.0,
    1.0, -1.0, 1.0,
    1.0, -1.0, -1.0,
    1.0, 1.0, 1.0,
    1.0, 1.0, -1.0,
    -1.0, 1.0, 1.0,
    -1.0, 1.0, -1.0,
    -1.0, -1.0, 1.0,
    -1.0, -1.0, -1.0,
    1.0, -1.0, -1.0,
    -1.0, 1.0, -1.0,
    1.0, 1.0, -1.0)

    GL.glColor3f(255, 255, 255)

    GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
    data = (GL.GLfloat * len(vertices))(*vertices)
    GL.glVertexPointer(3, GL.GL_FLOAT, 0, data)

    GL.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 14)
    GL.glDisableClientState(GL.GL_VERTEX_ARRAY)

display = (600, 500)

screen = pygame.display.set_mode(display, pygame.DOUBLEBUF|pygame.OPENGL)

GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
GLU.gluPerspective(90, (display[0]/display[1]), 0.1, 100.0)

angle = 0
game = 1
clock = pygame.time.Clock()
while game:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            game = 0

    GL.glMatrixMode(GL.GL_MODELVIEW)
    GL.glLoadIdentity()
    GLU.gluLookAt(0, 0, 0, -1.0, 0, 0, 0, 1, 0)

    GL.glClearColor(0, 0, 0, 1)
    GL.glClear(GL.GL_COLOR_BUFFER_BIT|GL.GL_DEPTH_BUFFER_BIT)

    GL.glTranslatef(-5, 0, 0)
    GL.glRotatef(angle, 0, 1, 0)
    angle += 1

    GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE)
    solidCube()

    pygame.display.flip()
    clock.tick(50)
    
pygame.quit()

【讨论】:

以上是关于在 glClear 之后 PyOpenGL 不会多次重绘三角形条的主要内容,如果未能解决你的问题,请参考以下文章

Python OpenGL第一个三角形(Pyopengl)

pyopengl 帧缓冲区

PyOpenGL 无头渲染

Pyopengl 黑屏

PyOpenGL安装

PyOpenGL - 如何加载在 mtl 文件中定义了颜色的 obj 文件