From cd94dc15f9fd4d05368704246c70b118f7f623aa Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Fri, 27 Sep 2019 16:13:55 -0700 Subject: [PATCH] Add CollectShapeVerticesTask --- .../model-baker/src/model-baker/Baker.cpp | 11 ++- .../model-baker/CollectShapeVerticesTask.cpp | 92 +++++++++++++++++++ .../model-baker/CollectShapeVerticesTask.h | 30 ++++++ 3 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 libraries/model-baker/src/model-baker/CollectShapeVerticesTask.cpp create mode 100644 libraries/model-baker/src/model-baker/CollectShapeVerticesTask.h diff --git a/libraries/model-baker/src/model-baker/Baker.cpp b/libraries/model-baker/src/model-baker/Baker.cpp index a567537105..ccb5e1816f 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -14,6 +14,7 @@ #include "BakerTypes.h" #include "ModelMath.h" #include "ReweightDeformersTask.h" +#include "CollectShapeVerticesTask.h" #include "BuildGraphicsMeshTask.h" #include "CalculateMeshNormalsTask.h" #include "CalculateMeshTangentsTask.h" @@ -105,7 +106,7 @@ namespace baker { class BuildModelTask { public: - using Input = VaryingSet6, std::vector, QMap, QHash, FlowData>; + using Input = VaryingSet7, std::vector, QMap, QHash, FlowData, std::vector>; using Output = hfm::Model::Pointer; using JobModel = Job::ModelIO; @@ -116,6 +117,9 @@ namespace baker { hfmModelOut->jointRotationOffsets = input.get3(); hfmModelOut->jointIndices = input.get4(); hfmModelOut->flowData = input.get5(); + hfmModelOut->shapeVertices = input.get6(); + // These depend on the ShapeVertices + // TODO: Create a task for this rather than calculating it here hfmModelOut->computeKdops(); output = hfmModelOut; } @@ -156,6 +160,9 @@ namespace baker { // NOTE: Due to limitations in the current graphics::MeshPointer representation, the output list of ReweightedDeformers is per-mesh. An element is empty if there are no deformers for the mesh of the same index. const auto reweightDeformersInputs = ReweightDeformersTask::Input(meshesIn, shapesIn, dynamicTransformsIn, deformersIn).asVarying(); const auto reweightedDeformers = model.addJob("ReweightDeformers", reweightDeformersInputs); + // Shape vertices are included/rejected based on skinning weight, and thus must use the reweighted deformers. + const auto collectShapeVerticesInputs = CollectShapeVerticesTask::Input(meshesIn, shapesIn, jointsIn, dynamicTransformsIn, reweightedDeformers).asVarying(); + const auto shapeVerticesPerJoint = model.addJob("CollectShapeVertices", collectShapeVerticesInputs); // Build the graphics::MeshPointer for each hfm::Mesh const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh, shapesIn, dynamicTransformsIn, reweightedDeformers).asVarying(); @@ -191,7 +198,7 @@ namespace baker { const auto blendshapesPerMeshOut = model.addJob("BuildBlendshapes", buildBlendshapesInputs); const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying(); const auto meshesOut = model.addJob("BuildMeshes", buildMeshesInputs); - const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices, flowData).asVarying(); + const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices, flowData, shapeVerticesPerJoint).asVarying(); const auto hfmModelOut = model.addJob("BuildModel", buildModelInputs); output = Output(hfmModelOut, materialMapping, dracoMeshes, dracoErrors, materialList); diff --git a/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.cpp b/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.cpp new file mode 100644 index 0000000000..755b61b7df --- /dev/null +++ b/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.cpp @@ -0,0 +1,92 @@ +// +// CollectShapeVerticesTask.h +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/09/27. +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "CollectShapeVerticesTask.h" + +#include + +// Used to track and avoid duplicate shape vertices, as multiple shapes can have the same mesh and dynamicTransform +class VertexSource { +public: + uint32_t mesh; + uint32_t dynamicTransform; + + bool operator==(const VertexSource& other) const { + return mesh == other.mesh && + dynamicTransform == other.dynamicTransform; + } +}; + +void CollectShapeVerticesTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) { + const auto& meshes = input.get0(); + const auto& shapes = input.get1(); + const auto& joints = input.get2(); + const auto& dynamicTransforms = input.get3(); + const auto& reweightedDeformers = input.get4(); + auto& shapeVerticesPerJoint = output; + + shapeVerticesPerJoint.reserve(joints.size()); + std::vector> vertexSourcesPerJoint; + vertexSourcesPerJoint.resize(joints.size()); + for (size_t i = 0; i < shapes.size(); ++i) { + const auto& shape = shapes[i]; + const uint32_t dynamicTransformKey = shape.dynamicTransform; + if (dynamicTransformKey == hfm::UNDEFINED_KEY) { + continue; + } + + VertexSource vertexSource; + vertexSource.mesh = shape.mesh; + vertexSource.dynamicTransform = dynamicTransformKey; + + const auto& dynamicTransform = dynamicTransforms[dynamicTransformKey]; + for (size_t j = 0; j < dynamicTransform.clusters.size(); ++j) { + const auto& cluster = dynamicTransform.clusters[j]; + const uint32_t jointIndex = cluster.jointIndex; + + auto& vertexSources = vertexSourcesPerJoint[jointIndex]; + if (std::find(vertexSources.cbegin(), vertexSources.cend(), vertexSource) == vertexSources.cend()) { + vertexSources.push_back(vertexSource); + auto& shapeVertices = shapeVerticesPerJoint[jointIndex]; + + const uint16_t deformerIndex = dynamicTransform.deformers[j]; + const auto& mesh = meshes[shape.mesh]; + const auto& vertices = mesh.vertices; + const auto& reweightedDeformer = reweightedDeformers[shape.mesh]; + const glm::mat4 meshToJoint = cluster.inverseBindMatrix; + + const uint16_t weightsPerVertex = reweightedDeformer.weightsPerVertex; + if (weightsPerVertex == 0) { + for (int vertexIndex = 0; vertexIndex < (int)vertices.size(); ++vertexIndex) { + const glm::mat4 vertexTransform = meshToJoint * glm::translate(vertices[vertexIndex]); + shapeVertices.push_back(extractTranslation(vertexTransform)); + } + } else { + for (int vertexIndex = 0; vertexIndex < (int)vertices.size(); ++vertexIndex) { + for (uint16_t weightIndex = 0; weightIndex < weightsPerVertex; ++weightIndex) { + const size_t index = vertexIndex*4 + weightIndex; + const uint16_t clusterIndex = reweightedDeformer.indices[index]; + const uint16_t clusterWeight = reweightedDeformer.weights[index]; + // Remember vertices associated with this joint with at least 1/4 weight + const uint16_t EXPANSION_WEIGHT_THRESHOLD = std::numeric_limits::max() / 4; + if (clusterIndex != j || clusterWeight < EXPANSION_WEIGHT_THRESHOLD) { + continue; + } + + const glm::mat4 vertexTransform = meshToJoint * glm::translate(vertices[vertexIndex]); + shapeVertices.push_back(extractTranslation(vertexTransform)); + } + } + } + } + } + } +} diff --git a/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.h b/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.h new file mode 100644 index 0000000000..3111dcadc1 --- /dev/null +++ b/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.h @@ -0,0 +1,30 @@ +// +// CollectShapeVerticesTask.h +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/09/27. +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_CollectShapeVerticesTask_h +#define hifi_CollectShapeVerticesTask_h + +#include + +#include "Engine.h" +#include "BakerTypes.h" + +class CollectShapeVerticesTask { +public: + using Input = baker::VaryingSet5, std::vector, std::vector, std::vector, std::vector>; + using Output = std::vector; + using JobModel = baker::Job::ModelIO; + + void run(const baker::BakeContextPointer& context, const Input& input, Output& output); +}; + +#endif // hifi_CollectShapeVerticesTask_h +