Add CollectShapeVerticesTask

This commit is contained in:
sabrina-shanman 2019-09-27 16:13:55 -07:00
parent 2077da6f37
commit cd94dc15f9
3 changed files with 131 additions and 2 deletions

View file

@ -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<hfm::Model::Pointer, std::vector<hfm::Mesh>, std::vector<hfm::Joint>, QMap<int, glm::quat>, QHash<QString, int>, FlowData>;
using Input = VaryingSet7<hfm::Model::Pointer, std::vector<hfm::Mesh>, std::vector<hfm::Joint>, QMap<int, glm::quat>, QHash<QString, int>, FlowData, std::vector<ShapeVertices>>;
using Output = hfm::Model::Pointer;
using JobModel = Job::ModelIO<BuildModelTask, Input, Output>;
@ -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<ReweightDeformersTask>("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<CollectShapeVerticesTask>("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<BuildBlendshapesTask>("BuildBlendshapes", buildBlendshapesInputs);
const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying();
const auto meshesOut = model.addJob<BuildMeshesTask>("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<BuildModelTask>("BuildModel", buildModelInputs);
output = Output(hfmModelOut, materialMapping, dracoMeshes, dracoErrors, materialList);

View file

@ -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 <glm/gtx/transform.hpp>
// 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<std::vector<VertexSource>> 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<uint16_t>::max() / 4;
if (clusterIndex != j || clusterWeight < EXPANSION_WEIGHT_THRESHOLD) {
continue;
}
const glm::mat4 vertexTransform = meshToJoint * glm::translate(vertices[vertexIndex]);
shapeVertices.push_back(extractTranslation(vertexTransform));
}
}
}
}
}
}
}

View file

@ -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 <hfm/HFM.h>
#include "Engine.h"
#include "BakerTypes.h"
class CollectShapeVerticesTask {
public:
using Input = baker::VaryingSet5<std::vector<hfm::Mesh>, std::vector<hfm::Shape>, std::vector<hfm::Joint>, std::vector<hfm::DynamicTransform>, std::vector<baker::ReweightedDeformers>>;
using Output = std::vector<ShapeVertices>;
using JobModel = baker::Job::ModelIO<CollectShapeVerticesTask, Input, Output>;
void run(const baker::BakeContextPointer& context, const Input& input, Output& output);
};
#endif // hifi_CollectShapeVerticesTask_h