python - 如何让 OpenGL 在 pygame 中绘制非显示表面?

标签 python opengl pygame pyopengl

我正在尝试制作一款看起来像复古太空射击游戏的游戏,其中的线条是 3d 线框。 为了在 Python 中实现 3D,我使用 pygame 作为窗口并使用 PyOpenGL 来渲染对象。

我想让 OpenGL 渲染到一个表面(而不是显示表面),然后通过 pygame 放大表面并将其渲染到显示表面上。这有望在适合在现代屏幕上工作的同时提供低分辨率窗口的效果。

阻止我这样做的是 OpenGL 渲染到显示表面,我找不到任何允许我更改它绘制到的表面的选项。

所以过程应该是:OpenGL 渲染到小表面,pygame 缩放表面并将其绘制到显示屏,重复。

这是我当前的代码:

def main():
    pygame.init()
    display = (500,500)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL) # Create display window

    gluPerspective(70, (display[0]/display[1]), 0.1, 50.0) # Setup view

    glTranslatef(0.0,0.0, -5) # Set view position

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT: # If X is clicked
                pygame.quit() # Close
                quit()
        glRotatef(1, 3, 1, 1) # Rotates view
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) # Clears the screen
        Cube() # Renders the cube onto the screen
        pygame.display.flip() # Updates the display
        pygame.time.wait(10)

main()

我已经尝试创建一个与显示器具有完全相同设置的表面,但 OpenGL 仍然不会将其渲染到该表面。

最佳答案

你必须创建一个 Framebuffer Object (在主循环之前)分辨率小于窗口分辨率。另见 Framebuffer Object Extension Examples :

fb_size = [50, 50]

depth_buffer_obj = glGenRenderbuffers(1)
glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer_obj)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fb_size[0], fb_size[1])

color_buffer_obj = glGenRenderbuffers(1)
glBindRenderbuffer(GL_RENDERBUFFER, color_buffer_obj)
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, fb_size[0], fb_size[1])

fb_obj = glGenFramebuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER, fb_obj)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer_obj)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_buffer_obj)

status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
if status != GL_FRAMEBUFFER_COMPLETE:
    print("incomplete framebuffer object")
glBindFramebuffer(GL_FRAMEBUFFER, 0)

将视口(viewport)的大小设置为帧缓冲区的大小,清除帧缓冲区并将立方体渲染到Framebuffer。 :

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit() 
            quit()

    glBindFramebuffer(GL_FRAMEBUFFER, fb_obj)
    glViewport (0, 0, fb_size[0], fb_size[1])
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

    glRotatef(1, 3, 1, 1)
    Cube()

将视口(viewport)大小设置为窗口大小并使用glBlitFramebuffer使用过滤器参数 GL_NEAREST 将像素从命名的帧缓冲区对象复制到默认帧缓冲区。请注意,没有必要清除默认帧缓冲区,因为它已被完全覆盖:

while True:

    # .....

    glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_obj)
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)
    glViewport(0, 0, 500, 500)

    glBlitFramebuffer(
        0, 0, fb_size[0], fb_size[1],
        0, 0, 500, 500,
        GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
        GL_NEAREST)

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

请注意,glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_obj) 行不是必需的,因为此时 fb_obj 已绑定(bind)用于读取和绘制。


如果您的系统不支持 glBlitFramebuffer,您可以创建一个带有附加到其颜色平面的纹理的帧缓冲区:

fb_size = [50, 50]

depth_buffer_obj = glGenRenderbuffers(1)
glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer_obj)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fb_size[0], fb_size[1])

#color_buffer_obj = glGenRenderbuffers(1)
#glBindRenderbuffer(GL_RENDERBUFFER, color_buffer_obj)
#glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, fb_size[0], fb_size[1])

color_tex_obj = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, color_tex_obj)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fb_size[0], fb_size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, None)

fb_obj = glGenFramebuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER, fb_obj)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer_obj)
#glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_buffer_obj)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_tex_obj, 0)

status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
if status != GL_FRAMEBUFFER_COMPLETE:
    print("incomplete framebuffer object")
glBindFramebuffer(GL_FRAMEBUFFER, 0)
glBindTexture(GL_TEXTURE_2D, 0) 

渲染到帧缓冲区并在整个窗口上绘制一个带有纹理的四边形到默认帧缓冲区:

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit() 
            quit()

    glBindFramebuffer(GL_FRAMEBUFFER, fb_obj)
    glViewport (0, 0, fb_size[0], fb_size[1])
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

    glRotatef(1, 3, 1, 1)
    gluSphere(gluNewQuadric( ), 2.0, 32, 32)

    glBindFramebuffer(GL_FRAMEBUFFER, 0)
    glViewport(0, 0, 500, 500)
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

    glMatrixMode(GL_PROJECTION)
    glPushMatrix()
    glLoadIdentity()
    glMatrixMode(GL_MODELVIEW)
    glPushMatrix()
    glLoadIdentity()

    #glBlitFramebuffer(
    #    0, 0, fb_size[0], fb_size[1],
    #    0, 0, 500, 500,
    #    GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
    #    GL_NEAREST)

    glEnable(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, color_tex_obj)
    glBegin(GL_TRIANGLE_FAN)
    glTexCoord2f(0,0)
    glVertex2f(-1,-1)
    glTexCoord2f(1,0)
    glVertex2f(1,-1)
    glTexCoord2f(1,1)
    glVertex2f(1,1)
    glTexCoord2f(0,1)
    glVertex2f(-1,1)
    glEnd()
    glDisable(GL_TEXTURE_2D)

    glMatrixMode(GL_PROJECTION)
    glPopMatrix()
    glMatrixMode(GL_MODELVIEW)
    glPopMatrix()

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

关于python - 如何让 OpenGL 在 pygame 中绘制非显示表面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53748691/

相关文章:

python - 添加到购物车时 selenium 失败,如何单击 javascript 按钮?

python - 数据点颜色从预先指定的点呈放射状变化

python - 将碰撞检测添加到 pygame 中的平台

python - 如何让 Sprite 从 pygame 中的随机 x 位置掉落

python - 图片不更新pygame

python - 使用自定义 __getitem__ 方法解包的参数永远不会终止

Python Pythonic 方式来组织/设计 if 语句

opengl - 我可以在调用glLinkProgram后调用glDeleteShader吗?

opengl - GLSL 2D 圆角

linux - 如何在 linux 中使用 CMake 和 Kdevelop 编译 GLUT + OpenGL 项目?