Search code examples
pythonopenglpygamepyopengl

OpenGL: How do I apply a texture to this cube?


I'm trying to learn OpenGL, and I've been going through a lot of tutorials on loading a texture, but every single one seems to miss the most important step: how do I actually put a texture on something?

I'm using Python for this, and here is my function that loads the texture:

def loadTexture():
    textureSurface = pygame.image.load('test_image.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

And here is the function that loads my Cube:

vertices = (
        # x  y  z
        ( 1,-1,-1),
        ( 1, 1,-1),
        (-1, 1,-1),
        (-1,-1,-1),
        ( 1,-1, 1),
        ( 1, 1, 1),
        (-1,-1, 1),
        (-1, 1, 1)
        )

edges = (
         (0,1),
         (0,3),
         (0,4),
         (2,1),
         (2,3),
         (2,7),
         (6,3),
         (6,4),
         (6,7),
         (5,1),
         (5,4),
         (5,7)
         )

def Cube():
    glBegin(GL_LINES)
    for edge in edges:
        glColor3fv((1,1,1))
        for vertex in edge:
            glVertex3fv(vertices[vertex])
    glEnd()

And here's the main loop:

pygame.init()
display = (800,600)
screen = pygame.display.set_mode(display, DOUBLEBUF | OPENGL | OPENGLBLIT)

gluPerspective(45, display[0]/display[1],0.1,50.0)
glTranslatef(0.0,0.0,-5)

while True:
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    Cube()

    pygame.display.flip()
    pygame.time.wait(10)

But the cube is untextured. I don't know how to actually use the loaded texture on the cube, and every texture tutorial I find takes me as far as the loadTexture function without actually telling me how to use it. Where do I call it? What do I do with texid?


Solution

  • There are few issues with your actual code:

    • You're not calling the method to load your textures.
    • You're drawing only lines of the cube, you need polygons to be filled up with the actual textures, which means using either triangles or quads with texture coordinates.
    • You're not processing the pygame events

    Here's some modifications of your code:

    import pygame
    import sys
    from OpenGL.GL import *
    from OpenGL.GLU import *
    
    vertices = (
        # x  y  z
        (1, -1, -1),
        (1, 1, -1),
        (-1, 1, -1),
        (-1, -1, -1),
        (1, -1, 1),
        (1, 1, 1),
        (-1, -1, 1),
        (-1, 1, 1)
    )
    
    edges = (
        (0, 1),
        (0, 3),
        (0, 4),
        (2, 1),
        (2, 3),
        (2, 7),
        (6, 3),
        (6, 4),
        (6, 7),
        (5, 1),
        (5, 4),
        (5, 7)
    )
    
    
    def loadTexture():
        textureSurface = pygame.image.load('test_image.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 draw_cube(lines=False):
        if lines:
            glBegin(GL_LINES)
            for edge in edges:
                glColor3fv((1, 1, 1))
                for vertex in edge:
                    glVertex3fv(vertices[vertex])
            glEnd()
        else:
            glBegin(GL_QUADS)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(-1.0, -1.0,  1.0)
            glTexCoord2f(1.0, 0.0)
            glVertex3f(1.0, -1.0,  1.0)
            glTexCoord2f(1.0, 1.0)
            glVertex3f(1.0,  1.0,  1.0)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(-1.0,  1.0,  1.0)
            glTexCoord2f(1.0, 0.0)
            glVertex3f(-1.0, -1.0, -1.0)
            glTexCoord2f(1.0, 1.0)
            glVertex3f(-1.0,  1.0, -1.0)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(1.0,  1.0, -1.0)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(1.0, -1.0, -1.0)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(-1.0,  1.0, -1.0)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(-1.0,  1.0,  1.0)
            glTexCoord2f(1.0, 0.0)
            glVertex3f(1.0,  1.0,  1.0)
            glTexCoord2f(1.0, 1.0)
            glVertex3f(1.0,  1.0, -1.0)
            glTexCoord2f(1.0, 1.0)
            glVertex3f(-1.0, -1.0, -1.0)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(1.0, -1.0, -1.0)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(1.0, -1.0,  1.0)
            glTexCoord2f(1.0, 0.0)
            glVertex3f(-1.0, -1.0,  1.0)
            glTexCoord2f(1.0, 0.0)
            glVertex3f(1.0, -1.0, -1.0)
            glTexCoord2f(1.0, 1.0)
            glVertex3f(1.0,  1.0, -1.0)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(1.0,  1.0,  1.0)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(1.0, -1.0,  1.0)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(-1.0, -1.0, -1.0)
            glTexCoord2f(1.0, 0.0)
            glVertex3f(-1.0, -1.0,  1.0)
            glTexCoord2f(1.0, 1.0)
            glVertex3f(-1.0,  1.0,  1.0)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(-1.0,  1.0, -1.0)
            glEnd()
    
    pygame.init()
    display = (800, 600)
    screen = pygame.display.set_mode(
        display, pygame.DOUBLEBUF | pygame.OPENGL | pygame.OPENGLBLIT)
    
    loadTexture()
    
    gluPerspective(45, display[0] / display[1], 0.1, 50.0)
    glTranslatef(0.0, 0.0, -5)
    
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    
        draw_cube(lines=False)
    
        pygame.display.flip()
    

    The above code is not using the best practices but it'll help you with your commented issues.

    One advice though, I'd recommend you go through some opengl tutorial before dumping some code randomly from the internet, try to understand how the graphics pipeline works and then everything will start making sense. Also, I'd recommend you learn about modern Opengl instead using the old opengl fixed pipeline