0

In the OBJFileLoader found at https://www.pygame.org/wiki/OBJFileLoader, what am I supposed to put in place of "filename".

In the Class OBJ, in the line: def init(self, filename, swapyz=False): when I put the full path to the .obj file, it says incorrect syntax.

New Error Message:

Traceback (most recent call last):
 File "C:/Users/Winter/PycharmProjects/Plane/Plane.py", line 26, in <module>
    obj = OBJ('C:/Users/Winter/Desktop/TAL16OBJ.obj')
  File "C:\Users\Winter\PycharmProjects\Plane\Main.py", line 86, in __init__
    mtl = self.mtl[material]
AttributeError: 'OBJ' object has no attribute 'mtl'

This is the current code:

import pygame
from OpenGL.GL import *

def MTL(filename):
    contents = {}
    mtl = None
    for line in open("C:/Users/Winter/Desktop/TAL16OBJ.mtl", "r"):
        if line.startswith('#'): continue
        values = line.split()
        if not values: continue
        if values[0] == 'newmtl':
            mtl = contents[values[1]] = {}
        elif mtl is None:
            raise ValueError("mtl file doesn't start with newmtl stmt")
        elif values[0] == 'map_Kd':
            # load the texture referred to by this declaration
            mtl[values[0]] = values[1]
            surf = pygame.image.load(mtl['map_Kd'])
            image = pygame.image.tostring(surf, 'RGBA', 1)
            ix, iy = surf.get_rect().size
            texid = mtl['texture_Kd'] = glGenTextures(1)
            glBindTexture(GL_TEXTURE_2D, texid)
            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_RGBA, ix, iy, 0, GL_RGBA,
                GL_UNSIGNED_BYTE, image)
        else:
            mtl[values[0]] = list(map(float, values[1:]))
    return contents

class OBJ:
    def __init__(self, filename, swapyz=False):
        """Loads a Wavefront OBJ file. """
        self.vertices = []
        self.normals = []
        self.texcoords = []
        self.faces = []

        material = None
        for line in open("C:/Users/Winter/Desktop/TAL16OBJ.obj", "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'v':
                v = list(map(float, values[1:4]))
                if swapyz:
                    v = v[0], v[2], v[1]
                self.vertices.append(v)
            elif values[0] == 'vn':
                v = list(map(float, values[1:4]))
                if swapyz:
                    v = v[0], v[2], v[1]
                self.normals.append(v)
            elif values[0] == 'vt':
                self.texcoords.append(list(map(float, values[1:3])))
            elif values[0] in ('usemtl', 'usemat'):
                material = values[1]
            elif values[0] == 'mtllib':
                self.mtl = MTL(values[1])
            elif values[0] == 'f':
                face = []
                texcoords = []
                norms = []
                for v in values[1:]:
                    w = v.split('/')
                    face.append(int(w[0]))
                    if len(w) >= 2 and len(w[1]) > 0:
                        texcoords.append(int(w[1]))
                    else:
                        texcoords.append(0)
                    if len(w) >= 3 and len(w[2]) > 0:
                        norms.append(int(w[2]))
                    else:
                        norms.append(0)
                self.faces.append((face, norms, texcoords, material))

        self.gl_list = glGenLists(1)
        glNewList(self.gl_list, GL_COMPILE)
        glEnable(GL_TEXTURE_2D)
        glFrontFace(GL_CCW)
        for face in self.faces:
            vertices, normals, texture_coords, material = face

            mtl = self.mtl[material]
            if 'texture_Kd' in mtl:
                # use diffuse texmap
                glBindTexture(GL_TEXTURE_2D, mtl['texture_Kd'])
            else:
                # just use diffuse colour
                glColor(*mtl['Kd'])

            glBegin(GL_POLYGON)
            for i in range(len(vertices)):
                if normals[i] > 0:
                    glNormal3fv(self.normals[normals[i] - 1])
                if texture_coords[i] > 0:
                    glTexCoord2fv(self.texcoords[texture_coords[i] - 1])
                glVertex3fv(self.vertices[vertices[i] - 1])
            glEnd()
        glDisable(GL_TEXTURE_2D)
        glEndList()

from Main import *
import sys
import pygame
from pygame.locals import *
from pygame.constants import *
from OpenGL.GL import *
from OpenGL.GLU import *

pygame.init()
viewport = (800,600)
hx = viewport[0]/2
hy = viewport[1]/2
srf = pygame.display.set_mode(viewport, OPENGL | DOUBLEBUF)

glLightfv(GL_LIGHT0, GL_POSITION,  (-40, 200, 100, 0.0))
glLightfv(GL_LIGHT0, GL_AMBIENT, (0.2, 0.2, 0.2, 1.0))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (0.5, 0.5, 0.5, 1.0))
glEnable(GL_LIGHT0)
glEnable(GL_LIGHTING)
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_DEPTH_TEST)
glShadeModel(GL_SMOOTH)           # most obj files expect to be smooth-shaded

# LOAD OBJECT AFTER PYGAME INIT
obj = OBJ("C:/Users/Winter/Desktop/TAL16OBJ.obj")

clock = pygame.time.Clock()

glMatrixMode(GL_PROJECTION)
glLoadIdentity()
width, height = viewport
gluPerspective(90.0, width/float(height), 1, 100.0)
glEnable(GL_DEPTH_TEST)
glMatrixMode(GL_MODELVIEW)

rx, ry = (0,0)
tx, ty = (0,0)
zpos = 5
rotate = move = False
while 1:
    clock.tick(30)
    for e in pygame.event.get():
        if e.type == QUIT:
            sys.exit()
        elif e.type == KEYDOWN and e.key == K_ESCAPE:
            sys.exit()
        elif e.type == MOUSEBUTTONDOWN:
            if e.button == 4: zpos = max(1, zpos-1)
            elif e.button == 5: zpos += 1
            elif e.button == 1: rotate = True
            elif e.button == 3: move = True
        elif e.type == MOUSEBUTTONUP:
            if e.button == 1: rotate = False
            elif e.button == 3: move = False
        elif e.type == MOUSEMOTION:
            i, j = e.rel
            if rotate:
                rx += i
                ry += j
            if move:
                tx += i
                ty -= j

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()

    # RENDER OBJECT
    glTranslate(tx/20., ty/20., - zpos)
    glRotate(ry, 1, 0, 0)
    glRotate(rx, 0, 1, 0)
    glCallList(obj.gl_list)
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Manly Winter
  • 21
  • 1
  • 9
  • Please show exactly how you call it –  Nov 29 '18 at 04:25
  • def __init__(self, C:/Users/Winter/Desktop/TAL16OBJ.obj, swapyz=False): – Manly Winter Nov 29 '18 at 04:25
  • 1
    filename expects a string. That is, the path should be in quotes –  Nov 29 '18 at 04:27
  • Still the same result. – Manly Winter Nov 29 '18 at 04:30
  • This is not how to use a class. You might want to look at a python beginners guide. – tkausl Nov 29 '18 at 04:33
  • This is coming from this: https://www.pygame.org/wiki/OBJFileLoader. I just need to know what I'm supposed to place in filename. – Manly Winter Nov 29 '18 at 04:34
  • Could you look at the code from pygame.org/wiki/OBJFileLoader. Is there anything wrong with the code that perhaps that's why it's not working. – Manly Winter Nov 29 '18 at 04:55
  • Possible duplicate of [OBJFILELOADER - pygame](https://stackoverflow.com/questions/46609928/objfileloader-pygame) – skrx Nov 29 '18 at 05:30
  • Just pass the path/filename when you create the instance. – skrx Nov 29 '18 at 05:37
  • I dug around and found that on another thread, I've learned that the OBJLoader was written for python 2 and needs to be fixed for python 3. So with that said, I did that obj = OBJ('TAL16OBJ.obj'). Now the error is: in __init__ mtl = self.mtl[material] AttributeError: 'OBJ' object has no attribute 'mtl'. – Manly Winter Nov 29 '18 at 05:42
  • Please post the complete error message (you can add it to the question). And are you using this version of the script now https://stackoverflow.com/a/47660960 ? – skrx Nov 29 '18 at 05:56
  • I updated the code from the link you provided and added the new error message I'm getting to the question. – Manly Winter Nov 29 '18 at 06:04
  • It seems the model (.obj file) doesn't have a material. Open the .obj file and check if a line starts with `mtllib`. – skrx Nov 29 '18 at 06:18
  • It doesn't, do I just add it? – Manly Winter Nov 29 '18 at 06:20
  • Did you export the model yourself? Then assign a material to the model in your graphics editor and export again. You also need an .mtl file that contains the material information. If you already have one, you could try to add `mtllib NameOfYourMTLfile.mtl` at the top of the .obj file, but I'm not sure if that'll work. – skrx Nov 29 '18 at 06:29
  • So now, I've fixed everything with no error messages. The Pygame window pops up with no crashes it's just the obj file isn't showing.It's just a white screen showing. – Manly Winter Nov 29 '18 at 06:42
  • Add your current code to the question as well. – skrx Nov 29 '18 at 06:56
  • Alright, I added the most current code I have. – Manly Winter Nov 29 '18 at 07:11

1 Answers1

0

The AttributeError: 'OBJ' object has no attribute 'mtl' was raised because the material was missing in the .obj file. There should be a line like this at the top of the .obj file

mtllib NameOfYourMTLfile.mtl 

that indicates which material/.mtl file should be used for the model. The model was probably not exported correctly.


You have to call pygame.display.flip() at the bottom of the while loop to update the pygame window.

while 1:
    # ... other code omitted.
    # Call this at the bottom of the loop.
    pygame.display.flip()

Also, in the MTL function and the OBJ class you should pass the filename variable/parameter to open instead of this string literal "C:/Users/Winter/Desktop/TAL16OBJ.mtl".

def MTL(filename):
    contents = {}
    mtl = None
    for line in open(filename, "r"):  # open(filename)


class OBJ:
    def __init__(self, filename, swapyz=False):
        """Loads a Wavefront OBJ file. """
        self.vertices = []
        self.normals = []
        self.texcoords = []
        self.faces = []

        material = None
        for line in open(filename, "r"):  # open(filename)
skrx
  • 19,980
  • 5
  • 34
  • 48