Load a Wavefront OBJ file (*.obj).

Loads vertex, normals, and texture coordinates from the provided *.obj file into arrays. These arrays can be processed then loaded into vertex buffer objects (VBOs) for rendering. The *.obj file must at least specify vertex position data to be loaded successfully. Normals and texture coordinates are optional.

Faces can be either triangles or quads, but not both. Faces are grouped by their materials. Index arrays are generated for each material present in the file.

Data from the returned ObjMeshInfo object can be used to create vertex buffer objects and arrays for rendering. See Examples below for details on how to do this.


objFile (str) – Path to the *.OBJ file to load.


Mesh data.

Return type


See also


Load a *.mtl file.


  1. This importer should work fine for most sanely generated files. Export your model with Blender for best results, even if you used some other package to create it.

  2. The mesh cannot contain both triangles and quads.


Loading a *.OBJ mode from file:

objModel = loadObjFile('/path/to/file.obj')
# load the material (*.mtl) file, textures are also loaded
mtllib = loadMtl('/path/to/' + objModel.mtlFile)

Creating separate vertex buffer objects (VBOs) for each vertex attribute:

vertexPosVBO = createVBO(objModel.vertexPos)
texCoordVBO = createVBO(objModel.texCoords)
normalsVBO = createVBO(objModel.normals)

Create vertex array objects (VAOs) to draw the mesh. We create VAOs for each face material:

objVAOs = {}  # dictionary for VAOs
# for each material create a VAO
# keys are material names, values are index buffers
for material, faces in objModel.faces.items():
    # convert index buffer to VAO
    indexBuffer =                 gltools.createVBO(
            faces.flatten(),  # flatten face index for element array

    # see `setVertexAttribPointer` for more information about attribute
    # pointer indices
    objVAOs[material] = gltools.createVAO(
        {0: vertexPosVBO,  # 0 = gl_Vertex
         8: texCoordVBO,   # 8 = gl_MultiTexCoord0
         2: normalsVBO},   # 2 = gl_Normal

    # if using legacy attribute pointers, do this instead ...
    # objVAOs[key] = createVAO({GL_VERTEX_ARRAY: vertexPosVBO,
    #                           GL_TEXTURE_COORD_ARRAY: texCoordVBO,
    #                           GL_NORMAL_ARRAY: normalsVBO},
    #                           indexBuffer=indexBuffer,
    #                           legacy=True)  # this needs to be `True`

To render the VAOs using objVAOs created above, do the following:

for material, vao in objVAOs.items():

useMaterial(None)  # disable materials when done

Optionally, you can create a single-storage, interleaved VBO by using numpy.hstack. On some GL implementations, using single-storage buffers offers better performance:

interleavedData = numpy.hstack(
    (objModel.vertexPos, objModel.texCoords, objModel.normals))
vertexData = createVBO(interleavedData)

Creating VAOs with interleaved, single-storage buffers require specifying additional information, such as size and offset:

objVAOs = {}
for key, val in objModel.faces.items():
    indexBuffer =                 gltools.createVBO(

    objVAOs[key] = createVAO({0: (vertexData, 3, 0),  # size=3, offset=0
                              8: (vertexData, 2, 3),  # size=2, offset=3
                              2: (vertexData, 3, 5),  # size=3, offset=5

Drawing VAOs with interleaved buffers is exactly the same as shown before with separate buffers.

Back to top