Hi, I've been working on a game engine for a while now and just switched from using OBJ files to FBX so I can start importing skinned meshes. I got an importer working in the last hour with vertices and normals, but I ran into a problem now that I'm importing UVs.
In my engine, the vertex, normal, and UV arrays must all be the same length. Each number in the indices array maps to a the same index in the vertex, normal, and UV arrays. Importing fbx is becoming a problem now because of the indices. In a model I'm importing, the vertices and normals are shared, but the UVs are duplicated for each vertex. For example, I try to import a model with 1000 vertices, 1000 normals, and 3000 UVs. But the UVs are not supposed to be duplicated because they do not differ for each triangle, so there should only be 1000 UVs.
My question is, what's the best way to convert FBX's weird indices into the format I need? Is there a function in the FBX SDK that does this? If not, this seems like a difficult problem to solve, because the FBX file might not share normals or UVs where it should (the example above), or it might share them where it shouldn't (example: a file where a cube only has 8 vertices, but there should be 24 because the normals are different, so the vertices cannot be shared)
If anyone knows a way to do this, I would really appreciate the help. Thank you.
Right now I get the position, normal, and UV for each vertex of every triangle and add them to arrays. Then I search the arrays for unique vertices and add them to the final vertex, normal, and UV arrays. It works alright, but is there a more efficient way of doing this? The time required to convert the indices would increase greatly with the size of the mesh. Though I haven't tested with huge meshes yet.
I used an STL map operator to remove duplicates and to get a unique index.
#pragma pack(4) class lpUnskinnedVertex { public: float3 pos; float3 normal; float2 texcoord; float3 color; int4 materialData; // materialID /texture ID // to orient normal map float3x3 normal_orientation; friend bool operator < (const lpUnskinnedVertex& v1, const lpUnskinnedVertex& v2) { if (v1.pos < v2.pos) return true; if (v1.pos > v2.pos) return false; if (v1.normal < v2.normal) return true; if (v1.normal > v2.normal) return false; const float2 & v1tc = v1.texcoord; const float2 & v2tc = v2.texcoord; if (v1tc < v2tc) return true; if (v1tc > v2tc) return false; return false; } }; // you will also need the 'less' operator for float3 and float2. //create a flattened vertex list size = # triangles * 3 std::vector<lpUnskinnedVertex> vertex_list(numTriangles * 3); // to reduce to unique verts: std::map<lpUnskinned, int> vertexUnique; for each vertex (v) in vertex_list vertexUnique.insert(v); // now you have a unique set of vertex, now you can number them std::vector<lpUnskinnedVertex> new_vertex_list(vertexUnique.size()); int i = 0; for each vertex (v) in vertexUnique { v->second = i; // new index new_vertex_list[i] = v->first; // save vertex in new list i++; } // now each unique vertex has an index, make a remap table to map old vertex index to new index std::vector<int> remap(numTriangles * 3); int i = 0; for each vertex (v) in vertex_list { std::map<lpUnskinned, int>::iterator it = vertexUnique.find(v); remap[i++] = it->second; }
Can't find what you're looking for? Ask the community or share your knowledge.