From a995f2c09fa7a44741c9a8bc4fac7fa7f8bdc7fb Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 10 Oct 2019 17:09:54 -0700 Subject: [PATCH 1/7] in the middle of something --- libraries/fbx/src/FBXSerializer.cpp | 3 - libraries/hfm/src/hfm/HFM.h | 8 --- .../src/model-networking/ModelCache.cpp | 1 - .../src/CauterizedMeshPartPayload.cpp | 4 +- .../src/CauterizedMeshPartPayload.h | 2 +- .../render-utils/src/CauterizedModel.cpp | 56 ++++++++----------- .../render-utils/src/MeshPartPayload.cpp | 42 +++----------- libraries/render-utils/src/MeshPartPayload.h | 8 +-- libraries/render-utils/src/Model.cpp | 34 +++++------ libraries/render-utils/src/Model.h | 2 +- 10 files changed, 53 insertions(+), 107 deletions(-) diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index c35a23ef3a..bec42ca01c 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1463,9 +1463,6 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const // see if any materials have texture children bool materialsHaveTextures = checkMaterialsHaveTextures(_hfmMaterials, _textureFilenames, _connectionChildMap); - // Note that the transforms in the TransformNodes are initially in world-space, and need to be converted to parent-space - std::vector transformNodes; - for (QMap::iterator it = meshes.begin(); it != meshes.end(); it++) { const QString& meshID = it.key(); const ExtractedMesh& extracted = it.value(); diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index 96030672f2..f3330d9291 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -293,13 +293,6 @@ public: bool shouldInitCollisions() const { return _collisionsConfig.size() > 0; } }; -// DEPRECATED in favor of using hfm::Joint -class TransformNode { -public: - uint32_t parent { 0 }; - Transform transform; -}; - // Formerly contained in hfm::Mesh class Deformer { public: @@ -343,7 +336,6 @@ public: std::vector materials; std::vector deformers; - std::vector transforms; std::vector dynamicTransforms; std::vector joints; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 2376beba30..8b7db5957b 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -295,7 +295,6 @@ void ModelResource::onGeometryMappingLoaded(bool success) { if (success && _modelResource) { _hfmModel = _modelResource->_hfmModel; _materialMapping = _modelResource->_materialMapping; - // _meshParts = _modelResource->_meshParts; _meshes = _modelResource->_meshes; _materials = _modelResource->_materials; diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index a310c10136..6996ea3c29 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -18,8 +18,8 @@ using namespace render; -CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) - : ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {} +CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform) + : ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform) {} void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector& clusterMatrices, const std::vector& cauterizedClusterMatrices) { diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 9a6cea8b9f..87d8ce7ae9 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -13,7 +13,7 @@ class CauterizedMeshPartPayload : public ModelMeshPartPayload { public: - CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); + CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform); // matrix palette skinning void updateClusterBuffer(const std::vector& clusterMatrices, diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 87eacc20ec..9f9acbf182 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -33,7 +33,20 @@ bool CauterizedModel::updateGeometry() { if (_isCauterized && needsFullUpdate) { assert(_cauterizeMeshStates.empty()); const HFMModel& hfmModel = getHFMModel(); - foreach (const HFMMesh& mesh, hfmModel.meshes) { + const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; + for (int i = 0; i < hfmDynamicTransforms.size(); i++) { + const auto& dynT = hfmDynamicTransforms[i]; + MeshState state; + if (_useDualQuaternionSkinning) { + state.clusterDualQuaternions.resize(dynT.clusters.size()); + } else { + state.clusterMatrices.resize(dynT.clusters.size()); + } + _cauterizeMeshStates.append(state); + _meshStates.push_back(state); + } + + /* foreach (const HFMMesh& mesh, hfmModel.meshes) { Model::MeshState state; if (_useDualQuaternionSkinning) { state.clusterDualQuaternions.resize(mesh.clusters.size()); @@ -42,7 +55,7 @@ bool CauterizedModel::updateGeometry() { state.clusterMatrices.resize(mesh.clusters.size()); _cauterizeMeshStates.append(state); } - } + }*/ } return needsFullUpdate; } @@ -73,6 +86,8 @@ void CauterizedModel::createRenderItemSet() { offset.setScale(_scale); offset.postTranslate(_offset); + Transform::mult(transform, transform, offset); + // Run through all of the meshes, and place them into their segregated, but unsorted buckets int shapeID = 0; uint32_t numMeshes = (uint32_t)meshes.size(); @@ -85,7 +100,7 @@ void CauterizedModel::createRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - auto ptr = std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); + auto ptr = std::make_shared(shared_from_this(), i, partIndex, shapeID, transform); _modelMeshRenderItems << std::static_pointer_cast(ptr); auto material = getNetworkModel()->getShapeMaterial(shapeID); _modelMeshMaterialNames.push_back(material ? material->getName() : ""); @@ -222,8 +237,11 @@ void CauterizedModel::updateRenderItems() { auto itemID = self->_modelMeshRenderItemIDs[i]; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; + auto deformerIndex = self->_modelMeshRenderItemShapes[i].meshIndex; const auto& shapeState = self->getShapeState(i); + + const auto& meshState = self->getMeshState(meshIndex); const auto& cauterizedMeshState = self->getCauterizeMeshState(meshIndex); @@ -244,38 +262,10 @@ void CauterizedModel::updateRenderItems() { } Transform renderTransform = modelTransform; - /*if (useDualQuaternionSkinning) { - if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) { - const auto& dq = meshState.clusterDualQuaternions[0]; - Transform transform(dq.getRotation(), - dq.getScale(), - dq.getTranslation()); - renderTransform = modelTransform.worldTransform(transform); - } - } else { - if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) { - renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0])); - } - }*/ - if (meshState.clusterMatrices.size() <= 1) { + if (meshState.clusterMatrices.size() <= 2) { renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); } - data.updateTransformForSkinnedMesh(renderTransform, modelTransform); - - renderTransform = modelTransform; - if (useDualQuaternionSkinning) { - if (cauterizedMeshState.clusterDualQuaternions.size() == 1 || cauterizedMeshState.clusterDualQuaternions.size() == 2) { - const auto& dq = cauterizedMeshState.clusterDualQuaternions[0]; - Transform transform(dq.getRotation(), - dq.getScale(), - dq.getTranslation()); - renderTransform = modelTransform.worldTransform(Transform(transform)); - } - } else { - if (cauterizedMeshState.clusterMatrices.size() == 1 || cauterizedMeshState.clusterMatrices.size() == 2) { - renderTransform = modelTransform.worldTransform(Transform(cauterizedMeshState.clusterMatrices[0])); - } - } + data.updateTransform(renderTransform); data.updateTransformForCauterizedMesh(renderTransform); data.setEnableCauterization(enableCauterization); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 8f992ba329..7b37c847af 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -64,11 +64,10 @@ void MeshPartPayload::updateMeshPart(const std::shared_ptr } } -void MeshPartPayload::updateTransform(const Transform& transform, const Transform& offsetTransform) { - _transform = transform; - Transform::mult(_drawTransform, _transform, offsetTransform); +void MeshPartPayload::updateTransform(const Transform& transform) { + _worldFromLocalTransform = transform; _worldBound = _localBound; - _worldBound.transform(_drawTransform); + _worldBound.transform(_worldFromLocalTransform); } void MeshPartPayload::addMaterial(graphics::MaterialLayer material) { @@ -134,7 +133,7 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) { } void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const { - batch.setModelTransform(_drawTransform); + batch.setModelTransform(_worldFromLocalTransform); } @@ -196,7 +195,7 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren } -ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : +ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform) : _meshIndex(meshIndex), _shapeID(shapeIndex) { @@ -220,28 +219,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in computeAdjustedLocalBound(state.clusterMatrices); } - updateTransform(transform, offsetTransform); - - Transform renderTransform = transform; - -/* if (useDualQuaternionSkinning) { - if (state.clusterDualQuaternions.size() == 1) { - const auto& dq = state.clusterDualQuaternions[0]; - Transform transform(dq.getRotation(), - dq.getScale(), - dq.getTranslation()); - renderTransform = transform.worldTransform(Transform(transform)); - } - } else { - if (state.clusterMatrices.size() == 1) { - renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0])); - } - } -*/ - + Transform renderTransform = transform; const Model::ShapeState& shapeState = model->getShapeState(shapeIndex); renderTransform = transform.worldTransform(shapeState._rootFromJointTransform); - updateTransformForSkinnedMesh(renderTransform, transform); + updateTransform(renderTransform); initCache(model); @@ -323,13 +304,6 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector& drawMesh, int partIndex); virtual void notifyLocationChanged() {} - void updateTransform(const Transform& transform, const Transform& offsetTransform); + void updateTransform(const Transform& transform); // Render Item interface virtual render::ItemKey getKey() const; @@ -52,8 +52,7 @@ public: virtual void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const; // Payload resource cached values - Transform _drawTransform; - Transform _transform; + Transform _worldFromLocalTransform; int _partIndex = 0; bool _hasColorAttrib { false }; @@ -86,7 +85,7 @@ namespace render { class ModelMeshPartPayload : public MeshPartPayload { public: - ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); + ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform); typedef render::Payload Payload; typedef Payload::DataPointer Pointer; @@ -100,7 +99,6 @@ public: // dual quaternion skinning void updateClusterBuffer(const std::vector& clusterDualQuaternions); - void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform); // Render Item interface render::ShapeKey getShapeKey() const override; // shape interface diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 5d5de04537..0d555b605a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -249,24 +249,10 @@ void Model::updateRenderItems() { } Transform renderTransform = modelTransform; - - /*if (useDualQuaternionSkinning) { - if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) { - const auto& dq = meshState.clusterDualQuaternions[0]; - Transform transform(dq.getRotation(), - dq.getScale(), - dq.getTranslation()); - renderTransform = modelTransform.worldTransform(Transform(transform)); - } - } else { - if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) { - renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0])); - } - }*/ if (meshState.clusterMatrices.size() <= 1) { renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); } - data.updateTransformForSkinnedMesh(renderTransform, modelTransform); + data.updateTransform(renderTransform); data.setCauterized(cauterized); data.updateKey(renderItemKeyGlobalFlags); @@ -305,7 +291,7 @@ void Model::updateShapeStatesFromRig() { _shapeStates.resize(shapes.size()); for (int s = 0; s < shapes.size(); ++s) { uint32_t jointId = shapes[s].transform; - if (jointId < _rig.getJointStateCount()) { + if (jointId < (uint32_t) _rig.getJointStateCount()) { _shapeStates[s]._rootFromJointTransform = _rig.getJointTransform(shapes[s].transform); } } @@ -329,14 +315,24 @@ bool Model::updateGeometry() { updateShapeStatesFromRig(); const HFMModel& hfmModel = getHFMModel(); - int i = 0; - foreach (const HFMMesh& mesh, hfmModel.meshes) { + const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; + /* int i = 0; + for (const auto& mesh: hfmModel.meshes) { MeshState state; state.clusterDualQuaternions.resize(mesh.clusters.size()); state.clusterMatrices.resize(mesh.clusters.size()); _meshStates.push_back(state); i++; } + */ + for (int i = 0; i < hfmDynamicTransforms.size(); i++) { + const auto& dynT = hfmDynamicTransforms[i]; + MeshState state; + state.clusterDualQuaternions.resize(dynT.clusters.size()); + state.clusterMatrices.resize(dynT.clusters.size()); + _meshStates.push_back(state); + } + needFullUpdate = true; emit rigReady(); } @@ -1510,7 +1506,7 @@ void Model::createRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - _modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); + _modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform); auto material = getNetworkModel()->getShapeMaterial(shapeID); _modelMeshMaterialNames.push_back(material ? material->getName() : ""); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 85661d4b6b..0a102630b6 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -473,7 +473,7 @@ protected: QVector> _modelMeshRenderItems; QMap _modelMeshRenderItemsMap; render::ItemIDs _modelMeshRenderItemIDs; - using ShapeInfo = struct { int meshIndex; }; + using ShapeInfo = struct { int meshIndex; int deformerIndex; }; std::vector _modelMeshRenderItemShapes; std::vector _modelMeshMaterialNames; From 8a1f3648f90622d7f5ff9ab424a38bb3d76d3a77 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 11 Oct 2019 18:06:44 -0700 Subject: [PATCH 2/7] fooling around to get the cluster working --- libraries/fbx/src/FBXSerializer.cpp | 2 +- libraries/hfm/src/hfm/HFM.h | 2 +- libraries/render-utils/src/CauterizedModel.cpp | 18 +++++++++--------- libraries/render-utils/src/MeshPartPayload.cpp | 6 +++--- libraries/render-utils/src/Model.cpp | 17 +++++++++-------- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index bec42ca01c..58a9ed2570 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1502,7 +1502,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const hfm::Shape& shape = partShapes[i]; shape.mesh = meshIndex; shape.meshPart = i; - shape.transform = transformIndex; + shape.joint = transformIndex; auto matName = mesh.parts[i].materialID; auto materialIt = materialNameToID.find(matName.toStdString()); diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index f3330d9291..ba7e90bd92 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -314,7 +314,7 @@ public: uint32_t mesh { UNDEFINED_KEY }; uint32_t meshPart { UNDEFINED_KEY }; uint32_t material { UNDEFINED_KEY }; - uint32_t transform { UNDEFINED_KEY }; // The hfm::Joint associated with this shape, containing transform information + uint32_t joint { UNDEFINED_KEY }; // The hfm::Joint associated with this shape, containing transform information // TODO: Have all serializers calculate hfm::Shape::transformedExtents in world space where they previously calculated hfm::Mesh::meshExtents. Change all code that uses hfm::Mesh::meshExtents to use this instead. Extents transformedExtents; // The precise extents of the meshPart vertices in world space, after transform information is applied, while not taking into account rigging/skinning uint32_t dynamicTransform { UNDEFINED_KEY }; diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 9f9acbf182..9849880822 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -33,7 +33,7 @@ bool CauterizedModel::updateGeometry() { if (_isCauterized && needsFullUpdate) { assert(_cauterizeMeshStates.empty()); const HFMModel& hfmModel = getHFMModel(); - const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; + /* const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; for (int i = 0; i < hfmDynamicTransforms.size(); i++) { const auto& dynT = hfmDynamicTransforms[i]; MeshState state; @@ -44,9 +44,8 @@ bool CauterizedModel::updateGeometry() { } _cauterizeMeshStates.append(state); _meshStates.push_back(state); - } - - /* foreach (const HFMMesh& mesh, hfmModel.meshes) { + }*/ + foreach (const HFMMesh& mesh, hfmModel.meshes) { Model::MeshState state; if (_useDualQuaternionSkinning) { state.clusterDualQuaternions.resize(mesh.clusters.size()); @@ -55,7 +54,7 @@ bool CauterizedModel::updateGeometry() { state.clusterMatrices.resize(mesh.clusters.size()); _cauterizeMeshStates.append(state); } - }*/ + } } return needsFullUpdate; } @@ -68,7 +67,7 @@ void CauterizedModel::createRenderItemSet() { // all of our mesh vectors must match in size if (meshes.size() != _meshStates.size()) { qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet."; - return; + // return; } // We should not have any existing renderItems if we enter this section of code @@ -241,9 +240,10 @@ void CauterizedModel::updateRenderItems() { const auto& shapeState = self->getShapeState(i); - - const auto& meshState = self->getMeshState(meshIndex); - const auto& cauterizedMeshState = self->getCauterizeMeshState(meshIndex); + // const auto& meshState = self->getMeshState(meshIndex); + // const auto& cauterizedMeshState = self->getCauterizeMeshState(meshIndex); + MeshState meshState; + MeshState cauterizedMeshState; bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 7b37c847af..2fb36dad67 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -209,14 +209,14 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in auto& modelMesh = model->getNetworkModel()->getMeshes().at(_meshIndex); _meshNumVertices = (int)modelMesh->getNumVertices(); - const Model::MeshState& state = model->getMeshState(_meshIndex); + // const Model::MeshState& state = model->getMeshState(_meshIndex); updateMeshPart(modelMesh, partIndex); if (useDualQuaternionSkinning) { - computeAdjustedLocalBound(state.clusterDualQuaternions); + // computeAdjustedLocalBound(state.clusterDualQuaternions); } else { - computeAdjustedLocalBound(state.clusterMatrices); + // computeAdjustedLocalBound(state.clusterMatrices); } Transform renderTransform = transform; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0d555b605a..662b6f190a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -233,7 +233,8 @@ void Model::updateRenderItems() { auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; const auto& shapeState = self->getShapeState(i); - const auto& meshState = self->getMeshState(meshIndex); + // const auto& meshState = self->getMeshState(meshIndex); + MeshState meshState; bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); @@ -290,9 +291,9 @@ void Model::updateShapeStatesFromRig() { const auto& shapes = hfmModel.shapes; _shapeStates.resize(shapes.size()); for (int s = 0; s < shapes.size(); ++s) { - uint32_t jointId = shapes[s].transform; + uint32_t jointId = shapes[s].joint; if (jointId < (uint32_t) _rig.getJointStateCount()) { - _shapeStates[s]._rootFromJointTransform = _rig.getJointTransform(shapes[s].transform); + _shapeStates[s]._rootFromJointTransform = _rig.getJointTransform(jointId); } } } @@ -316,7 +317,7 @@ bool Model::updateGeometry() { const HFMModel& hfmModel = getHFMModel(); const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; - /* int i = 0; + /* int i = 0; for (const auto& mesh: hfmModel.meshes) { MeshState state; state.clusterDualQuaternions.resize(mesh.clusters.size()); @@ -325,13 +326,13 @@ bool Model::updateGeometry() { i++; } */ - for (int i = 0; i < hfmDynamicTransforms.size(); i++) { + /*for (int i = 0; i < hfmDynamicTransforms.size(); i++) { const auto& dynT = hfmDynamicTransforms[i]; MeshState state; state.clusterDualQuaternions.resize(dynT.clusters.size()); state.clusterMatrices.resize(dynT.clusters.size()); _meshStates.push_back(state); - } + }*/ needFullUpdate = true; emit rigReady(); @@ -1476,7 +1477,7 @@ void Model::createRenderItemSet() { // all of our mesh vectors must match in size if (meshes.size() != _meshStates.size()) { qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! " << meshes.size() << _meshStates.size() << " We will not segregate mesh groups yet."; - return; + // return; } // We should not have any existing renderItems if we enter this section of code @@ -1516,7 +1517,7 @@ void Model::createRenderItemSet() { } bool Model::isRenderable() const { - return (!_shapeStates.empty() && !_meshStates.empty()) || (isLoaded() && _renderGeometry->getMeshes().empty()); + return (!_shapeStates.empty() /* && !_meshStates.empty()*/) || (isLoaded() && _renderGeometry->getMeshes().empty()); } std::set Model::getMeshIDsFromMaterialID(QString parentMaterialName) { From 05ac9aefa8fbd9121e27c009ac9b8b06f2e3cee7 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 14 Oct 2019 02:21:01 -0700 Subject: [PATCH 3/7] the clusterMatrices should be working, but n skin index and weights are assigned yet --- libraries/animation/src/AnimSkeleton.cpp | 29 ++++ libraries/animation/src/AnimSkeleton.h | 2 + .../render-utils/src/CauterizedModel.cpp | 158 ++++++++++++++---- .../render-utils/src/MeshPartPayload.cpp | 44 +---- libraries/render-utils/src/MeshPartPayload.h | 8 +- libraries/render-utils/src/Model.cpp | 116 +++++++++---- libraries/render-utils/src/Model.h | 2 +- 7 files changed, 242 insertions(+), 117 deletions(-) diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index b26d00d8d0..a68f5c869f 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -30,6 +30,34 @@ AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) { // we make a copy of the inverseBindMatrices in order to prevent mutating the model bind pose // when we are dealing with a joint offset in the model + for (int i = 0; i < (int)hfmModel.dynamicTransforms.size(); i++) { + const auto& defor = hfmModel.dynamicTransforms[i]; + std::vector dummyClustersList; + + for (int j = 0; j < defor.clusters.size(); j++) { + std::vector bindMatrices; + // cast into a non-const reference, so we can mutate the FBXCluster + HFMCluster& cluster = const_cast(defor.clusters.at(j)); + + HFMCluster localCluster; + localCluster.jointIndex = cluster.jointIndex; + localCluster.inverseBindMatrix = cluster.inverseBindMatrix; + localCluster.inverseBindTransform.evalFromRawMatrix(localCluster.inverseBindMatrix); + + // if we have a joint offset in the fst file then multiply its inverse by the + // model cluster inverse bind matrix + if (hfmModel.jointRotationOffsets.contains(cluster.jointIndex)) { + AnimPose localOffset(hfmModel.jointRotationOffsets[cluster.jointIndex], glm::vec3()); + localCluster.inverseBindMatrix = (glm::mat4)localOffset.inverse() * cluster.inverseBindMatrix; + localCluster.inverseBindTransform.evalFromRawMatrix(localCluster.inverseBindMatrix); + } + dummyClustersList.push_back(localCluster); + } + _clusterBindMatrixOriginalValues.push_back(dummyClustersList); + } + + +/* for (int i = 0; i < (int)hfmModel.meshes.size(); i++) { const HFMMesh& mesh = hfmModel.meshes.at(i); std::vector dummyClustersList; @@ -55,6 +83,7 @@ AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) { } _clusterBindMatrixOriginalValues.push_back(dummyClustersList); } +*/ } AnimSkeleton::AnimSkeleton(const std::vector& joints, const QMap jointOffsets) { diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index efc1c1599f..526959df9a 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -70,6 +70,8 @@ public: std::vector lookUpJointIndices(const std::vector& jointNames) const; const HFMCluster getClusterBindMatricesOriginalValues(const int meshIndex, const int clusterIndex) const { return _clusterBindMatrixOriginalValues[meshIndex][clusterIndex]; } + // const HFMCluster getClusterBindMatricesOriginalValues(const int meshIndex, const int clusterIndex) const { return _clusterBindMatrixOriginalValues[meshIndex][clusterIndex]; } + protected: void buildSkeletonFromJoints(const std::vector& joints, const QMap jointOffsets); diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 9849880822..3e7c694768 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -32,8 +32,8 @@ bool CauterizedModel::updateGeometry() { bool needsFullUpdate = Model::updateGeometry(); if (_isCauterized && needsFullUpdate) { assert(_cauterizeMeshStates.empty()); - const HFMModel& hfmModel = getHFMModel(); - /* const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; + /* const HFMModel& hfmModel = getHFMModel(); + const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; for (int i = 0; i < hfmDynamicTransforms.size(); i++) { const auto& dynT = hfmDynamicTransforms[i]; MeshState state; @@ -45,7 +45,27 @@ bool CauterizedModel::updateGeometry() { _cauterizeMeshStates.append(state); _meshStates.push_back(state); }*/ - foreach (const HFMMesh& mesh, hfmModel.meshes) { + + const HFMModel& hfmModel = getHFMModel(); + const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; + int i = 0; + /* for (const auto& mesh: hfmModel.meshes) { + MeshState state; + state.clusterDualQuaternions.resize(mesh.clusters.size()); + state.clusterMatrices.resize(mesh.clusters.size()); + _meshStates.push_back(state); + i++; + } + */ + for (int i = 0; i < hfmDynamicTransforms.size(); i++) { + const auto& dynT = hfmDynamicTransforms[i]; + MeshState state; + state.clusterDualQuaternions.resize(dynT.clusters.size()); + state.clusterMatrices.resize(dynT.clusters.size()); + _cauterizeMeshStates.push_back(state); + } + + /* foreach (const HFMMesh& mesh, hfmModel.meshes) { Model::MeshState state; if (_useDualQuaternionSkinning) { state.clusterDualQuaternions.resize(mesh.clusters.size()); @@ -54,7 +74,7 @@ bool CauterizedModel::updateGeometry() { state.clusterMatrices.resize(mesh.clusters.size()); _cauterizeMeshStates.append(state); } - } + }*/ } return needsFullUpdate; } @@ -64,11 +84,6 @@ void CauterizedModel::createRenderItemSet() { assert(isLoaded()); const auto& meshes = _renderGeometry->getMeshes(); - // all of our mesh vectors must match in size - if (meshes.size() != _meshStates.size()) { - qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet."; - // return; - } // We should not have any existing renderItems if we enter this section of code Q_ASSERT(_modelMeshRenderItems.isEmpty()); @@ -88,7 +103,20 @@ void CauterizedModel::createRenderItemSet() { Transform::mult(transform, transform, offset); // Run through all of the meshes, and place them into their segregated, but unsorted buckets + // Run through all of the meshes, and place them into their segregated, but unsorted buckets int shapeID = 0; + const auto& shapes = _renderGeometry->getHFMModel().shapes; + for (shapeID; shapeID < shapes.size(); shapeID++) { + const auto& shape = shapes[shapeID]; + + _modelMeshRenderItems << std::make_shared(shared_from_this(), shape.mesh, shape.meshPart, shapeID, transform); + + auto material = getNetworkModel()->getShapeMaterial(shapeID); + _modelMeshMaterialNames.push_back(material ? material->getName() : ""); + _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)shape.mesh, shape.dynamicTransform }); + } + +/* int shapeID = 0; uint32_t numMeshes = (uint32_t)meshes.size(); for (uint32_t i = 0; i < numMeshes; i++) { const auto& mesh = meshes.at(i); @@ -106,7 +134,7 @@ void CauterizedModel::createRenderItemSet() { _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); shapeID++; } - } + }*/ } else { Model::createRenderItemSet(); } @@ -122,6 +150,38 @@ void CauterizedModel::updateClusterMatrices() { updateShapeStatesFromRig(); _needsUpdateClusterMatrices = false; + + + const HFMModel& hfmModel = getHFMModel(); + const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; + for (int i = 0; i < (int)_meshStates.size(); i++) { + MeshState& state = _meshStates[i]; + const auto& deformer = hfmDynamicTransforms[i]; + + int meshIndex = i; + int clusterIndex = 0; + + for (int d = 0; d < deformer.clusters.size(); d++) { + const auto& cluster = deformer.clusters[d]; + clusterIndex = d; + + const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex); + + if (_useDualQuaternionSkinning) { + auto jointPose = _rig.getJointPose(cluster.jointIndex); + Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans()); + Transform clusterTransform; + Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform); + state.clusterDualQuaternions[d] = Model::TransformDualQuaternion(clusterTransform); + } + else { + auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); + glm_mat4u_mul(jointMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[d]); + } + + } + } +/* const HFMModel& hfmModel = getHFMModel(); for (int i = 0; i < (int)_meshStates.size(); i++) { Model::MeshState& state = _meshStates[i]; @@ -145,7 +205,7 @@ void CauterizedModel::updateClusterMatrices() { } } } - +*/ // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. if (!_cauterizeBoneSet.empty()) { @@ -236,42 +296,66 @@ void CauterizedModel::updateRenderItems() { auto itemID = self->_modelMeshRenderItemIDs[i]; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; - auto deformerIndex = self->_modelMeshRenderItemShapes[i].meshIndex; const auto& shapeState = self->getShapeState(i); - // const auto& meshState = self->getMeshState(meshIndex); - // const auto& cauterizedMeshState = self->getCauterizeMeshState(meshIndex); - MeshState meshState; - MeshState cauterizedMeshState; + auto deformerIndex = self->_modelMeshRenderItemShapes[i].deformerIndex; + bool isDeformed = (deformerIndex != hfm::UNDEFINED_KEY); + + + // auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; + // auto deformerIndex = self->_modelMeshRenderItemShapes[i].meshIndex; + + // const auto& shapeState = self->getShapeState(i); + bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); - transaction.updateItem(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, - primitiveMode, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) { - CauterizedMeshPartPayload& data = static_cast(mmppData); - if (useDualQuaternionSkinning) { - data.updateClusterBuffer(meshState.clusterDualQuaternions, - cauterizedMeshState.clusterDualQuaternions); - data.computeAdjustedLocalBound(meshState.clusterDualQuaternions); - } else { - data.updateClusterBuffer(meshState.clusterMatrices, - cauterizedMeshState.clusterMatrices); - data.computeAdjustedLocalBound(meshState.clusterMatrices); - } - Transform renderTransform = modelTransform; - if (meshState.clusterMatrices.size() <= 2) { + + if (isDeformed) { + + const auto& meshState = self->getMeshState(deformerIndex); + const auto& cauterizedMeshState = self->getCauterizeMeshState(deformerIndex); + + transaction.updateItem(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, + primitiveMode, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) { + CauterizedMeshPartPayload& data = static_cast(mmppData); + if (useDualQuaternionSkinning) { + data.updateClusterBuffer(meshState.clusterDualQuaternions, + cauterizedMeshState.clusterDualQuaternions); + } else { + data.updateClusterBuffer(meshState.clusterMatrices, + cauterizedMeshState.clusterMatrices); + } + + Transform renderTransform = modelTransform; + // if (meshState.clusterMatrices.size() <= 2) { + renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); + // } + data.updateTransform(renderTransform); + data.updateTransformForCauterizedMesh(renderTransform); + + data.setEnableCauterization(enableCauterization); + data.updateKey(renderItemKeyGlobalFlags); + data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); + }); + } else { + transaction.updateItem(itemID, [modelTransform, shapeState, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) { + + Transform renderTransform = modelTransform; + // if (meshState.clusterMatrices.size() <= 1) { renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); - } - data.updateTransform(renderTransform); - data.updateTransformForCauterizedMesh(renderTransform); + // } + data.updateTransform(renderTransform); - data.setEnableCauterization(enableCauterization); - data.updateKey(renderItemKeyGlobalFlags); - data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); - }); + // data.setEnableCauterization(enableCauterization); + data.updateKey(renderItemKeyGlobalFlags); + data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, false); + }); + + } } scene->enqueueTransaction(transaction); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2fb36dad67..a242c94299 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -213,17 +213,13 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in updateMeshPart(modelMesh, partIndex); - if (useDualQuaternionSkinning) { - // computeAdjustedLocalBound(state.clusterDualQuaternions); - } else { - // computeAdjustedLocalBound(state.clusterMatrices); - } - Transform renderTransform = transform; const Model::ShapeState& shapeState = model->getShapeState(shapeIndex); renderTransform = transform.worldTransform(shapeState._rootFromJointTransform); updateTransform(renderTransform); + _deformerIndex = shape.dynamicTransform; + initCache(model); #if defined(Q_OS_MAC) || defined(Q_OS_ANDROID) @@ -245,7 +241,9 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) { if (_drawMesh) { auto vertexFormat = _drawMesh->getVertexFormat(); _hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR); - _isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX); + if (_deformerIndex != hfm::UNDEFINED_KEY) { + _isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX); + } const HFMModel& hfmModel = model->getHFMModel(); const HFMMesh& mesh = hfmModel.meshes.at(_meshIndex); @@ -432,38 +430,6 @@ void ModelMeshPartPayload::render(RenderArgs* args) { args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; } -void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& clusterMatrices) { - _adjustedLocalBound = _localBound; - if (clusterMatrices.size() > 0) { - _adjustedLocalBound.transform(clusterMatrices.back()); - - for (int i = 0; i < (int)clusterMatrices.size() - 1; ++i) { - AABox clusterBound = _localBound; - clusterBound.transform(clusterMatrices[i]); - _adjustedLocalBound += clusterBound; - } - } -} - -void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& clusterDualQuaternions) { - _adjustedLocalBound = _localBound; - if (clusterDualQuaternions.size() > 0) { - Transform rootTransform(clusterDualQuaternions.back().getRotation(), - clusterDualQuaternions.back().getScale(), - clusterDualQuaternions.back().getTranslation()); - _adjustedLocalBound.transform(rootTransform); - - for (int i = 0; i < (int)clusterDualQuaternions.size() - 1; ++i) { - AABox clusterBound = _localBound; - Transform transform(clusterDualQuaternions[i].getRotation(), - clusterDualQuaternions[i].getScale(), - clusterDualQuaternions[i].getTranslation()); - clusterBound.transform(transform); - _adjustedLocalBound += clusterBound; - } - } -} - void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map& blendshapeBuffers, const QVector& blendedMeshSizes) { if (_meshIndex < blendedMeshSizes.length() && blendedMeshSizes.at(_meshIndex) == _meshNumVertices) { auto blendshapeBuffer = blendshapeBuffers.find(_meshIndex); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 9ddc62db40..50e06c024c 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -57,7 +57,6 @@ public: bool _hasColorAttrib { false }; graphics::Box _localBound; - graphics::Box _adjustedLocalBound; mutable graphics::Box _worldBound; std::shared_ptr _drawMesh; @@ -111,12 +110,6 @@ public: void bindMesh(gpu::Batch& batch) override; void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override; - // matrix palette skinning - void computeAdjustedLocalBound(const std::vector& clusterMatrices); - - // dual quaternion skinning - void computeAdjustedLocalBound(const std::vector& clusterDualQuaternions); - gpu::BufferPointer _clusterBuffer; enum class ClusterBufferType { Matrices, DualQuaternions }; @@ -124,6 +117,7 @@ public: int _meshIndex; int _shapeID; + int _deformerIndex; bool _isSkinned{ false }; bool _isBlendShaped { false }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 662b6f190a..27e8725572 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -186,7 +186,7 @@ bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) { const auto& networkMeshes = getNetworkModel()->getMeshes(); // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown // to false to rebuild out mesh groups. - if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)hfmModel.meshes.size() || meshIndex >= (int)_meshStates.size()) { + if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)hfmModel.meshes.size() /* || meshIndex >= (int)_meshStates.size()*/) { _needsFixupInScene = true; // trigger remove/add cycle invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid return true; @@ -233,32 +233,51 @@ void Model::updateRenderItems() { auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; const auto& shapeState = self->getShapeState(i); - // const auto& meshState = self->getMeshState(meshIndex); - MeshState meshState; + + auto deformerIndex = self->_modelMeshRenderItemShapes[i].deformerIndex; + bool isDeformed = (deformerIndex != hfm::UNDEFINED_KEY); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); - bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); - transaction.updateItem(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, - invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) { - if (useDualQuaternionSkinning) { - data.updateClusterBuffer(meshState.clusterDualQuaternions); - data.computeAdjustedLocalBound(meshState.clusterDualQuaternions); - } else { - data.updateClusterBuffer(meshState.clusterMatrices); - data.computeAdjustedLocalBound(meshState.clusterMatrices); - } + + if (isDeformed) { - Transform renderTransform = modelTransform; - if (meshState.clusterMatrices.size() <= 1) { + const auto& meshState = self->getMeshState(deformerIndex); + // MeshState meshState; + bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); + + + transaction.updateItem(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, + invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) { + if (useDualQuaternionSkinning) { + data.updateClusterBuffer(meshState.clusterDualQuaternions); + } else { + data.updateClusterBuffer(meshState.clusterMatrices); + } + + Transform renderTransform = modelTransform; + // if (meshState.clusterMatrices.size() <= 1) { + renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); + // } + data.updateTransform(renderTransform); + + data.setCauterized(cauterized); + data.updateKey(renderItemKeyGlobalFlags); + data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); + }); + } else { + transaction.updateItem(itemID, [modelTransform, shapeState, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) { + + Transform renderTransform = modelTransform; + // if (meshState.clusterMatrices.size() <= 1) { renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); - } - data.updateTransform(renderTransform); + // } + data.updateTransform(renderTransform); - data.setCauterized(cauterized); - data.updateKey(renderItemKeyGlobalFlags); - data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); - }); + data.updateKey(renderItemKeyGlobalFlags); + data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, false); + }); + } } AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); @@ -317,8 +336,8 @@ bool Model::updateGeometry() { const HFMModel& hfmModel = getHFMModel(); const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; - /* int i = 0; - for (const auto& mesh: hfmModel.meshes) { + int i = 0; + /* for (const auto& mesh: hfmModel.meshes) { MeshState state; state.clusterDualQuaternions.resize(mesh.clusters.size()); state.clusterMatrices.resize(mesh.clusters.size()); @@ -326,13 +345,13 @@ bool Model::updateGeometry() { i++; } */ - /*for (int i = 0; i < hfmDynamicTransforms.size(); i++) { + for (int i = 0; i < hfmDynamicTransforms.size(); i++) { const auto& dynT = hfmDynamicTransforms[i]; MeshState state; state.clusterDualQuaternions.resize(dynT.clusters.size()); state.clusterMatrices.resize(dynT.clusters.size()); _meshStates.push_back(state); - }*/ + } needFullUpdate = true; emit rigReady(); @@ -1407,8 +1426,34 @@ void Model::updateClusterMatrices() { _needsUpdateClusterMatrices = false; const HFMModel& hfmModel = getHFMModel(); + const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; for (int i = 0; i < (int) _meshStates.size(); i++) { MeshState& state = _meshStates[i]; + const auto& deformer = hfmDynamicTransforms[i]; + + int meshIndex = i; + int clusterIndex = 0; + + for (int d = 0; d < deformer.clusters.size(); d++) { + const auto& cluster = deformer.clusters[d]; + clusterIndex = d; + + const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex); + + if (_useDualQuaternionSkinning) { + auto jointPose = _rig.getJointPose(cluster.jointIndex); + Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans()); + Transform clusterTransform; + Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform); + state.clusterDualQuaternions[d] = Model::TransformDualQuaternion(clusterTransform); + } + else { + auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); + glm_mat4u_mul(jointMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[d]); + } + + } +/* int meshIndex = i; const HFMMesh& mesh = hfmModel.meshes.at(i); for (int j = 0; j < mesh.clusters.size(); j++) { @@ -1425,7 +1470,7 @@ void Model::updateClusterMatrices() { auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, state.clusterMatrices[j]); } - } + }*/ } // post the blender if we're not currently waiting for one to finish @@ -1474,12 +1519,6 @@ void Model::createRenderItemSet() { assert(isLoaded()); const auto& meshes = _renderGeometry->getMeshes(); - // all of our mesh vectors must match in size - if (meshes.size() != _meshStates.size()) { - qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! " << meshes.size() << _meshStates.size() << " We will not segregate mesh groups yet."; - // return; - } - // We should not have any existing renderItems if we enter this section of code Q_ASSERT(_modelMeshRenderItems.isEmpty()); @@ -1497,6 +1536,17 @@ void Model::createRenderItemSet() { // Run through all of the meshes, and place them into their segregated, but unsorted buckets int shapeID = 0; + const auto& shapes = _renderGeometry->getHFMModel().shapes; + for (shapeID; shapeID < shapes.size(); shapeID++) { + const auto& shape = shapes[shapeID]; + + _modelMeshRenderItems << std::make_shared(shared_from_this(), shape.mesh, shape.meshPart, shapeID, transform); + + auto material = getNetworkModel()->getShapeMaterial(shapeID); + _modelMeshMaterialNames.push_back(material ? material->getName() : ""); + _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)shape.mesh, shape.dynamicTransform }); + } +/* uint32_t numMeshes = (uint32_t)meshes.size(); for (uint32_t i = 0; i < numMeshes; i++) { const auto& mesh = meshes.at(i); @@ -1513,7 +1563,7 @@ void Model::createRenderItemSet() { _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); shapeID++; } - } + }*/ } bool Model::isRenderable() const { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 0a102630b6..09fb9b581e 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -473,7 +473,7 @@ protected: QVector> _modelMeshRenderItems; QMap _modelMeshRenderItemsMap; render::ItemIDs _modelMeshRenderItemIDs; - using ShapeInfo = struct { int meshIndex; int deformerIndex; }; + using ShapeInfo = struct { int meshIndex; uint32_t deformerIndex{ hfm::UNDEFINED_KEY }; }; std::vector _modelMeshRenderItemShapes; std::vector _modelMeshMaterialNames; From 108d331d86923ffd1783ad5bd3a2ede8366c16f2 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 14 Oct 2019 17:45:07 -0700 Subject: [PATCH 4/7] more --- libraries/fbx/src/FBXSerializer.cpp | 2 +- libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp | 2 +- libraries/render-utils/src/Model.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 58a9ed2570..f15443aeb5 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1653,7 +1653,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const int oldIndex = fbxCluster.indices[i]; uint32_t newIndex = (uint32_t)extracted.newIndices.value(oldIndex); deformer.indices.push_back(newIndex); - deformer.indices.push_back((float)fbxCluster.weights[i]); + deformer.weights.push_back((float)fbxCluster.weights[i]); } } diff --git a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp index 8c27968de9..7fefe614d4 100644 --- a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp +++ b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp @@ -95,7 +95,7 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics 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.weightsPerVertex ? hfmMesh.clusterIndices.size() / reweightedDeformers.weightsPerVertex : 0); + const size_t numVertClusters = (reweightedDeformers.weightsPerVertex ? reweightedDeformers.indices.size() / reweightedDeformers.weightsPerVertex : 0); const size_t clusterIndicesSize = numVertClusters * clusterIndiceElement.getSize(); const size_t clusterWeightsSize = numVertClusters * clusterWeightElement.getSize(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 27e8725572..56dadf0537 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -257,7 +257,7 @@ void Model::updateRenderItems() { Transform renderTransform = modelTransform; // if (meshState.clusterMatrices.size() <= 1) { - renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); + renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); // } data.updateTransform(renderTransform); From f049ab7887af6c221abd7f6675a25c701dc761d8 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 15 Oct 2019 18:12:09 -0700 Subject: [PATCH 5/7] Understanding that CLuster can be just one for a mesh and we need the bindingMatrix to be applied correctly, differenciating intentionnally the transform for bound evaluation and the one used for render in the case of SKinned mesh because the clusterMatrices contain the extra offset from rig to model --- libraries/fbx/src/FBXSerializer.cpp | 4 ++-- .../render-utils/src/CauterizedModel.cpp | 23 +++++++++++-------- .../render-utils/src/MeshPartPayload.cpp | 5 ++++ libraries/render-utils/src/MeshPartPayload.h | 1 + libraries/render-utils/src/Model.cpp | 3 ++- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index f15443aeb5..8d2d1336a9 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1592,7 +1592,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const } // whether we're skinned depends on how many clusters are attached - if (clusterIDs.size() > 1) { + if (clusterIDs.size() > 0) { hfm::DynamicTransform dynamicTransform; auto& clusters = dynamicTransform.clusters; std::vector deformers; @@ -1670,7 +1670,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const shape.dynamicTransform = dynamicTransformID; } } else { - // this is a single-joint mesh + // this is a no cluster mesh HFMJoint& joint = hfmModel.joints[rootJointIndex]; // Apply geometric offset, if present, by transforming the vertices directly diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 3e7c694768..7d94cd61a5 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -319,7 +319,8 @@ void CauterizedModel::updateRenderItems() { const auto& meshState = self->getMeshState(deformerIndex); const auto& cauterizedMeshState = self->getCauterizeMeshState(deformerIndex); - transaction.updateItem(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, + transaction.updateItem(itemID, + [modelTransform, shapeState, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) { CauterizedMeshPartPayload& data = static_cast(mmppData); if (useDualQuaternionSkinning) { @@ -331,26 +332,30 @@ void CauterizedModel::updateRenderItems() { } Transform renderTransform = modelTransform; - // if (meshState.clusterMatrices.size() <= 2) { - renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); + // if (meshState.clusterMatrices.size() <= 2) { + // renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); // } data.updateTransform(renderTransform); data.updateTransformForCauterizedMesh(renderTransform); + data.updateTransformAndBound(modelTransform.worldTransform(shapeState._rootFromJointTransform)); data.setEnableCauterization(enableCauterization); data.updateKey(renderItemKeyGlobalFlags); data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); }); } else { - transaction.updateItem(itemID, [modelTransform, shapeState, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) { + transaction.updateItem(itemID, + [modelTransform, shapeState, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, enableCauterization] + (ModelMeshPartPayload& mmppData) { + CauterizedMeshPartPayload& data = static_cast(mmppData); Transform renderTransform = modelTransform; - // if (meshState.clusterMatrices.size() <= 1) { - renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); - // } - data.updateTransform(renderTransform); - // data.setEnableCauterization(enableCauterization); + renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); + data.updateTransform(renderTransform); + data.updateTransformForCauterizedMesh(renderTransform); + + data.setEnableCauterization(enableCauterization); data.updateKey(renderItemKeyGlobalFlags); data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, false); }); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index a242c94299..5dc39d8674 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -70,6 +70,11 @@ void MeshPartPayload::updateTransform(const Transform& transform) { _worldBound.transform(_worldFromLocalTransform); } +void MeshPartPayload::updateTransformAndBound(const Transform& transform) { + _worldBound = _localBound; + _worldBound.transform(transform); +} + void MeshPartPayload::addMaterial(graphics::MaterialLayer material) { _drawMaterials.push(material); } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 50e06c024c..5d351e90d4 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -39,6 +39,7 @@ public: virtual void notifyLocationChanged() {} void updateTransform(const Transform& transform); + void updateTransformAndBound(const Transform& transform ); // Render Item interface virtual render::ItemKey getKey() const; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 56dadf0537..1e258a8dd1 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -257,9 +257,10 @@ void Model::updateRenderItems() { Transform renderTransform = modelTransform; // if (meshState.clusterMatrices.size() <= 1) { - renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); + // renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); // } data.updateTransform(renderTransform); + data.updateTransformAndBound(modelTransform.worldTransform(shapeState._rootFromJointTransform)); data.setCauterized(cauterized); data.updateKey(renderItemKeyGlobalFlags); From eecaeb11551cb5f7661e829cd675aebd96004965 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 16 Oct 2019 04:02:05 -0700 Subject: [PATCH 6/7] FOund the issue why the skinning was incorrect, removed unecessary data structures in the newly added objects and renamed Deformer to SkinCluster and DYnamicTransform to SkinDeformer --- libraries/animation/src/AnimSkeleton.cpp | 4 +- libraries/fbx/src/FBXSerializer.cpp | 49 +++++++++-------- libraries/hfm/src/hfm/HFM.h | 27 +++++----- .../model-baker/src/model-baker/Baker.cpp | 14 ++--- .../src/model-baker/BuildGraphicsMeshTask.cpp | 22 ++++---- .../src/model-baker/BuildGraphicsMeshTask.h | 2 +- .../model-baker/CollectShapeVerticesTask.cpp | 20 +++---- .../model-baker/CollectShapeVerticesTask.h | 2 +- .../src/model-baker/ReweightDeformersTask.cpp | 52 +++++++++---------- .../src/model-baker/ReweightDeformersTask.h | 2 +- .../render-utils/src/CauterizedModel.cpp | 8 +-- libraries/render-utils/src/Model.cpp | 12 ++--- 12 files changed, 110 insertions(+), 104 deletions(-) diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index a68f5c869f..bae1fb5b69 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -30,8 +30,8 @@ AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) { // we make a copy of the inverseBindMatrices in order to prevent mutating the model bind pose // when we are dealing with a joint offset in the model - for (int i = 0; i < (int)hfmModel.dynamicTransforms.size(); i++) { - const auto& defor = hfmModel.dynamicTransforms[i]; + for (int i = 0; i < (int)hfmModel.skinDeformers.size(); i++) { + const auto& defor = hfmModel.skinDeformers[i]; std::vector dummyClustersList; for (int j = 0; j < defor.clusters.size(); j++) { diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp index 8d2d1336a9..ac01d6f31a 100644 --- a/libraries/fbx/src/FBXSerializer.cpp +++ b/libraries/fbx/src/FBXSerializer.cpp @@ -1593,9 +1593,9 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const // whether we're skinned depends on how many clusters are attached if (clusterIDs.size() > 0) { - hfm::DynamicTransform dynamicTransform; - auto& clusters = dynamicTransform.clusters; - std::vector deformers; + hfm::SkinDeformer skinDeformer; + auto& clusters = skinDeformer.clusters; + std::vector skinClusters; for (const auto& clusterID : clusterIDs) { HFMCluster hfmCluster; const Cluster& fbxCluster = fbxClusters[clusterID]; @@ -1639,35 +1639,40 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const clusters.push_back(cluster); // Skinned mesh instances have a dynamic transform - dynamicTransform.deformers.reserve(clusterIDs.size()); - clusters.reserve(clusterIDs.size()); + skinDeformer.skinClusterIndices.reserve(clusterIDs.size()); for (const auto& clusterID : clusterIDs) { const Cluster& fbxCluster = fbxClusters[clusterID]; - dynamicTransform.deformers.emplace_back(); - deformers.emplace_back(); - hfm::Deformer& deformer = deformers.back(); + skinDeformer.skinClusterIndices.emplace_back(); + skinClusters.emplace_back(); + hfm::SkinCluster& skinCluster = skinClusters.back(); size_t indexWeightPairs = (size_t)std::min(fbxCluster.indices.size(), fbxCluster.weights.size()); - deformer.indices.reserve(indexWeightPairs); - deformer.weights.reserve(indexWeightPairs); - for (int i = 0; i < (int)indexWeightPairs; i++) { - int oldIndex = fbxCluster.indices[i]; - uint32_t newIndex = (uint32_t)extracted.newIndices.value(oldIndex); - deformer.indices.push_back(newIndex); - deformer.weights.push_back((float)fbxCluster.weights[i]); + skinCluster.indices.reserve(indexWeightPairs); + skinCluster.weights.reserve(indexWeightPairs); + + for (int j = 0; j < fbxCluster.indices.size(); j++) { + int oldIndex = fbxCluster.indices.at(j); + float weight = fbxCluster.weights.at(j); + for (QMultiHash::const_iterator it = extracted.newIndices.constFind(oldIndex); + it != extracted.newIndices.end() && it.key() == oldIndex; it++) { + int newIndex = it.value(); + + skinCluster.indices.push_back(newIndex); + skinCluster.weights.push_back(weight); + } } } // Store this model's deformers, this dynamic transform's deformer IDs - uint32_t deformerMinID = (uint32_t)hfmModel.deformers.size(); - hfmModel.deformers.insert(hfmModel.deformers.end(), deformers.cbegin(), deformers.cend()); - dynamicTransform.deformers.resize(deformers.size()); - std::iota(dynamicTransform.deformers.begin(), dynamicTransform.deformers.end(), deformerMinID); + uint32_t deformerMinID = (uint32_t)hfmModel.skinClusters.size(); + hfmModel.skinClusters.insert(hfmModel.skinClusters.end(), skinClusters.cbegin(), skinClusters.cend()); + skinDeformer.skinClusterIndices.resize(skinClusters.size()); + std::iota(skinDeformer.skinClusterIndices.begin(), skinDeformer.skinClusterIndices.end(), deformerMinID); // Store the model's dynamic transform, and put its ID in the shapes - hfmModel.dynamicTransforms.push_back(dynamicTransform); - uint32_t dynamicTransformID = (uint32_t)(hfmModel.dynamicTransforms.size() - 1); + hfmModel.skinDeformers.push_back(skinDeformer); + uint32_t skinDeformerID = (uint32_t)(hfmModel.skinDeformers.size() - 1); for (hfm::Shape& shape : partShapes) { - shape.dynamicTransform = dynamicTransformID; + shape.skinDeformer = skinDeformerID; } } else { // this is a no cluster mesh diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index ba7e90bd92..15ed876d94 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -242,17 +242,20 @@ public: QVector colors; QVector texCoords; QVector texCoords1; - QVector clusterIndices; // DEPRECATED (see hfm::Shape::dynamicTransform, hfm::DynamicTransform::deformers, hfm::Deformer) - QVector clusterWeights; // DEPRECATED (see hfm::Shape::dynamicTransform, hfm::DynamicTransform::deformers, hfm::Deformer) - QVector originalIndices; QVector clusters; // DEPRECATED (see hfm::Shape::dynamicTransform, hfm::DynamicTransform::clusters) - Extents meshExtents; // DEPRECATED (see hfm::Shape::transformedExtents) glm::mat4 modelTransform; // DEPRECATED (see hfm::Joint::globalTransform, hfm::Shape::transform, hfm::Model::joints) + // Skinning cluster attributes + QVector clusterIndices; + QVector clusterWeights; + + // Blendshape attributes QVector blendshapes; + + QVector originalIndices; // Original indices of the vertices unsigned int meshIndex; // the order the meshes appeared in the object file graphics::MeshPointer _mesh; @@ -294,18 +297,16 @@ public: }; // Formerly contained in hfm::Mesh -class Deformer { +class SkinCluster { public: std::vector indices; std::vector weights; }; -class DynamicTransform { +class SkinDeformer { public: - std::vector deformers; - std::vector clusters; // affect the deformer of the same index - std::vector blendshapes; - // There are also the meshExtents and modelTransform, which for now are left in hfm::Mesh + std::vector skinClusterIndices; + std::vector clusters; }; // The lightweight model part description. @@ -317,7 +318,7 @@ public: uint32_t joint { UNDEFINED_KEY }; // The hfm::Joint associated with this shape, containing transform information // TODO: Have all serializers calculate hfm::Shape::transformedExtents in world space where they previously calculated hfm::Mesh::meshExtents. Change all code that uses hfm::Mesh::meshExtents to use this instead. Extents transformedExtents; // The precise extents of the meshPart vertices in world space, after transform information is applied, while not taking into account rigging/skinning - uint32_t dynamicTransform { UNDEFINED_KEY }; + uint32_t skinDeformer { UNDEFINED_KEY }; }; /// The runtime model format. @@ -334,9 +335,9 @@ public: std::vector meshes; std::vector materials; - std::vector deformers; - std::vector dynamicTransforms; + std::vector skinDeformers; + std::vector skinClusters; std::vector joints; QHash jointIndices; ///< 1-based, so as to more easily detect missing indices diff --git a/libraries/model-baker/src/model-baker/Baker.cpp b/libraries/model-baker/src/model-baker/Baker.cpp index ccb5e1816f..0b23c39aeb 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -29,7 +29,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 = VaryingSet8, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, std::vector, std::vector, std::vector, std::vector>; using JobModel = Job::ModelIO; void run(const BakeContextPointer& context, const Input& input, Output& output) { @@ -44,8 +44,8 @@ namespace baker { } output.edit4() = hfmModelIn->joints; output.edit5() = hfmModelIn->shapes; - output.edit6() = hfmModelIn->dynamicTransforms; - output.edit7() = hfmModelIn->deformers; + output.edit6() = hfmModelIn->skinDeformers; + output.edit7() = hfmModelIn->skinClusters; } }; @@ -143,7 +143,7 @@ namespace baker { const auto blendshapesPerMeshIn = modelPartsIn.getN(3); const auto jointsIn = modelPartsIn.getN(4); const auto shapesIn = modelPartsIn.getN(5); - const auto dynamicTransformsIn = modelPartsIn.getN(6); + const auto skinDeformersIn = modelPartsIn.getN(6); const auto deformersIn = modelPartsIn.getN(7); // Calculate normals and tangents for meshes and blendshapes if they do not exist @@ -158,14 +158,14 @@ namespace baker { // 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 reweightDeformersInputs = ReweightDeformersTask::Input(meshesIn, shapesIn, skinDeformersIn, deformersIn).asVarying(); const auto reweightedDeformers = model.addJob("ReweightDeformers", reweightDeformersInputs); // Shape vertices are included/rejected based on skinning weight, and thus must use the reweighted deformers. - const auto collectShapeVerticesInputs = CollectShapeVerticesTask::Input(meshesIn, shapesIn, jointsIn, dynamicTransformsIn, reweightedDeformers).asVarying(); + const auto collectShapeVerticesInputs = CollectShapeVerticesTask::Input(meshesIn, shapesIn, jointsIn, skinDeformersIn, reweightedDeformers).asVarying(); const auto shapeVerticesPerJoint = model.addJob("CollectShapeVertices", collectShapeVerticesInputs); // Build the graphics::MeshPointer for each hfm::Mesh - const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh, shapesIn, dynamicTransformsIn, reweightedDeformers).asVarying(); + const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh, shapesIn, skinDeformersIn, reweightedDeformers).asVarying(); const auto graphicsMeshes = model.addJob("BuildGraphicsMesh", buildGraphicsMeshInputs); // Prepare joint information diff --git a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp index 7fefe614d4..88546e0975 100644 --- a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp +++ b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.cpp @@ -381,16 +381,16 @@ void BuildGraphicsMeshTask::run(const baker::BakeContextPointer& context, const const auto& normalsPerMesh = input.get3(); const auto& tangentsPerMesh = input.get4(); const auto& shapes = input.get5(); - const auto& dynamicTransforms = input.get6(); + const auto& skinDeformers = input.get6(); 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 - std::vector dynamicTransformPerMesh; - dynamicTransformPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY); + // Currently, there is only (at most) one skinDeformer per mesh + // An undefined shape.skinDeformer has the value hfm::UNDEFINED_KEY + std::vector skinDeformerPerMesh; + skinDeformerPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY); for (const auto& shape : shapes) { - uint32_t dynamicTransformIndex = shape.dynamicTransform; - dynamicTransformPerMesh[shape.mesh] = dynamicTransformIndex; + uint32_t skinDeformerIndex = shape.skinDeformer; + skinDeformerPerMesh[shape.mesh] = skinDeformerIndex; } auto& graphicsMeshes = output; @@ -403,10 +403,10 @@ void BuildGraphicsMeshTask::run(const baker::BakeContextPointer& context, const uint16_t numDeformerControllers = 0; if (reweightedDeformers.weightsPerVertex != 0) { - uint32_t dynamicTransformIndex = dynamicTransformPerMesh[i]; - if (dynamicTransformIndex != hfm::UNDEFINED_KEY) { - const hfm::DynamicTransform& dynamicTransform = dynamicTransforms[dynamicTransformIndex]; - numDeformerControllers = (uint16_t)dynamicTransform.deformers.size(); + uint32_t skinDeformerIndex = skinDeformerPerMesh[i]; + if (skinDeformerIndex != hfm::UNDEFINED_KEY) { + const hfm::SkinDeformer& skinDeformer = skinDeformers[skinDeformerIndex]; + numDeformerControllers = (uint16_t)skinDeformer.skinClusterIndices.size(); } } diff --git a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.h b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.h index 1bb9b9be0c..b60f6f7a43 100644 --- a/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.h +++ b/libraries/model-baker/src/model-baker/BuildGraphicsMeshTask.h @@ -20,7 +20,7 @@ class BuildGraphicsMeshTask { public: - using Input = baker::VaryingSet8, hifi::URL, baker::MeshIndicesToModelNames, baker::NormalsPerMesh, baker::TangentsPerMesh, std::vector, std::vector, std::vector>; + using Input = baker::VaryingSet8, hifi::URL, baker::MeshIndicesToModelNames, baker::NormalsPerMesh, baker::TangentsPerMesh, std::vector, std::vector, std::vector>; using Output = std::vector; using JobModel = baker::Job::ModelIO; diff --git a/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.cpp b/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.cpp index 36c2aa04a6..e597bbf507 100644 --- a/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.cpp +++ b/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.cpp @@ -13,15 +13,15 @@ #include -// Used to track and avoid duplicate shape vertices, as multiple shapes can have the same mesh and dynamicTransform +// Used to track and avoid duplicate shape vertices, as multiple shapes can have the same mesh and skinDeformer class VertexSource { public: uint32_t mesh; - uint32_t dynamicTransform; + uint32_t skinDeformer; bool operator==(const VertexSource& other) const { return mesh == other.mesh && - dynamicTransform == other.dynamicTransform; + skinDeformer == other.skinDeformer; } }; @@ -29,7 +29,7 @@ void CollectShapeVerticesTask::run(const baker::BakeContextPointer& context, con const auto& meshes = input.get0(); const auto& shapes = input.get1(); const auto& joints = input.get2(); - const auto& dynamicTransforms = input.get3(); + const auto& skinDeformers = input.get3(); const auto& reweightedDeformers = input.get4(); auto& shapeVerticesPerJoint = output; @@ -38,18 +38,18 @@ void CollectShapeVerticesTask::run(const baker::BakeContextPointer& context, con 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) { + const uint32_t skinDeformerKey = shape.skinDeformer; + if (skinDeformerKey == hfm::UNDEFINED_KEY) { continue; } VertexSource vertexSource; vertexSource.mesh = shape.mesh; - vertexSource.dynamicTransform = dynamicTransformKey; + vertexSource.skinDeformer = skinDeformerKey; - const auto& dynamicTransform = dynamicTransforms[dynamicTransformKey]; - for (size_t j = 0; j < dynamicTransform.clusters.size(); ++j) { - const auto& cluster = dynamicTransform.clusters[j]; + const auto& skinDeformer = skinDeformers[skinDeformerKey]; + for (size_t j = 0; j < skinDeformer.clusters.size(); ++j) { + const auto& cluster = skinDeformer.clusters[j]; const uint32_t jointIndex = cluster.jointIndex; auto& vertexSources = vertexSourcesPerJoint[jointIndex]; diff --git a/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.h b/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.h index 3111dcadc1..f14c440f2f 100644 --- a/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.h +++ b/libraries/model-baker/src/model-baker/CollectShapeVerticesTask.h @@ -19,7 +19,7 @@ class CollectShapeVerticesTask { public: - using Input = baker::VaryingSet5, std::vector, std::vector, std::vector, std::vector>; + using Input = baker::VaryingSet5, std::vector, std::vector, std::vector, std::vector>; using Output = std::vector; using JobModel = baker::Job::ModelIO; diff --git a/libraries/model-baker/src/model-baker/ReweightDeformersTask.cpp b/libraries/model-baker/src/model-baker/ReweightDeformersTask.cpp index 097833e110..f210a5dd6f 100644 --- a/libraries/model-baker/src/model-baker/ReweightDeformersTask.cpp +++ b/libraries/model-baker/src/model-baker/ReweightDeformersTask.cpp @@ -11,30 +11,30 @@ #include "ReweightDeformersTask.h" -baker::ReweightedDeformers getReweightedDeformers(size_t numMeshVertices, const std::vector deformers, const uint16_t weightsPerVertex) { +baker::ReweightedDeformers getReweightedDeformers(size_t numMeshVertices, const std::vector skinClusters, const uint16_t weightsPerVertex) { baker::ReweightedDeformers reweightedDeformers; - if (deformers.size() == 0) { + if (skinClusters.size() == 0) { return reweightedDeformers; } size_t numClusterIndices = numMeshVertices * weightsPerVertex; 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.indices.resize(numClusterIndices, (uint16_t)(skinClusters.size() - 1)); reweightedDeformers.weights.resize(numClusterIndices, 0); std::vector weightAccumulators; weightAccumulators.resize(numClusterIndices, 0.0f); - for (uint16_t i = 0; i < (uint16_t)deformers.size(); ++i) { - const hfm::Deformer& deformer = *deformers[i]; + for (uint16_t i = 0; i < (uint16_t)skinClusters.size(); ++i) { + const hfm::SkinCluster& skinCluster = *skinClusters[i]; - if (deformer.indices.size() != deformer.weights.size()) { + if (skinCluster.indices.size() != skinCluster.weights.size()) { reweightedDeformers.trimmedToMatch = true; } - size_t numIndicesOrWeights = std::min(deformer.indices.size(), deformer.weights.size()); + size_t numIndicesOrWeights = std::min(skinCluster.indices.size(), skinCluster.weights.size()); for (size_t j = 0; j < numIndicesOrWeights; ++j) { - uint32_t index = deformer.indices[j]; - float weight = deformer.weights[j]; + uint32_t index = skinCluster.indices[j]; + float weight = skinCluster.weights[j]; // look for an unused slot in the weights vector uint32_t weightIndex = index * weightsPerVertex; @@ -90,34 +90,34 @@ void ReweightDeformersTask::run(const baker::BakeContextPointer& context, const const auto& meshes = input.get0(); const auto& shapes = input.get1(); - const auto& dynamicTransforms = input.get2(); - const auto& deformers = input.get3(); + const auto& skinDeformers = input.get2(); + const auto& skinClusters = 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 dynamicTransformPerMesh; - dynamicTransformPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY); + // Currently, there is only (at most) one skinDeformer per mesh + // An undefined shape.skinDeformer has the value hfm::UNDEFINED_KEY + std::vector skinDeformerPerMesh; + skinDeformerPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY); for (const auto& shape : shapes) { - uint32_t dynamicTransformIndex = shape.dynamicTransform; - dynamicTransformPerMesh[shape.mesh] = dynamicTransformIndex; + uint32_t skinDeformerIndex = shape.skinDeformer; + skinDeformerPerMesh[shape.mesh] = skinDeformerIndex; } reweightedDeformers.reserve(meshes.size()); for (size_t i = 0; i < meshes.size(); ++i) { const auto& mesh = meshes[i]; - uint32_t dynamicTransformIndex = dynamicTransformPerMesh[i]; + uint32_t skinDeformerIndex = skinDeformerPerMesh[i]; - const hfm::DynamicTransform* dynamicTransform = nullptr; - std::vector meshDeformers; - if (dynamicTransformIndex != hfm::UNDEFINED_KEY) { - dynamicTransform = &dynamicTransforms[dynamicTransformIndex]; - for (const auto& deformerIndex : dynamicTransform->deformers) { - const auto& deformer = deformers[deformerIndex]; - meshDeformers.push_back(&deformer); + const hfm::SkinDeformer* skinDeformer = nullptr; + std::vector meshSkinClusters; + if (skinDeformerIndex != hfm::UNDEFINED_KEY) { + skinDeformer = &skinDeformers[skinDeformerIndex]; + for (const auto& skinClusterIndex : skinDeformer->skinClusterIndices) { + const auto& skinCluster = skinClusters[skinClusterIndex]; + meshSkinClusters.push_back(&skinCluster); } } - reweightedDeformers.push_back(getReweightedDeformers((size_t)mesh.vertices.size(), meshDeformers, NUM_WEIGHTS_PER_VERTEX)); + reweightedDeformers.push_back(getReweightedDeformers((size_t)mesh.vertices.size(), meshSkinClusters, NUM_WEIGHTS_PER_VERTEX)); } } diff --git a/libraries/model-baker/src/model-baker/ReweightDeformersTask.h b/libraries/model-baker/src/model-baker/ReweightDeformersTask.h index 98befa8000..c40ad4c1b4 100644 --- a/libraries/model-baker/src/model-baker/ReweightDeformersTask.h +++ b/libraries/model-baker/src/model-baker/ReweightDeformersTask.h @@ -19,7 +19,7 @@ class ReweightDeformersTask { public: - using Input = baker::VaryingSet4, std::vector, std::vector, std::vector>; + using Input = baker::VaryingSet4, std::vector, std::vector, std::vector>; using Output = std::vector; using JobModel = baker::Job::ModelIO; diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 7d94cd61a5..cbd608e092 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -33,7 +33,7 @@ bool CauterizedModel::updateGeometry() { if (_isCauterized && needsFullUpdate) { assert(_cauterizeMeshStates.empty()); /* const HFMModel& hfmModel = getHFMModel(); - const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; + const auto& hfmDynamicTransforms = hfmModel.skinDeformers; for (int i = 0; i < hfmDynamicTransforms.size(); i++) { const auto& dynT = hfmDynamicTransforms[i]; MeshState state; @@ -47,7 +47,7 @@ bool CauterizedModel::updateGeometry() { }*/ const HFMModel& hfmModel = getHFMModel(); - const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; + const auto& hfmDynamicTransforms = hfmModel.skinDeformers; int i = 0; /* for (const auto& mesh: hfmModel.meshes) { MeshState state; @@ -113,7 +113,7 @@ void CauterizedModel::createRenderItemSet() { auto material = getNetworkModel()->getShapeMaterial(shapeID); _modelMeshMaterialNames.push_back(material ? material->getName() : ""); - _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)shape.mesh, shape.dynamicTransform }); + _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)shape.mesh, shape.skinDeformer }); } /* int shapeID = 0; @@ -153,7 +153,7 @@ void CauterizedModel::updateClusterMatrices() { const HFMModel& hfmModel = getHFMModel(); - const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; + const auto& hfmDynamicTransforms = hfmModel.skinDeformers; for (int i = 0; i < (int)_meshStates.size(); i++) { MeshState& state = _meshStates[i]; const auto& deformer = hfmDynamicTransforms[i]; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 1e258a8dd1..d3766fa65c 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -336,7 +336,7 @@ bool Model::updateGeometry() { updateShapeStatesFromRig(); const HFMModel& hfmModel = getHFMModel(); - const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; + const auto& hfmSkinDeformers = hfmModel.skinDeformers; int i = 0; /* for (const auto& mesh: hfmModel.meshes) { MeshState state; @@ -346,8 +346,8 @@ bool Model::updateGeometry() { i++; } */ - for (int i = 0; i < hfmDynamicTransforms.size(); i++) { - const auto& dynT = hfmDynamicTransforms[i]; + for (int i = 0; i < hfmSkinDeformers.size(); i++) { + const auto& dynT = hfmSkinDeformers[i]; MeshState state; state.clusterDualQuaternions.resize(dynT.clusters.size()); state.clusterMatrices.resize(dynT.clusters.size()); @@ -1427,10 +1427,10 @@ void Model::updateClusterMatrices() { _needsUpdateClusterMatrices = false; const HFMModel& hfmModel = getHFMModel(); - const auto& hfmDynamicTransforms = hfmModel.dynamicTransforms; + const auto& hfmSkinDeformers = hfmModel.skinDeformers; for (int i = 0; i < (int) _meshStates.size(); i++) { MeshState& state = _meshStates[i]; - const auto& deformer = hfmDynamicTransforms[i]; + const auto& deformer = hfmSkinDeformers[i]; int meshIndex = i; int clusterIndex = 0; @@ -1545,7 +1545,7 @@ void Model::createRenderItemSet() { auto material = getNetworkModel()->getShapeMaterial(shapeID); _modelMeshMaterialNames.push_back(material ? material->getName() : ""); - _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)shape.mesh, shape.dynamicTransform }); + _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)shape.mesh, shape.skinDeformer }); } /* uint32_t numMeshes = (uint32_t)meshes.size(); From 0a9c38964153e005ee99fcadbaefeb0338365798 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 16 Oct 2019 08:06:35 -0700 Subject: [PATCH 7/7] last issue --- libraries/render-utils/src/MeshPartPayload.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 5dc39d8674..3f25d2ef80 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -223,7 +223,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in renderTransform = transform.worldTransform(shapeState._rootFromJointTransform); updateTransform(renderTransform); - _deformerIndex = shape.dynamicTransform; + _deformerIndex = shape.skinDeformer; initCache(model);