Parsing obj models

Started by
5 comments, last by Volgogradetzzz 12 years ago
Hello. I need an obj parser. And althought specification is simple I met some problems. For example this teapot (found in google):
http://isg.cs.tcd.ie/spheretree/models/teapot.obj
Number of vertices - 599. Number of texture coordinates - 553. Number of normals - 694. Why their counts are different??? How it's possible?
Now lets invectigate index data. For example take 1-st vertex - and we can see that this vertex can share data 1/1/1 and also 1/1/496!!!
So having all this I can't load model properly. I'm searching the web and I can't find correct model with uvs and normals. Or maybe they are correct and it's only my misunderstanding?
Advertisement
Check the documentation of the "f" (face) instruction.

The obj describes an indexed mesh, where each of the data arrays (positions, texture coordinates and normals) have different indices. D3D, on the other hand, expects only single index array to an interleaved data array (index buffer + 1 vertex buffer). I don't remember whether OpenGL supports different index streams for different vertex elements.

To load the obj to a d3d-compatible format, you need to interleave the data based on the f instructions in order to get a single vertex buffer. The new indices should then be set to point to the resulting interleaved vertex array.

To see an example, see the DX SDK sample "MeshFromObj".

Niko Suni


The obj describes an indexed mesh, where each of the data arrays (positions, texture coordinates and normals) have different indices. D3D, on the other hand, expects only single index array to an interleaved data array (index buffer + 1 vertex buffer). I don't remember whether OpenGL supports different index streams for different vertex elements.

OpenGL also can handle at most one index stream.


To load the obj to a d3d-compatible format, you need to interleave the data based on the f instructions in order to get a single vertex buffer. The new indices should then be set to point to the resulting interleaved vertex array.

Interleaving is not a strict neccessity (AFAIK also not for the most modern D3D / OpenGL versions). You can have more than a single data stream.


...
So having all this I can't load model properly. I'm searching the web and I can't find correct model with uvs and normals. Or maybe they are correct and it's only my misunderstanding?

As Nik02 has stated, every vertex in D3D / OpenGL must provide data for each declared vertex attribute. Addressing a vertex can be done only in its entirety due to the single index. This means usually that for each index combination found in the OBJ's f section one needs to assemble a vertex for D3D / OpenGL (i.e. copying the indexed attribute data in a consistent order) and to generate a new index (a counter is just sufficient). If you want a smaller memory footprint, you can investigate whether the OBJ's index combination was already used earlier; if so, you can re-use the formerly made vertex by just push the belonging D3D / OpenGL index into the index buffer (instead of assembling a copy of the same vertex).
I'm flash programmer and new stage3D API require me to pass vertex buffer (can be several) and index buffer. And each index corresponds to single vertex. So I'm very confused about this phrase (I repeate it again):
For example take 1-st vertex - and we can see that this vertex can share data 1//1 and also 1//496!!![/quote]
How I understand this: take first vertex and take first normal for this face index. And take first vertex and take 496-th normal for this face index (second case).
But it's impossible in actionScript to tell GPU to use 1-st normal for 1-st vertex as wel as 496-th normal for the same 1-st vertex. Please correct me if I wrong.

Upd.: I rephrase my question. In the link to obj model array in face instructions points to the same vertex, but different normals. Is it ok that vertext have 2 normals?
First we should clear up some confusion. To begin with, a vertex is a collection of attributes that defines a point on a model. A vertex can have different attributes, such as position, normal, texture coordinate, color, and so on; whatever attribute you have to describe your vertex. A vertex is not only the position.

The model you linked contains three different attributes: position (the v-tag), texture coordinate (the vt-tag) and normal (the vn-tag). These tags list all individual position attributes, all texture coordinate attributes and all normal attributes that will be used by your list of vertices.

Then you have the face descriptors (the f-tag). Let's take two typical lines from the file. First, "f 1/1/1 2/2/2 3/3/3". The list of triplets references each individual attribute that makes the vertex, and the tree triplets makes the three vertices in the face (the triangle in this case, since there are three vertices).

So, first, 1/1/1 means that the first vertex of the triangle is made up of the first position in the position list, the first texture coordinate in the texture coordinate list, and the first normal in the normal list. Likewise, 2/2/2 and 3/3/3 makes up two more vertices, of the second and third attribute of each corresponding list.

Then look at an example of what I think is confusing you: "f 4/4/5 3/3/6 5/5/7". It follows the very same pattern as previous example. The face is made up of three vertices, and the first vertex is made up from the fourth position, fourth texture coordinate, and the fifth normal. Likewise, the second vertex is made up of the third position, third texture coordinate, and the sixth normal.

So no vertex has two normals, but you may have two different vertices that have the same position but different normals. That is what 1/1/1 and 1/1/496 means; two vertices with the same position but different normals.

If your API does not support individual attribute indices, then you need to split and duplicate vertices. You cannot base your vertex arrays on the position attribute and attach texture coordinate and normal to each position. You have to base it on the face list, and build the vertices from there. Merging and duplicating vertices from one indexed format to another is not very difficult, but definitely a challenge if you're a beginner.

I would drop the index completely and build a flat vertex array instead. That is, load all attributes into separate arrays, load the face list, and construct a vertex array by passing over the face list and copying the attributes into the vertex array in the order determined by the face indices. When you have passed over the whole face list, you have a flat vertex array that stores the attributes in the order specified by the face list.

Interleaving is not a strict neccessity (AFAIK also not for the most modern D3D / OpenGL versions). You can have more than a single data stream.



Yea, but in this particular case I didn't see the point of causing even more confusion by saying that smile.png

The point was that only one index buffer could be used at a time.

Niko Suni

Thanks guys. Now it's all clean.

This topic is closed to new replies.

Advertisement