在 Python 中使用 OpenGL 渲染纹理不是

Posted

技术标签:

【中文标题】在 Python 中使用 OpenGL 渲染纹理不是【英文标题】:Rendering a texture with OpenGL in Python is not 【发布时间】:2019-11-19 23:29:41 【问题描述】:

我想使用下面的代码渲染纹理(使用 .png):

一切顺利,直到我取消注释 object_cube.loadTextures()

# Execute with Python 3

import pygame
import random
import math
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *

camera_x = 0
camera_z = 0
camera_y = 0
x = 0

Vertices = [
    [1, -1, 1],
    [-1, -1, 1],
    [-1, -1, -1],
    [1, -1, -1],
    [1, 1, -1],
    [-1, 1, -1],
    [-1, 1, 1],
    [1, 1, 1]
]

class Ground:
    global camera_z

    def __init__(self):
        self.ground_vertices = (
            (-11, -2.01, 20),
            (11, -2.01, 20),
            (11, -2.01, -300),
            (-11, -2.01, -300)
        )

    def draw(self):
        glPushMatrix()
        glTranslatef(0, 0, camera_z)
        glBegin(GL_QUADS)

        for vertex in self.ground_vertices:
            glColor3fv((0, 0.5, 0.5))
            glVertex3fv(vertex)

        glEnd()
        glPopMatrix()


class Cube:
    def __init__(self, v=False):
        self.vertices = [
            [1, -1, 1],
            [-1, -1, 1],
            [-1, -1, -1],
            [1, -1, -1],
            [1, 1, -1],
            [-1, 1, -1],
            [-1, 1, 1],
            [1, 1, 1]
        ]
        self.surfaces = (
            (0, 1, 6, 7),
            (0, 1, 2, 3),
            (0, 3, 4, 7),
            (1, 2, 6, 5),
            (2, 3, 4, 5),
            (4, 5, 6, 7)
        )
        self.colors = (
            (105 / 255, 210 / 255, 231 / 255),
            (167 / 255, 219 / 255, 216 / 255),
            (224 / 255, 228 / 255, 204 / 255),
            (243 / 255, 134 / 255, 48 / 255)
        )
        self.colors2 = (
            (0.91, 0.31, 0.47),
            (0.84, 0.51, 0.54),
            (0.78, 0.64, 0.6),
            (0.78, 0.9, 0.85)
        )
        self.vertices_texture = (
            (0.0, 0.0),
            (1.0, 0.0),
            (1.0, 1.0),
            (0.0, 1.0),
        )
        self.v = v
        self.center = [0, 0, 0]

    def draw(self):
        glBegin(GL_QUADS)

        if not self.v:
            for surface in self.surfaces:
                x = 0
                for vertex in surface:
                    glColor3fv(self.colors2[x])
                    # glTexCoord2f(self.vertices_texture[x])
                    glVertex3fv(self.vertices[vertex])
                    x += 1
        else:
            for surface in self.surfaces:
                x = 0
                for vertex in surface:
                    glColor3fv(self.colors[x])
                    glTexCoord2fv(self.vertices_texture[x])
                    glVertex3fv(self.vertices[vertex])
                    x += 1

        glEnd()


    def set_vertices(self, max_distance, min_distance=-40):
        x_value_change = random.randrange(-10, 10)
        y_value_change = -1
        z_value_change = random.randrange(-1 * max_distance, min_distance)
        new_vertices = []
        for vertex in Vertices:
            new_vertex = []

            new_x = vertex[0] + x_value_change
            new_y = vertex[1] + y_value_change
            new_z = vertex[2] + z_value_change

            new_vertex.append(new_x)
            new_vertex.append(new_y)
            new_vertex.append(new_z)

            new_vertices.append(new_vertex)
        self.vertices = new_vertices
        self.center = [
            (self.vertices[2][0]+self.vertices[7][0])/2,
            (self.vertices[2][1]+self.vertices[7][1])/2,
            (self.vertices[2][2]+self.vertices[7][2])/2
        ]

    def rotate(self):
        glPushMatrix()
        glRotatef(25, 1, 0, 0)
        glPopMatrix()

    def loadTexture(self):
        textureSurface = pygame.image.load('./textures/ursa.png')
        textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
        width = textureSurface.get_width()
        height = textureSurface.get_height()

        glEnable(GL_TEXTURE_2D)
        texid = glGenTextures(1)

        glBindTexture(GL_TEXTURE_2D, texid)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData)

        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        # return texid


def movInverse(event):
    global x
    y = 0
    if event.type == pygame.KEYDOWN:
        if(math.fabs(x) < 11):
            if event.key == pygame.K_LEFT:
                x -= 1
            if event.key == pygame.K_RIGHT:
                x += 1
        else:
            if(x < 0):
                if event.key == pygame.K_RIGHT:
                    x += 1
            else:
                if event.key == pygame.K_LEFT:
                    x -= 1
        if event.key == pygame.K_UP:
            y += 1
        if event.key == pygame.K_DOWN:
            y -= 1

    glTranslatef(0, y, 0)


def leave(event):
    if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == K_ESCAPE):
        pygame.quit()
        quit()


def main():
    global camera_x, camera_y, camera_z, x
    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF | OPENGL | OPENGLBLIT)
    max_distance = 300
    gluPerspective(45, (display[0] / display[1]), 0.1, max_distance)
    glEnable(GL_DEPTH_TEST)
    glTranslatef(0, -10 / 2.4, -50)

    ground = Ground()

    cube = Cube(True)

    # cube.loadTexture()
    # I want to render the texture here, but when I do it, everything get screwed.
    my_cubes = []

    for i in range(50):
        tmp_cube = Cube()
        # tmp_cube.loadTexture()
        # I also tried to render it here, but I got the same result
        tmp_cube.set_vertices(max_distance)
        my_cubes.append(tmp_cube)

    while True:
        for event in pygame.event.get():
            leave(event)
            movInverse(event)

        M = glGetDoublev(GL_MODELVIEW_MATRIX)
        # print(M)
        camera_x = M[3][0]
        camera_y = M[3][1]
        camera_z = M[3][2]

        glTranslatef(0, 0, 1.5)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        ground.draw()

        glPushMatrix()
        if(math.fabs(x) < 11):  
            glTranslatef(x, -1.5, camera_z-20)

        glScalef(1 / 2, 1 / 2, 0)
        cube.draw()
        glPopMatrix()
        for tmp_cube in my_cubes:
            tmp_cube.draw()
            tmp_cube.center[2] += camera_z
            print(tmp_cube.center)

        for tmp_cube in my_cubes:
            if camera_z <= tmp_cube.vertices[0][2]:
                new_max = int(-1 * (camera_z - max_distance * 2))
                tmp_cube.set_vertices(new_max, int(camera_z - max_distance))

        pygame.display.flip()


if __name__ == '__main__':
    main()

我遇到的主要问题是渲染图像有一个小立方体,但其余部分是黑色的。我不知道它应该绘制的其余元素会发生什么。

【问题讨论】:

【参考方案1】:

如果启用纹理,则默认情况下纹理元素的颜色乘以当前颜色,因为默认情况下纹理环境模式 (GL_TEXTURE_ENV_MODE) 为GL_MODULATE。见glTexEnv。 这会导致纹理纹理像素的颜色与您设置的最后一个颜色“混合”glColor3fv

在渲染纹理对象之前设置“白色”颜色:

glColor3f(1, 1, 1)

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

如果你想绘制有纹理的对象,而其他没有纹理的对象,那么你必须在绘制对象之前启用纹理并在之后禁用它:

class Cube:

    # [...]

    def draw(self):

        if self.v:
            glEnable(GL_TEXTURE_2D)
            glColor3f(1, 1, 1)

        glBegin(GL_QUADS)
        if not self.v:
            for surface in self.surfaces:
                for x, vertex in enumerate(surface):
                    glColor3fv(self.colors2[x])
                    glVertex3fv(self.vertices[vertex])
        else:
            for surface in self.surfaces:
                for x, vertex in enumerate(surface):
                    glTexCoord2fv(self.vertices_texture[x])
                    glVertex3fv(self.vertices[vertex])
        glEnd()

        if self.v:
            glDisable(GL_TEXTURE_2D)

【讨论】:

嗨。您提出的解决方案有效,我对此表示感谢,但我还有另一个问题,我如何渲染多个纹理?也就是说,一旦最后一个纹理被加载,它就会与上面的另一个“加载”重叠。我在不同的对象中加载了一个新的“纹理”,但它不起作用。 @AnthonyLuzquiños 您所要做的就是在绘制四边形之前绑定正确的纹理对象 (glBindTexture(GL_TEXTURE_2D, texid))。如果您有超过 1 个纹理,那么您必须为每个纹理创建 1 个纹理对象(例如 texid1texid2、...)

以上是关于在 Python 中使用 OpenGL 渲染纹理不是的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL纹理渲染与原始不匹配

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

使用现代 OpenGL 渲染纹理

使用 VAO/VBO 进行 OpenGL 模型/纹理渲染

OpenGL - 纹理加载不正确

OpenGL + QT:渲染到纹理并显示回来