Search code examples
pythonopenglpyopengl

OpenGL texture alignment on objects


I have an issue with texture alignment on objects. This is what the image looks like.

I've been kind of following this tutorial on PyOpengl:

This is the way I load textures:

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_NEAREST_MIPMAP_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

    image = pg.image.load(filepath).convert()
    image_width,image_height = image.get_rect().size
    img_data = pg.image.tostring(image,'RGBA')
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,image_width,image_height,0,GL_RGBA,GL_UNSIGNED_BYTE,img_data)

And this is the way I load the OBJ file:

v = []
    vt = []
    vn = []
    
    #final, assembled and packed result
    vertices = []

    #open the obj file and read the data
    with open(filename,'r') as f:
        line = f.readline()
        while line:
            firstSpace = line.find(" ")
            flag = line[0:firstSpace]
            if flag=="v":
                #vertex
                line = line.replace("v ","")
                line = line.split(" ")
                l = [float(x) for x in line]
                v.append(l)
            elif flag=="vt":
                #texture coordinate
                line = line.replace("vt ","")
                line = line.split(" ")
                l = [float(x) for x in line]
                vt.append(l)
            elif flag=="vn":
                #normal
                line = line.replace("vn ","")
                line = line.split(" ")
                l = [float(x) for x in line]
                vn.append(l)
            elif flag=="f":
                #face, three or more vertices in v/vt/vn form
                line = line.replace("f ","")
                line = line.replace("\n","")
                #get the individual vertices for each line
                line = line.split(" ")
                faceVertices = []
                faceTextures = []
                faceNormals = []
                for vertex in line:
                    #break out into [v,vt,vn],
                    #correct for 0 based indexing.
                    l = vertex.split("/")
                    position = int(l[0]) - 1
                    faceVertices.append(v[position])
                    texture = int(l[1]) - 1
                    faceTextures.append(vt[texture])
                    normal = int(l[2]) - 1
                    faceNormals.append(vn[normal])
                # obj file uses triangle fan format for each face individually.
                # unpack each face
                triangles_in_face = len(line) - 2

                vertex_order = []
                """
                    eg. 0,1,2,3 unpacks to vertices: [0,1,2,0,2,3]
                """
                for i in range(triangles_in_face):
                    vertex_order.append(0)
                    vertex_order.append(i+1)
                    vertex_order.append(i+2)
                for i in vertex_order:
                    for x in faceVertices[i]:
                        vertices.append(x)
                    for x in faceTextures[i]:
                        vertices.append(x)
                    for x in faceNormals[i]:
                        vertices.append(x)
            line = f.readline()
    return vertices

I am not sure why it's not loading correctly. The only idea I have is that there is some issue with the way texture coordinates are loaded when reading the OBJ file, but the texture doesn't seem to be stretching just being misaligned.

I tried opening the object in blender and checking the UVs and even reexporting the model. I also tried rotating the image around thinking maybe some axis was swapped but that also didn't help.


Solution

  • Most image formats consider the data to be written in raster order, top to bottom. But GL's texture functions expect the bottom row to appear first in memory. It doesn't look like your image load routine is flipping the images vertically, and your OBJ importer isn't inverting the texture coordinates along the y axis either.