From 78d04c137d4a7ddb04f0a4cd9e7640fb475883fd Mon Sep 17 00:00:00 2001 From: Sebastian Matusik Date: Thu, 26 Apr 2018 17:34:27 +0100 Subject: [PATCH 1/4] Fix for blendshapes import when using the JoinIdenticalVertices optimization flag --- code/JoinVerticesProcess.cpp | 276 +++++++++++++++++++---------------- include/assimp/Vertex.h | 24 +++ 2 files changed, 178 insertions(+), 122 deletions(-) diff --git a/code/JoinVerticesProcess.cpp b/code/JoinVerticesProcess.cpp index cffe74fb2..881481f9c 100644 --- a/code/JoinVerticesProcess.cpp +++ b/code/JoinVerticesProcess.cpp @@ -114,6 +114,125 @@ void JoinVerticesProcess::Execute( aiScene* pScene) pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; } +namespace { + +bool areVerticesEqual(const Vertex &lhs, const Vertex &rhs, bool complex) +{ + // A little helper to find locally close vertices faster. + // Try to reuse the lookup table from the last step. + const static float epsilon = 1e-5f; + // Squared because we check against squared length of the vector difference + static const float squareEpsilon = epsilon * epsilon; + + // Square compare is useful for animeshes vertexes compare + if ((lhs.position - rhs.position).SquareLength() > squareEpsilon) { + return false; + } + + // We just test the other attributes even if they're not present in the mesh. + // In this case they're initialized to 0 so the comparison succeeds. + // By this method the non-present attributes are effectively ignored in the comparison. + if ((lhs.normal - rhs.normal).SquareLength() > squareEpsilon) { + return false; + } + + if ((lhs.texcoords[0] - rhs.texcoords[0]).SquareLength() > squareEpsilon) { + return false; + } + + if ((lhs.tangent - rhs.tangent).SquareLength() > squareEpsilon) { + return false; + } + + if ((lhs.bitangent - rhs.bitangent).SquareLength() > squareEpsilon) { + return false; + } + + // Usually we won't have vertex colors or multiple UVs, so we can skip from here + // Actually this increases runtime performance slightly, at least if branch + // prediction is on our side. + if (complex) { + for (int i = 0; i < 8; i++) { + if (i > 0 && (lhs.texcoords[i] - rhs.texcoords[i]).SquareLength() > squareEpsilon) { + return false; + } + if (GetColorDifference(lhs.colors[i], rhs.colors[i]) > squareEpsilon) { + return false; + } + } + } + return true; +} + +template +void updateXMeshVertices(XMesh *pMesh, std::vector &uniqueVertices) { + // replace vertex data with the unique data sets + pMesh->mNumVertices = (unsigned int)uniqueVertices.size(); + + // ---------------------------------------------------------------------------- + // NOTE - we're *not* calling Vertex::SortBack() because it would check for + // presence of every single vertex component once PER VERTEX. And our CPU + // dislikes branches, even if they're easily predictable. + // ---------------------------------------------------------------------------- + + // Position, if present (check made for aiAnimMesh) + if (pMesh->mVertices) + { + delete [] pMesh->mVertices; + pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { + pMesh->mVertices[a] = uniqueVertices[a].position; + } + } + + // Normals, if present + if (pMesh->mNormals) + { + delete [] pMesh->mNormals; + pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; + for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { + pMesh->mNormals[a] = uniqueVertices[a].normal; + } + } + // Tangents, if present + if (pMesh->mTangents) + { + delete [] pMesh->mTangents; + pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { + pMesh->mTangents[a] = uniqueVertices[a].tangent; + } + } + // Bitangents as well + if (pMesh->mBitangents) + { + delete [] pMesh->mBitangents; + pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { + pMesh->mBitangents[a] = uniqueVertices[a].bitangent; + } + } + // Vertex colors + for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) + { + delete [] pMesh->mColors[a]; + pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices]; + for( unsigned int b = 0; b < pMesh->mNumVertices; b++) { + pMesh->mColors[a][b] = uniqueVertices[b].colors[a]; + } + } + // Texture coords + for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) + { + delete [] pMesh->mTextureCoords[a]; + pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int b = 0; b < pMesh->mNumVertices; b++) { + pMesh->mTextureCoords[a][b] = uniqueVertices[b].texcoords[a]; + } + } +} +} // namespace + // ------------------------------------------------------------------------------------------------ // Unites identical vertices in the given mesh int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) @@ -138,9 +257,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff"); std::vector replaceIndex( pMesh->mNumVertices, 0xffffffff); - // A little helper to find locally close vertices faster. - // Try to reuse the lookup table from the last step. - const static float epsilon = 1e-5f; // float posEpsilonSqr; SpatialSort* vertexFinder = NULL; SpatialSort _vertexFinder; @@ -162,9 +278,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) // posEpsilonSqr = ComputePositionEpsilon(pMesh); } - // Squared because we check against squared length of the vector difference - static const float squareEpsilon = epsilon * epsilon; - // Again, better waste some bytes than a realloc ... std::vector verticesFound; verticesFound.reserve(10); @@ -172,6 +285,15 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) // Run an optimized code path if we don't have multiple UVs or vertex colors. // This should yield false in more than 99% of all imports ... const bool complex = ( pMesh->GetNumColorChannels() > 0 || pMesh->GetNumUVChannels() > 1); + const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0; + + // We'll never have more vertices afterwards. + std::vector uniqueAnimatedVertices[pMesh->mNumAnimMeshes]; + if (hasAnimMeshes) { + for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { + uniqueAnimatedVertices[animMeshIndex].reserve(pMesh->mNumVertices); + } + } // Now check each vertex if it brings something new to the table for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { @@ -184,74 +306,32 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) // check all unique vertices close to the position if this vertex is already present among them for( unsigned int b = 0; b < verticesFound.size(); b++) { - const unsigned int vidx = verticesFound[b]; const unsigned int uidx = replaceIndex[ vidx]; if( uidx & 0x80000000) continue; const Vertex& uv = uniqueVertices[ uidx]; - // Position mismatch is impossible - the vertex finder already discarded all non-matching positions - // We just test the other attributes even if they're not present in the mesh. - // In this case they're initialized to 0 so the comparison succeeds. - // By this method the non-present attributes are effectively ignored in the comparison. - if( (uv.normal - v.normal).SquareLength() > squareEpsilon) - continue; - if( (uv.texcoords[0] - v.texcoords[0]).SquareLength() > squareEpsilon) - continue; - if( (uv.tangent - v.tangent).SquareLength() > squareEpsilon) - continue; - if( (uv.bitangent - v.bitangent).SquareLength() > squareEpsilon) + if (!areVerticesEqual(v, uv, complex)) { continue; + } - // Usually we won't have vertex colors or multiple UVs, so we can skip from here - // Actually this increases runtime performance slightly, at least if branch - // prediction is on our side. - if (complex){ - // manually unrolled because continue wouldn't work as desired in an inner loop, - // also because some compilers seem to fail the task. Colors and UV coords - // are interleaved since the higher entries are most likely to be - // zero and thus useless. By interleaving the arrays, vertices are, - // on average, rejected earlier. - - if( (uv.texcoords[1] - v.texcoords[1]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[0], v.colors[0]) > squareEpsilon) - continue; - - if( (uv.texcoords[2] - v.texcoords[2]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[1], v.colors[1]) > squareEpsilon) - continue; - - if( (uv.texcoords[3] - v.texcoords[3]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[2], v.colors[2]) > squareEpsilon) - continue; - - if( (uv.texcoords[4] - v.texcoords[4]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[3], v.colors[3]) > squareEpsilon) - continue; - - if( (uv.texcoords[5] - v.texcoords[5]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[4], v.colors[4]) > squareEpsilon) - continue; - - if( (uv.texcoords[6] - v.texcoords[6]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[5], v.colors[5]) > squareEpsilon) - continue; - - if( (uv.texcoords[7] - v.texcoords[7]).SquareLength() > squareEpsilon) - continue; - if( GetColorDifference( uv.colors[6], v.colors[6]) > squareEpsilon) - continue; - - if( GetColorDifference( uv.colors[7], v.colors[7]) > squareEpsilon) + if (hasAnimMeshes) { + // If given vertex is animated, then it has to be preserver 1 to 1 (base mesh and animated mesh require same topology) + // NOTE: not doing this totaly breaks anim meshes as they don't have their own faces (they use pMesh->mFaces) + bool breaksAnimMesh = false; + for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { + const Vertex& animatedUV = uniqueAnimatedVertices[animMeshIndex][ uidx]; + Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a); + if (!areVerticesEqual(aniMeshVertex, animatedUV, complex)) { + breaksAnimMesh = true; + break; + } + } + if (breaksAnimMesh) { continue; + } } // we're still here -> this vertex perfectly matches our given vertex @@ -270,6 +350,12 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) // no unique vertex matches it up to now -> so add it replaceIndex[a] = (unsigned int)uniqueVertices.size(); uniqueVertices.push_back( v); + if (hasAnimMeshes) { + for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { + Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a); + uniqueAnimatedVertices[animMeshIndex].push_back(aniMeshVertex); + } + } } } @@ -287,64 +373,10 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) )); } - // replace vertex data with the unique data sets - pMesh->mNumVertices = (unsigned int)uniqueVertices.size(); - - // ---------------------------------------------------------------------------- - // NOTE - we're *not* calling Vertex::SortBack() because it would check for - // presence of every single vertex component once PER VERTEX. And our CPU - // dislikes branches, even if they're easily predictable. - // ---------------------------------------------------------------------------- - - // Position - delete [] pMesh->mVertices; - pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) - pMesh->mVertices[a] = uniqueVertices[a].position; - - // Normals, if present - if( pMesh->mNormals) - { - delete [] pMesh->mNormals; - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mNormals[a] = uniqueVertices[a].normal; - } - } - // Tangents, if present - if( pMesh->mTangents) - { - delete [] pMesh->mTangents; - pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mTangents[a] = uniqueVertices[a].tangent; - } - } - // Bitangents as well - if( pMesh->mBitangents) - { - delete [] pMesh->mBitangents; - pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mBitangents[a] = uniqueVertices[a].bitangent; - } - } - // Vertex colors - for( unsigned int a = 0; pMesh->HasVertexColors(a); a++) - { - delete [] pMesh->mColors[a]; - pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices]; - for( unsigned int b = 0; b < pMesh->mNumVertices; b++) { - pMesh->mColors[a][b] = uniqueVertices[b].colors[a]; - } - } - // Texture coords - for( unsigned int a = 0; pMesh->HasTextureCoords(a); a++) - { - delete [] pMesh->mTextureCoords[a]; - pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int b = 0; b < pMesh->mNumVertices; b++) { - pMesh->mTextureCoords[a][b] = uniqueVertices[b].texcoords[a]; + updateXMeshVertices(pMesh, uniqueVertices); + if (hasAnimMeshes) { + for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { + updateXMeshVertices(pMesh->mAnimMeshes[animMeshIndex], uniqueAnimatedVertices[animMeshIndex]); } } diff --git a/include/assimp/Vertex.h b/include/assimp/Vertex.h index 02ae3c0f4..f1c02ee07 100644 --- a/include/assimp/Vertex.h +++ b/include/assimp/Vertex.h @@ -134,6 +134,30 @@ public: } } + // ---------------------------------------------------------------------------- + /** Extract a particular vertex from a anim mesh and interleave all components */ + explicit Vertex(const aiAnimMesh* msh, unsigned int idx) { + ai_assert(idx < msh->mNumVertices); + position = msh->mVertices[idx]; + + if (msh->HasNormals()) { + normal = msh->mNormals[idx]; + } + + if (msh->HasTangentsAndBitangents()) { + tangent = msh->mTangents[idx]; + bitangent = msh->mBitangents[idx]; + } + + for (unsigned int i = 0; msh->HasTextureCoords(i); ++i) { + texcoords[i] = msh->mTextureCoords[i][idx]; + } + + for (unsigned int i = 0; msh->HasVertexColors(i); ++i) { + colors[i] = msh->mColors[i][idx]; + } + } + public: Vertex& operator += (const Vertex& v) { From 3e3a7857504fd5d4afd7ce9f1450ca2e857651c0 Mon Sep 17 00:00:00 2001 From: Sebastian Matusik Date: Thu, 5 Jul 2018 14:28:29 +0100 Subject: [PATCH 2/4] glTF v2 importer morph targets support --- code/glTF2Asset.h | 7 +++++ code/glTF2Asset.inl | 45 ++++++++++++++++++++++++++++++++ code/glTF2Importer.cpp | 59 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 107 insertions(+), 4 deletions(-) diff --git a/code/glTF2Asset.h b/code/glTF2Asset.h index 0ce843d09..b4545baa2 100644 --- a/code/glTF2Asset.h +++ b/code/glTF2Asset.h @@ -766,10 +766,17 @@ namespace glTF2 Ref indices; Ref material; + + struct Target { + AccessorList position, normal, tangent; + }; + std::vector targets; }; std::vector primitives; + std::vector weights; + Mesh() {} /// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root) diff --git a/code/glTF2Asset.inl b/code/glTF2Asset.inl index 5aa658f61..5a87715ce 100644 --- a/code/glTF2Asset.inl +++ b/code/glTF2Asset.inl @@ -931,6 +931,21 @@ namespace { else return false; return true; } + + inline bool GetAttribTargetVector(Mesh::Primitive& p, const int targetIndex, const char* attr, Mesh::AccessorList*& v, int& pos) + { + if ((pos = Compare(attr, "POSITION"))) { + v = &(p.targets[targetIndex].position); + } + else if ((pos = Compare(attr, "NORMAL"))) { + v = &(p.targets[targetIndex].normal); + } + else if ((pos = Compare(attr, "TANGENT"))) { + v = &(p.targets[targetIndex].tangent); + } + else return false; + return true; + } } inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root) @@ -965,6 +980,26 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root) } } + if (Value* targetsArray = FindArray(primitive, "targets")) { + prim.targets.resize(targetsArray->Size()); + for (unsigned int i = 0; i < targetsArray->Size(); ++i) { + Value& target = (*targetsArray)[i]; + if (!target.IsObject()) continue; + for (Value::MemberIterator it = target.MemberBegin(); it != target.MemberEnd(); ++it) { + if (!it->value.IsUint()) continue; + const char* attr = it->name.GetString(); + // Valid attribute semantics include POSITION, NORMAL, TANGENT + int undPos = 0; + Mesh::AccessorList* vec = 0; + if (GetAttribTargetVector(prim, i, attr, vec, undPos)) { + size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0; + if ((*vec).size() <= idx) (*vec).resize(idx + 1); + (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint()); + } + } + } + } + if (Value* indices = FindUInt(primitive, "indices")) { prim.indices = pAsset_Root.accessors.Retrieve(indices->GetUint()); } @@ -974,6 +1009,16 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root) } } } + + if (Value* weights = FindArray(pJSON_Object, "weights")) { + this->weights.resize(weights->Size()); + for (unsigned int i = 0; i < weights->Size(); ++i) { + Value& weightValue = (*weights)[i]; + if (weightValue.IsNumber()) { + this->weights[i] = weightValue.GetFloat(); + } + } + } } inline void Camera::Read(Value& obj, Asset& /*r*/) diff --git a/code/glTF2Importer.cpp b/code/glTF2Importer.cpp index 15c338716..ab1f9b13f 100644 --- a/code/glTF2Importer.cpp +++ b/code/glTF2Importer.cpp @@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include @@ -65,6 +66,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; using namespace glTF2; +namespace { + // generate bitangents from normals and tangents according to spec + struct Tangent { + aiVector3D xyz; + ai_real w; + }; +} // namespace // // glTF2Importer @@ -416,10 +424,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) // only extract tangents if normals are present if (attr.tangent.size() > 0 && attr.tangent[0]) { // generate bitangents from normals and tangents according to spec - struct Tangent { - aiVector3D xyz; - ai_real w; - } *tangents = nullptr; + Tangent *tangents = nullptr; attr.tangent[0]->ExtractData(tangents); @@ -445,6 +450,52 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) } } + std::vector& targets = prim.targets; + if (targets.size() > 0) { + aim->mNumAnimMeshes = targets.size(); + aim->mAnimMeshes = new aiAnimMesh*[aim->mNumAnimMeshes]; + for (size_t i = 0; i < targets.size(); i++) { + aim->mAnimMeshes[i] = aiCreateAnimMesh(aim); + aiAnimMesh& aiAnimMesh = *(aim->mAnimMeshes[i]); + Mesh::Primitive::Target& target = targets[i]; + + if (target.position.size() > 0) { + aiVector3D *positionDiff == nullptr; + target.position[0]->ExtractData(positionDiff); + for(int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { + aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId]; + } + delete [] positionDiff; + } + if (target.normal.size() > 0) { + aiVector3D *normalDiff == nullptr; + target.normal[0]->ExtractData(normalDiff); + for(int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { + aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId]; + } + delete [] normalDiff; + } + if (target.tangent.size() > 0) { + Tangent *tangent = nullptr; + attr.tangent[0]->ExtractData(tangent); + + aiVector3D *tangentDiff = nullptr; + target.tangent[0]->ExtractData(tangentDiff); + + for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) { + tangent[vertexId].xyz += tangentDiff[vertexId]; + aiAnimMesh.mTangents[vertexId] = tangent[vertexId]; + aiAnimMesh.mBitangents[vertexId] = (aiAnimMesh.mNormals[vertexId] ^ tangent[vertexId].xyz) * tangent[vertexId].w; + } + delete [] tangent; + delete [] tangentDiff; + } + if (mesh.weights.size() > i) { + aiAnimMesh.mWeight = mesh.weights[i]; + } + } + } + if (prim.indices) { aiFace* faces = 0; From 0cc924088660d16343a938cfe3f5eb363969416b Mon Sep 17 00:00:00 2001 From: Sebastian Matusik Date: Thu, 5 Jul 2018 14:46:15 +0100 Subject: [PATCH 3/4] Build fix --- code/glTF2Importer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/glTF2Importer.cpp b/code/glTF2Importer.cpp index ab1f9b13f..969afa405 100644 --- a/code/glTF2Importer.cpp +++ b/code/glTF2Importer.cpp @@ -460,7 +460,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) Mesh::Primitive::Target& target = targets[i]; if (target.position.size() > 0) { - aiVector3D *positionDiff == nullptr; + aiVector3D *positionDiff = nullptr; target.position[0]->ExtractData(positionDiff); for(int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId]; @@ -468,7 +468,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) delete [] positionDiff; } if (target.normal.size() > 0) { - aiVector3D *normalDiff == nullptr; + aiVector3D *normalDiff = nullptr; target.normal[0]->ExtractData(normalDiff); for(int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId]; @@ -484,7 +484,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) { tangent[vertexId].xyz += tangentDiff[vertexId]; - aiAnimMesh.mTangents[vertexId] = tangent[vertexId]; + aiAnimMesh.mTangents[vertexId] = tangent[vertexId].xyz; aiAnimMesh.mBitangents[vertexId] = (aiAnimMesh.mNormals[vertexId] ^ tangent[vertexId].xyz) * tangent[vertexId].w; } delete [] tangent; From 992194b1b9f9a75242a2ba10a9dd8442ac0ca269 Mon Sep 17 00:00:00 2001 From: Sebastian Matusik Date: Thu, 5 Jul 2018 15:15:50 +0100 Subject: [PATCH 4/4] Removed signed int vs unsigned int comparison in for loops --- code/glTF2Importer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/glTF2Importer.cpp b/code/glTF2Importer.cpp index 969afa405..7b19dda50 100644 --- a/code/glTF2Importer.cpp +++ b/code/glTF2Importer.cpp @@ -462,7 +462,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) if (target.position.size() > 0) { aiVector3D *positionDiff = nullptr; target.position[0]->ExtractData(positionDiff); - for(int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { + for(unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId]; } delete [] positionDiff; @@ -470,7 +470,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) if (target.normal.size() > 0) { aiVector3D *normalDiff = nullptr; target.normal[0]->ExtractData(normalDiff); - for(int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { + for(unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) { aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId]; } delete [] normalDiff;