diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index c61f03d070..ec06832f22 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -229,6 +229,14 @@ public: bool needTangentSpace() const; }; + +/// Simple Triangle List Mesh +struct TriangleListMesh { + std::vector vertices; + std::vector indices; + std::vector parts; // Offset in the indices, Number of indices +}; + /// A single mesh (with optional blendshapes). class Mesh { public: @@ -254,12 +262,15 @@ public: // Blendshape attributes QVector blendshapes; + // Simple Triangle List Mesh generated during baking + hfm::TriangleListMesh triangleListMesh; QVector originalIndices; // Original indices of the vertices unsigned int meshIndex; // the order the meshes appeared in the object file graphics::MeshPointer _mesh; bool wasCompressed { false }; + }; /// A single animation frame. diff --git a/libraries/hfm/src/hfm/HFMModelMath.cpp b/libraries/hfm/src/hfm/HFMModelMath.cpp index 0026378060..d0288d684c 100644 --- a/libraries/hfm/src/hfm/HFMModelMath.cpp +++ b/libraries/hfm/src/hfm/HFMModelMath.cpp @@ -12,7 +12,11 @@ #include "HFMModelMath.h" #include -#include "ModelFormatLogging.h" + +#include + +#include +#include namespace hfm { @@ -139,4 +143,60 @@ ReweightedDeformers getReweightedDeformers(const size_t numMeshVertices, const s return reweightedDeformers; } +const TriangleListMesh generateTriangleListMesh(const std::vector& srcVertices, const std::vector& srcParts) { + + TriangleListMesh dest; + + // copy vertices for now + dest.vertices = srcVertices; + + std::vector oldToNewIndex(srcVertices.size()); + { + std::unordered_map uniqueVertexToNewIndex; + int oldIndex = 0; + int newIndex = 0; + for (const auto& srcVertex : srcVertices) { + auto foundIndex = uniqueVertexToNewIndex.find(srcVertex); + if (foundIndex != uniqueVertexToNewIndex.end()) { + oldToNewIndex[oldIndex] = foundIndex->second; + } else { + uniqueVertexToNewIndex[srcVertex] = newIndex; + oldToNewIndex[oldIndex] = newIndex; + dest.vertices[newIndex] = srcVertex; + ++newIndex; + } + ++oldIndex; + } + if (uniqueVertexToNewIndex.size() < srcVertices.size()) { + dest.vertices.resize(uniqueVertexToNewIndex.size()); + dest.vertices.shrink_to_fit(); + } + } + + auto newIndicesCount = 0; + for (const auto& part : srcParts) { + newIndicesCount += part.triangleIndices.size() + part.quadTrianglesIndices.size(); + } + + { + dest.indices.resize(newIndicesCount); + int i = 0; + for (const auto& part : srcParts) { + glm::ivec2 spart(i, 0); + for (const auto& qti : part.quadTrianglesIndices) { + dest.indices[i] = oldToNewIndex[qti]; + ++i; + } + for (const auto& ti : part.triangleIndices) { + dest.indices[i] = oldToNewIndex[ti]; + ++i; + } + spart.y = i - spart.x; + dest.parts.push_back(spart); + } + } + + return dest; +} + }; diff --git a/libraries/hfm/src/hfm/HFMModelMath.h b/libraries/hfm/src/hfm/HFMModelMath.h index b80adad3d0..dc397c5e6f 100644 --- a/libraries/hfm/src/hfm/HFMModelMath.h +++ b/libraries/hfm/src/hfm/HFMModelMath.h @@ -25,8 +25,7 @@ void calculateExtentsForShape(hfm::Shape& shape, const std::vector& m void calculateExtentsForModel(Extents& modelExtents, const std::vector& shapes); -class ReweightedDeformers { -public: +struct ReweightedDeformers { std::vector indices; std::vector weights; uint16_t weightsPerVertex { 0 }; @@ -36,6 +35,9 @@ public: const uint16_t DEFAULT_SKINNING_WEIGHTS_PER_VERTEX = 4; ReweightedDeformers getReweightedDeformers(const size_t numMeshVertices, const std::vector skinClusters, const uint16_t weightsPerVertex = DEFAULT_SKINNING_WEIGHTS_PER_VERTEX); + +const TriangleListMesh generateTriangleListMesh(const std::vector& srcVertices, const std::vector& srcParts); + }; #endif // #define hifi_hfm_ModelMath_h diff --git a/libraries/model-baker/src/model-baker/Baker.cpp b/libraries/model-baker/src/model-baker/Baker.cpp index c63495c169..bd39b3178f 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -23,6 +23,7 @@ #include "CalculateExtentsTask.h" #include "BuildDracoMeshTask.h" #include "ParseFlowDataTask.h" +#include namespace baker { @@ -49,6 +50,26 @@ namespace baker { } }; + class BuildMeshTriangleListTask { + public: + using Input = std::vector; + using Output = std::vector; + using JobModel = Job::ModelIO; + + void run(const BakeContextPointer& context, const Input& input, Output& output) { + const auto& meshesIn = input; + auto& indexedTrianglesMeshOut = output; + indexedTrianglesMeshOut.clear(); + indexedTrianglesMeshOut.resize(meshesIn.size()); + + for (size_t i = 0; i < meshesIn.size(); i++) { + auto& mesh = meshesIn[i]; + const auto verticesStd = mesh.vertices.toStdVector(); + indexedTrianglesMeshOut[i] = hfm::generateTriangleListMesh(verticesStd, mesh.parts); + } + } + }; + class BuildBlendshapesTask { public: using Input = VaryingSet3, std::vector>; @@ -80,21 +101,23 @@ namespace baker { class BuildMeshesTask { public: - using Input = VaryingSet5, std::vector, NormalsPerMesh, TangentsPerMesh, BlendshapesPerMesh>; + using Input = VaryingSet6, std::vector, std::vector, NormalsPerMesh, TangentsPerMesh, BlendshapesPerMesh>; using Output = std::vector; using JobModel = Job::ModelIO; void run(const BakeContextPointer& context, const Input& input, Output& output) { auto& meshesIn = input.get0(); int numMeshes = (int)meshesIn.size(); - auto& graphicsMeshesIn = input.get1(); - auto& normalsPerMeshIn = input.get2(); - auto& tangentsPerMeshIn = input.get3(); - auto& blendshapesPerMeshIn = input.get4(); + auto& triangleListMeshesIn = input.get1(); + auto& graphicsMeshesIn = input.get2(); + auto& normalsPerMeshIn = input.get3(); + auto& tangentsPerMeshIn = input.get4(); + auto& blendshapesPerMeshIn = input.get5(); auto meshesOut = meshesIn; for (int i = 0; i < numMeshes; i++) { auto& meshOut = meshesOut[i]; + meshOut.triangleListMesh = triangleListMeshesIn[i]; meshOut._mesh = safeGet(graphicsMeshesIn, i); meshOut.normals = QVector::fromStdVector(safeGet(normalsPerMeshIn, i)); meshOut.tangents = QVector::fromStdVector(safeGet(tangentsPerMeshIn, i)); @@ -162,6 +185,9 @@ namespace baker { const auto collectShapeVerticesInputs = CollectShapeVerticesTask::Input(meshesIn, shapesIn, jointsIn, skinDeformersIn).asVarying(); const auto shapeVerticesPerJoint = model.addJob("CollectShapeVertices", collectShapeVerticesInputs); + // Build the slim triangle list mesh for each hfm::mesh + const auto triangleListMeshes = model.addJob("BuildMeshTriangleListTask", meshesIn); + // Build the graphics::MeshPointer for each hfm::Mesh const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh, shapesIn, skinDeformersIn).asVarying(); const auto graphicsMeshes = model.addJob("BuildGraphicsMesh", buildGraphicsMeshInputs); @@ -200,7 +226,7 @@ namespace baker { // Combine the outputs into a new hfm::Model const auto buildBlendshapesInputs = BuildBlendshapesTask::Input(blendshapesPerMeshIn, normalsPerBlendshapePerMesh, tangentsPerBlendshapePerMesh).asVarying(); const auto blendshapesPerMeshOut = model.addJob("BuildBlendshapes", buildBlendshapesInputs); - const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying(); + const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, triangleListMeshes, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying(); const auto meshesOut = model.addJob("BuildMeshes", buildMeshesInputs); const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices, flowData, shapeVerticesPerJoint, shapesOut, modelExtentsOut).asVarying(); const auto hfmModelOut = model.addJob("BuildModel", buildModelInputs); diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index cfb4bb6398..5787295da6 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -392,4 +392,14 @@ inline glm::vec4 extractFov( const glm::mat4& m) { return result; } +inline bool operator<(const glm::vec3& lhs, const glm::vec3& rhs) { + return (lhs.x < rhs.x) || ( + (lhs.x == rhs.x) && ( + (lhs.y < rhs.y) || ( + (lhs.y == rhs.y) && (lhs.z < rhs.z) + ) + ) + ); +} + #endif // hifi_GLMHelpers_h