#include "BoneAnimatedModel.h" #include #include #include #include #include namespace ZL { int getIndexByValue(const std::string& name, const std::vector& words) { for (int i = 0; i < words.size(); i++) { if (words[i] == name) { return i; } } return -1; } void BoneSystem::LoadFromFile(const std::string& fileName, const std::string& ZIPFileName) { std::ifstream filestream; std::istringstream zipStream; if (!ZIPFileName.empty()) { std::vector fileData = readFileFromZIP(fileName, ZIPFileName); std::string fileContents(fileData.begin(), fileData.end()); zipStream.str(fileContents); } else { filestream.open(fileName); } std::istream& f = (!ZIPFileName.empty()) ? static_cast(zipStream) : static_cast(filestream); //Skip first 5 lines std::string tempLine; for (int i = 0; i < 5; i++) { std::getline(f, tempLine); } std::getline(f, tempLine); static const std::regex pattern_count(R"(\d+)"); static const std::regex pattern_float(R"([-]?\d+\.\d+)"); static const std::regex pattern_int(R"([-]?\d+)"); static const std::regex pattern_boneChildren(R"(\'([^\']+)\')"); static const std::regex pattern_bone_weight(R"(\'([^\']+)\'.*?([-]?\d+\.\d+))"); std::smatch match; int numberBones; if (std::regex_search(tempLine, match, pattern_count)) { std::string number_str = match.str(); numberBones = std::stoi(number_str); } else { throw std::runtime_error("No number found in the input string."); } std::vector bones; std::vector boneNames; std::vector boneParentNames; std::unordered_map> boneChildren; bones.resize(numberBones); boneNames.resize(numberBones); boneParentNames.resize(numberBones); for (int i = 0; i < numberBones; i++) { std::getline(f, tempLine); std::string boneName = tempLine.substr(6); boneNames[i] = boneName; std::getline(f, tempLine); std::vector floatValues; auto b = tempLine.cbegin(); auto e = tempLine.cend(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } bones[i].boneStartWorld = Vector3f{ floatValues[0], floatValues[1], floatValues[2] }; std::getline(f, tempLine); //skip tail std::getline(f, tempLine); //len if (std::regex_search(tempLine, match, pattern_float)) { std::string len_str = match.str(); bones[i].boneLength = std::stof(len_str); } else { throw std::runtime_error("No number found in the input string."); } //---------- matrix begin std::getline(f, tempLine); b = tempLine.cbegin(); e = tempLine.cend(); floatValues.clear(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } bones[i].boneMatrixWorld.m[0] = floatValues[0]; bones[i].boneMatrixWorld.m[0 + 1 * 3] = floatValues[1]; bones[i].boneMatrixWorld.m[0 + 2 * 3] = floatValues[2]; std::getline(f, tempLine); b = tempLine.cbegin(); e = tempLine.cend(); floatValues.clear(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } bones[i].boneMatrixWorld.m[1] = floatValues[0]; bones[i].boneMatrixWorld.m[1 + 1 * 3] = floatValues[1]; bones[i].boneMatrixWorld.m[1 + 2 * 3] = floatValues[2]; std::getline(f, tempLine); b = tempLine.cbegin(); e = tempLine.cend(); floatValues.clear(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } bones[i].boneMatrixWorld.m[2] = floatValues[0]; bones[i].boneMatrixWorld.m[2 + 1 * 3] = floatValues[1]; bones[i].boneMatrixWorld.m[2 + 2 * 3] = floatValues[2]; //----------- matrix end std::getline(f, tempLine); //parent if (tempLine == " Parent: None") { bones[i].parent = -1; } else { std::string boneParent = tempLine.substr(10); boneParentNames[i] = boneParent; } std::getline(f, tempLine); //children b = tempLine.cbegin(); e = tempLine.cend(); while (std::regex_search(b, e, match, pattern_boneChildren)) { boneChildren[boneName].push_back(match.str(1)); b = match.suffix().first; } } //Now process all the bones: for (int i = 0; i < numberBones; i++) { std::string boneName = boneNames[i]; std::string boneParent = boneParentNames[i]; if (boneParent == "") { bones[i].parent = -1; } else { bones[i].parent = getIndexByValue(boneParent, boneNames); } for (int j = 0; j < boneChildren[boneName].size(); j++) { bones[i].children.push_back(getIndexByValue(boneChildren[boneName][j], boneNames)); } /*if (boneName == "Bone.020") { std::cout << i << std::endl; }*/ } startBones = bones; currentBones = bones; ///std::cout << "Hello!" << std::endl; std::getline(f, tempLine); //vertice count int numberVertices; if (std::regex_search(tempLine, match, pattern_count)) { std::string number_str = match.str(); numberVertices = std::stoi(number_str); } else { throw std::runtime_error("No number found in the input string."); } std::vector vertices; vertices.resize(numberVertices); for (int i = 0; i < numberVertices; i++) { std::getline(f, tempLine); std::vector floatValues; auto b = tempLine.cbegin(); auto e = tempLine.cend(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } vertices[i] = Vector3f{floatValues[0], floatValues[1], floatValues[2]}; } //==== process uv and normals begin std::cout << "Hello x1" << std::endl; std::getline(f, tempLine); //===UV Coordinates: std::getline(f, tempLine); //triangle count int numberTriangles; if (std::regex_search(tempLine, match, pattern_count)) { std::string number_str = match.str(); numberTriangles = std::stoi(number_str); } else { throw std::runtime_error("No number found in the input string."); } // Now process UVs std::vector> uvCoords; uvCoords.resize(numberTriangles); for (int i = 0; i < numberTriangles; i++) { std::getline(f, tempLine); //Face 0 int uvCount; std::getline(f, tempLine); if (std::regex_search(tempLine, match, pattern_count)) { std::string number_str = match.str(); uvCount = std::stoi(number_str); } else { throw std::runtime_error("No number found in the input string."); } if (uvCount != 3) { throw std::runtime_error("more than 3 uvs"); } std::vector floatValues; for (int j = 0; j < 3; j++) { std::getline(f, tempLine); //UV auto b = tempLine.cbegin(); auto e = tempLine.cend(); floatValues.clear(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } if (floatValues.size() != 2) { throw std::runtime_error("more than 2 uvs---"); } uvCoords[i][j] = Vector2f{ floatValues[0],floatValues[1] }; } } std::cout << "Hello eee" << std::endl; std::getline(f, tempLine); //===Normals: std::vector normals; normals.resize(numberVertices); for (int i = 0; i < numberVertices; i++) { std::getline(f, tempLine); std::vector floatValues; auto b = tempLine.cbegin(); auto e = tempLine.cend(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } normals[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] }; } //==== process uv and normals end std::getline(f, tempLine); //triangle count. //numberTriangles; //Need to check if new value is the same as was read before if (std::regex_search(tempLine, match, pattern_count)) { std::string number_str = match.str(); numberTriangles = std::stoi(number_str); } else { throw std::runtime_error("No number found in the input string."); } std::vector> triangles; triangles.resize(numberTriangles); for (int i = 0; i < numberTriangles; i++) { std::getline(f, tempLine); std::vector intValues; auto b = tempLine.cbegin(); auto e = tempLine.cend(); while (std::regex_search(b, e, match, pattern_int)) { intValues.push_back(std::stoi(match.str())); b = match.suffix().first; } triangles[i] = { intValues[0], intValues[1], intValues[2] }; } std::getline(f, tempLine);//=== Vertex Weights === std::vector> localVerticesBoneWeight; localVerticesBoneWeight.resize(numberVertices); for (int i = 0; i < numberVertices; i++) { std::getline(f, tempLine); //skip Vertex 0: std::getline(f, tempLine); //vertex group count int boneCount; if (std::regex_search(tempLine, match, pattern_count)) { std::string number_str = match.str(); boneCount = std::stoi(number_str); } else { throw std::runtime_error("No number found in the input string."); } if (boneCount > MAX_BONE_COUNT) { throw std::runtime_error("more than 5 bones"); } float sumWeights = 0; for (int j = 0; j < boneCount; j++) { std::getline(f, tempLine); //Group: 'Bone', Weight: 0.9929084181785583 if (std::regex_search(tempLine, match, pattern_bone_weight)) { // ��������� ����� (��� �������) std::string word = match.str(1); double weight = std::stod(match.str(2)); int boneNumber = getIndexByValue(word, boneNames); localVerticesBoneWeight[i][j].boneIndex = boneNumber; localVerticesBoneWeight[i][j].weight = weight; sumWeights += weight; } else { throw std::runtime_error("No match found in the input string."); } } //Normalize weights: for (int j = 0; j < boneCount; j++) { localVerticesBoneWeight[i][j].weight = localVerticesBoneWeight[i][j].weight / sumWeights; } } std::getline(f, tempLine);//=== Animation Keyframes === std::getline(f, tempLine);//=== Bone Transforms per Keyframe === std::getline(f, tempLine); int numberKeyFrames; if (std::regex_search(tempLine, match, pattern_count)) { std::string number_str = match.str(); numberKeyFrames = std::stoi(number_str); } else { throw std::runtime_error("No number found in the input string."); } animations.resize(1); animations[0].keyFrames.resize(numberKeyFrames); for (int i = 0; i < numberKeyFrames; i++) { std::getline(f, tempLine); int numberFrame; if (std::regex_search(tempLine, match, pattern_count)) { std::string number_str = match.str(); numberFrame = std::stoi(number_str); } else { throw std::runtime_error("No number found in the input string."); } animations[0].keyFrames[i].frame = numberFrame; animations[0].keyFrames[i].bones.resize(numberBones); for (int j = 0; j < numberBones; j++) { std::getline(f, tempLine); std::string boneName = tempLine.substr(8); int boneNumber = getIndexByValue(boneName, boneNames); animations[0].keyFrames[i].bones[boneNumber] = startBones[boneNumber]; std::getline(f, tempLine); // Location: std::vector floatValues; auto b = tempLine.cbegin(); auto e = tempLine.cend(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } animations[0].keyFrames[i].bones[boneNumber].boneStartWorld = Vector3f{ floatValues[0], floatValues[1], floatValues[2] }; std::getline(f, tempLine); // Rotation std::getline(f, tempLine); // Matrix //=============== Matrix begin ================== std::getline(f, tempLine); b = tempLine.cbegin(); e = tempLine.cend(); floatValues.clear(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[0] = floatValues[0]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[0 + 1 * 4] = floatValues[1]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[0 + 2 * 4] = floatValues[2]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[0 + 3 * 4] = floatValues[3]; std::getline(f, tempLine); b = tempLine.cbegin(); e = tempLine.cend(); floatValues.clear(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[1] = floatValues[0]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[1 + 1 * 4] = floatValues[1]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[1 + 2 * 4] = floatValues[2]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[1 + 3 * 4] = floatValues[3]; std::getline(f, tempLine); b = tempLine.cbegin(); e = tempLine.cend(); floatValues.clear(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[2] = floatValues[0]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[2 + 1 * 4] = floatValues[1]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[2 + 2 * 4] = floatValues[2]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[2 + 3 * 4] = floatValues[3]; std::getline(f, tempLine); b = tempLine.cbegin(); e = tempLine.cend(); floatValues.clear(); while (std::regex_search(b, e, match, pattern_float)) { floatValues.push_back(std::stof(match.str())); b = match.suffix().first; } animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[3] = floatValues[0]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[3 + 1 * 4] = floatValues[1]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[3 + 2 * 4] = floatValues[2]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[3 + 3 * 4] = floatValues[3]; //std::getline(f, tempLine);// ignore last matrix line //=============== Matrix end ================== } } // Now let's process bone weights and vertices for (int i = 0; i < numberTriangles; i++) { mesh.PositionData.push_back(vertices[triangles[i][0]]); mesh.PositionData.push_back(vertices[triangles[i][1]]); mesh.PositionData.push_back(vertices[triangles[i][2]]); verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][0]]); verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][1]]); verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][2]]); mesh.TexCoordData.push_back(uvCoords[i][0]); mesh.TexCoordData.push_back(uvCoords[i][1]); mesh.TexCoordData.push_back(uvCoords[i][2]); } startMesh = mesh; } void BoneSystem::Interpolate(int frame) { int startingFrame = -1; for (int i = 0; i < animations[0].keyFrames.size() - 1; i++) { int oldFrame = animations[0].keyFrames[i].frame; int nextFrame = animations[0].keyFrames[i + 1].frame; if (frame >= oldFrame && frame < nextFrame) { startingFrame = i; break; } } if (startingFrame == -1) { throw std::runtime_error("Exception here"); } int modifiedFrameNumber = frame - animations[0].keyFrames[startingFrame].frame; int diffFrames = animations[0].keyFrames[startingFrame + 1].frame - animations[0].keyFrames[startingFrame].frame; float t = (modifiedFrameNumber + 0.f) / diffFrames; std::vector& oneFrameBones = animations[0].keyFrames[startingFrame].bones; std::vector& nextFrameBones = animations[0].keyFrames[startingFrame+1].bones; std::vector skinningMatrixForEachBone; //std::vector skinningMatrixForEachBone; skinningMatrixForEachBone.resize(currentBones.size()); for (int i = 0; i < currentBones.size(); i++) { currentBones[i].boneStartWorld.v[0] = oneFrameBones[i].boneStartWorld.v[0] + t * (nextFrameBones[i].boneStartWorld.v[0] - oneFrameBones[i].boneStartWorld.v[0]); currentBones[i].boneStartWorld.v[1] = oneFrameBones[i].boneStartWorld.v[1] + t * (nextFrameBones[i].boneStartWorld.v[1] - oneFrameBones[i].boneStartWorld.v[1]); currentBones[i].boneStartWorld.v[2] = oneFrameBones[i].boneStartWorld.v[2] + t * (nextFrameBones[i].boneStartWorld.v[2] - oneFrameBones[i].boneStartWorld.v[2]); Matrix3f oneFrameBonesMatrix; oneFrameBonesMatrix.m[0] = oneFrameBones[i].boneMatrixWorld.m[0]; oneFrameBonesMatrix.m[1] = oneFrameBones[i].boneMatrixWorld.m[1]; oneFrameBonesMatrix.m[2] = oneFrameBones[i].boneMatrixWorld.m[2]; oneFrameBonesMatrix.m[3] = oneFrameBones[i].boneMatrixWorld.m[0 + 1*4]; oneFrameBonesMatrix.m[4] = oneFrameBones[i].boneMatrixWorld.m[1 + 1*4]; oneFrameBonesMatrix.m[5] = oneFrameBones[i].boneMatrixWorld.m[2 + 1*4]; oneFrameBonesMatrix.m[6] = oneFrameBones[i].boneMatrixWorld.m[0 + 2*4]; oneFrameBonesMatrix.m[7] = oneFrameBones[i].boneMatrixWorld.m[1 + 2*4]; oneFrameBonesMatrix.m[8] = oneFrameBones[i].boneMatrixWorld.m[2 + 2*4]; Matrix3f nextFrameBonesMatrix; nextFrameBonesMatrix.m[0] = nextFrameBones[i].boneMatrixWorld.m[0]; nextFrameBonesMatrix.m[1] = nextFrameBones[i].boneMatrixWorld.m[1]; nextFrameBonesMatrix.m[2] = nextFrameBones[i].boneMatrixWorld.m[2]; nextFrameBonesMatrix.m[3] = nextFrameBones[i].boneMatrixWorld.m[0 + 1 * 4]; nextFrameBonesMatrix.m[4] = nextFrameBones[i].boneMatrixWorld.m[1 + 1 * 4]; nextFrameBonesMatrix.m[5] = nextFrameBones[i].boneMatrixWorld.m[2 + 1 * 4]; nextFrameBonesMatrix.m[6] = nextFrameBones[i].boneMatrixWorld.m[0 + 2 * 4]; nextFrameBonesMatrix.m[7] = nextFrameBones[i].boneMatrixWorld.m[1 + 2 * 4]; nextFrameBonesMatrix.m[8] = nextFrameBones[i].boneMatrixWorld.m[2 + 2 * 4]; Vector4f q1 = MatrixToQuat(oneFrameBonesMatrix); Vector4f q2 = MatrixToQuat(nextFrameBonesMatrix); Vector4f q1_norm = q1.normalized(); Vector4f q2_norm = q2.normalized(); Vector4f result = slerp(q1_norm, q2_norm, t); Matrix3f boneMatrixWorld3 = QuatToMatrix(result); currentBones[i].boneMatrixWorld = MakeMatrix4x4(boneMatrixWorld3, currentBones[i].boneStartWorld); Matrix4f currentBoneMatrixWorld4 = currentBones[i].boneMatrixWorld; Matrix4f startBoneMatrixWorld4 = animations[0].keyFrames[0].bones[i].boneMatrixWorld; Matrix4f inverstedStartBoneMatrixWorld4 = InverseMatrix(startBoneMatrixWorld4); skinningMatrixForEachBone[i] = MultMatrixMatrix(currentBoneMatrixWorld4, inverstedStartBoneMatrixWorld4); } /* for (int i = 0; i < currentBones.size(); i++) { currentBones[i].boneStartWorld = oneFrameBones[i].boneStartWorld; currentBones[i].boneMatrixWorld = oneFrameBones[i].boneMatrixWorld; //Matrix4f currentBoneMatrixWorld4 = MakeMatrix4x4(currentBones[i].boneMatrixWorld, currentBones[i].boneStartWorld); //Matrix4f startBoneMatrixWorld4 = MakeMatrix4x4(animations[0].keyFrames[0].bones[i].boneMatrixWorld, animations[0].keyFrames[0].bones[i].boneStartWorld); Matrix4f currentBoneMatrixWorld4 = currentBones[i].boneMatrixWorld; Matrix4f startBoneMatrixWorld4 = animations[0].keyFrames[0].bones[i].boneMatrixWorld; Matrix4f inverstedStartBoneMatrixWorld4 = InverseMatrix(startBoneMatrixWorld4); skinningMatrixForEachBone[i] = MultMatrixMatrix(currentBoneMatrixWorld4, inverstedStartBoneMatrixWorld4); if (i == 10) { std::cout << i << std::endl; } }*/ for (int i = 0; i < mesh.PositionData.size(); i++) { Vector4f originalPos = { startMesh.PositionData[i].v[0], startMesh.PositionData[i].v[1], startMesh.PositionData[i].v[2], 1.0}; Vector4f finalPos = Vector4f{0.f, 0.f, 0.f, 0.f}; bool vMoved = false; //Vector3f finalPos = Vector3f{ 0.f, 0.f, 0.f }; for (int j = 0; j < MAX_BONE_COUNT; j++) { if (verticesBoneWeight[i][j].weight != 0) { vMoved = true; //finalPos = finalPos + MultVectorMatrix(originalPos, skinningMatrixForEachBone[verticesBoneWeight[i][j].boneIndex]) * verticesBoneWeight[i][j].weight; finalPos = finalPos + MultMatrixVector(skinningMatrixForEachBone[verticesBoneWeight[i][j].boneIndex], originalPos) * verticesBoneWeight[i][j].weight; } } if (abs(finalPos.v[0] - originalPos.v[0]) > 1 || abs(finalPos.v[1] - originalPos.v[1]) > 1 || abs(finalPos.v[2] - originalPos.v[2]) > 1) { } if (!vMoved) { finalPos = originalPos; } mesh.PositionData[i].v[0] = finalPos.v[0]; mesh.PositionData[i].v[1] = finalPos.v[1]; mesh.PositionData[i].v[2] = finalPos.v[2]; } } }