Merge pull request #16263 from sabrina-shanman/instancing_collectshapevertices

(DEV-654) Define ShapeVertices in model preparation step
This commit is contained in:
Sabrina Shanman 2019-10-01 17:15:28 -07:00 committed by GitHub
commit 2468b5affc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 310 additions and 102 deletions

View file

@ -13,6 +13,8 @@
#include "BakerTypes.h"
#include "ModelMath.h"
#include "ReweightDeformersTask.h"
#include "CollectShapeVerticesTask.h"
#include "BuildGraphicsMeshTask.h"
#include "CalculateMeshNormalsTask.h"
#include "CalculateMeshTangentsTask.h"
@ -104,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>;
@ -115,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;
}
@ -151,8 +156,16 @@ namespace baker {
const auto calculateBlendshapeTangentsInputs = CalculateBlendshapeTangentsTask::Input(normalsPerBlendshapePerMesh, blendshapesPerMeshIn, meshesIn).asVarying();
const auto tangentsPerBlendshapePerMesh = model.addJob<CalculateBlendshapeTangentsTask>("CalculateBlendshapeTangents", calculateBlendshapeTangentsInputs);
// Skinning weight calculations
// 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, deformersIn).asVarying();
const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh, shapesIn, dynamicTransformsIn, reweightedDeformers).asVarying();
const auto graphicsMeshes = model.addJob<BuildGraphicsMeshTask>("BuildGraphicsMesh", buildGraphicsMeshInputs);
// Prepare joint information
@ -185,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

@ -36,6 +36,14 @@ namespace baker {
using TangentsPerBlendshape = std::vector<std::vector<glm::vec3>>;
using MeshIndicesToModelNames = QHash<int, QString>;
class ReweightedDeformers {
public:
std::vector<uint16_t> indices;
std::vector<uint16_t> weights;
uint16_t weightsPerVertex { 0 };
bool trimmedToMatch { false };
};
};
#endif // hifi_BakerTypes_h

View file

@ -2,8 +2,8 @@
// BuildGraphicsMeshTask.h
// model-baker/src/model-baker
//
// Created by Sabrina Shanman on 2018/12/06.
// Copyright 2018 High Fidelity, Inc.
// Created by Sabrina Shanman on 2019/09/16.
// 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
@ -27,83 +27,7 @@ glm::vec3 normalizeDirForPacking(const glm::vec3& dir) {
return dir;
}
class ReweightedDeformers {
public:
std::vector<uint16_t> indices;
std::vector<uint16_t> weights;
bool trimmedToMatch { false };
};
ReweightedDeformers getReweightedDeformers(size_t numMeshVertices, const hfm::DynamicTransform* dynamicTransform, const std::vector<const hfm::Deformer*> deformers, const uint16_t weightsPerVertex) {
size_t numClusterIndices = numMeshVertices * weightsPerVertex;
ReweightedDeformers reweightedDeformers;
// TODO: Consider having a rootCluster property in the DynamicTransform rather than appending the root to the end of the cluster list.
reweightedDeformers.indices.resize(numClusterIndices, (uint16_t)(deformers.size() - 1));
reweightedDeformers.weights.resize(numClusterIndices, 0);
std::vector<float> weightAccumulators;
weightAccumulators.resize(numClusterIndices, 0.0f);
for (uint16_t i = 0; i < (uint16_t)deformers.size(); ++i) {
const hfm::Deformer& deformer = *deformers[i];
if (deformer.indices.size() != deformer.weights.size()) {
reweightedDeformers.trimmedToMatch = true;
}
size_t numIndicesOrWeights = std::min(deformer.indices.size(), deformer.weights.size());
for (size_t j = 0; j < numIndicesOrWeights; ++j) {
uint32_t index = deformer.indices[j];
float weight = deformer.weights[j];
// look for an unused slot in the weights vector
uint32_t weightIndex = index * weightsPerVertex;
uint32_t lowestIndex = -1;
float lowestWeight = FLT_MAX;
uint16_t k = 0;
for (; k < weightsPerVertex; k++) {
if (weightAccumulators[weightIndex + k] == 0.0f) {
reweightedDeformers.indices[weightIndex + k] = i;
weightAccumulators[weightIndex + k] = weight;
break;
}
if (weightAccumulators[weightIndex + k] < lowestWeight) {
lowestIndex = k;
lowestWeight = weightAccumulators[weightIndex + k];
}
}
if (k == weightsPerVertex && weight > lowestWeight) {
// no space for an additional weight; we must replace the lowest
weightAccumulators[weightIndex + lowestIndex] = weight;
reweightedDeformers.indices[weightIndex + lowestIndex] = i;
}
}
}
// now that we've accumulated the most relevant weights for each vertex
// normalize and compress to 16-bits
for (size_t i = 0; i < numMeshVertices; ++i) {
size_t j = i * weightsPerVertex;
// normalize weights into uint16_t
float totalWeight = 0.0f;
for (size_t k = j; k < j + weightsPerVertex; ++k) {
totalWeight += weightAccumulators[k];
}
const float ALMOST_HALF = 0.499f;
if (totalWeight > 0.0f) {
float weightScalingFactor = (float)(UINT16_MAX) / totalWeight;
for (size_t k = j; k < j + weightsPerVertex; ++k) {
reweightedDeformers.weights[k] = (uint16_t)(weightScalingFactor * weightAccumulators[k] + ALMOST_HALF);
}
} else {
reweightedDeformers.weights[j] = (uint16_t)((float)(UINT16_MAX) + ALMOST_HALF);
}
}
return reweightedDeformers;
}
void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphicsMeshPointer, const baker::MeshNormals& meshNormals, const baker::MeshTangents& meshTangentsIn, const hfm::DynamicTransform* dynamicTransform, const std::vector<const hfm::Deformer*> meshDeformers) {
void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphicsMeshPointer, const baker::MeshNormals& meshNormals, const baker::MeshTangents& meshTangentsIn, uint16_t numDeformerControllers, const baker::ReweightedDeformers reweightedDeformers) {
auto graphicsMesh = std::make_shared<graphics::Mesh>();
// Fill tangents with a dummy value to force tangents to be present if there are normals
@ -162,19 +86,16 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics
// Support for 4 skinning clusters:
// 4 Indices are uint8 ideally, uint16 if more than 256.
const auto clusterIndiceElement = ((meshDeformers.size() < (size_t)UINT8_MAX) ? gpu::Element(gpu::VEC4, gpu::UINT8, gpu::XYZW) : gpu::Element(gpu::VEC4, gpu::UINT16, gpu::XYZW));
const auto clusterIndiceElement = ((numDeformerControllers < (uint16_t)UINT8_MAX) ? gpu::Element(gpu::VEC4, gpu::UINT8, gpu::XYZW) : gpu::Element(gpu::VEC4, gpu::UINT16, gpu::XYZW));
// 4 Weights are normalized 16bits
const auto clusterWeightElement = gpu::Element(gpu::VEC4, gpu::NUINT16, gpu::XYZW);
// Calculate a more condensed view of all the deformer weights
const uint16_t NUM_CLUSTERS_PER_VERT = 4;
ReweightedDeformers reweightedDeformers = getReweightedDeformers(hfmMesh.vertices.size(), dynamicTransform, meshDeformers, NUM_CLUSTERS_PER_VERT);
// Cluster indices and weights must be the same sizes
if (reweightedDeformers.trimmedToMatch) {
HIFI_FCDEBUG_ID(model_baker(), repeatMessageID, "BuildGraphicsMeshTask -- The number of indices and weights for a deformer had different sizes and have been trimmed to match");
}
// Record cluster sizes
const size_t numVertClusters = reweightedDeformers.indices.size() / NUM_CLUSTERS_PER_VERT;
const size_t numVertClusters = reweightedDeformers.indices.size() / reweightedDeformers.weightsPerVertex;
const size_t clusterIndicesSize = numVertClusters * clusterIndiceElement.getSize();
const size_t clusterWeightsSize = numVertClusters * clusterWeightElement.getSize();
@ -263,7 +184,7 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics
// Clusters data
if (clusterIndicesSize > 0) {
if (meshDeformers.size() < UINT8_MAX) {
if (numDeformerControllers < (uint16_t)UINT8_MAX) {
// yay! we can fit the clusterIndices within 8-bits
int32_t numIndices = (int32_t)reweightedDeformers.indices.size();
std::vector<uint8_t> packedDeformerIndices;
@ -461,7 +382,7 @@ void BuildGraphicsMeshTask::run(const baker::BakeContextPointer& context, const
const auto& tangentsPerMesh = input.get4();
const auto& shapes = input.get5();
const auto& dynamicTransforms = input.get6();
const auto& deformers = input.get7();
const auto& reweightedDeformersPerMesh = input.get7();
// Currently, there is only (at most) one dynamicTransform per mesh
// An undefined shape.dynamicTransform has the value hfm::UNDEFINED_KEY
@ -478,20 +399,17 @@ void BuildGraphicsMeshTask::run(const baker::BakeContextPointer& context, const
for (int i = 0; i < n; i++) {
graphicsMeshes.emplace_back();
auto& graphicsMesh = graphicsMeshes[i];
const auto& reweightedDeformers = reweightedDeformersPerMesh[i];
auto dynamicTransformIndex = dynamicTransformPerMesh[i];
const hfm::DynamicTransform* dynamicTransform = nullptr;
std::vector<const hfm::Deformer*> meshDeformers;
if (dynamicTransformIndex != hfm::UNDEFINED_KEY) {
dynamicTransform = &dynamicTransforms[dynamicTransformIndex];
for (const auto& deformerIndex : dynamicTransform->deformers) {
const auto& deformer = deformers[deformerIndex];
meshDeformers.push_back(&deformer);
}
uint16_t numDeformerControllers = 0;
if (reweightedDeformers.weightsPerVertex != 0) {
uint32_t dynamicTransformIndex = dynamicTransformPerMesh[i];
const hfm::DynamicTransform& dynamicTransform = dynamicTransforms[dynamicTransformIndex];
numDeformerControllers = (uint16_t)dynamicTransform.deformers.size();
}
// Try to create the graphics::Mesh
buildGraphicsMesh(meshes[i], graphicsMesh, baker::safeGet(normalsPerMesh, i), baker::safeGet(tangentsPerMesh, i), dynamicTransform, meshDeformers);
buildGraphicsMesh(meshes[i], graphicsMesh, baker::safeGet(normalsPerMesh, i), baker::safeGet(tangentsPerMesh, i), numDeformerControllers, reweightedDeformers);
// Choose a name for the mesh
if (graphicsMesh) {

View file

@ -2,8 +2,8 @@
// BuildGraphicsMeshTask.h
// model-baker/src/model-baker
//
// Created by Sabrina Shanman on 2018/12/06.
// Copyright 2018 High Fidelity, Inc.
// Created by Sabrina Shanman on 2019/09/16.
// 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
@ -20,7 +20,7 @@
class BuildGraphicsMeshTask {
public:
using Input = baker::VaryingSet8<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::NormalsPerMesh, baker::TangentsPerMesh, std::vector<hfm::Shape>, std::vector<hfm::DynamicTransform>, std::vector<hfm::Deformer>>;
using Input = baker::VaryingSet8<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::NormalsPerMesh, baker::TangentsPerMesh, std::vector<hfm::Shape>, std::vector<hfm::DynamicTransform>, std::vector<baker::ReweightedDeformers>>;
using Output = std::vector<graphics::MeshPointer>;
using JobModel = baker::Job::ModelIO<BuildGraphicsMeshTask, Input, Output>;

View file

@ -0,0 +1,91 @@
//
// 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 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

View file

@ -0,0 +1,119 @@
//
// ReweightDeformersTask.h
// model-baker/src/model-baker
//
// Created by Sabrina Shanman on 2019/09/26.
// 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 "ReweightDeformersTask.h"
baker::ReweightedDeformers getReweightedDeformers(size_t numMeshVertices, const std::vector<const hfm::Deformer*> deformers, const uint16_t weightsPerVertex) {
size_t numClusterIndices = numMeshVertices * weightsPerVertex;
baker::ReweightedDeformers reweightedDeformers;
reweightedDeformers.weightsPerVertex = weightsPerVertex;
// TODO: Consider having a rootCluster property in the DynamicTransform rather than appending the root to the end of the cluster list.
reweightedDeformers.indices.resize(numClusterIndices, (uint16_t)(deformers.size() - 1));
reweightedDeformers.weights.resize(numClusterIndices, 0);
std::vector<float> weightAccumulators;
weightAccumulators.resize(numClusterIndices, 0.0f);
for (uint16_t i = 0; i < (uint16_t)deformers.size(); ++i) {
const hfm::Deformer& deformer = *deformers[i];
if (deformer.indices.size() != deformer.weights.size()) {
reweightedDeformers.trimmedToMatch = true;
}
size_t numIndicesOrWeights = std::min(deformer.indices.size(), deformer.weights.size());
for (size_t j = 0; j < numIndicesOrWeights; ++j) {
uint32_t index = deformer.indices[j];
float weight = deformer.weights[j];
// look for an unused slot in the weights vector
uint32_t weightIndex = index * weightsPerVertex;
uint32_t lowestIndex = -1;
float lowestWeight = FLT_MAX;
uint16_t k = 0;
for (; k < weightsPerVertex; k++) {
if (weightAccumulators[weightIndex + k] == 0.0f) {
reweightedDeformers.indices[weightIndex + k] = i;
weightAccumulators[weightIndex + k] = weight;
break;
}
if (weightAccumulators[weightIndex + k] < lowestWeight) {
lowestIndex = k;
lowestWeight = weightAccumulators[weightIndex + k];
}
}
if (k == weightsPerVertex && weight > lowestWeight) {
// no space for an additional weight; we must replace the lowest
weightAccumulators[weightIndex + lowestIndex] = weight;
reweightedDeformers.indices[weightIndex + lowestIndex] = i;
}
}
}
// now that we've accumulated the most relevant weights for each vertex
// normalize and compress to 16-bits
for (size_t i = 0; i < numMeshVertices; ++i) {
size_t j = i * weightsPerVertex;
// normalize weights into uint16_t
float totalWeight = 0.0f;
for (size_t k = j; k < j + weightsPerVertex; ++k) {
totalWeight += weightAccumulators[k];
}
const float ALMOST_HALF = 0.499f;
if (totalWeight > 0.0f) {
float weightScalingFactor = (float)(UINT16_MAX) / totalWeight;
for (size_t k = j; k < j + weightsPerVertex; ++k) {
reweightedDeformers.weights[k] = (uint16_t)(weightScalingFactor * weightAccumulators[k] + ALMOST_HALF);
}
} else {
reweightedDeformers.weights[j] = (uint16_t)((float)(UINT16_MAX) + ALMOST_HALF);
}
}
return reweightedDeformers;
}
void ReweightDeformersTask::run(const baker::BakeContextPointer& context, const Input& input, Output& output) {
const uint16_t NUM_WEIGHTS_PER_VERTEX { 4 };
const auto& meshes = input.get0();
const auto& shapes = input.get1();
const auto& dynamicTransforms = input.get2();
const auto& deformers = input.get3();
auto& reweightedDeformers = output;
// Currently, there is only (at most) one dynamicTransform per mesh
// An undefined shape.dynamicTransform has the value hfm::UNDEFINED_KEY
std::vector<uint32_t> dynamicTransformPerMesh;
dynamicTransformPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY);
for (const auto& shape : shapes) {
uint32_t dynamicTransformIndex = shape.dynamicTransform;
dynamicTransformPerMesh[shape.mesh] = dynamicTransformIndex;
}
reweightedDeformers.reserve(meshes.size());
for (size_t i = 0; i < meshes.size(); ++i) {
const auto& mesh = meshes[i];
uint32_t dynamicTransformIndex = dynamicTransformPerMesh[i];
const hfm::DynamicTransform* dynamicTransform = nullptr;
std::vector<const hfm::Deformer*> meshDeformers;
if (dynamicTransformIndex != hfm::UNDEFINED_KEY) {
dynamicTransform = &dynamicTransforms[dynamicTransformIndex];
for (const auto& deformerIndex : dynamicTransform->deformers) {
const auto& deformer = deformers[deformerIndex];
meshDeformers.push_back(&deformer);
}
}
reweightedDeformers.push_back(getReweightedDeformers((size_t)mesh.vertices.size(), meshDeformers, NUM_WEIGHTS_PER_VERTEX));
}
}

View file

@ -0,0 +1,29 @@
//
// ReweightDeformersTask.h
// model-baker/src/model-baker
//
// Created by Sabrina Shanman on 2019/09/26.
// 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_ReweightDeformersTask_h
#define hifi_ReweightDeformersTask_h
#include <hfm/HFM.h>
#include "Engine.h"
#include "BakerTypes.h"
class ReweightDeformersTask {
public:
using Input = baker::VaryingSet4<std::vector<hfm::Mesh>, std::vector<hfm::Shape>, std::vector<hfm::DynamicTransform>, std::vector<hfm::Deformer>>;
using Output = std::vector<baker::ReweightedDeformers>;
using JobModel = baker::Job::ModelIO<ReweightDeformersTask, Input, Output>;
void run(const baker::BakeContextPointer& context, const Input& input, Output& output);
};
#endif // hifi_ReweightDeformersTask_h