parsing obj files

Started by
11 comments, last by LongRunGames 6 years, 11 months ago

Hi All,

does anyone know any good tutorials on parsing an object file into your program, specifically with regards to when a vertex has multiple normal values defined in the faces section?

Much appreciated,

Graham

Advertisement

I do not think that a tutorial is needed for this because the file format is well known and described e.g. on Wikipedia https://en.wikipedia.org/wiki/Wavefront_.obj_file and there are also very good implementations out there you could take a look at https://github.com/syoyo/tinyobjloader

I already implemented multiple parsers and it wasnt absolutely difficult nor time consuming to understand the file format

It's likely one of the easiest file formats, with dozens or more loaders already existing. Plenty of documentation as Shaarigan pointed out.

http://www.fileformat.info/format/material/

http://www.martinreddy.net/gfx/3d/OBJ.spec

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

It seems my question was not specific enough.

As far as I can see there are 3 ways of converting an obj file to arrays of vertices and normals and I was wondering which Is the best / industry standard way of doing it.

E.g. For the following obj file

v 1.0 0.0 0.0
v 0.0 -0.5 -1.0
v -1.0 0.0 0.0
v 0.0 -0.5 1.0

vn 0.0 0.707106 0.707106
vn 0.0 0.707106 -0.707106

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

You could
Option 1: have the normals averaged as I currently do

Vertices = 1.0 0.0 0.0 0.0 -0.5 -1.0 -1.0 0.0 0.0 0.0 -0.5 1.0

Normals = 0.0 1.0 0.0 0.0 0.707106 -0.707106 0.0 1.0 0.0 0.0 0.707106 0.707106

Indices = 1 2 3 1 3 4

Or option 2: sort the data into the vertex order described by the faces section

Vertices = 1.0 0.0 0.0 0.0 -0.5 -1.0 -1.0 0.0 0.0 1.0 0.0 0.0 -1.0 0.0 0.0 0.0 -0.5 1.0

Normals = 0.0 0.707106 -0.707106 0.0 0.707106 -0.707106 0.0 0.707106 -0.707106 0.0 0.707106 0.707106 0.0 0.707106 0.707106 0.0 0.707106 0.707106

Indices = 1 2 3 4 5 6

Or option 3: start with the vertices in the order defined and add any with multiple normal values to the end

Vertices = 1.0 0.0 0.0 0.0 -0.5 -1.0 -1.0 0.0 0.0 0.0 -0.5 1.0 1.0 0.0 0.0 -1.0 0.0 0.0

Normals = 0.0 0.707106 -0.707106 0.0 0.707106 -0.707106 0.0 0.707106 -0.707106 0.0 0.707106 0.707106 0.0 0.707106 0.707107 0.0 0.707107 0.707106

Indices = 1 2 3 5 6 4

Option 1 is the current way I do it, option 2 seems like the easiest but option 3 seems like it could be the best in terms of data size but would be the hardest algorithm to implement.

Hopefully that makes my question more clear

When you have vertex normals, you don't average them. Something like weighted averaging needed only when you calculating normals on your own, because there's no normals data in obj file.

Now you must construct all vertices with all corresponding data (just like that, combined value of position/texture_coord/normal), then build index, removing duplicate vertices, i.e verts that has all the same pos/tex_co/norm. In the end there might be more verts in your vertex buffer than there's 'v' directives in obj file, and that's normal.

The first thing you must accept - is that 'v' directive does not create your final vertex. It only describes position in space. Resulting vertex is a combination of all data from all v/vt/vn streams.

Face vertex index in 'v' stream will tell about source vertex identity (same index means physically same point, while different indices means unrelated verts even if those are in same position), but that's needed only when you reconstruct normals, so shouldn't bother you at the moment.

You might misunderstand something while indices are for storing less data, .obj files define faces the original model was build from so this isnt something inside the file format itself but more a thing your game (engine) would process.

For your example


v 1.0 0.0 0.0
v 0.0 -0.5 -1.0
v -1.0 0.0 0.0
v 0.0 -0.5 1.0

vn 0.0 0.707106 0.707106
vn 0.0 0.707106 -0.707106

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

The resulting mesh would consist of


//First Triangle
vec3 1.0 0.0 0.0 | vec3 0.0 0.707106 -0.707106
vec3 0.0 -0.5 -1.0 | vec3 0.0 0.707106 -0.707106
vec3 -1.0 0.0 0.0 | vec3 0.0 0.707106 -0.707106

//Second Triangle
vec3 1.0 0.0 0.0 | vec3 0.0 0.707106 0.707106
vec3 -1.0 0.0 0.0 | vec3 0.0 0.707106 0.707106
vec3 0.0 -0.5 1.0 | vec3 0.0 0.707106 0.707106

//in a 6 component Vertex Buffer 3 components Vertices and 3 components Normals

To get an Index Buffer you need to store each combination of values once and set an index at its position. In your case you have to store all 6 faces because they do not share any vertex.

How you do it is up to you, someone store them in a constant array so vertex positions first then normals, I prefer normaly storing vertices as is in the buffer so vertex | normals | vertex | normals. Both work as expected and there is no right way of indexing

https://www.gamedev.net/topic/663264-obj-file-problem/#entry5195460

Derp

If you want actual working code for parsing, please try this link -> https://github.com/chrisjansson/ObjLoader

I used this code early on when I was understanding the format, its a good start. It has some flaws, but its useable. Assumes all models are only using 3 verts per face so you need to triangulate models first.

Indie game developer - Game WIP

Strafe (Working Title) - Currently in need of another developer and modeler/graphic artist (professional & amateur's artists welcome)

Insane Software Facebook

As far as I can see there are 3 ways of converting an obj file to arrays of vertices and normals and I was wondering which Is the best / industry standard way of doing it.


If what you're asking is "what way does GameX parse .obj files?" then you should understand that GameX most likely doesn't even use .obj files at all. Thing is, .obj is a fine enough format for tutorial material, but it's a horrible format for real-world usage; slow and error-prone to parse. GameX most likely uses it's own proprietary binary model format, with it's own exporter(s) from common modelling program(s), and just loads the format directly into vertex buffers without any parsing at all. So the best/industry standard way of parsing .obj files is actually: don't; use a better format instead.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Thanks for the replies.

I see now that option 2 and 3 that I mentioned are just two different ways of doing the same thing and I knew option 1 was not the way to go.

I have a script which extracts the data from the .obj file and creates 3 text files one for the vertices in the correct order, one for the normals in the correct order and one for the indices, which I then read in in my game.

This topic is closed to new replies.

Advertisement