| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- #include "anki/resource/MeshLoader.h"
- #include "anki/util/BinaryStream.h"
- #include <fstream>
- #include <cstring>
- #include <unordered_map>
- namespace anki {
- //==============================================================================
- // Misc =
- //==============================================================================
- /// The hash functor
- struct Hasher
- {
- size_t operator()(const Vec3& pos) const
- {
- F32 sum = pos.x() * 100.0 + pos.y() * 10.0 + pos.z();
- size_t hash = 0;
- memcpy(&hash, &sum, sizeof(F32));
- return hash;
- }
- };
- /// The value of the hash map
- struct MapValue
- {
- U8 indicesCount = 0;
- Array<U32, 16> indices;
- };
- typedef std::unordered_map<Vec3, MapValue, Hasher> FixNormalsMap;
- //==============================================================================
- // MeshLoader =
- //==============================================================================
- //==============================================================================
- void MeshLoader::load(const char* filename)
- {
- // Try
- try
- {
- // Open the file
- std::fstream file(filename, std::fstream::in | std::fstream::binary);
- if(!file.is_open())
- {
- throw ANKI_EXCEPTION("Cannot open file:" + filename);
- }
- BinaryStream bs(file.rdbuf());
- // Magic word
- char magic[8];
- bs.read(magic, sizeof(magic));
- if(bs.fail() || memcmp(magic, "ANKIMESH", 8))
- {
- throw ANKI_EXCEPTION("Incorrect magic word");
- }
- // Mesh name
- std::string meshName = bs.readString();
- // Verts num
- uint vertsNum = bs.readUint();
- vertCoords.resize(vertsNum);
- // Vert coords
- for(Vec3& vertCoord : vertCoords)
- {
- for(U j = 0; j < 3; j++)
- {
- vertCoord[j] = bs.readFloat();
- }
- }
- // Faces num
- U facesNum = bs.readUint();
- tris.resize(facesNum);
- // Faces IDs
- for(Triangle& tri : tris)
- {
- for(U j = 0; j < 3; j++)
- {
- tri.vertIds[j] = bs.readUint();
- // a sanity check
- if(tri.vertIds[j] >= vertCoords.size())
- {
- throw ANKI_EXCEPTION("Vert index out of bounds");
- }
- }
- }
- // Tex coords num
- U texCoordsNum = bs.readUint();
- texCoords.resize(texCoordsNum);
- // Tex coords
- for(Vec2& texCoord : texCoords)
- {
- for(uint i = 0; i < 2; i++)
- {
- texCoord[i] = bs.readFloat();
- }
- }
- // Vert weights num
- U vertWeightsNum = bs.readUint();
- vertWeights.resize(vertWeightsNum);
- // Vert weights
- for(VertexWeight& vw : vertWeights)
- {
- // get the bone connections num
- uint boneConnections = bs.readUint();
- // we treat as error if one vert doesnt have a bone
- if(boneConnections < 1)
- {
- throw ANKI_EXCEPTION("Vert sould have at least one bone");
- }
- // and here is another possible error
- if(boneConnections > VertexWeight::MAX_BONES_PER_VERT)
- {
- uint tmp = VertexWeight::MAX_BONES_PER_VERT;
- throw ANKI_EXCEPTION("Cannot have more than "
- + std::to_string(tmp) + " bones per vertex");
- }
- vw.bonesNum = boneConnections;
- // for all the weights of the current vertes
- for(uint i = 0; i < vw.bonesNum; i++)
- {
- // read bone id
- uint boneId = bs.readUint();
- vw.boneIds[i] = boneId;
- // read the weight of that bone
- float weight = bs.readFloat();
- vw.weights[i] = weight;
- }
- } // end for all vert weights
- doPostLoad();
- }
- catch(Exception& e)
- {
- throw ANKI_EXCEPTION("Loading of file failed: " + filename) << e;
- }
- }
- //==============================================================================
- void MeshLoader::doPostLoad()
- {
- // Sanity checks
- if(vertCoords.size() < 1 || tris.size() < 1)
- {
- throw ANKI_EXCEPTION("Vert coords and tris must be filled");
- }
- if(texCoords.size() != 0 && texCoords.size() != vertCoords.size())
- {
- throw ANKI_EXCEPTION("Tex coords num must be "
- "zero or equal to the vertex "
- "coords num");
- }
- if(vertWeights.size() != 0 && vertWeights.size() != vertCoords.size())
- {
- throw ANKI_EXCEPTION("Vert weights num must be zero or equal to the "
- "vertex coords num");
- }
- createAllNormals();
- fixNormals();
- if(texCoords.size() > 0)
- {
- createVertTangents();
- }
- createVertIndeces();
- }
- //==============================================================================
- void MeshLoader::createVertIndeces()
- {
- vertIndices.resize(tris.size() * 3);
- U j = 0;
- for(U i = 0; i < tris.size(); ++i)
- {
- vertIndices[j + 0] = tris[i].vertIds[0];
- vertIndices[j + 1] = tris[i].vertIds[1];
- vertIndices[j + 2] = tris[i].vertIds[2];
- j += 3;
- }
- }
- //==============================================================================
- void MeshLoader::createFaceNormals()
- {
- for(Triangle& tri : tris)
- {
- const Vec3& v0 = vertCoords[tri.vertIds[0]];
- const Vec3& v1 = vertCoords[tri.vertIds[1]];
- const Vec3& v2 = vertCoords[tri.vertIds[2]];
- tri.normal = (v1 - v0).cross(v2 - v0);
- if(tri.normal != Vec3(0.0))
- {
- //tri.normal.normalize();
- }
- else
- {
- tri.normal = Vec3(1.0, 0.0, 0.0);
- }
- }
- }
- //==============================================================================
- void MeshLoader::createVertNormals()
- {
- vertNormals.resize(vertCoords.size());
- for(Vec3& vertNormal : vertNormals)
- {
- vertNormal = Vec3(0.0, 0.0, 0.0);
- }
- for(Triangle& tri : tris)
- {
- vertNormals[tri.vertIds[0]] += tri.normal;
- vertNormals[tri.vertIds[1]] += tri.normal;
- vertNormals[tri.vertIds[2]] += tri.normal;
- }
- for(Vec3& vertNormal : vertNormals)
- {
- vertNormal.normalize();
- }
- }
- //==============================================================================
- void MeshLoader::createVertTangents()
- {
- vertTangents.resize(vertCoords.size(), Vec4(0.0)); // alloc
- Vector<Vec3> bitagents(vertCoords.size(), Vec3(0.0));
- for(uint i = 0; i < tris.size(); i++)
- {
- const Triangle& tri = tris[i];
- const I i0 = tri.vertIds[0];
- const I i1 = tri.vertIds[1];
- const I i2 = tri.vertIds[2];
- const Vec3& v0 = vertCoords[i0];
- const Vec3& v1 = vertCoords[i1];
- const Vec3& v2 = vertCoords[i2];
- Vec3 edge01 = v1 - v0;
- Vec3 edge02 = v2 - v0;
- Vec2 uvedge01 = texCoords[i1] - texCoords[i0];
- Vec2 uvedge02 = texCoords[i2] - texCoords[i0];
- F32 det = (uvedge01.y() * uvedge02.x()) -
- (uvedge01.x() * uvedge02.y());
- if(isZero(det))
- {
- //ANKI_LOGW(getRsrcName() << ": det == " << fixed << det);
- det = 0.0001;
- }
- else
- {
- // Calc the det
- det = 1.0 / det;
- // Add a noise to the det to avoid zero tangents on mirrored cases
- det *= ((rand() % 10) * getEpsilon<F32>());
- }
- Vec3 t = (edge02 * uvedge01.y() - edge01 * uvedge02.y()) * det;
- Vec3 b = (edge02 * uvedge01.x() - edge01 * uvedge02.x()) * det;
- //t.normalize();
- //b.normalize();
- vertTangents[i0] += Vec4(t, 1.0);
- vertTangents[i1] += Vec4(t, 1.0);
- vertTangents[i2] += Vec4(t, 1.0);
- bitagents[i0] += b;
- bitagents[i1] += b;
- bitagents[i2] += b;
- }
- for(U i = 0; i < vertTangents.size(); i++)
- {
- Vec3 t = vertTangents[i].xyz();
- const Vec3& n = vertNormals[i];
- Vec3& b = bitagents[i];
- t = t - n * n.dot(t);
- t.normalize();
- b.normalize();
- F32 w = ((n.cross(t)).dot(b) < 0.0) ? 1.0 : -1.0;
- vertTangents[i] = Vec4(t, w);
- }
- }
- //==============================================================================
- void MeshLoader::fixNormals()
- {
- FixNormalsMap map;
- // For all verts
- for(U i = 1; i < vertCoords.size(); i++)
- {
- const Vec3& pos = vertCoords[i];
- Vec3& norm = vertNormals[i];
- // Find pos
- FixNormalsMap::iterator it = map.find(pos);
- // Check if found
- if(it == map.end())
- {
- // Not found
- MapValue val;
- val.indices[0] = i;
- val.indicesCount = 1;
- map[pos] = val;
- }
- else
- {
- // Found
- MapValue& mapVal = it->second;
- ANKI_ASSERT(mapVal.indicesCount > 0);
- // Search the verts with the same position
- for(U j = 0; j < mapVal.indicesCount; j++)
- {
- const Vec3& posB = vertCoords[mapVal.indices[j]];
- Vec3& normB = vertNormals[mapVal.indices[j]];
- ANKI_ASSERT(posB == pos);
- (void)posB;
- F32 dot = norm.dot(normB);
- F32 ang = acos(dot);
- if(ang <= NORMALS_ANGLE_MERGE)
- {
- Vec3 newNormal = (norm + normB) * 0.5;
- newNormal.normalize();
- norm = newNormal;
- normB = newNormal;
- }
- }
- // Update the map
- mapVal.indices[mapVal.indicesCount++] = i;
- }
- }
- }
- } // end namespace anki
|