Search code examples
pythonopengltexturespyopengl

Pyopengl: OSError: exception: access violation reading 0x000001E5AE56E000 while adding a texture


This exception randomly occurred a few times while trying to bind a texture to a cube.

Texture function:

def textureBind():
    img = Image.open('Image.png')
    img_data = numpy.array(list(img.getdata()), numpy.int8)
    glEnable(GL_TEXTURE_2D)
    texture_id = glGenTextures(1)
    glBindTexture(GL_TEXTURE_2D, texture_id)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.size[0], img.size[1],
             0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)

    return texture_id

It happened a few times while trying to use another image, and then randomly stopped giving me the exception. Is there any way to stop the error from happening permanently? If not, is there any alternative to change the texture function above so it doesn't happen again?

Full code:

import time
import numpy
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image

x = 3
y = 1
z = 1


width = 500
height = 500

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)]
faces = [(4,0,3,7), (1,0,4,5), (0,1,2,3), (1,5,6,2), (3,2,6,7), (5,4,7,6)]
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1)]

def cube():

    glRotatef(1, 3, 1, 1)
    glColor3fv((3, 1, 1))
    glBegin(GL_QUADS)
    for i, face in enumerate(faces):
        glColor3fv(colors[i])
        for surftex, vertex in enumerate(face):
            if surftex == 0:
                glTexCoord2f(0.0, 0.0)
            elif surftex == 1:
                glTexCoord2f(0.0, 1.0)
            elif surftex == 2:
                glTexCoord2f(1.0, 1.0)
            elif surftex == 3:
                glTexCoord2f(1.0, 0.0)
            glVertex3fv(vertices[vertex])
    glEnd()




def textureBind():
    img = Image.open('Image.png')
    img_data = numpy.array(list(img.getdata()), numpy.int8)
    glEnable(GL_TEXTURE_2D)
    texture_id = glGenTextures(1)
    glBindTexture(GL_TEXTURE_2D, texture_id)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.size[0], img.size[1],
                 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)

    return texture_id

def showScreen():
    global width, height
    glClearColor(0, 0, 0, 1)

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    cube()
    glEnable(GL_DEPTH_TEST)
    glEnable(GL_LIGHTING)
    glEnable(GL_LIGHT0)
    glEnable(GL_COLOR_MATERIAL)
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)
    glLight(GL_LIGHT0, GL_POSITION,  (2, 2, 2, 1)) # point light from the left, top, front
    glLightfv(GL_LIGHT0, GL_AMBIENT, (0, 1, 0, 1))

    glutSwapBuffers()


def mouseTracker(mousex, mousey):
    print(f"Mouse pos: {mousex}, {mousey}")


def reshapeWindow(x, y):
    global width, height
    width = x
    height = y
    print(x, y)
    glutReshapeWindow(width, height)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45, (width / height), 0.0001, 1000)
    glViewport(0, 0, width, height)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glTranslatef(0, 0, -5)



glutInit()
glutInitDisplayMode(GLUT_RGBA)
glutInitWindowSize(500, 500)
wind = glutCreateWindow("OpenGL")
glutDisplayFunc(showScreen)
glutIdleFunc(showScreen)
glutMotionFunc(mouseTracker)
glutPassiveMotionFunc(mouseTracker)
glutReshapeFunc(reshapeWindow)
gluPerspective(45, (width / height), 0.0001, 1000)

textureBind()

while True:
    glutMainLoopEvent()
    glutPostRedisplay()
    time.sleep(0.001)

Edit: The hexadecimal number changes with each time I run the program, and running this in idle does not quit the program.


Solution

  • The format arguments depends on the image mode (img.mode). You must check the image mode:

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.size[0], img.size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)

    format = GL_RGBA if img.mode == 'RGBA' else GL_RGB
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.size[0], img.size[1],
                 0, format, GL_UNSIGNED_BYTE, img_data)
    

    When texturing is activated, by default the color of the texel is multiplied by the current color, because by default the texture environment mode (GL_TEXTURE_ENV_MODE) is GL_MODULATE. See glTexEnv.

    This causes that the color of the texels of the texture is "mixed" by the last color which you have set by glColor3f.

    Set a "white" color before you render the texture:

    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)]
    faces = [(4,0,3,7), (1,0,4,5), (0,1,2,3), (1,5,6,2), (3,2,6,7), (5,4,7,6)]
    colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1)]
    uv = [(0, 0), (0, 1), (1, 1), (1, 0)]
    
    def cube():
    
        glRotatef(1, 3, 1, 1)
        glColor3fv((3, 1, 1))
        glBegin(GL_QUADS)
        glColor3f(1, 1, 1)        # <--- INSERT
        for i, face in enumerate(faces):
            
            # glColor3fv(colors[i]) <--- DELETE
            
            for surftex, vertex in enumerate(face):
                glTexCoord2fv(uv[surftex])
                glVertex3fv(vertices[vertex])
        glEnd()