| 55 | |
| 56 | std::unordered_map<std::string, uint32_t> bonesNameIDMap; |
| 57 | Ref<SkinnedModel> ModelLoader::LoadSkinnedModel(const std::string& path, bool absolute) |
| 58 | { |
| 59 | bonesNameIDMap = std::unordered_map<std::string, uint32_t>(); |
| 60 | m_BoneMap = std::unordered_map<std::string, Bone>(); |
| 61 | |
| 62 | m_SkinnedMeshes.clear(); |
| 63 | Ref<SkinnedModel> model = CreateRef<SkinnedModel>(path); |
| 64 | |
| 65 | Assimp::Importer importer; |
| 66 | importer.SetPropertyFloat("PP_GSN_MAX_SMOOTHING_ANGLE", 90); |
| 67 | |
| 68 | auto importFlags = |
| 69 | aiProcess_Triangulate | |
| 70 | aiProcess_GenSmoothNormals | |
| 71 | aiProcess_FixInfacingNormals | |
| 72 | aiProcess_CalcTangentSpace | |
| 73 | aiProcess_OptimizeGraph; |
| 74 | |
| 75 | modelDir = absolute ? path + "/../" : FileSystem::Root + path + "/../"; |
| 76 | const std::string filePath = absolute ? path : FileSystem::Root + path; |
| 77 | const aiScene* scene = importer.ReadFile(filePath, importFlags); |
| 78 | if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) |
| 79 | { |
| 80 | std::string assimpErrorMsg = std::string(importer.GetErrorString()); |
| 81 | std::string logMsg = "Failed to load model: " + assimpErrorMsg; |
| 82 | Logger::Log(logMsg, "model", WARNING); |
| 83 | |
| 84 | return model; |
| 85 | } |
| 86 | |
| 87 | ProcessSkinnedNode(scene->mRootNode, scene); |
| 88 | if (scene->HasAnimations()) |
| 89 | { |
| 90 | std::vector<Ref<SkeletalAnimation>> animations = std::vector<Ref<SkeletalAnimation>>(); |
| 91 | |
| 92 | // Parse animations |
| 93 | for (uint32_t i = 0; i < scene->mNumAnimations; i++) |
| 94 | { |
| 95 | aiAnimation* aiAnim = scene->mAnimations[i]; |
| 96 | |
| 97 | const std::string animationName = aiAnim->mName.data; |
| 98 | const float animationDuration = static_cast<float>(aiAnim->mDuration); |
| 99 | const float animationTicksPerSecond = static_cast<float>(aiAnim->mTicksPerSecond); |
| 100 | auto animation = CreateRef<SkeletalAnimation>(animationName, animationDuration, animationTicksPerSecond); |
| 101 | |
| 102 | // Here we iterate over every channel(each channel represents a bone) and fill the SkeletalAnimation |
| 103 | // object with every keyframe. We essentially just convert every assimp vector, quat, string to our own types. |
| 104 | for (uint32_t j = 0; j < aiAnim->mNumChannels; j++) |
| 105 | { |
| 106 | aiNodeAnim* animChannel = aiAnim->mChannels[j]; |
| 107 | const std::string channelName = animChannel->mNodeName.data; // this should be a bone name |
| 108 | |
| 109 | // Create the track |
| 110 | BoneTransformTrack& track = animation->GetTrack(channelName); |
| 111 | |
| 112 | // Create every keyframe in the current channel |
| 113 | // Position |
| 114 | for (uint32_t p = 0; p < animChannel->mNumPositionKeys; p++) |
no test coverage detected