在pyopengl中无限渲染透明图像

Posted

技术标签:

【中文标题】在pyopengl中无限渲染透明图像【英文标题】:Transparent image rendering infinitely in pyopengl 【发布时间】:2021-12-05 06:49:35 【问题描述】:

我已从这篇帖子 here 中获取代码。我的主要目标是在 OpenGL 中绘制我的整个 PyGame 项目,以便它能够更好地运行。我遇到的问题是我有一个有点透明的图像,看起来它被无限绘制并且失去了颜色和不透明度。我也尝试过其他不透明的图像,它似乎在做同样的事情。

Link for the transparent image I am using.

代码:

import pygame
from OpenGL.GL import *
from pygame.locals import *

pygame.init()
pygame.display.set_mode((1900, 900), OPENGL | DOUBLEBUF | pygame.OPENGLBLIT)
pygame.display.init()
info = pygame.display.Info()

# basic opengl configuration
glViewport(0, 0, info.current_w, info.current_h)
glDepthRange(0, 1)
glMatrixMode(GL_PROJECTION)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glShadeModel(GL_SMOOTH)
glClearColor(0.0, 0.0, 0.0, 0.0)
glClearDepth(1.0)
glDisable(GL_DEPTH_TEST)
glDisable(GL_LIGHTING)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glEnable(GL_BLEND)

# Images
sun = pygame.image.load("menuimages/sun.png").convert_alpha()

texID = glGenTextures(1)
def surfaceToTexture( pygame_surface ):
    global texID
    rgb_surface = pygame.image.tostring(pygame_surface, 'RGB')
    glBindTexture(GL_TEXTURE_2D, texID)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
    surface_rect = pygame_surface.get_rect()
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, surface_rect.width, surface_rect.height, 0, GL_RGB, GL_UNSIGNED_BYTE, rgb_surface)
    glGenerateMipmap(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, 0)


clock = pygame.time.Clock()

# make an offscreen surface for drawing PyGame to
offscreen_surface = pygame.Surface((info.current_w, info.current_h))

while True:
    offscreen_surface.blit(sun, (50, 250))

    # prepare to render the texture-mapped rectangle
    glClear(GL_COLOR_BUFFER_BIT)
    glLoadIdentity()
    glDisable(GL_LIGHTING)
    glEnable(GL_TEXTURE_2D)

    #draw texture openGL Texture
    surfaceToTexture( offscreen_surface )
    glBindTexture(GL_TEXTURE_2D, texID)
    glBegin(GL_QUADS)
    glTexCoord2f(0, 0); glVertex2f(-1, 1)
    glTexCoord2f(0, 1); glVertex2f(-1, -1)
    glTexCoord2f(1, 1); glVertex2f(1, -1)
    glTexCoord2f(1, 0); glVertex2f(1, 1)
    glEnd()

    pygame.display.flip()
    clock.tick(60)

感谢任何帮助。

【问题讨论】:

【参考方案1】:

IT 没有必要在应用程序循环中调用surfaceToTexture。在循环之前调用一次,但在循环中绑定纹理。

此外,您还必须处理应用程序循环中的事件。分别见pygame.event.get()pygame.event.pump()

对于游戏的每一帧,您都需要对事件队列进行某种调用。这确保您的程序可以在内部与操作系统的其余部分进行交互。

offscreen_surface.blit(sun, (50, 250))
surfaceToTexture( offscreen_surface )

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

    # prepare to render the texture-mapped rectangle
    glClear(GL_COLOR_BUFFER_BIT)
    glLoadIdentity()
    glDisable(GL_LIGHTING)
    glEnable(GL_TEXTURE_2D)

    #draw texture openGL Texture
    glBindTexture(GL_TEXTURE_2D, texID)
    glBegin(GL_QUADS)
    glTexCoord2f(0, 0); glVertex2f(-1, 1)
    glTexCoord2f(0, 1); glVertex2f(-1, -1)
    glTexCoord2f(1, 1); glVertex2f(1, -1)
    glTexCoord2f(1, 0); glVertex2f(1, 1)
    glEnd()

    pygame.display.flip()
    clock.tick(60)

现有的纹理对象 (texID) 可以使用 glTexSubImage2D 进行更改:

def updateTexture(pygame_surface, texID):
    rgb_surface = pygame.image.tostring(pygame_surface, 'RGB')
    surface_rect = pygame_surface.get_rect()
    glBindTexture(GL_TEXTURE_2D, texID)
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surface_rect.width, surface_rect.height, GL_RGB, GL_UNSIGNED_BYTE, rgb_surface)

当您想要移动时,您应该更喜欢仅绘制和移动“小”图像。用glOrtho 设置Orthographic projection 并用窗口坐标指定四边形顶点。

另请参阅Render pygame sprites with pyopengl 或 PyGame and OpenGL immediate mode (Legacy OpenGL)

完整示例:

import pygame
from OpenGL.GL import *
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((1900, 900), OPENGL | DOUBLEBUF | pygame.OPENGLBLIT)
pygame.display.init()
info = pygame.display.Info()

# basic opengl configuration
glViewport(0, 0, info.current_w, info.current_h)
glDepthRange(0, 1)
glMatrixMode(GL_PROJECTION)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glShadeModel(GL_SMOOTH)
glClearColor(0.0, 0.0, 0.0, 0.0)
glClearDepth(1.0)
glDisable(GL_LIGHTING)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)

# Images
sun = pygame.image.load("menuimages/sun.png").convert_alpha()

def surfaceToTexture(pygame_surface):
    texID = glGenTextures(1)
    rgb_surface = pygame.image.tostring(pygame_surface, 'RGBA')
    glBindTexture(GL_TEXTURE_2D, texID)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
    surface_rect = pygame_surface.get_rect()
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface_rect.width, surface_rect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgb_surface)
    glGenerateMipmap(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, 0)
    return texID

def drawTextureImage(textureId, rect):
    glEnable(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, textureId)
    glBegin(GL_QUADS)
    glTexCoord2f(0, 0); glVertex2f(rect.left, rect.bottom)
    glTexCoord2f(0, 1); glVertex2f(rect.left, rect.top)
    glTexCoord2f(1, 1); glVertex2f(rect.right, rect.top)
    glTexCoord2f(1, 0); glVertex2f(rect.right, rect.bottom)
    glEnd()
    glDisable(GL_TEXTURE_2D)

clock = pygame.time.Clock()

sun_x = 0
texID = surfaceToTexture(sun)

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

    sun_x = (sun_x + 1) % screen.get_width()
    sun_rect = sun.get_rect(topleft = (sun_x, 250))

    glViewport(0, 0, screen.get_width(), screen.get_height())
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(0, screen.get_width(), 0, screen.get_height(), -1, 1)
    glMatrixMode(GL_MODELVIEW)

    # prepare to render the texture-mapped rectangle
    glClear(GL_COLOR_BUFFER_BIT)
    glLoadIdentity()
    glDisable(GL_LIGHTING)
    glDisable(GL_DEPTH_TEST)
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

    #draw texture openGL Texture
    drawTextureImage(texID, sun_rect)

    pygame.display.flip()
    clock.tick(60)

【讨论】:

以上是关于在pyopengl中无限渲染透明图像的主要内容,如果未能解决你的问题,请参考以下文章

Libgdx/Opengl alpha blending(结果 alpha 被源 alpha 替换)

在 OpenGL 中渲染透明块

如何将 PYopenGL 写入 JPG 图像

在 OpenGL 中渲染一个*填充的*半透明立方体

OpenGL - 在附加层下渲染透明度

渲染具有透明度的纹理时 OpenGL 不需要的像素