From 9bb7e4dcede24a780a17486f9e722e956080f25a Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Mon, 7 Jan 2019 16:49:52 -0800 Subject: [PATCH 1/4] Create normal/tangent calculation tasks for meshes/blendshapes --- .../model-baker/src/model-baker/Baker.cpp | 72 +++++++++-- .../model-baker/src/model-baker/BakerTypes.h | 15 +++ .../src/model-baker/BuildGraphicsMeshTask.cpp | 62 ++++----- .../src/model-baker/BuildGraphicsMeshTask.h | 4 +- .../CalculateBlendshapeNormalsTask.cpp | 70 ++++++++++ .../CalculateBlendshapeNormalsTask.h | 28 ++++ .../CalculateBlendshapeTangentsTask.cpp | 95 ++++++++++++++ .../CalculateBlendshapeTangentsTask.h | 28 ++++ .../model-baker/CalculateMeshNormalsTask.cpp | 40 ++++++ .../model-baker/CalculateMeshNormalsTask.h | 30 +++++ .../model-baker/CalculateMeshTangentsTask.cpp | 66 ++++++++++ .../model-baker/CalculateMeshTangentsTask.h | 32 +++++ .../model-baker/src/model-baker/ModelMath.cpp | 121 ++++++++++++++++++ .../model-baker/src/model-baker/ModelMath.h | 34 +++++ 14 files changed, 645 insertions(+), 52 deletions(-) create mode 100644 libraries/model-baker/src/model-baker/CalculateBlendshapeNormalsTask.cpp create mode 100644 libraries/model-baker/src/model-baker/CalculateBlendshapeNormalsTask.h create mode 100644 libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.cpp create mode 100644 libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.h create mode 100644 libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.cpp create mode 100644 libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.h create mode 100644 libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp create mode 100644 libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.h create mode 100644 libraries/model-baker/src/model-baker/ModelMath.cpp create mode 100644 libraries/model-baker/src/model-baker/ModelMath.h diff --git a/libraries/model-baker/src/model-baker/Baker.cpp b/libraries/model-baker/src/model-baker/Baker.cpp index bf2b21993c..c15b2c9926 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -15,26 +15,64 @@ #include "BakerTypes.h" #include "BuildGraphicsMeshTask.h" +#include "CalculateMeshNormalsTask.h" +#include "CalculateMeshTangentsTask.h" +#include "CalculateBlendshapeNormalsTask.h" +#include "CalculateBlendshapeTangentsTask.h" namespace baker { class GetModelPartsTask { public: using Input = hfm::Model::Pointer; - using Output = VaryingSet3, hifi::URL, MeshIndicesToModelNames>; + using Output = VaryingSet4, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh>; using JobModel = Job::ModelIO; void run(const BakeContextPointer& context, const Input& input, Output& output) { - auto& hfmModelIn = input; + const auto& hfmModelIn = input; output.edit0() = hfmModelIn->meshes.toStdVector(); output.edit1() = hfmModelIn->originalURL; output.edit2() = hfmModelIn->meshIndicesToModelNames; + auto& blendshapesPerMesh = output.edit3(); + blendshapesPerMesh.reserve(hfmModelIn->meshes.size()); + for (int i = 0; i < hfmModelIn->meshes.size(); i++) { + blendshapesPerMesh.push_back(hfmModelIn->meshes[i].blendshapes.toStdVector()); + } + } + }; + + class BuildBlendshapesTask { + public: + using Input = VaryingSet3, std::vector>; + using Output = BlendshapesPerMesh; + using JobModel = Job::ModelIO; + + void run(const BakeContextPointer& context, const Input& input, Output& output) { + const auto& blendshapesPerMeshIn = input.get0(); + const auto& normalsPerBlendshapePerMesh = input.get1(); + const auto& tangentsPerBlendshapePerMesh = input.get2(); + auto& blendshapesPerMeshOut = output; + + blendshapesPerMeshOut = blendshapesPerMeshIn; + + for (int i = 0; i < blendshapesPerMeshOut.size(); i++) { + const auto& normalsPerBlendshape = normalsPerBlendshapePerMesh[i]; + const auto& tangentsPerBlendshape = tangentsPerBlendshapePerMesh[i]; + auto& blendshapesOut = blendshapesPerMeshOut[i]; + for (int j = 0; j < blendshapesOut.size(); j++) { + const auto& normals = normalsPerBlendshape[j]; + const auto& tangents = tangentsPerBlendshape[j]; + auto& blendshape = blendshapesOut[j]; + blendshape.normals = QVector::fromStdVector(normals); + blendshape.tangents = QVector::fromStdVector(tangents); + } + } } }; class BuildMeshesTask { public: - using Input = VaryingSet4, std::vector, TangentsPerMesh, BlendshapesPerMesh>; + using Input = VaryingSet5, std::vector, NormalsPerMesh, TangentsPerMesh, BlendshapesPerMesh>; using Output = std::vector; using JobModel = Job::ModelIO; @@ -42,13 +80,15 @@ namespace baker { auto& meshesIn = input.get0(); int numMeshes = (int)meshesIn.size(); auto& graphicsMeshesIn = input.get1(); - auto& tangentsPerMeshIn = input.get2(); - auto& blendshapesPerMeshIn = input.get3(); + auto& normalsPerMeshIn = input.get2(); + auto& tangentsPerMeshIn = input.get3(); + auto& blendshapesPerMeshIn = input.get4(); auto meshesOut = meshesIn; for (int i = 0; i < numMeshes; i++) { auto& meshOut = meshesOut[i]; meshOut._mesh = graphicsMeshesIn[i]; + meshOut.normals = QVector::fromStdVector(normalsPerMeshIn[i]); meshOut.tangents = QVector::fromStdVector(tangentsPerMeshIn[i]); meshOut.blendshapes = QVector::fromStdVector(blendshapesPerMeshIn[i]); } @@ -80,17 +120,25 @@ namespace baker { const auto meshesIn = modelPartsIn.getN(0); const auto url = modelPartsIn.getN(1); const auto meshIndicesToModelNames = modelPartsIn.getN(2); + const auto blendshapesPerMeshIn = modelPartsIn.getN(3); + + // Calculate normals and tangents for meshes and blendshapes if they do not exist + const auto normalsPerMesh = model.addJob("CalculateMeshNormals", meshesIn); + const auto calculateMeshTangentsInputs = CalculateMeshTangentsTask::Input(normalsPerMesh, meshesIn, hfmModelIn).asVarying(); + const auto tangentsPerMesh = model.addJob("CalculateMeshTangents", calculateMeshTangentsInputs); + const auto calculateBlendshapeNormalsInputs = CalculateBlendshapeNormalsTask::Input(blendshapesPerMeshIn, meshesIn).asVarying(); + const auto normalsPerBlendshapePerMesh = model.addJob("CalculateBlendshapeNormals", calculateBlendshapeNormalsInputs); + const auto calculateBlendshapeTangentsInputs = CalculateBlendshapeTangentsTask::Input(normalsPerBlendshapePerMesh, blendshapesPerMeshIn, meshesIn, hfmModelIn).asVarying(); + const auto tangentsPerBlendshapePerMesh = model.addJob("CalculateBlendshapeTangents", calculateBlendshapeTangentsInputs); // Build the graphics::MeshPointer for each hfm::Mesh - const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames).asVarying(); - const auto buildGraphicsMeshOutputs = model.addJob("BuildGraphicsMesh", buildGraphicsMeshInputs); - const auto graphicsMeshes = buildGraphicsMeshOutputs.getN(0); - // TODO: Move tangent/blendshape validation/calculation to an earlier step - const auto tangentsPerMesh = buildGraphicsMeshOutputs.getN(1); - const auto blendshapesPerMesh = buildGraphicsMeshOutputs.getN(2); + const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh).asVarying(); + const auto graphicsMeshes = model.addJob("BuildGraphicsMesh", buildGraphicsMeshInputs); // Combine the outputs into a new hfm::Model - const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, tangentsPerMesh, blendshapesPerMesh).asVarying(); + 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 meshesOut = model.addJob("BuildMeshes", buildMeshesInputs); const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut).asVarying(); hfmModelOut = model.addJob("BuildModel", buildModelInputs); diff --git a/libraries/model-baker/src/model-baker/BakerTypes.h b/libraries/model-baker/src/model-baker/BakerTypes.h index 8615c1b17c..5d14ee5420 100644 --- a/libraries/model-baker/src/model-baker/BakerTypes.h +++ b/libraries/model-baker/src/model-baker/BakerTypes.h @@ -15,10 +15,25 @@ #include namespace baker { + using MeshIndices = std::vector; + using IndicesPerMesh = std::vector>; + using VerticesPerMesh = std::vector>; + using MeshNormals = std::vector; + using NormalsPerMesh = std::vector>; using MeshTangents = std::vector; using TangentsPerMesh = std::vector>; + using Blendshapes = std::vector; using BlendshapesPerMesh = std::vector>; + using BlendshapeVertices = std::vector; + using BlendshapeNormals = std::vector; + using BlendshapeIndices = std::vector; + using VerticesPerBlendshape = std::vector>; + using NormalsPerBlendshape = std::vector>; + using IndicesPerBlendshape = std::vector>; + using BlendshapeTangents = std::vector; + using TangentsPerBlendshape = std::vector>; + using MeshIndicesToModelNames = QHash; }; diff --git a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp index 6d351a99e9..370add2c2e 100644 --- a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp +++ b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp @@ -26,9 +26,18 @@ glm::vec3 normalizeDirForPacking(const glm::vec3& dir) { return dir; } -void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphicsMeshPointer, baker::MeshTangents& meshTangents, baker::Blendshapes& blendshapes) { +void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphicsMeshPointer, const baker::MeshNormals& meshNormals, const baker::MeshTangents& meshTangentsIn) { auto graphicsMesh = std::make_shared(); + // Fill tangents with a dummy value to force tangents to be present if there are normals + baker::MeshTangents meshTangents; + if (!meshTangentsIn.empty()) { + meshTangents = meshTangentsIn; + } else { + meshTangents.reserve(meshNormals.size()); + std::fill_n(std::back_inserter(meshTangents), meshNormals.size(), Vectors::UNIT_X); + } + unsigned int totalSourceIndices = 0; foreach(const HFMMeshPart& part, hfmMesh.parts) { totalSourceIndices += (part.quadTrianglesIndices.size() + part.triangleIndices.size()); @@ -48,23 +57,6 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics int numVerts = hfmMesh.vertices.size(); - if (!hfmMesh.normals.empty() && hfmMesh.tangents.empty()) { - // Fill with a dummy value to force tangents to be present if there are normals - meshTangents.reserve(hfmMesh.normals.size()); - std::fill_n(std::back_inserter(meshTangents), hfmMesh.normals.size(), Vectors::UNIT_X); - } else { - meshTangents = hfmMesh.tangents.toStdVector(); - } - // Same thing with blend shapes - blendshapes = hfmMesh.blendshapes.toStdVector(); - for (auto& blendShape : blendshapes) { - if (!blendShape.normals.empty() && blendShape.tangents.empty()) { - // Fill with a dummy value to force tangents to be present if there are normals - blendShape.tangents.reserve(blendShape.normals.size()); - std::fill_n(std::back_inserter(blendShape.tangents), blendShape.normals.size(), Vectors::UNIT_X); - } - } - // evaluate all attribute elements and data sizes // Position is a vec3 @@ -73,12 +65,12 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics // Normal and tangent are always there together packed in normalized xyz32bits word (times 2) const auto normalElement = HFM_NORMAL_ELEMENT; - const int normalsSize = hfmMesh.normals.size() * normalElement.getSize(); + const int normalsSize = (int)meshNormals.size() * normalElement.getSize(); const int tangentsSize = (int)meshTangents.size() * normalElement.getSize(); // If there are normals then there should be tangents assert(normalsSize <= tangentsSize); if (tangentsSize > normalsSize) { - HIFI_FCDEBUG_ID(model_baker(), repeatMessageID, "BuildGraphicsMeshTask -- Unexpected tangents in file"); + HIFI_FCDEBUG_ID(model_baker(), repeatMessageID, "BuildGraphicsMeshTask -- Unexpected tangents in mesh"); } const auto normalsAndTangentsSize = normalsSize + tangentsSize; @@ -124,11 +116,11 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics if (normalsSize > 0) { std::vector normalsAndTangents; - normalsAndTangents.reserve(hfmMesh.normals.size() + (int)meshTangents.size()); - auto normalIt = hfmMesh.normals.constBegin(); + normalsAndTangents.reserve(meshNormals.size() + (int)meshTangents.size()); + auto normalIt = meshNormals.cbegin(); auto tangentIt = meshTangents.cbegin(); for (; - normalIt != hfmMesh.normals.constEnd(); + normalIt != meshNormals.cend(); ++normalIt, ++tangentIt) { #if HFM_PACK_NORMALS const auto normal = normalizeDirForPacking(*normalIt); @@ -212,11 +204,6 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics auto vertexFormat = std::make_shared(); auto vertexBufferStream = std::make_shared(); - // Decision time: - // if blendshapes then keep position and normals/tangents as separated channel buffers from interleaved attributes - // else everything is interleaved in one buffer - - // Default case is no blend shapes gpu::BufferPointer attribBuffer; int totalAttribBufferSize = totalVertsSize; gpu::uint8 posChannel = 0; @@ -244,7 +231,7 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics } } - // Pack normal and Tangent with the rest of atributes if no blend shapes + // Pack normal and Tangent with the rest of atributes if (colorsSize) { vertexFormat->setAttribute(gpu::Stream::COLOR, attribChannel, colorElement, bufOffset); bufOffset += colorElement.getSize(); @@ -384,22 +371,21 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics } void BuildGraphicsMeshTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) { - auto& meshes = input.get0(); - auto& url = input.get1(); - auto& meshIndicesToModelNames = input.get2(); + const auto& meshes = input.get0(); + const auto& url = input.get1(); + const auto& meshIndicesToModelNames = input.get2(); + const auto& normalsPerMesh = input.get3(); + const auto& tangentsPerMesh = input.get4(); + + auto& graphicsMeshes = output; - auto& graphicsMeshes = output.edit0(); - auto& tangentsPerMesh = output.edit1(); - auto& blendshapesPerMesh = output.edit2(); int n = (int)meshes.size(); for (int i = 0; i < n; i++) { graphicsMeshes.emplace_back(); auto& graphicsMesh = graphicsMeshes[i]; - tangentsPerMesh.emplace_back(); - blendshapesPerMesh.emplace_back(); // Try to create the graphics::Mesh - buildGraphicsMesh(meshes[i], graphicsMesh, tangentsPerMesh[i], blendshapesPerMesh[i]); + buildGraphicsMesh(meshes[i], graphicsMesh, normalsPerMesh[i], tangentsPerMesh[i]); // Choose a name for the mesh if (graphicsMesh) { diff --git a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.h b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.h index 3c8985ef9a..bb4136c086 100644 --- a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.h +++ b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.h @@ -20,8 +20,8 @@ class BuildGraphicsMeshTask { public: - using Input = baker::VaryingSet3, hifi::URL, baker::MeshIndicesToModelNames>; - using Output = baker::VaryingSet3, std::vector, std::vector>; + using Input = baker::VaryingSet5, hifi::URL, baker::MeshIndicesToModelNames, baker::NormalsPerMesh, baker::TangentsPerMesh>; + using Output = std::vector; using JobModel = baker::Job::ModelIO; void run(const baker::BakeContextPointer& context, const Input& input, Output& output); diff --git a/libraries/model-baker/src/model-baker/CalculateBlendshapeNormalsTask.cpp b/libraries/model-baker/src/model-baker/CalculateBlendshapeNormalsTask.cpp new file mode 100644 index 0000000000..b908fa9ced --- /dev/null +++ b/libraries/model-baker/src/model-baker/CalculateBlendshapeNormalsTask.cpp @@ -0,0 +1,70 @@ +// +// CalculateBlendshapeNormalsTask.h +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/01/07. +// 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 "CalculateBlendshapeNormalsTask.h" + +#include "ModelMath.h" + +void CalculateBlendshapeNormalsTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) { + const auto& blendshapesPerMesh = input.get0(); + const auto& meshes = input.get1(); + auto& normalsPerBlendshapePerMeshOut = output; + + normalsPerBlendshapePerMeshOut.reserve(blendshapesPerMesh.size()); + for (size_t i = 0; i < blendshapesPerMesh.size(); i++) { + const auto& mesh = meshes[i]; + const auto& blendshapes = blendshapesPerMesh[i]; + normalsPerBlendshapePerMeshOut.emplace_back(); + auto& normalsPerBlendshapeOut = normalsPerBlendshapePerMeshOut[normalsPerBlendshapePerMeshOut.size()-1]; + + normalsPerBlendshapeOut.reserve(blendshapes.size()); + for (size_t j = 0; j < blendshapes.size(); j++) { + const auto& blendshape = blendshapes[j]; + const auto& normalsIn = blendshape.normals; + // Check if normals are already defined. Otherwise, calculate them from existing blendshape vertices. + if (!normalsIn.empty()) { + normalsPerBlendshapeOut.push_back(normalsIn.toStdVector()); + } else { + // Create lookup to get index in blendshape from vertex index in mesh + std::vector reverseIndices; + reverseIndices.resize(mesh.vertices.size()); + std::iota(reverseIndices.begin(), reverseIndices.end(), 0); + for (int indexInBlendShape = 0; indexInBlendShape < blendshape.indices.size(); ++indexInBlendShape) { + auto indexInMesh = blendshape.indices[indexInBlendShape]; + reverseIndices[indexInMesh] = indexInBlendShape; + } + + normalsPerBlendshapeOut.emplace_back(); + auto& normals = normalsPerBlendshapeOut[normalsPerBlendshapeOut.size()-1]; + normals.resize(mesh.vertices.size()); + baker::calculateNormals(mesh, + [&reverseIndices, &blendshape, &normals](int normalIndex) /* NormalAccessor */ { + const auto lookupIndex = reverseIndices[normalIndex]; + if (lookupIndex < blendshape.vertices.size()) { + return &normals[lookupIndex]; + } else { + // Index isn't in the blendshape. Request that the normal not be calculated. + return (glm::vec3*)nullptr; + } + }, + [&mesh, &reverseIndices, &blendshape](int vertexIndex, glm::vec3& outVertex) /* VertexSetter */ { + const auto lookupIndex = reverseIndices[vertexIndex]; + if (lookupIndex < blendshape.vertices.size()) { + outVertex = blendshape.vertices[lookupIndex]; + } else { + // Index isn't in the blendshape, so return vertex from mesh + outVertex = mesh.vertices[lookupIndex]; + } + }); + } + } + } +} diff --git a/libraries/model-baker/src/model-baker/CalculateBlendshapeNormalsTask.h b/libraries/model-baker/src/model-baker/CalculateBlendshapeNormalsTask.h new file mode 100644 index 0000000000..0eb7d3c4e7 --- /dev/null +++ b/libraries/model-baker/src/model-baker/CalculateBlendshapeNormalsTask.h @@ -0,0 +1,28 @@ +// +// CalculateBlendshapeNormalsTask.h +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/01/07. +// 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_CalculateBlendshapeNormalsTask_h +#define hifi_CalculateBlendshapeNormalsTask_h + +#include "Engine.h" +#include "BakerTypes.h" + +// Calculate blendshape normals if not already present in the blendshape +class CalculateBlendshapeNormalsTask { +public: + using Input = baker::VaryingSet2>; + using Output = std::vector; + using JobModel = baker::Job::ModelIO; + + void run(const baker::BakeContextPointer& context, const Input& input, Output& output); +}; + +#endif // hifi_CalculateBlendshapeNormalsTask_h diff --git a/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.cpp b/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.cpp new file mode 100644 index 0000000000..66e1dadc41 --- /dev/null +++ b/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.cpp @@ -0,0 +1,95 @@ +// +// CalculateBlendshapeTangentsTask.cpp +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/01/08. +// 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 "CalculateBlendshapeTangentsTask.h" + +#include + +#include "ModelMath.h" + +void CalculateBlendshapeTangentsTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) { + const auto& normalsPerBlendshapePerMesh = input.get0(); + const auto& blendshapesPerMesh = input.get1(); + const auto& meshes = input.get2(); + const hfm::Model& model = *input.get3(); + auto& tangentsPerBlendshapePerMeshOut = output; + + tangentsPerBlendshapePerMeshOut.reserve(normalsPerBlendshapePerMesh.size()); + for (size_t i = 0; i < blendshapesPerMesh.size(); i++) { + const auto& normalsPerBlendshape = normalsPerBlendshapePerMesh[i]; + const auto& blendshapes = blendshapesPerMesh[i]; + const auto& mesh = meshes[i]; + tangentsPerBlendshapePerMeshOut.emplace_back(); + auto& tangentsPerBlendshapeOut = tangentsPerBlendshapePerMeshOut[tangentsPerBlendshapePerMeshOut.size()-1]; + + // Check if we actually need to calculate the tangents, or just append empty arrays + bool needTangents = false; + for (const auto& meshPart : mesh.parts) { + auto materialIt = model.materials.find(meshPart.materialID); + if (materialIt != model.materials.end() && (*materialIt).needTangentSpace()) { + needTangents = true; + break; + } + } + + for (size_t j = 0; j < blendshapes.size(); j++) { + const auto& blendshape = blendshapes[j]; + const auto& tangentsIn = blendshape.tangents; + const auto& normals = normalsPerBlendshape[j]; + tangentsPerBlendshapeOut.emplace_back(); + auto& tangentsOut = tangentsPerBlendshapeOut[tangentsPerBlendshapeOut.size()-1]; + + // Check if we already have tangents + if (!tangentsIn.empty()) { + tangentsOut = tangentsIn.toStdVector(); + continue; + } + + // Check if we can and should calculate tangents (we need normals to calculate the tangents) + if (normals.empty() || !needTangents) { + continue; + } + tangentsOut.resize(normals.size()); + + // Create lookup to get index in blend shape from vertex index in mesh + std::vector reverseIndices; + reverseIndices.resize(mesh.vertices.size()); + std::iota(reverseIndices.begin(), reverseIndices.end(), 0); + for (int indexInBlendShape = 0; indexInBlendShape < blendshape.indices.size(); ++indexInBlendShape) { + auto indexInMesh = blendshape.indices[indexInBlendShape]; + reverseIndices[indexInMesh] = indexInBlendShape; + } + + baker::calculateTangents(mesh, + [&mesh, &blendshape, &normals, &tangentsOut, &reverseIndices](int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec2* outTexCoords, glm::vec3& outNormal) { + const auto index1 = reverseIndices[firstIndex]; + const auto index2 = reverseIndices[secondIndex]; + + if (index1 < blendshape.vertices.size()) { + outVertices[0] = blendshape.vertices[index1]; + outTexCoords[0] = mesh.texCoords[index1]; + outTexCoords[1] = mesh.texCoords[index2]; + if (index2 < blendshape.vertices.size()) { + outVertices[1] = blendshape.vertices[index2]; + } else { + // Index isn't in the blend shape so return vertex from mesh + outVertices[1] = mesh.vertices[secondIndex]; + } + outNormal = normals[index1]; + return &tangentsOut[index1]; + } else { + // Index isn't in blend shape so return nullptr + return (glm::vec3*)nullptr; + } + }); + } + } +} diff --git a/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.h b/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.h new file mode 100644 index 0000000000..9ff79d17a6 --- /dev/null +++ b/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.h @@ -0,0 +1,28 @@ +// +// CalculateBlendshapeTangentsTask.h +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/01/07. +// 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_CalculateBlendshapeTangentsTask_h +#define hifi_CalculateBlendshapeTangentsTask_h + +#include "Engine.h" +#include "BakerTypes.h" + +// Calculate blendshape tangents if not already present in the blendshape +class CalculateBlendshapeTangentsTask { +public: + using Input = baker::VaryingSet4, baker::BlendshapesPerMesh, std::vector, hfm::Model::Pointer>; + using Output = std::vector; + using JobModel = baker::Job::ModelIO; + + void run(const baker::BakeContextPointer& context, const Input& input, Output& output); +}; + +#endif // hifi_CalculateBlendshapeTangentsTask_h diff --git a/libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.cpp b/libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.cpp new file mode 100644 index 0000000000..02986e160e --- /dev/null +++ b/libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.cpp @@ -0,0 +1,40 @@ +// +// CalculateMeshNormalsTask.cpp +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/01/22. +// 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 "CalculateMeshNormalsTask.h" + +#include "ModelMath.h" + +void CalculateMeshNormalsTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) { + const auto& meshes = input; + auto& normalsPerMeshOut = output; + + normalsPerMeshOut.reserve(meshes.size()); + for (int i = 0; i < meshes.size(); i++) { + const auto& mesh = meshes[i]; + normalsPerMeshOut.emplace_back(); + auto& normalsOut = normalsPerMeshOut[normalsPerMeshOut.size()-1]; + // Only calculate normals if this mesh doesn't already have them + if (!mesh.normals.empty()) { + normalsOut = mesh.normals.toStdVector(); + } else { + normalsOut.resize(mesh.vertices.size()); + baker::calculateNormals(mesh, + [&normalsOut](int normalIndex) /* NormalAccessor */ { + return &normalsOut[normalIndex]; + }, + [&mesh](int vertexIndex, glm::vec3& outVertex) /* VertexSetter */ { + outVertex = mesh.vertices[vertexIndex]; + } + ); + } + } +} diff --git a/libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.h b/libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.h new file mode 100644 index 0000000000..b32780c68d --- /dev/null +++ b/libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.h @@ -0,0 +1,30 @@ +// +// CalculateMeshNormalsTask.h +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/01/07. +// 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_CalculateMeshNormalsTask_h +#define hifi_CalculateMeshNormalsTask_h + +#include + +#include "Engine.h" +#include "BakerTypes.h" + +// Calculate mesh normals if not already present in the mesh +class CalculateMeshNormalsTask { +public: + using Input = std::vector; + using Output = baker::NormalsPerMesh; + using JobModel = baker::Job::ModelIO; + + void run(const baker::BakeContextPointer& context, const Input& input, Output& output); +}; + +#endif // hifi_CalculateMeshNormalsTask_h diff --git a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp new file mode 100644 index 0000000000..96cf4ddc5c --- /dev/null +++ b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp @@ -0,0 +1,66 @@ +// +// CalculateMeshTangentsTask.cpp +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/01/22. +// 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 "CalculateMeshTangentsTask.h" + +#include "ModelMath.h" + +void CalculateMeshTangentsTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) { + const auto& normalsPerMesh = input.get0(); + const std::vector& meshes = input.get1(); + const hfm::Model& model = *input.get2(); + auto& tangentsPerMeshOut = output; + + tangentsPerMeshOut.reserve(meshes.size()); + for (int i = 0; i < meshes.size(); i++) { + const auto& mesh = meshes[i]; + const auto& tangentsIn = mesh.tangents; + const auto& normals = normalsPerMesh[i]; + const auto& vertices = mesh.vertices; + tangentsPerMeshOut.emplace_back(); + auto& tangentsOut = tangentsPerMeshOut[tangentsPerMeshOut.size()-1]; + + // Check if we already have tangents and therefore do not need to do any calculation + if (!tangentsIn.empty()) { + tangentsOut = tangentsIn.toStdVector(); + continue; + } + + // Check if we have normals, and if not then tangents can't be calculated + if (normals.empty()) { + continue; + } + + // Check if we actually need to calculate the tangents + bool needTangents = false; + for (const auto& meshPart : mesh.parts) { + auto materialIt = model.materials.find(meshPart.materialID); + if (materialIt != model.materials.end() && (*materialIt).needTangentSpace()) { + needTangents = true; + break; + } + } + if (needTangents) { + continue; + } + + tangentsOut.resize(normals.size()); + baker::calculateTangents(mesh, + [&mesh, &normals, &tangentsOut](int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec2* outTexCoords, glm::vec3& outNormal) { + outVertices[0] = mesh.vertices[firstIndex]; + outVertices[1] = mesh.vertices[secondIndex]; + outNormal = normals[firstIndex]; + outTexCoords[0] = mesh.texCoords[firstIndex]; + outTexCoords[1] = mesh.texCoords[secondIndex]; + return &(tangentsOut[firstIndex]); + }); + } +} diff --git a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.h b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.h new file mode 100644 index 0000000000..1d0d572b28 --- /dev/null +++ b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.h @@ -0,0 +1,32 @@ +// +// CalculateMeshTangentsTask.h +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/01/07. +// 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_CalculateMeshTangentsTask_h +#define hifi_CalculateMeshTangentsTask_h + +#include + +#include "Engine.h" +#include "BakerTypes.h" + +// Calculate mesh tangents if not already present in the mesh +class CalculateMeshTangentsTask { +public: + using NormalsPerMesh = std::vector>; + + using Input = baker::VaryingSet3, hfm::Model::Pointer>; + using Output = baker::TangentsPerMesh; + using JobModel = baker::Job::ModelIO; + + void run(const baker::BakeContextPointer& context, const Input& input, Output& output); +}; + +#endif // hifi_CalculateMeshTangentsTask_h diff --git a/libraries/model-baker/src/model-baker/ModelMath.cpp b/libraries/model-baker/src/model-baker/ModelMath.cpp new file mode 100644 index 0000000000..50e7e89cf4 --- /dev/null +++ b/libraries/model-baker/src/model-baker/ModelMath.cpp @@ -0,0 +1,121 @@ +// +// ModelMath.cpp +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/01/18. +// 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 "ModelMath.h" + +#include +#include "ModelBakerLogging.h" + +namespace baker { + template + const T& checkedAt(const QVector& vector, int i) { + if (i < 0 || i >= vector.size()) { + throw std::out_of_range("baker::checked_at (ModelMath.cpp): index " + std::to_string(i) + " is out of range"); + } + return vector[i]; + } + + template + const T& checkedAt(const std::vector& vector, int i) { + if (i < 0 || i >= vector.size()) { + throw std::out_of_range("baker::checked_at (ModelMath.cpp): index " + std::to_string(i) + " is out of range"); + } + return vector[i]; + } + + template + T& checkedAt(std::vector& vector, int i) { + if (i < 0 || i >= vector.size()) { + throw std::out_of_range("baker::checked_at (ModelMath.cpp): index " + std::to_string(i) + " is out of range"); + } + return vector[i]; + } + + void setTangent(const HFMMesh& mesh, const IndexAccessor& vertexAccessor, int firstIndex, int secondIndex) { + glm::vec3 vertex[2]; + glm::vec2 texCoords[2]; + glm::vec3 normal; + glm::vec3* tangent = vertexAccessor(firstIndex, secondIndex, vertex, texCoords, normal); + if (tangent) { + glm::vec3 bitangent = glm::cross(normal, vertex[1] - vertex[0]); + if (glm::length(bitangent) < EPSILON) { + return; + } + glm::vec2 texCoordDelta = texCoords[1] - texCoords[0]; + glm::vec3 normalizedNormal = glm::normalize(normal); + *tangent += glm::cross(glm::angleAxis(-atan2f(-texCoordDelta.t, texCoordDelta.s), normalizedNormal) * + glm::normalize(bitangent), normalizedNormal); + } + } + + void calculateNormals(const hfm::Mesh& mesh, NormalAccessor normalAccessor, VertexSetter vertexSetter) { + static int repeatMessageID = LogHandler::getInstance().newRepeatedMessageID(); + for (const HFMMeshPart& part : mesh.parts) { + for (int i = 0; i < part.quadIndices.size(); i += 4) { + glm::vec3* n0 = normalAccessor(part.quadIndices[i]); + glm::vec3* n1 = normalAccessor(part.quadIndices[i + 1]); + glm::vec3* n2 = normalAccessor(part.quadIndices[i + 2]); + glm::vec3* n3 = normalAccessor(part.quadIndices[i + 3]); + if (!n0 || !n1 || !n2 || !n3) { + // Quad is not in the mesh (can occur with blendshape meshes, which are a subset of the hfm Mesh vertices) + continue; + } + glm::vec3 vertices[3]; // Assume all vertices in this quad are in the same plane, so only the first three are needed to calculate the normal + vertexSetter(part.quadIndices[i], vertices[0]); + vertexSetter(part.quadIndices[i + 1], vertices[1]); + vertexSetter(part.quadIndices[i + 2], vertices[2]); + *n0 = *n1 = *n2 = *n3 = glm::cross(vertices[1] - vertices[0], vertices[2] - vertices[0]); + } + // <= size - 3 in order to prevent overflowing triangleIndices when (i % 3) != 0 + // This is most likely evidence of a further problem in extractMesh() + for (int i = 0; i <= part.triangleIndices.size() - 3; i += 3) { + glm::vec3* n0 = normalAccessor(part.triangleIndices[i]); + glm::vec3* n1 = normalAccessor(part.triangleIndices[i + 1]); + glm::vec3* n2 = normalAccessor(part.triangleIndices[i + 2]); + if (!n0 || !n1 || !n2) { + // Tri is not in the mesh (can occur with blendshape meshes, which are a subset of the hfm Mesh vertices) + continue; + } + glm::vec3 vertices[3]; + vertexSetter(part.triangleIndices[i], vertices[0]); + vertexSetter(part.triangleIndices[i + 1], vertices[1]); + vertexSetter(part.triangleIndices[i + 2], vertices[2]); + *n0 = *n1 = *n2 = glm::cross(vertices[1] - vertices[0], vertices[2] - vertices[0]); + } + if ((part.triangleIndices.size() % 3) != 0) { + HIFI_FCDEBUG_ID(model_baker(), repeatMessageID, "Error in baker::calculateNormals: part.triangleIndices.size() is not divisible by three"); + } + } + } + + void calculateTangents(const hfm::Mesh& mesh, IndexAccessor accessor) { + static int repeatMessageID = LogHandler::getInstance().newRepeatedMessageID(); + for (const HFMMeshPart& part : mesh.parts) { + for (int i = 0; i < part.quadIndices.size(); i += 4) { + setTangent(mesh, accessor, part.quadIndices.at(i), part.quadIndices.at(i + 1)); + setTangent(mesh, accessor, part.quadIndices.at(i + 1), part.quadIndices.at(i + 2)); + setTangent(mesh, accessor, part.quadIndices.at(i + 2), part.quadIndices.at(i + 3)); + setTangent(mesh, accessor, part.quadIndices.at(i + 3), part.quadIndices.at(i)); + } + // <= size - 3 in order to prevent overflowing triangleIndices when (i % 3) != 0 + // This is most likely evidence of a further problem in extractMesh() + for (int i = 0; i <= part.triangleIndices.size() - 3; i += 3) { + setTangent(mesh, accessor, part.triangleIndices.at(i), part.triangleIndices.at(i + 1)); + setTangent(mesh, accessor, part.triangleIndices.at(i + 1), part.triangleIndices.at(i + 2)); + setTangent(mesh, accessor, part.triangleIndices.at(i + 2), part.triangleIndices.at(i)); + } + if ((part.triangleIndices.size() % 3) != 0) { + HIFI_FCDEBUG_ID(model_baker(), repeatMessageID, "Error in baker::calculateTangents: part.triangleIndices.size() is not divisible by three"); + } + } + } +} + diff --git a/libraries/model-baker/src/model-baker/ModelMath.h b/libraries/model-baker/src/model-baker/ModelMath.h new file mode 100644 index 0000000000..2a909e6eed --- /dev/null +++ b/libraries/model-baker/src/model-baker/ModelMath.h @@ -0,0 +1,34 @@ +// +// ModelMath.h +// model-baker/src/model-baker +// +// Created by Sabrina Shanman on 2019/01/07. +// 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 + +#include "BakerTypes.h" + +namespace baker { + // Returns a reference to the normal at the specified index, or nullptr if it cannot be accessed + using NormalAccessor = std::function; + + // Assigns a vertex to outVertex given the lookup index + using VertexSetter = std::function; + + void calculateNormals(const hfm::Mesh& mesh, NormalAccessor normalAccessor, VertexSetter vertexAccessor); + + // firstIndex, secondIndex: the vertex indices to be used for calculation + // outVertices: should be assigned a 2 element array containing the vertices at firstIndex and secondIndex + // outTexCoords: same as outVertices but for texture coordinates + // outNormal: reference to the normal of this triangle + // + // Return value: pointer to the tangent you want to be calculated + using IndexAccessor = std::function; + + void calculateTangents(const hfm::Mesh& mesh, IndexAccessor accessor); +}; From fe60b8e69bd8752e4c40252d8bd4d1083566352d Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 24 Jan 2019 11:49:44 -0800 Subject: [PATCH 2/4] Remove now redundant tangent generation code --- libraries/fbx/src/FBXSerializer.cpp | 3 - libraries/hfm/src/hfm/HFM.cpp | 102 ------------------ libraries/hfm/src/hfm/HFM.h | 3 - .../model-baker/src/model-baker/Baker.cpp | 1 + 4 files changed, 1 insertion(+), 108 deletions(-) diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 68019c2f4b..bd43de429b 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1452,9 +1452,6 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr } } - extracted.mesh.createMeshTangents(generateTangents); - extracted.mesh.createBlendShapeTangents(generateTangents); - // find the clusters with which the mesh is associated QVector clusterIDs; foreach (const QString& childID, _connectionChildMap.values(it.key())) { diff --git a/libraries/hfm/src/hfm/HFM.cpp b/libraries/hfm/src/hfm/HFM.cpp index b9e630456d..908fb1e97b 100644 --- a/libraries/hfm/src/hfm/HFM.cpp +++ b/libraries/hfm/src/hfm/HFM.cpp @@ -67,108 +67,6 @@ bool HFMMaterial::needTangentSpace() const { return !normalTexture.isNull(); } -static void _createBlendShapeTangents(HFMMesh& mesh, bool generateFromTexCoords, HFMBlendshape& blendShape); - -void HFMMesh::createBlendShapeTangents(bool generateTangents) { - for (auto& blendShape : blendshapes) { - _createBlendShapeTangents(*this, generateTangents, blendShape); - } -} - -using IndexAccessor = std::function; - -static void setTangents(const HFMMesh& mesh, const IndexAccessor& vertexAccessor, int firstIndex, int secondIndex, - const QVector& vertices, const QVector& normals, QVector& tangents) { - glm::vec3 vertex[2]; - glm::vec3 normal; - glm::vec3* tangent = vertexAccessor(mesh, firstIndex, secondIndex, vertex, normal); - if (tangent) { - glm::vec3 bitangent = glm::cross(normal, vertex[1] - vertex[0]); - if (glm::length(bitangent) < EPSILON) { - return; - } - glm::vec2 texCoordDelta = mesh.texCoords.at(secondIndex) - mesh.texCoords.at(firstIndex); - glm::vec3 normalizedNormal = glm::normalize(normal); - *tangent += glm::cross(glm::angleAxis(-atan2f(-texCoordDelta.t, texCoordDelta.s), normalizedNormal) * - glm::normalize(bitangent), normalizedNormal); - } -} - -static void createTangents(const HFMMesh& mesh, bool generateFromTexCoords, - const QVector& vertices, const QVector& normals, QVector& tangents, - IndexAccessor accessor) { - // if we have a normal map (and texture coordinates), we must compute tangents - if (generateFromTexCoords && !mesh.texCoords.isEmpty()) { - tangents.resize(vertices.size()); - - foreach(const HFMMeshPart& part, mesh.parts) { - for (int i = 0; i < part.quadIndices.size(); i += 4) { - setTangents(mesh, accessor, part.quadIndices.at(i), part.quadIndices.at(i + 1), vertices, normals, tangents); - setTangents(mesh, accessor, part.quadIndices.at(i + 1), part.quadIndices.at(i + 2), vertices, normals, tangents); - setTangents(mesh, accessor, part.quadIndices.at(i + 2), part.quadIndices.at(i + 3), vertices, normals, tangents); - setTangents(mesh, accessor, part.quadIndices.at(i + 3), part.quadIndices.at(i), vertices, normals, tangents); - } - // <= size - 3 in order to prevent overflowing triangleIndices when (i % 3) != 0 - // This is most likely evidence of a further problem in extractMesh() - for (int i = 0; i <= part.triangleIndices.size() - 3; i += 3) { - setTangents(mesh, accessor, part.triangleIndices.at(i), part.triangleIndices.at(i + 1), vertices, normals, tangents); - setTangents(mesh, accessor, part.triangleIndices.at(i + 1), part.triangleIndices.at(i + 2), vertices, normals, tangents); - setTangents(mesh, accessor, part.triangleIndices.at(i + 2), part.triangleIndices.at(i), vertices, normals, tangents); - } - if ((part.triangleIndices.size() % 3) != 0) { - qCDebug(modelformat) << "Error in extractHFMModel part.triangleIndices.size() is not divisible by three "; - } - } - } -} - -void HFMMesh::createMeshTangents(bool generateFromTexCoords) { - HFMMesh& mesh = *this; - // This is the only workaround I've found to trick the compiler into understanding that mesh.tangents isn't - // const in the lambda function. - auto& tangents = mesh.tangents; - createTangents(mesh, generateFromTexCoords, mesh.vertices, mesh.normals, mesh.tangents, - [&](const HFMMesh& mesh, int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec3& outNormal) { - outVertices[0] = mesh.vertices[firstIndex]; - outVertices[1] = mesh.vertices[secondIndex]; - outNormal = mesh.normals[firstIndex]; - return &(tangents[firstIndex]); - }); -} - -static void _createBlendShapeTangents(HFMMesh& mesh, bool generateFromTexCoords, HFMBlendshape& blendShape) { - // Create lookup to get index in blend shape from vertex index in mesh - std::vector reverseIndices; - reverseIndices.resize(mesh.vertices.size()); - std::iota(reverseIndices.begin(), reverseIndices.end(), 0); - - for (int indexInBlendShape = 0; indexInBlendShape < blendShape.indices.size(); ++indexInBlendShape) { - auto indexInMesh = blendShape.indices[indexInBlendShape]; - reverseIndices[indexInMesh] = indexInBlendShape; - } - - createTangents(mesh, generateFromTexCoords, blendShape.vertices, blendShape.normals, blendShape.tangents, - [&](const HFMMesh& mesh, int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec3& outNormal) { - const auto index1 = reverseIndices[firstIndex]; - const auto index2 = reverseIndices[secondIndex]; - - if (index1 < blendShape.vertices.size()) { - outVertices[0] = blendShape.vertices[index1]; - if (index2 < blendShape.vertices.size()) { - outVertices[1] = blendShape.vertices[index2]; - } else { - // Index isn't in the blend shape so return vertex from mesh - outVertices[1] = mesh.vertices[secondIndex]; - } - outNormal = blendShape.normals[index1]; - return &blendShape.tangents[index1]; - } else { - // Index isn't in blend shape so return nullptr - return (glm::vec3*)nullptr; - } - }); -} - QStringList HFMModel::getJointNames() const { QStringList names; foreach (const HFMJoint& joint, joints) { diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index 78f608d72e..1bd87332a1 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -239,9 +239,6 @@ public: graphics::MeshPointer _mesh; bool wasCompressed { false }; - - void createMeshTangents(bool generateFromTexCoords); - void createBlendShapeTangents(bool generateTangents); }; /**jsdoc diff --git a/libraries/model-baker/src/model-baker/Baker.cpp b/libraries/model-baker/src/model-baker/Baker.cpp index c15b2c9926..765003fef7 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -123,6 +123,7 @@ namespace baker { const auto blendshapesPerMeshIn = modelPartsIn.getN(3); // 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. const auto normalsPerMesh = model.addJob("CalculateMeshNormals", meshesIn); const auto calculateMeshTangentsInputs = CalculateMeshTangentsTask::Input(normalsPerMesh, meshesIn, hfmModelIn).asVarying(); const auto tangentsPerMesh = model.addJob("CalculateMeshTangents", calculateMeshTangentsInputs); From 64ef8b691983a0fe5a240a65534b70cc32f3df27 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 24 Jan 2019 13:02:53 -0800 Subject: [PATCH 3/4] Do not pass in whole hfm::Model by reference to tangent calculation prep steps --- libraries/model-baker/src/model-baker/Baker.cpp | 8 +++++--- .../src/model-baker/CalculateBlendshapeTangentsTask.cpp | 6 +++--- .../src/model-baker/CalculateBlendshapeTangentsTask.h | 2 +- .../src/model-baker/CalculateMeshTangentsTask.cpp | 6 +++--- .../src/model-baker/CalculateMeshTangentsTask.h | 2 +- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/libraries/model-baker/src/model-baker/Baker.cpp b/libraries/model-baker/src/model-baker/Baker.cpp index 765003fef7..f9680ab89f 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -25,7 +25,7 @@ namespace baker { class GetModelPartsTask { public: using Input = hfm::Model::Pointer; - using Output = VaryingSet4, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh>; + using Output = VaryingSet5, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, QHash>; using JobModel = Job::ModelIO; void run(const BakeContextPointer& context, const Input& input, Output& output) { @@ -38,6 +38,7 @@ namespace baker { for (int i = 0; i < hfmModelIn->meshes.size(); i++) { blendshapesPerMesh.push_back(hfmModelIn->meshes[i].blendshapes.toStdVector()); } + output.edit4() = hfmModelIn->materials; } }; @@ -121,15 +122,16 @@ namespace baker { const auto url = modelPartsIn.getN(1); const auto meshIndicesToModelNames = modelPartsIn.getN(2); const auto blendshapesPerMeshIn = modelPartsIn.getN(3); + const auto materials = modelPartsIn.getN(4); // 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. const auto normalsPerMesh = model.addJob("CalculateMeshNormals", meshesIn); - const auto calculateMeshTangentsInputs = CalculateMeshTangentsTask::Input(normalsPerMesh, meshesIn, hfmModelIn).asVarying(); + const auto calculateMeshTangentsInputs = CalculateMeshTangentsTask::Input(normalsPerMesh, meshesIn, materials).asVarying(); const auto tangentsPerMesh = model.addJob("CalculateMeshTangents", calculateMeshTangentsInputs); const auto calculateBlendshapeNormalsInputs = CalculateBlendshapeNormalsTask::Input(blendshapesPerMeshIn, meshesIn).asVarying(); const auto normalsPerBlendshapePerMesh = model.addJob("CalculateBlendshapeNormals", calculateBlendshapeNormalsInputs); - const auto calculateBlendshapeTangentsInputs = CalculateBlendshapeTangentsTask::Input(normalsPerBlendshapePerMesh, blendshapesPerMeshIn, meshesIn, hfmModelIn).asVarying(); + const auto calculateBlendshapeTangentsInputs = CalculateBlendshapeTangentsTask::Input(normalsPerBlendshapePerMesh, blendshapesPerMeshIn, meshesIn, materials).asVarying(); const auto tangentsPerBlendshapePerMesh = model.addJob("CalculateBlendshapeTangents", calculateBlendshapeTangentsInputs); // Build the graphics::MeshPointer for each hfm::Mesh diff --git a/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.cpp b/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.cpp index 66e1dadc41..04e05f0378 100644 --- a/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.cpp +++ b/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.cpp @@ -19,7 +19,7 @@ void CalculateBlendshapeTangentsTask::run(const baker::BakeContextPointer& conte const auto& normalsPerBlendshapePerMesh = input.get0(); const auto& blendshapesPerMesh = input.get1(); const auto& meshes = input.get2(); - const hfm::Model& model = *input.get3(); + const auto& materials = input.get3(); auto& tangentsPerBlendshapePerMeshOut = output; tangentsPerBlendshapePerMeshOut.reserve(normalsPerBlendshapePerMesh.size()); @@ -33,8 +33,8 @@ void CalculateBlendshapeTangentsTask::run(const baker::BakeContextPointer& conte // Check if we actually need to calculate the tangents, or just append empty arrays bool needTangents = false; for (const auto& meshPart : mesh.parts) { - auto materialIt = model.materials.find(meshPart.materialID); - if (materialIt != model.materials.end() && (*materialIt).needTangentSpace()) { + auto materialIt = materials.find(meshPart.materialID); + if (materialIt != materials.end() && (*materialIt).needTangentSpace()) { needTangents = true; break; } diff --git a/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.h b/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.h index 9ff79d17a6..c24b41d2d9 100644 --- a/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.h +++ b/libraries/model-baker/src/model-baker/CalculateBlendshapeTangentsTask.h @@ -18,7 +18,7 @@ // Calculate blendshape tangents if not already present in the blendshape class CalculateBlendshapeTangentsTask { public: - using Input = baker::VaryingSet4, baker::BlendshapesPerMesh, std::vector, hfm::Model::Pointer>; + using Input = baker::VaryingSet4, baker::BlendshapesPerMesh, std::vector, QHash>; using Output = std::vector; using JobModel = baker::Job::ModelIO; diff --git a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp index 96cf4ddc5c..51251a0005 100644 --- a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp +++ b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp @@ -16,7 +16,7 @@ void CalculateMeshTangentsTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) { const auto& normalsPerMesh = input.get0(); const std::vector& meshes = input.get1(); - const hfm::Model& model = *input.get2(); + const auto& materials = input.get2(); auto& tangentsPerMeshOut = output; tangentsPerMeshOut.reserve(meshes.size()); @@ -42,8 +42,8 @@ void CalculateMeshTangentsTask::run(const baker::BakeContextPointer& context, co // Check if we actually need to calculate the tangents bool needTangents = false; for (const auto& meshPart : mesh.parts) { - auto materialIt = model.materials.find(meshPart.materialID); - if (materialIt != model.materials.end() && (*materialIt).needTangentSpace()) { + auto materialIt = materials.find(meshPart.materialID); + if (materialIt != materials.end() && (*materialIt).needTangentSpace()) { needTangents = true; break; } diff --git a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.h b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.h index 1d0d572b28..b8fdb7d5f4 100644 --- a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.h +++ b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.h @@ -22,7 +22,7 @@ class CalculateMeshTangentsTask { public: using NormalsPerMesh = std::vector>; - using Input = baker::VaryingSet3, hfm::Model::Pointer>; + using Input = baker::VaryingSet3, QHash>; using Output = baker::TangentsPerMesh; using JobModel = baker::Job::ModelIO; From 5993aab1743e8e5765f315d91e8e03b8e3695138 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 24 Jan 2019 14:43:43 -0800 Subject: [PATCH 4/4] Fix linker error and build warnings --- libraries/model-baker/CMakeLists.txt | 4 +--- libraries/model-baker/src/model-baker/Baker.cpp | 4 ++-- .../model-baker/src/model-baker/CalculateMeshNormalsTask.cpp | 2 +- .../model-baker/src/model-baker/CalculateMeshTangentsTask.cpp | 3 +-- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/libraries/model-baker/CMakeLists.txt b/libraries/model-baker/CMakeLists.txt index 50b113976f..6fa7c1815a 100644 --- a/libraries/model-baker/CMakeLists.txt +++ b/libraries/model-baker/CMakeLists.txt @@ -1,6 +1,4 @@ set(TARGET_NAME model-baker) setup_hifi_library() -link_hifi_libraries(shared task gpu graphics) - -include_hifi_library_headers(hfm) +link_hifi_libraries(shared task gpu graphics hfm) diff --git a/libraries/model-baker/src/model-baker/Baker.cpp b/libraries/model-baker/src/model-baker/Baker.cpp index f9680ab89f..8d1a82518d 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -56,11 +56,11 @@ namespace baker { blendshapesPerMeshOut = blendshapesPerMeshIn; - for (int i = 0; i < blendshapesPerMeshOut.size(); i++) { + for (int i = 0; i < (int)blendshapesPerMeshOut.size(); i++) { const auto& normalsPerBlendshape = normalsPerBlendshapePerMesh[i]; const auto& tangentsPerBlendshape = tangentsPerBlendshapePerMesh[i]; auto& blendshapesOut = blendshapesPerMeshOut[i]; - for (int j = 0; j < blendshapesOut.size(); j++) { + for (int j = 0; j < (int)blendshapesOut.size(); j++) { const auto& normals = normalsPerBlendshape[j]; const auto& tangents = tangentsPerBlendshape[j]; auto& blendshape = blendshapesOut[j]; diff --git a/libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.cpp b/libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.cpp index 02986e160e..a6884e104d 100644 --- a/libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.cpp +++ b/libraries/model-baker/src/model-baker/CalculateMeshNormalsTask.cpp @@ -18,7 +18,7 @@ void CalculateMeshNormalsTask::run(const baker::BakeContextPointer& context, con auto& normalsPerMeshOut = output; normalsPerMeshOut.reserve(meshes.size()); - for (int i = 0; i < meshes.size(); i++) { + for (int i = 0; i < (int)meshes.size(); i++) { const auto& mesh = meshes[i]; normalsPerMeshOut.emplace_back(); auto& normalsOut = normalsPerMeshOut[normalsPerMeshOut.size()-1]; diff --git a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp index 51251a0005..e94e15507e 100644 --- a/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp +++ b/libraries/model-baker/src/model-baker/CalculateMeshTangentsTask.cpp @@ -20,11 +20,10 @@ void CalculateMeshTangentsTask::run(const baker::BakeContextPointer& context, co auto& tangentsPerMeshOut = output; tangentsPerMeshOut.reserve(meshes.size()); - for (int i = 0; i < meshes.size(); i++) { + for (int i = 0; i < (int)meshes.size(); i++) { const auto& mesh = meshes[i]; const auto& tangentsIn = mesh.tangents; const auto& normals = normalsPerMesh[i]; - const auto& vertices = mesh.vertices; tangentsPerMeshOut.emplace_back(); auto& tangentsOut = tangentsPerMeshOut[tangentsPerMeshOut.size()-1];