From 09f584818b0b9dae93a03f4dd7020689f795b09d Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Fri, 4 Oct 2019 14:15:44 -0700 Subject: [PATCH] Add extent calculation utilities, CalculateExtentsTask, make tangent calculation more lenient --- libraries/hfm/src/hfm/HFMModelMath.cpp | 66 +++++++++++++++++++ libraries/hfm/src/hfm/HFMModelMath.h | 30 +++++++++ .../model-baker/src/model-baker/Baker.cpp | 17 ++++- .../src/model-baker/CalculateExtentsTask.cpp | 41 ++++++++++++ .../src/model-baker/CalculateExtentsTask.h | 29 ++++++++ .../model-baker/CalculateMeshTangentsTask.cpp | 2 +- 6 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 libraries/hfm/src/hfm/HFMModelMath.cpp create mode 100644 libraries/hfm/src/hfm/HFMModelMath.h create mode 100644 libraries/model-baker/src/model-baker/CalculateExtentsTask.cpp create mode 100644 libraries/model-baker/src/model-baker/CalculateExtentsTask.h diff --git a/libraries/hfm/src/hfm/HFMModelMath.cpp b/libraries/hfm/src/hfm/HFMModelMath.cpp new file mode 100644 index 0000000000..8812163fe2 --- /dev/null +++ b/libraries/hfm/src/hfm/HFMModelMath.cpp @@ -0,0 +1,66 @@ +// +// HFMModelMath.cpp +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/10/04. +// 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 "HFMModelMath.h" + +namespace hfm { + +void forEachIndex(const hfm::MeshPart& meshPart, std::function func) { + for (int i = 0; i <= meshPart.quadIndices.size() - 4; i += 4) { + func((uint32_t)meshPart.quadIndices[i]); + func((uint32_t)meshPart.quadIndices[i+1]); + func((uint32_t)meshPart.quadIndices[i+2]); + func((uint32_t)meshPart.quadIndices[i+3]); + } + for (int i = 0; i <= meshPart.triangleIndices.size() - 3; i += 3) { + func((uint32_t)meshPart.triangleIndices[i]); + func((uint32_t)meshPart.triangleIndices[i+1]); + func((uint32_t)meshPart.triangleIndices[i+2]); + } +} + +void thickenFlatExtents(Extents& extents) { + // Add epsilon to extents to compensate for flat plane + extents.minimum -= glm::vec3(EPSILON, EPSILON, EPSILON); + extents.maximum += glm::vec3(EPSILON, EPSILON, EPSILON); +} + +void calculateExtentsForShape(hfm::Shape& shape, const std::vector& meshes, const std::vector joints) { + auto& shapeExtents = shape.transformedExtents; + shapeExtents.reset(); + + const auto& mesh = meshes[shape.mesh]; + const auto& meshPart = mesh.parts[shape.meshPart]; + + glm::mat4 globalTransform = joints[shape.transform].globalTransform; + forEachIndex(meshPart, [&](int32_t idx){ + if (mesh.vertices.size() <= idx) { + return; + } + const glm::vec3& vertex = mesh.vertices[idx]; + const glm::vec3 transformedVertex = glm::vec3(globalTransform * glm::vec4(vertex, 1.0f)); + shapeExtents.addPoint(vertex); + }); + + thickenFlatExtents(shapeExtents); +} + +void calculateExtentsForModel(Extents& modelExtents, const std::vector& shapes) { + modelExtents.reset(); + + for (size_t i = 0; i < shapes.size(); ++i) { + const auto& shape = shapes[i]; + const auto& shapeExtents = shape.transformedExtents; + modelExtents.addExtents(shapeExtents); + } +} + +}; diff --git a/libraries/hfm/src/hfm/HFMModelMath.h b/libraries/hfm/src/hfm/HFMModelMath.h new file mode 100644 index 0000000000..d1e3c09763 --- /dev/null +++ b/libraries/hfm/src/hfm/HFMModelMath.h @@ -0,0 +1,30 @@ +// +// HFMModelMath.h +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/10/04. +// 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_hfm_ModelMath_h +#define hifi_hfm_ModelMath_h + +#include "HFM.h" + +namespace hfm { + +void forEachIndex(const hfm::MeshPart& meshPart, std::function func); + +void initializeExtents(Extents& extents); + +// This can't be moved to model-baker until +void calculateExtentsForShape(hfm::Shape& shape, const std::vector& meshes, const std::vector joints); + +void calculateExtentsForModel(Extents& modelExtents, const std::vector& shapes); + +}; + +#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 ccb5e1816f..1b7242f2d4 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -21,6 +21,7 @@ #include "CalculateBlendshapeNormalsTask.h" #include "CalculateBlendshapeTangentsTask.h" #include "PrepareJointsTask.h" +#include "CalculateExtentsTask.h" #include "BuildDracoMeshTask.h" #include "ParseFlowDataTask.h" @@ -29,7 +30,7 @@ namespace baker { class GetModelPartsTask { public: using Input = hfm::Model::Pointer; - using Output = VaryingSet8, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, std::vector, std::vector, std::vector, std::vector>; + using Output = VaryingSet9, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, std::vector, std::vector, std::vector, std::vector, Extents>; using JobModel = Job::ModelIO; void run(const BakeContextPointer& context, const Input& input, Output& output) { @@ -46,6 +47,7 @@ namespace baker { output.edit5() = hfmModelIn->shapes; output.edit6() = hfmModelIn->dynamicTransforms; output.edit7() = hfmModelIn->deformers; + output.edit8() = hfmModelIn->meshExtents; } }; @@ -106,7 +108,7 @@ namespace baker { class BuildModelTask { public: - using Input = VaryingSet7, std::vector, QMap, QHash, FlowData, std::vector>; + using Input = VaryingSet9, std::vector, QMap, QHash, FlowData, std::vector, std::vector, Extents>; using Output = hfm::Model::Pointer; using JobModel = Job::ModelIO; @@ -118,6 +120,8 @@ namespace baker { hfmModelOut->jointIndices = input.get4(); hfmModelOut->flowData = input.get5(); hfmModelOut->shapeVertices = input.get6(); + hfmModelOut->shapes = input.get7(); + hfmModelOut->meshExtents = input.get8(); // These depend on the ShapeVertices // TODO: Create a task for this rather than calculating it here hfmModelOut->computeKdops(); @@ -145,6 +149,7 @@ namespace baker { const auto shapesIn = modelPartsIn.getN(5); const auto dynamicTransformsIn = modelPartsIn.getN(6); const auto deformersIn = modelPartsIn.getN(7); + const auto modelExtentsIn = modelPartsIn.getN(8); // Calculate normals and tangents for meshes and blendshapes if they do not exist // Note: Normals are never calculated here for OBJ models. OBJ files optionally define normals on a per-face basis, so for consistency normals are calculated beforehand in OBJSerializer. @@ -175,6 +180,12 @@ namespace baker { const auto jointRotationOffsets = jointInfoOut.getN(1); const auto jointIndices = jointInfoOut.getN(2); + // Use transform information to compute extents + const auto calculateExtentsInputs = CalculateExtentsTask::Input(modelExtentsIn, meshesIn, shapesIn, jointsOut).asVarying(); + const auto calculateExtentsOutputs = model.addJob("CalculateExtents", calculateExtentsInputs); + const auto modelExtentsOut = calculateExtentsOutputs.getN(0); + const auto shapesOut = calculateExtentsOutputs.getN(1); + // Parse material mapping const auto parseMaterialMappingInputs = ParseMaterialMappingTask::Input(mapping, materialMappingBaseURL).asVarying(); const auto materialMapping = model.addJob("ParseMaterialMapping", parseMaterialMappingInputs); @@ -198,7 +209,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, shapeVerticesPerJoint).asVarying(); + const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices, flowData, shapeVerticesPerJoint, shapesOut, modelExtentsOut).asVarying(); const auto hfmModelOut = model.addJob("BuildModel", buildModelInputs); output = Output(hfmModelOut, materialMapping, dracoMeshes, dracoErrors, materialList); diff --git a/libraries/model-baker/src/model-baker/CalculateExtentsTask.cpp b/libraries/model-baker/src/model-baker/CalculateExtentsTask.cpp new file mode 100644 index 0000000000..e237cdb402 --- /dev/null +++ b/libraries/model-baker/src/model-baker/CalculateExtentsTask.cpp @@ -0,0 +1,41 @@ +// +// CalculateExtentsTask.cpp +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/10/04. +// 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 "CalculateExtentsTask.h" + +#include "hfm/HFMModelMath.h" + +void CalculateExtentsTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) { + const auto& modelExtentsIn = input.get0(); + const auto& meshes = input.get1(); + const auto& shapesIn = input.get2(); + const auto& joints = input.get3(); + auto& modelExtentsOut = output.edit0(); + auto& shapesOut = output.edit1(); + + shapesOut.reserve(shapesIn.size()); + for (size_t i = 0; i < shapesIn.size(); ++i) { + shapesOut.push_back(shapesIn[i]); + auto& shapeOut = shapesOut.back(); + + auto& shapeExtents = shapeOut.transformedExtents; + if (shapeExtents.isValid()) { + continue; + } + + hfm::calculateExtentsForShape(shapeOut, meshes, joints); + } + + modelExtentsOut = modelExtentsIn; + if (!modelExtentsOut.isValid()) { + hfm::calculateExtentsForModel(modelExtentsOut, shapesOut); + } +} diff --git a/libraries/model-baker/src/model-baker/CalculateExtentsTask.h b/libraries/model-baker/src/model-baker/CalculateExtentsTask.h new file mode 100644 index 0000000000..006688ec5a --- /dev/null +++ b/libraries/model-baker/src/model-baker/CalculateExtentsTask.h @@ -0,0 +1,29 @@ +// +// CalculateExtentsTask.h +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/10/04. +// 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_CalculateExtentsTask_h +#define hifi_CalculateExtentsTask_h + +#include "Engine.h" +#include "hfm/HFM.h" + +// Calculates any undefined extents in the shapes and the model. Precalculated extents will be left alone. +// Bind extents will currently not be calculated +class CalculateExtentsTask { +public: + using Input = baker::VaryingSet4, std::vector, std::vector>; + using Output = baker::VaryingSet2>; + using JobModel = baker::Job::ModelIO; + + void run(const baker::BakeContextPointer& context, const Input& input, Output& output); +}; + +#endif // hifi_CalculateExtentsTask_h diff --git a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp index 297d8cbde7..6147ce72e7 100644 --- a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp +++ b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp @@ -30,7 +30,7 @@ void CalculateMeshTangentsTask::run(const baker::BakeContextPointer& context, co // Otherwise confirm if we have the normals and texcoords needed if (!tangentsIn.empty()) { tangentsOut = tangentsIn.toStdVector(); - } else if (!normals.empty() && mesh.vertices.size() == mesh.texCoords.size()) { + } else if (!normals.empty() && mesh.vertices.size() <= mesh.texCoords.size()) { tangentsOut.resize(normals.size()); baker::calculateTangents(mesh, [&mesh, &normals, &tangentsOut](int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec2* outTexCoords, glm::vec3& outNormal) {