diff --git a/Engine/lib/assimp/code/glTF2Asset.inl b/Engine/lib/assimp/code/glTF2Asset.inl index 196d664cb..b12a92f3a 100644 --- a/Engine/lib/assimp/code/glTF2Asset.inl +++ b/Engine/lib/assimp/code/glTF2Asset.inl @@ -405,8 +405,10 @@ inline void Buffer::Read(Value& obj, Asset& r) inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseOffset) { byteLength = length ? length : stream.FileSize(); + //T3D_CHANGE_BEGIN if ((byteLength + baseOffset) > stream.FileSize()) byteLength = stream.FileSize() - baseOffset; + //T3D_CHANGE_END if (baseOffset) { stream.Seek(baseOffset, aiOrigin_SET); diff --git a/Engine/lib/assimp/code/glTF2Importer.cpp b/Engine/lib/assimp/code/glTF2Importer.cpp index 4228db23f..c2acdcd66 100644 --- a/Engine/lib/assimp/code/glTF2Importer.cpp +++ b/Engine/lib/assimp/code/glTF2Importer.cpp @@ -822,8 +822,6 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector& if (node.skin) { for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) { aiMesh* mesh = pScene->mMeshes[meshOffsets[mesh_idx]+primitiveNo]; - mesh->mNumBones = static_cast(node.skin->jointNames.size()); - mesh->mBones = new aiBone*[mesh->mNumBones]; // GLTF and Assimp choose to store bone weights differently. // GLTF has each vertex specify which bones influence the vertex. @@ -834,39 +832,98 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector& // both because it's somewhat slow and because, for many applications, // we then need to reconvert the data back into the vertex-to-bone // mapping which makes things doubly-slow. - std::vector> weighting(mesh->mNumBones); + + //T3D_CHANGE_BEGIN + // The following commented block has been completely replaced. + // Portions of the replacement code block have been taken from: + // https://github.com/ConfettiFX/The-Forge/blob/master/Common_3/ThirdParty/OpenSource/assimp/4.1.0/code/glTF2Importer.cpp#L823-L860 + //std::vector> weighting(mesh->mNumBones); + //BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); + + //for (uint32_t i = 0; i < mesh->mNumBones; ++i) { + // aiBone* bone = new aiBone(); + + // Ref joint = node.skin->jointNames[i]; + // if (!joint->name.empty()) { + // bone->mName = joint->name; + // } else { + // // Assimp expects each bone to have a unique name. + // static const std::string kDefaultName = "bone_"; + // char postfix[10] = {0}; + // ASSIMP_itoa10(postfix, i); + // bone->mName = (kDefaultName + postfix); + // } + // GetNodeTransform(bone->mOffsetMatrix, *joint); + + // std::vector& weights = weighting[i]; + + // bone->mNumWeights = static_cast(weights.size()); + // if (bone->mNumWeights > 0) { + // bone->mWeights = new aiVertexWeight[bone->mNumWeights]; + // memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); + // } else { + // // Assimp expects all bones to have at least 1 weight. + // bone->mWeights = new aiVertexWeight[1]; + // bone->mNumWeights = 1; + // bone->mWeights->mVertexId = 0; + // bone->mWeights->mWeight = 0.f; + // } + // mesh->mBones[i] = bone; + + std::vector> weighting(node.skin->jointNames.size()); BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); - for (uint32_t i = 0; i < mesh->mNumBones; ++i) { - aiBone* bone = new aiBone(); - - Ref joint = node.skin->jointNames[i]; - if (!joint->name.empty()) { - bone->mName = joint->name; - } else { - // Assimp expects each bone to have a unique name. - static const std::string kDefaultName = "bone_"; - char postfix[10] = {0}; - ASSIMP_itoa10(postfix, i); - bone->mName = (kDefaultName + postfix); - } - GetNodeTransform(bone->mOffsetMatrix, *joint); - - std::vector& weights = weighting[i]; - - bone->mNumWeights = static_cast(weights.size()); - if (bone->mNumWeights > 0) { - bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); - } else { - // Assimp expects all bones to have at least 1 weight. - bone->mWeights = new aiVertexWeight[1]; - bone->mNumWeights = 1; - bone->mWeights->mVertexId = 0; - bone->mWeights->mWeight = 0.f; - } - mesh->mBones[i] = bone; + // CONFFX_BEGIN + // Assimp doesn't support bones with no weight. We have to count the + // number of bones that affect the mesh and limit it to just those bones. + int numBones = 0; + for (size_t i = 0; i < node.skin->jointNames.size(); ++i) { + if (!weighting[i].empty()) + ++numBones; } + + mesh->mNumBones = numBones; + if (numBones > 0) + { + mesh->mBones = new aiBone*[mesh->mNumBones]; + + int j = 0; + for (size_t i = 0; i < node.skin->jointNames.size(); ++i) { + if (!weighting[i].empty()) + { + aiBone* bone = new aiBone(); + + Ref joint = node.skin->jointNames[i]; + bone->mName = joint->name.empty() ? joint->id : joint->name; + + // Get the inverseBindMatrix for the joint, grab the position out of row 4, + // invert the matrix and put the position back as column 4. + aiMatrix4x4 *tmpMat; + uint8_t *matPtr = node.skin->inverseBindMatrices->GetPointer(); + tmpMat = (aiMatrix4x4*)matPtr; + bone->mOffsetMatrix = tmpMat[i]; + aiVector3D tmpPos(bone->mOffsetMatrix.d1, bone->mOffsetMatrix.d2, bone->mOffsetMatrix.d3); + bone->mOffsetMatrix.d1 = bone->mOffsetMatrix.d2 = bone->mOffsetMatrix.d3 = 0.0; + bone->mOffsetMatrix.Inverse(); + bone->mOffsetMatrix.a4 = tmpPos.x; + bone->mOffsetMatrix.b4 = tmpPos.y; + bone->mOffsetMatrix.c4 = tmpPos.z; + + std::vector& weights = weighting[i]; + + bone->mNumWeights = static_cast(weights.size()); + if (bone->mNumWeights > 0) { + bone->mWeights = new aiVertexWeight[bone->mNumWeights]; + memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); + } + mesh->mBones[j++] = bone; + } + } + } + else + mesh->mBones = nullptr; + // CONFFX_END + //T3D_CHANGE_END } } @@ -921,7 +978,10 @@ struct AnimationSamplers { aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers) { aiNodeAnim* anim = new aiNodeAnim(); - anim->mNodeName = node.name; + //T3D_CHANGE_BEGIN + //anim->mNodeName = node.name; + anim->mNodeName = node.name.empty() ? node.id : node.name; + //T3D_CHANGE_END static const float kMillisecondsFromSeconds = 1000.f; @@ -1042,15 +1102,27 @@ void glTF2Importer::ImportAnimations(glTF2::Asset& r) std::unordered_map samplers = GatherSamplers(anim); - ai_anim->mNumChannels = static_cast(samplers.size()); + //T3D_CHANGE_BEGIN + //ai_anim->mNumChannels = static_cast(samplers.size()); + //if (ai_anim->mNumChannels > 0) { + // ai_anim->mChannels = new aiNodeAnim*[ai_anim->mNumChannels]; + // int j = 0; + // for (auto& iter : samplers) { + // ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second); + // ++j; + // } + //} + + ai_anim->mNumChannels = r.skins.Size() > 0 ? r.skins[0].jointNames.size() : 0; if (ai_anim->mNumChannels > 0) { ai_anim->mChannels = new aiNodeAnim*[ai_anim->mNumChannels]; int j = 0; - for (auto& iter : samplers) { - ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second); + for (auto& iter : r.skins[0].jointNames) { + ai_anim->mChannels[j] = CreateNodeAnim(r, *iter, samplers[iter.GetIndex()]); ++j; } } + //T3D_CHANGE_END // Use the latest keyframe for the duration of the animation double maxDuration = 0; diff --git a/Engine/lib/assimp/code/glTFAsset.inl b/Engine/lib/assimp/code/glTFAsset.inl index 5c65767d1..10bc4d1ef 100644 --- a/Engine/lib/assimp/code/glTFAsset.inl +++ b/Engine/lib/assimp/code/glTFAsset.inl @@ -345,8 +345,10 @@ inline void Buffer::Read(Value& obj, Asset& r) inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseOffset) { byteLength = length ? length : stream.FileSize(); + //T3D_CHANGE_BEGIN if ((byteLength + baseOffset) > stream.FileSize()) byteLength = stream.FileSize() - baseOffset; + //T3D_CHANGE_END if (baseOffset) { stream.Seek(baseOffset, aiOrigin_SET);