OBJ parser: easy parse time triangulation

For some reason whenever I wrote a quick obj parser, I never bothered to think about the case where the faces in the file had more than 3 points. It was easier in the moment to just triangulate the meshes before loading them in the 3D app. In practice on a bigger project, with bigger scenes and lightmaps and all sorts this became a bit of a pain.

Since I was writing a quick obj parser again, I decided to think about it for more than a few minutes and since I didn't see too many easily found results on doing this: I figured I'd share what I implemented for future reference. The only thing you have to tweak is how you parse the f lines.

This solution may be obvious to some and that's fine!

Note that this assumes you want to parse the mesh details as triangle primitives, like GL_TRIANGLES or similar. This does NOT require using triangle fan primitives.

The solution

Parse the face points as if it was a triangle fan!

The details

All that means is they share a common vertex.
We can use the first vertex (0) of the face, and connect each of the points after that back to it.

tri fan

This is the basis for our easy triangulation. The points are almost always coplanar and should generally be convex but do be aware of what happens when they're not. This solution also applies to any other mesh formats that follow similar coplanar rules and stores faces of course.

If we imagine a simple quad, in our OBJ file we might have this line:

f 1/1/1 4/2/1 3/3/1 2/4/1

Using the above logic we can parse the face by hand/on paper/in mind as:

triangle one:  
[1, 1, 1],    [4, 2, 1],    [3, 3, 1]
triangle two:  
[1, 1, 1],    [3, 3, 1],    [2, 4, 1]

So the logic is for each point: connect itself & the next point back to the first point. We can do this in a very simple pseudoish for loop:

var points = split line by ' ', discard the first item ('f')  
var triangle_indices = []  
for(i in 1 ... points.count-1) {  
    tri_corner0 = points[0]
    tri_corner1 = points[i]
    tri_corner2 = points[i + 1]
    triangle_indices.push([corner1, corner2, corner3])

This logic applies the same if there are just 3 points, since it will loop from 1 to 2, adding a single triangle with the correct points!


That's all there is to it, now you can throw most meshes into the loader without any trouble, and the second part of obj loading (converting the indices into vertices) doesn't change.

Yay for better workflow!