Search code examples
import3dwavefrontassimpmeshlab

Assimp vs. MeshLab Wavefront Object (.obj) import


I was wondering why when I use the Assimp library to import a Wavefront Object file (.obj) it doubles certain vertices and I found the following answer in the Assimp SourceForge discussion (http://sourceforge.net/p/assimp/discussion/817654/thread/026e9640/?limit=25#ba6c):

Imagine the following: You upload a range of vertices to the graphics card. You then tell the GPU via an index buffer that you want the first triangle to be formed by vertex 3, 6 and 7. The second triangle is then 1, 2 and 6. What would happen? The GPU would draw you a cube, but each corner of the cube would share the same UV data, normal vectors, vertex colours or whatever else your mesh needs.

Now how do we get a cube corner but get different UV mappings on all sides touching that corner? We can't tell the GPU to "use vertex 3, but instead of the UV coords of that vertex, please use UV coords instead." The GPU can't do this. That's why it's necessary to duplicate the vertex at that corner. Now you have two vertices for the same position, but with different UV coords.

And that's what Assimp is doing for you. If you do specify JoinIdenticalVertices, you'll get a cube with 24 vertices. Why? A cube has 8 corners, but there are 3 cube sides touching at each corner, and each of that cube sides has a different UV coords set for that corner, so you end up with 3 versions of each corner. If you do not specify JoinIdenticalVertices, you get a plain array of vertices without any reuse. And that means that you need 2 triangles with 3 vertices each for every cube side, ending up at 36 vertices.

An alternative would be to use 3D uv coords and a cube map to texture that cube. This is a special case that only works for a cube, but there it would work. The GPU does the mapping to 6 textures internally then. The description above is the general case, it works like this for each and every mesh that you might encounter.

It does make sense.
Premising that I don't know how MeshLab handles the .obj import operation how comes that, if the answer I found is right, when I import such an object the vertices counter doesn't increase? Is it only a matter of how they do the counts or is there a way to import .obj files without having to split vertices when they have normals/tangents/UV?


Solution

  • This is not implementation-specific (for instance, they have several vectors - one for each variable), but the logic is the same.

    Meshlab generates one vertex per 3D coordinate with several possible "values" for variables such as normal and texture, besides the common position. These vertices are stored in a vertex vector.

    These multiple values are stored in a separate vertex data vector (which I will call VDV). A triangular face will point to 3 entries in the VDV, but a vertex may point to any number of them.

    On rendering, the VDV will be used for indexing purposes, but the actual vertices are used when calculating stuff and when counting the number of vertices. They have separate "combined" values on stuff like normal, that considers all of their adjoining faces.