首页 > 解决方案 > 使用 (py)OpenGL 处理纹理和图像

问题描述

我最近开始进入 pygame 并最终进入 pyOpenGL(仅使用二维),因为使用 pygame 将图像绘制到屏幕上会卡顿。但是,我遇到了两个问题,我一生都无法弄清楚如何解决。即在加载图像时处理两个以上的纹理并解决 pygame 和 OpenGL 的坐标不兼容问题。

我做了一个简单的类,叫做Thingie1

class Thingie1:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.width = 0
        self.height = 0
        self.sprite = "imageOne.png"
        self.lastsprite = ""
        self.img_data = 0
        self.load()

    def load(self):
        if self.sprite != self.lastsprite:
            im = open(self.sprite)
            self.width, self.height, self.img_data = im.size[0], im.size[1], im.tobytes("raw", "RGB", 0, -1)
            self.lastsprite = self.sprite

            self.Texture = glGenTextures(1)
            glBindTexture(GL_TEXTURE_2D, self.Texture)
            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_LINEAR)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, self.width, self.height, 0, GL_RGB, GL_UNSIGNED_BYTE, self.img_data)
            glEnable(GL_TEXTURE_2D)
        else:
            return

    def draw(self):
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        glTranslate(self.x, self.y, 0)
        glBegin(GL_QUADS)
        glVertex(0, 0, 0)
        glTexCoord2f(0, 0)
        glVertex(self.width, 0, 0)
        glTexCoord2f(0, 1)
        glVertex(self.width, self.height, 0)
        glTexCoord2f(1, 1)
        glVertex(0, self.height, 0)
        glTexCoord2f(1, 0)
        glEnd()
        glFlush()

以及所提到的类的精确副本(目前),称为Thingie2. (open()函数来自 PILLOW 的 Image 包(from PIL.Image import open)。)

然后我打电话

pygame.init()
pygame.display.set_mode((1024,768), pygame.DOUBLEBUF | pygame.OPENGL)

if True:
    glClearColor(*(0,0,0,255))
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluOrtho2D(0, 1024, 768, 0)
    Thing1 = Thingie1(200,200)
    Thing2 = Thingie2(0,0)

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

        Thing2.load()
        Thing1.load()

        Thing2.draw()
        Thing1.draw()
        pygame.display.flip()

绘制Thing1在 之上Thing2,这部分工作;以前,当load()anddraw()函数合并为一个时,它可以正确地对对象进行纹理化,但对我的计算机并不完全友好。现在,它使用 Thing2 的纹理对两个类实例进行纹理处理,这是第一个问题。

第二个问题是,绘制的图像旋转了 180°。我已经尝试使用 matplotlib、cv2 和其他包来加载图像,但我最接近解决这个问题的是当我glTexImage2DglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, self.width, self.height, 0, GL_RGB, GL_UNSIGNED_BYTE, self.img_data[::-1])(使用 PIL.Image's open())修改该行时,但这会以灰色+蓝色比例绘制图像(? )。

那么,首先,pyOpenGL 通常如何处理纹理?我希望这两种纹理都将存储在它们各自self.Texture的 s. 他们俩都必然会遇到的问题GL_TEXTURE_2D吗?我将如何区分这两种纹理?

其次,有没有更好的方法来加载图像,或者有没有办法以某种方式格式化图像像素字节数组,以便它可以轻松地反转(这也适用于 RGBA 图像)?

标签: pythonopenglpygamepython-imaging-librarypyopengl

解决方案


请注意,由glBegin/glEnd序列绘制和固定函数矩阵堆栈自几十年以来已被弃用。请参阅固定功能管道旧版 OpenGL。阅读有关顶点规范着色器的信息,了解最先进的渲染方式。


现在,它使用 Thing2 的纹理对两个类实例进行纹理处理,这是第一个问题。

二维纹理由 启用glEnable(GL_TEXTURE_2D)和禁用glDisable(GL_TEXTURE_2D)如果启用了纹理,则应用/序列
绘制几何图形时当前绑定的纹理。glBeginglEnd

在绘制几何之前,您必须绑定正确的纹理:

def draw(self):

    # [...]

    glEnable(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, self.Texture)
    glBegin()

    # [...]     

    glEnd()
    glDisable(GL_TEXTURE_2D)

第二个问题是,绘制的图像旋转了 180°

调用时glVertex,当前纹理坐标与顶点坐标相关联。纹理坐标由 设置glTexCoord2f

这意味着glTexCoord2f必须在之前 glVertex完成。

glBegin(GL_QUADS)

glTexCoord2f(0, 0)
glVertex(0, 0, 0)

glTexCoord2f(0, 1)
glVertex(self.width, 0, 0)

glTexCoord2f(1, 1)
glVertex(self.width, self.height, 0)

glTexCoord2f(1, 0)
glVertex(0, self.height, 0)

glEnd()

推荐阅读