Up to this point we've used a lot of placeholder geometry for spheres, cubes and planes. None of it was very impressive, and most of them render in a very sub-optimal kind of way. Let's go ahead and fix that.
In this section i'm going to show you how to load meshes from possibly the most common format out there, OBJ files. We're going to build a mesh class that can load these OBJ models and render them using vertex buffer objects.
An OBJ file is just a text file. It's a standard format that supports a LARGE standard with many features. We're only going to implement loading a small specific subset of obj files.
Every OBJ we load we're going to assume has a set vertex format containing a position, a texture coordinate and a normal. Not all OBJ files have all of this information, but the subset we load we assume will.
Let's take a look at what the inside of an OBJ file looks like:
# Blender3D v249 OBJ File: untitled.blend # www.blender3d.org mtllib cube.mtl v 1.000000 -1.000000 -1.000000 v 1.000000 -1.000000 1.000000 v -1.000000 -1.000000 1.000000 v -1.000000 -1.000000 -1.000000 v 1.000000 1.000000 -1.000000 v 0.999999 1.000000 1.000001 v -1.000000 1.000000 1.000000 v -1.000000 1.000000 -1.000000 vt 0.748573 0.750412 vt 0.749279 0.501284 vt 0.999110 0.501077 vt 0.999455 0.750380 vt 0.250471 0.500702 vt 0.249682 0.749677 vt 0.001085 0.750380 vt 0.001517 0.499994 vt 0.499422 0.500239 vt 0.500149 0.750166 vt 0.748355 0.998230 vt 0.500193 0.998728 vt 0.498993 0.250415 vt 0.748953 0.250920 vn 0.000000 0.000000 -1.000000 vn -1.000000 -0.000000 -0.000000 vn -0.000000 -0.000000 1.000000 vn -0.000001 0.000000 1.000000 vn 1.000000 -0.000000 0.000000 vn 1.000000 0.000000 0.000001 vn 0.000000 1.000000 -0.000000 vn -0.000000 -1.000000 0.000000 usemtl Material_ray.png s off f 5/1/1 1/2/1 4/3/1 f 5/1/1 4/3/1 8/4/1 f 3/5/2 7/6/2 8/7/2 f 3/5/2 8/7/2 4/8/2 f 2/9/3 6/10/3 3/5/3 f 6/10/4 7/6/4 3/5/4 f 1/2/5 5/1/5 2/9/5 f 5/1/6 6/10/6 2/9/6 f 5/1/7 8/11/7 6/10/7 f 8/11/7 7/12/7 6/10/7 f 1/2/8 2/9/8 3/13/8 f 1/2/8 3/13/8 4/14/8
Every line begins with some kind of a letter or phrase to describe the information the line will hold. Then, the information appears in a specific format. There are more line markers than what is listed above / what we will be using. This means its important for your parser to ignore unknown line starts.
Here are the lines we will care about:
- v is a vertex
- vt is the texture coordinate of one vertex
- vn is the normal of one vertex
- f is a face (triangle)
And these are the things we don't care about:
- Any line that begins with # is a comment, just like // in C#
- usemtl and mtllib describe the look of the model. We won’t use this in this tutorial.
- s stands for specular, it can be off or it can be some number
A material describes how to shade a model. OBJ files often come with .mtl files which then link to textures. We're not going to care about mtl files. We just want to get vertex data into our game!
Now that we know that we only care about v, vt, vn and f, let's take a look at the format of each of these lines:
v, vt and vn are simple to understand. The letter is followed by a space, then three space seperated floats. That's the line.
f is more tricky. So, for f 8/11/7 7/12/7 6/10/7 :
- 8/11/7 describes the first vertex of the triangle
- 7/12/7 describes the second vertex of the triangle
- 6/10/7 describes the third vertex of the triangle
- For the first vertex, 8 says which vertex to use. So in this case, -1.000000 1.000000 -1.000000 (index start to 1, not to 0 like in C#)
- 11 says which texture coordinate to use. So in this case, 0.748355 0.998230
- 7 says which normal to use. So in this case, 0.000000 1.000000 -0.000000
A triangle is described as 3 sets of indices into the vertex / uv / normal arrays. It's important to note that arrays in C# are indexed starting at 0, in OBJ land they start at 1. A conversion needs to be made when you write your parser.