Wavefront .Obj

Notes from adding (WaveFront) .obj export to a Unity3D plugin I’m working on.


Motivation

I want to … use … geometry … elsewhere.

I want to use Unity3D as a (sort of) map editor thing that I could pull the data out of and mess with it. Specifically, I’m trying to export geometry for “asset time”1 manipulation in the form of old-school .bsp files. I want to play with this in PureScript (or whatever) before loading it in a C/++ application. I want something I can dump from a Unity plugin, pull into a more suitable programming language, then re-export as a final baked format.

I’m using a .zip file with all geometry as a series of (merged) .obj files and a .png file per-merged object.

Crude stuff.

Plan

I’ll use an (otherwise conformant) subset of the .obj format that has;

  • all vertex coordinates and texture coordinates
    • the “full” version of .obj can handle more data
    • I don’t care about normals - they can be recomputed anyway[^unbake]
    • Tangents (et al) aren’t present in .obj AFAIK
  • all triangles following coordinates
    • the “full” version of .obj can handle n-gons
    • … and other types of geometry

Okay, so, my plan for developing this was to;

  1. write a sample model file by hand
  2. test/check import sample to Blender / Unity
  3. code and test Unity plugin based on this

As always Paul Bourke’s webpage is my go-to reference http://paulbourke.net/dataformats/obj/

It looks like the format can hold a lot of stuff, but, I’ll only need;

flag type usage
# comment starts comments that are otherwise ignored
v vertex coordinate it can be a lot of things, but, I’ll just do x/y/z
vt texture coordinate it can hold up to three! but I only need the two
f face will be the three v/vt of my triangles

My sample file came out like this, and, it worked in Blender and Unity. I needed the latter to check the texture coordinates by applying a material.

v 1 0 0
vt 1 0

v 0 1 0
vt 0 1

v 0 0 1
vt 0 0

f 1/1 2/2 3/3

Code

With the sample, I learned that the indices start at 1 (like animals would do it) and that I didn’t need the full v/vt/vn form. I also don’t need any sort of naming thing … which was surprising. I whacked together a C# section in an existing exporter (that already did the .png writing and .zip) and it looked like this;


... // do something prior to find/collect the/a scene tree/s you want in this surface brush


// write the obj geometry
using (var writer = new StreamWriter(file.CreateEntry("brush/" + surface + ".obj").Open()))
{
	writer.Write("# bsp brush '" + surface + "'");

	// where we record the vertex/texture
	var v = new Dictionary<string, int>();
	var t = new Dictionary<string, int>();

	// where we record the faces - i'm appending them (all) since that should make loading simpler
	var f = new LinkedList<string>();

	// ====
	// write the vertices and textures

	// write a vertex coordinate
	int put_vertex(Vector3 xyz)
	{
		var txt = xyz.x + " " + xyz.y + " " + xyz.z;

		if (!v.ContainsKey(txt))
		{
			v[txt] = v.Count + 1;
			writer.Write("\nv " + txt);
		}

		return v[txt];
	}

	// write a texture coordinate
	int put_texture(Vector2 uv)
	{
		var txt = uv.x + " " + uv.y;

		if (!t.ContainsKey(txt))
		{
			t[txt] = t.Count + 1;
			writer.Write("\nvt " + txt);
		}

		return t[txt];
	}

	// loop through all triangles
	foreach (var triangle in data[surface])
	{
		// start the line
		var l = "\nf";

		// append the verticies
		for (int i = 0; i < 3; ++i)
			l += " " + put_vertex(triangle[i].xyz) + "/" + put_texture(triangle[i].uv);

		// put it in the list
		f.AddLast(l);
	}

	// ====
	// write the faces now
	foreach (var l in f)
		writer.Write(l);
}

Conclusion

So … I can now write .obj files from geometry. I can get some data out of Unity3D scenes for other tools.


  1. .obj is not a format you should load at runtime. Bake your assets for your engine. ↩︎

comments powered by Disqus
Peter LaValle avatar
Peter LaValle
Any links probably include affiliate ids for that sweet sweet kickback - and some programs require that I tell you. The contents of this blog are likely unrelated - as they include games, paints, and build tools.