I’m going to go out on a limb here and guess that the title will have taken longer to come up with that the rest of this post…oh well.

Since we want to run some nifty graphics demos on our raspberry pi’s/ raspberries pi (no sure how to pluralize this), we thought it would be handy to have a way to loading some models. The representation we decided on was the Wavefront OBJ, as it is very popular.

Deciding that we only needed the most basic features, we limited the specs so that only triangles are accepted. Also, we only wanted to read in the verticies and the faces, leaving the calculation of the normals up to the loader.

Here it (slightly reformatted to fit nicely):

import re class TriMesh: def __init__(self, fileName): self.verts = [] self.faces = [] self.fNorms = [] self.vNorms = [] # read file with open(fileName) as f: for line in f: token = re.split('\s*', line.strip()) if token[0] == 'v': self.verts.extend( [float(token[i]) for i in range(1,4)]) elif line[0] == 'f': self.faces.extend( [int(token[i]) - 1 for i in range(1,4)]) #initialize the vertex normals self.vNorms = [0] * len(self.verts) x,y,z = 0,1,2 for i in xrange(0, len(self.faces), 3): #get the index of the x coordinate for the three points A = self.faces[i] * 3 B = self.faces[i+1] * 3 C = self.faces[i+2] * 3 #create two vectors from the three points of the triangle vBA = (self.verts[B] - self.verts[A], self.verts[B+1] - self.verts[A+1], self.verts[B+2] - self.verts[A+2]) vCA = (self.verts[C] - self.verts[A], self.verts[C+1] - self.verts[A+1], self.verts[C+2] - self.verts[A+2]) #do the cross product to get the face normal normal = (vBA[y] * vCA[z] - vBA[z] * vCA[y], vBA[z] * vCA[x] - vBA[x] * vCA[z], vBA[x] * vCA[y] - vBA[y] * vCA[x]) #unitize the face normal magnitude = (normal[x]**2 + normal[y]**2 + normal[z]**2)**.5 #dont divide by zero if magnitude != 0: unitNormal = (normal[x] / magnitude, normal[y] / magnitude, normal[z] / magnitude) else: unitNormal = (0.0,0.0,0.0) #incrementally calculate vertex normals for j in range(3): self.vNorms[A + j] += unitNormal[j] self.vNorms[B + j] += unitNormal[j] self.vNorms[C + j] += unitNormal[j] self.fNorms.extend(unitNormal) #unitize vertex normals for i in xrange(0, len(self.vNorms), 3): magnitude = ( self.vNorms[i]**2 + self.vNorms[i+1]**2 + self.vNorms[i+2]**2)**.5 if magnitude != 0: self.vNorms[i] /= magnitude self.vNorms[i+1] /= magnitude self.vNorms[i+2] /= magnitude def printObj(self): tmp = '' for i in xrange(0, len(self.verts), 3): tmp += "v " + str(self.verts[i]) tmp += " " + str(self.verts[i+1]) tmp += " " + str(self.verts[i+2]) + "\n" tmp += "\n" for i in xrange(0, len(self.vNorms), 3): tmp += "vn "+ str(self.vNorms[i]) tmp += " " + str(self.vNorms[i+1]) tmp += " " + str(self.vNorms[i+2]) + "\n" tmp += "\n" for i in xrange(0, len(self.faces), 3): tmp += "f " + str(self.faces[i] + 1) tmp += " " + str(self.faces[i+1] + 1) tmp += " " + str(self.faces[i+2] + 1) + "\n" tmp += "\n" print tmp

The title refers to the fact that I have also wrote a version that is much more object oriented, but never quite managed to finish it.

Here’s a render, in Blender, of a teapot loaded in from a OBJ:

The OBJ I used to load this,along with quite a few others, can be found at http://people.sc.fsu.edu/~jburkardt/data/obj/obj.html (the link tag keeps getting deleted for some reason)

[…] got his OBJ loader working, we think, so it came time for me to integrate his code with my demo renderers. It kind of […]