【问题标题】:How do I make OpenGL draw do a non-display surface in pygame?如何让 OpenGL 在 pygame 中绘制非显示表面?
【发布时间】:2018-12-12 17:50:51
【问题描述】:

我正在尝试制作一款看起来像复古太空射击游戏的游戏,其中的线条是 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 仍然不会将其渲染到该表面。

【问题讨论】:

    标签: python opengl pygame pyopengl


    【解决方案1】:

    您必须创建一个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)
    

    将视口的大小设置为帧缓冲区的大小,清除帧缓冲区并将立方体渲染到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()
    

    将视口大小设置为窗口大小,并使用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 被绑定为读取和绘制。


    如果您的系统不支持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)
    

    【讨论】:

    • 它在倒数第三个函数/行抛出一个 GLError 错误说“glBlitFramebuffer”是一个“无效操作”。
    • 我查看了一些不同的网站,他们对 OpenGL PyOpenGL 使用的版本有不同的看法。 Sourceforge 说它使用 1.1 - 4.4,但 Python wiki 说它使用最高版本 1.2。我打印了GL_VERSION,上面写着“GL_VERSION (7938)”。我找不到将我得到的数字翻译成网站谈论的版本的方法。你知道我用的是什么版本吗?
    • @HarryAnthony: GL_VERSION 是你传递给glGetString() 的枚举。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    • 2013-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多