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



我正在尝试制作一款看起来像复古太空射击游戏的游戏,其中的线条是三维线框。为了在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对象(在主循环之前(。另请参阅帧缓冲区对象扩展示例:

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)

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

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)

最新更新