diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index bae1fb5b69..3afa7b0e3e 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -34,8 +34,7 @@ AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) { const auto& defor = hfmModel.skinDeformers[i]; std::vector dummyClustersList; - for (int j = 0; j < defor.clusters.size(); j++) { - std::vector bindMatrices; + for (int j = 0; j < (uint32_t) defor.clusters.size(); j++) { // cast into a non-const reference, so we can mutate the FBXCluster HFMCluster& cluster = const_cast(defor.clusters.at(j)); @@ -55,35 +54,6 @@ AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) { } _clusterBindMatrixOriginalValues.push_back(dummyClustersList); } - - -/* - for (int i = 0; i < (int)hfmModel.meshes.size(); i++) { - const HFMMesh& mesh = hfmModel.meshes.at(i); - std::vector dummyClustersList; - - for (int j = 0; j < mesh.clusters.size(); j++) { - std::vector bindMatrices; - // cast into a non-const reference, so we can mutate the FBXCluster - HFMCluster& cluster = const_cast(mesh.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); - } -*/ } AnimSkeleton::AnimSkeleton(const std::vector& joints, const QMap jointOffsets) { diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index 526959df9a..1477efb223 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -68,9 +68,7 @@ public: void dump(const AnimPoseVec& poses) const; 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]; } + const HFMCluster getClusterBindMatricesOriginalValues(const int skinDeformerIndex, const int clusterIndex) const { return _clusterBindMatrixOriginalValues[skinDeformerIndex][clusterIndex]; } protected: void buildSkeletonFromJoints(const std::vector& joints, const QMap jointOffsets); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e75b28f9ed..d7da3879f6 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -479,8 +479,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT)); for (uint32_t i = 0; i < numHFMMeshes; i++) { const HFMMesh& mesh = hfmModel.meshes.at(i); - if (mesh.clusters.size() > 0) { - const HFMCluster& cluster = mesh.clusters.at(0); + if (i < hfmModel.skinDeformers.size() && hfmModel.skinDeformers[i].clusters.size() > 0) { + const HFMCluster& cluster = hfmModel.skinDeformers[i].clusters.at(0); auto jointMatrix = model->getRig().getJointTransform(cluster.jointIndex); // we backtranslate by the registration offset so we can apply that offset to the shapeInfo later localTransforms.push_back(invRegistraionOffset * jointMatrix * cluster.inverseBindMatrix); diff --git a/libraries/fbx/src/OBJSerializer.cpp b/libraries/fbx/src/OBJSerializer.cpp index 47c88168b4..57fcf79aac 100644 --- a/libraries/fbx/src/OBJSerializer.cpp +++ b/libraries/fbx/src/OBJSerializer.cpp @@ -1009,7 +1009,7 @@ HFMModel::Pointer OBJSerializer::read(const hifi::ByteArray& data, const hifi::V } // GO over the shapes once more to assign hte material index correctly - for (int i = 0; i < hfmModel.shapes.size(); ++i) { + for (int i = 0; i < (uint32_t) hfmModel.shapes.size(); ++i) { auto foundMaterialIndex = materialNameToIndex.find(materialNamePerShape[i]); if (foundMaterialIndex != materialNameToIndex.end()) { hfmModel.shapes[i].material = foundMaterialIndex.value(); diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index b2d8147ac6..6ee458da86 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -386,6 +386,7 @@ typedef hfm::Texture HFMTexture; typedef hfm::MeshPart HFMMeshPart; typedef hfm::Material HFMMaterial; typedef hfm::Mesh HFMMesh; +typedef hfm::SkinDeformer HFMSkinDeformer; typedef hfm::AnimationFrame HFMAnimationFrame; typedef hfm::Light HFMLight; typedef hfm::Model HFMModel; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 8b7db5957b..bb911c6914 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -491,8 +491,8 @@ bool NetworkModel::areTexturesLoaded() const { } const std::shared_ptr NetworkModel::getShapeMaterial(int shapeID) const { - auto materialID = getHFMModel().shapes[shapeID].material; - if ((materialID >= 0) && (materialID < (int)_materials.size())) { + uint32_t materialID = getHFMModel().shapes[shapeID].material; + if (materialID < (uint32_t)_materials.size()) { return _materials[materialID]; } return nullptr; diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 717d3cada7..ca26b9739c 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -33,14 +33,10 @@ bool CauterizedModel::updateGeometry() { if (_isCauterized && needsFullUpdate) { assert(_cauterizeMeshStates.empty()); - const HFMModel& hfmModel = getHFMModel(); - const auto& hfmDynamicTransforms = hfmModel.skinDeformers; - 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); + // initialize the cauterizedDeforemrStates as a copy of the standard deformerStates + _cauterizeMeshStates.resize(_meshStates.size()); + for (int i = 0; i < (int) _meshStates.size(); ++i) { + _cauterizeMeshStates[i] = _meshStates[i]; } } return needsFullUpdate; @@ -49,15 +45,12 @@ bool CauterizedModel::updateGeometry() { void CauterizedModel::createRenderItemSet() { if (_isCauterized) { assert(isLoaded()); - const auto& meshes = _renderGeometry->getMeshes(); - // We should not have any existing renderItems if we enter this section of code Q_ASSERT(_modelMeshRenderItems.isEmpty()); _modelMeshRenderItems.clear(); _modelMeshMaterialNames.clear(); - _modelMeshRenderItemShapes.clear(); Transform transform; transform.setTranslation(_translation); @@ -72,14 +65,13 @@ void CauterizedModel::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++) { + for (shapeID; shapeID < (int) 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.skinDeformer }); } } else { Model::createRenderItemSet(); @@ -97,26 +89,20 @@ void CauterizedModel::updateClusterMatrices() { _needsUpdateClusterMatrices = false; - - const HFMModel& hfmModel = getHFMModel(); - const auto& hfmSkinDeformers = hfmModel.skinDeformers; - for (int meshIndex = 0; meshIndex < (int)_meshStates.size(); meshIndex++) { - MeshState& state = _meshStates[meshIndex]; - const auto& deformer = hfmSkinDeformers[meshIndex]; - - for (int clusterIndex = 0; clusterIndex < deformer.clusters.size(); clusterIndex++) { - const auto& cluster = deformer.clusters[clusterIndex]; - - const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex); + for (int skinDeformerIndex = 0; skinDeformerIndex < (int)_meshStates.size(); skinDeformerIndex++) { + MeshState& state = _meshStates[skinDeformerIndex]; + auto numClusters = state.getNumClusters(); + for (uint32_t clusterIndex = 0; clusterIndex < numClusters; clusterIndex++) { + const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(skinDeformerIndex, clusterIndex); if (_useDualQuaternionSkinning) { - auto jointPose = _rig.getJointPose(cluster.jointIndex); + auto jointPose = _rig.getJointPose(cbmov.jointIndex); Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans()); Transform clusterTransform; Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform); state.clusterDualQuaternions[clusterIndex] = Model::TransformDualQuaternion(clusterTransform); } else { - auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); + auto jointMatrix = _rig.getJointTransform(cbmov.jointIndex); glm_mat4u_mul(jointMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[clusterIndex]); } } @@ -127,6 +113,7 @@ void CauterizedModel::updateClusterMatrices() { AnimPose cauterizePose = _rig.getJointPose(_rig.indexOfJoint("Neck")); cauterizePose.scale() = glm::vec3(0.0001f, 0.0001f, 0.0001f); + Transform cauterizedDQTransform(cauterizePose.rot(), cauterizePose.scale(), cauterizePose.trans()); static const glm::mat4 zeroScale( glm::vec4(0.0001f, 0.0f, 0.0f, 0.0f), @@ -135,30 +122,27 @@ void CauterizedModel::updateClusterMatrices() { glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); auto cauterizeMatrix = _rig.getJointTransform(_rig.indexOfJoint("Neck")) * zeroScale; - for (int meshIndex = 0; meshIndex < _cauterizeMeshStates.size(); meshIndex++) { - Model::MeshState& state = _cauterizeMeshStates[meshIndex]; - const auto& deformer = hfmSkinDeformers[meshIndex]; + for (int skinDeformerIndex = 0; skinDeformerIndex < (int) _cauterizeMeshStates.size(); skinDeformerIndex++) { + Model::MeshState& nonCauterizedState = _meshStates[skinDeformerIndex]; + Model::MeshState& state = _cauterizeMeshStates[skinDeformerIndex]; - for (int clusterIndex = 0; clusterIndex < deformer.clusters.size(); clusterIndex++) { - const auto& cluster = deformer.clusters[clusterIndex]; - - const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex); - - if (_useDualQuaternionSkinning) { - if (_cauterizeBoneSet.find(cluster.jointIndex) == _cauterizeBoneSet.end()) { - // not cauterized so just copy the value from the non-cauterized version. - state.clusterDualQuaternions[clusterIndex] = _meshStates[meshIndex].clusterDualQuaternions[clusterIndex]; - } else { - Transform jointTransform(cauterizePose.rot(), cauterizePose.scale(), cauterizePose.trans()); + // Just reset cauterized state with normal state memcpy style + if (_useDualQuaternionSkinning) { + state.clusterDualQuaternions = nonCauterizedState.clusterDualQuaternions; + } else { + state.clusterMatrices = nonCauterizedState.clusterMatrices; + } + + // ANd only cauterize affected joints + auto numClusters = state.getNumClusters(); + for (uint32_t clusterIndex = 0; clusterIndex < numClusters; clusterIndex++) { + const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(skinDeformerIndex, clusterIndex); + if (_cauterizeBoneSet.find(cbmov.jointIndex) != _cauterizeBoneSet.end()) { + if (_useDualQuaternionSkinning) { Transform clusterTransform; - Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform); + Transform::mult(clusterTransform, cauterizedDQTransform, cbmov.inverseBindTransform); state.clusterDualQuaternions[clusterIndex] = Model::TransformDualQuaternion(clusterTransform); state.clusterDualQuaternions[clusterIndex].setCauterizationParameters(1.0f, cauterizePose.trans()); - } - } else { - if (_cauterizeBoneSet.find(cluster.jointIndex) == _cauterizeBoneSet.end()) { - // not cauterized so just copy the value from the non-cauterized version. - state.clusterMatrices[clusterIndex] = _meshStates[meshIndex].clusterMatrices[clusterIndex]; } else { glm_mat4u_mul(cauterizeMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[clusterIndex]); } @@ -169,7 +153,7 @@ void CauterizedModel::updateClusterMatrices() { // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); - if (modelBlender->shouldComputeBlendshapes() && hfmModel.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (modelBlender->shouldComputeBlendshapes() && getHFMModel().hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } @@ -209,22 +193,19 @@ void CauterizedModel::updateRenderItems() { render::Transaction transaction; for (int i = 0; i < (int)self->_modelMeshRenderItemIDs.size(); i++) { - auto itemID = self->_modelMeshRenderItemIDs[i]; - auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; const auto& shapeState = self->getShapeState(i); - auto deformerIndex = self->_modelMeshRenderItemShapes[i].deformerIndex; - bool isDeformed = (deformerIndex != hfm::UNDEFINED_KEY); + auto skinDeformerIndex = shapeState._skinDeformerIndex; - bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); + bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(shapeState._meshIndex); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); - if (isDeformed) { + if (skinDeformerIndex != hfm::UNDEFINED_KEY) { - const auto& meshState = self->getMeshState(deformerIndex); - const auto& cauterizedMeshState = self->getCauterizeMeshState(deformerIndex); + const auto& meshState = self->getMeshState(skinDeformerIndex); + const auto& cauterizedMeshState = self->getCauterizeMeshState(skinDeformerIndex); transaction.updateItem(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, diff --git a/libraries/render-utils/src/CauterizedModel.h b/libraries/render-utils/src/CauterizedModel.h index 36a96fb006..7d241d7ac6 100644 --- a/libraries/render-utils/src/CauterizedModel.h +++ b/libraries/render-utils/src/CauterizedModel.h @@ -40,7 +40,7 @@ public: protected: std::unordered_set _cauterizeBoneSet; - QVector _cauterizeMeshStates; + std::vector _cauterizeMeshStates; bool _isCauterized { false }; bool _enableCauterization { false }; }; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 3f25d2ef80..6e3fe6ebec 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -210,11 +210,8 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in assert(shape.mesh == meshIndex); assert(shape.meshPart == partIndex); - bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning(); - auto& modelMesh = model->getNetworkModel()->getMeshes().at(_meshIndex); _meshNumVertices = (int)modelMesh->getNumVertices(); - // const Model::MeshState& state = model->getMeshState(_meshIndex); updateMeshPart(modelMesh, partIndex); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 5d351e90d4..b207bd9403 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -118,7 +118,7 @@ public: int _meshIndex; int _shapeID; - int _deformerIndex; + uint32_t _deformerIndex; bool _isSkinned{ false }; bool _isBlendShaped { false }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 6df3c76a67..20568635f0 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -151,7 +151,7 @@ void Model::setOffset(const glm::vec3& offset) { } void Model::calculateTextureInfo() { - if (!_hasCalculatedTextureInfo && isLoaded() && getNetworkModel()->areTexturesLoaded() && !_modelMeshRenderItemsMap.isEmpty()) { + if (!_hasCalculatedTextureInfo && isLoaded() && getNetworkModel()->areTexturesLoaded() && !_modelMeshRenderItemIDs.empty()) { size_t textureSize = 0; int textureCount = 0; bool allTexturesLoaded = true; @@ -228,25 +228,18 @@ void Model::updateRenderItems() { render::Transaction transaction; for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) { - auto itemID = self->_modelMeshRenderItemIDs[i]; - auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; const auto& shapeState = self->getShapeState(i); - auto deformerIndex = self->_modelMeshRenderItemShapes[i].deformerIndex; - bool isDeformed = (deformerIndex != hfm::UNDEFINED_KEY); + auto skinDeformerIndex = shapeState._skinDeformerIndex; - bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); + bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(shapeState._meshIndex); - - if (isDeformed) { - - const auto& meshState = self->getMeshState(deformerIndex); - // MeshState meshState; + if (skinDeformerIndex != hfm::UNDEFINED_KEY) { + const auto& meshState = self->getMeshState(skinDeformerIndex); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); - transaction.updateItem(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { @@ -303,15 +296,11 @@ void Model::reset() { } void Model::updateShapeStatesFromRig() { - const HFMModel& hfmModel = getHFMModel(); - // TODO: should all Models have a valid _rig? { // Shapes state: - const auto& shapes = hfmModel.shapes; - _shapeStates.resize(shapes.size()); - for (int s = 0; s < shapes.size(); ++s) { - uint32_t jointId = shapes[s].joint; + for (auto& shape : _shapeStates) { + uint32_t jointId = shape._jointIndex; if (jointId < (uint32_t) _rig.getJointStateCount()) { - _shapeStates[s]._rootFromJointTransform = _rig.getJointTransform(jointId); + shape._rootFromJointTransform = _rig.getJointTransform(jointId); } } } @@ -331,11 +320,21 @@ bool Model::updateGeometry() { initJointStates(); assert(_meshStates.empty()); + const HFMModel& hfmModel = getHFMModel(); + + const auto& shapes = hfmModel.shapes; + _shapeStates.resize(shapes.size()); + for (uint32_t s = 0; s < (uint32_t) shapes.size(); ++s) { + auto& shapeState = _shapeStates[s]; + shapeState._jointIndex = shapes[s].joint; + shapeState._meshIndex = shapes[s].mesh; + shapeState._meshPartIndex = shapes[s].meshPart; + shapeState._skinDeformerIndex = shapes[s].skinDeformer; + } updateShapeStatesFromRig(); - const HFMModel& hfmModel = getHFMModel(); const auto& hfmSkinDeformers = hfmModel.skinDeformers; - for (int i = 0; i < hfmSkinDeformers.size(); i++) { + for (uint32_t i = 0; i < (uint32_t) hfmSkinDeformers.size(); i++) { const auto& dynT = hfmSkinDeformers[i]; MeshState state; state.clusterDualQuaternions.resize(dynT.clusters.size()); @@ -740,9 +739,9 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe render::Transaction transaction; for (int i = 0; i < (int) _modelMeshRenderItemIDs.size(); i++) { auto itemID = _modelMeshRenderItemIDs[i]; - auto shape = _modelMeshRenderItemShapes[i]; + auto& shape = _shapeStates[i]; // TODO: check to see if .partIndex matches too - if (shape.meshIndex == meshIndex) { + if (shape._meshIndex == (uint32_t) meshIndex) { transaction.updateItem(itemID, [=](ModelMeshPartPayload& data) { data.updateMeshPart(mesh, partIndex); }); @@ -904,8 +903,8 @@ void Model::updateRenderItemsKey(const render::ScenePointer& scene) { } auto renderItemsKey = _renderItemKeyGlobalFlags; render::Transaction transaction; - foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [renderItemsKey](ModelMeshPartPayload& data) { + for(auto itemID: _modelMeshRenderItemIDs) { + transaction.updateItem(itemID, [renderItemsKey](ModelMeshPartPayload& data) { data.updateKey(renderItemsKey); }); } @@ -975,8 +974,8 @@ void Model::setCauterized(bool cauterized, const render::ScenePointer& scene) { return; } render::Transaction transaction; - foreach (auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [cauterized](ModelMeshPartPayload& data) { + for (auto itemID : _modelMeshRenderItemIDs) { + transaction.updateItem(itemID, [cauterized](ModelMeshPartPayload& data) { data.setCauterized(cauterized); }); } @@ -1003,26 +1002,25 @@ bool Model::addToScene(const render::ScenePointer& scene, bool somethingAdded = false; - if (_modelMeshRenderItemsMap.empty()) { + if (_modelMeshRenderItemIDs.empty()) { bool hasTransparent = false; size_t verticesCount = 0; foreach(auto renderItem, _modelMeshRenderItems) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); - if (_modelMeshRenderItemsMap.empty() && statusGetters.size()) { + if (_modelMeshRenderItemIDs.empty() && statusGetters.size()) { renderPayload->addStatusGetters(statusGetters); } transaction.resetItem(item, renderPayload); hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent(); verticesCount += renderItem.get()->getVerticesCount(); - _modelMeshRenderItemsMap.insert(item, renderPayload); _modelMeshRenderItemIDs.emplace_back(item); } - somethingAdded = !_modelMeshRenderItemsMap.empty(); + somethingAdded = !_modelMeshRenderItemIDs.empty(); _renderInfoVertexCount = verticesCount; - _renderInfoDrawCalls = _modelMeshRenderItemsMap.count(); + _renderInfoDrawCalls = (uint32_t) _modelMeshRenderItemIDs.size(); _renderInfoHasTransparent = hasTransparent; } @@ -1037,14 +1035,12 @@ bool Model::addToScene(const render::ScenePointer& scene, } void Model::removeFromScene(const render::ScenePointer& scene, render::Transaction& transaction) { - foreach (auto item, _modelMeshRenderItemsMap.keys()) { - transaction.removeItem(item); + for (auto itemID: _modelMeshRenderItemIDs) { + transaction.removeItem(itemID); } _modelMeshRenderItemIDs.clear(); - _modelMeshRenderItemsMap.clear(); _modelMeshRenderItems.clear(); _modelMeshMaterialNames.clear(); - _modelMeshRenderItemShapes.clear(); _priorityMap.clear(); _addedToScene = false; @@ -1415,25 +1411,21 @@ void Model::updateClusterMatrices() { updateShapeStatesFromRig(); _needsUpdateClusterMatrices = false; - const HFMModel& hfmModel = getHFMModel(); - const auto& hfmSkinDeformers = hfmModel.skinDeformers; - for (int meshIndex = 0; meshIndex < (int) _meshStates.size(); meshIndex++) { - MeshState& state = _meshStates[meshIndex]; - const auto& deformer = hfmSkinDeformers[meshIndex]; - for (int clusterIndex = 0; clusterIndex < deformer.clusters.size(); clusterIndex++) { - const auto& cluster = deformer.clusters[clusterIndex]; - - const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex); + for (int skinDeformerIndex = 0; skinDeformerIndex < (int)_meshStates.size(); skinDeformerIndex++) { + MeshState& state = _meshStates[skinDeformerIndex]; + auto numClusters = state.getNumClusters(); + for (uint32_t clusterIndex = 0; clusterIndex < numClusters; clusterIndex++) { + const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(skinDeformerIndex, clusterIndex); if (_useDualQuaternionSkinning) { - auto jointPose = _rig.getJointPose(cluster.jointIndex); + auto jointPose = _rig.getJointPose(cbmov.jointIndex); Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans()); Transform clusterTransform; Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform); state.clusterDualQuaternions[clusterIndex] = Model::TransformDualQuaternion(clusterTransform); } else { - auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); + auto jointMatrix = _rig.getJointTransform(cbmov.jointIndex); glm_mat4u_mul(jointMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[clusterIndex]); } } @@ -1441,7 +1433,7 @@ void Model::updateClusterMatrices() { // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); - if (modelBlender->shouldComputeBlendshapes() && hfmModel.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (modelBlender->shouldComputeBlendshapes() && getHFMModel().hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } @@ -1483,14 +1475,12 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const { void Model::createRenderItemSet() { assert(isLoaded()); - const auto& meshes = _renderGeometry->getMeshes(); // We should not have any existing renderItems if we enter this section of code Q_ASSERT(_modelMeshRenderItems.isEmpty()); _modelMeshRenderItems.clear(); _modelMeshMaterialNames.clear(); - _modelMeshRenderItemShapes.clear(); Transform transform; transform.setTranslation(_translation); @@ -1501,21 +1491,19 @@ void Model::createRenderItemSet() { offset.postTranslate(_offset); // 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++) { + for (uint32_t shapeID = 0; 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.skinDeformer }); } } bool Model::isRenderable() const { - return (!_shapeStates.empty() /* && !_meshStates.empty()*/) || (isLoaded() && _renderGeometry->getMeshes().empty()); + return (!_shapeStates.empty()) || (isLoaded() && _renderGeometry->getMeshes().empty()); } std::set Model::getMeshIDsFromMaterialID(QString parentMaterialName) { @@ -1571,11 +1559,11 @@ void Model::applyMaterialMapping() { PrimitiveMode primitiveMode = getPrimitiveMode(); bool useDualQuaternionSkinning = _useDualQuaternionSkinning; auto modelMeshRenderItemIDs = _modelMeshRenderItemIDs; - auto modelMeshRenderItemShapes = _modelMeshRenderItemShapes; + auto shapeStates = _shapeStates; std::unordered_map shouldInvalidatePayloadShapeKeyMap; - for (auto& shape : _modelMeshRenderItemShapes) { - shouldInvalidatePayloadShapeKeyMap[shape.meshIndex] = shouldInvalidatePayloadShapeKey(shape.meshIndex); + for (auto& shape : _shapeStates) { + shouldInvalidatePayloadShapeKeyMap[shape._meshIndex] = shouldInvalidatePayloadShapeKey(shape._meshIndex); } auto& materialMapping = getMaterialMapping(); @@ -1598,7 +1586,7 @@ void Model::applyMaterialMapping() { std::weak_ptr weakSelf = shared_from_this(); auto materialLoaded = [networkMaterialResource, shapeIDs, priorityMapPerResource, renderItemsKey, primitiveMode, useDualQuaternionSkinning, - modelMeshRenderItemIDs, modelMeshRenderItemShapes, shouldInvalidatePayloadShapeKeyMap, weakSelf]() { + modelMeshRenderItemIDs, shapeStates, shouldInvalidatePayloadShapeKeyMap, weakSelf]() { std::shared_ptr self = weakSelf.lock(); if (!self || networkMaterialResource->isFailed() || networkMaterialResource->parsedMaterials.names.size() == 0) { return; @@ -1624,7 +1612,7 @@ void Model::applyMaterialMapping() { for (auto shapeID : shapeIDs) { if (shapeID < modelMeshRenderItemIDs.size()) { auto itemID = modelMeshRenderItemIDs[shapeID]; - auto meshIndex = modelMeshRenderItemShapes[shapeID].meshIndex; + auto meshIndex = shapeStates[shapeID]._meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKeyMap.at(meshIndex); graphics::MaterialLayer material = graphics::MaterialLayer(networkMaterial, priorityMapPerResource.at(shapeID)); { @@ -1662,7 +1650,7 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par for (auto shapeID : shapeIDs) { if (shapeID < _modelMeshRenderItemIDs.size()) { auto itemID = _modelMeshRenderItemIDs[shapeID]; - auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + auto meshIndex = _shapeStates[shapeID]._meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); transaction.updateItem(itemID, [material, renderItemsKey, invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning](ModelMeshPartPayload& data) { @@ -1684,7 +1672,7 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string auto itemID = _modelMeshRenderItemIDs[shapeID]; auto renderItemsKey = _renderItemKeyGlobalFlags; PrimitiveMode primitiveMode = getPrimitiveMode(); - auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + auto meshIndex = _shapeStates[shapeID]._meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = _useDualQuaternionSkinning; transaction.updateItem(itemID, [material, renderItemsKey, diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 09fb9b581e..0c04aca70c 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -297,6 +297,16 @@ public: int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; } bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; } + class ShapeState { + public: + glm::mat4 _rootFromJointTransform; + uint32_t _jointIndex{ hfm::UNDEFINED_KEY }; + uint32_t _meshIndex{ hfm::UNDEFINED_KEY }; + uint32_t _meshPartIndex{ hfm::UNDEFINED_KEY }; + uint32_t _skinDeformerIndex{ hfm::UNDEFINED_KEY }; + }; + const ShapeState& getShapeState(int index) { return _shapeStates.at(index); } + class TransformDualQuaternion { public: TransformDualQuaternion() {} @@ -339,18 +349,13 @@ public: public: std::vector clusterDualQuaternions; std::vector clusterMatrices; - }; + uint32_t getNumClusters() const { return (uint32_t) std::max(clusterMatrices.size(), clusterMatrices.size()); } + }; const MeshState& getMeshState(int index) { return _meshStates.at(index); } - class ShapeState { - public: - glm::mat4 _rootFromJointTransform; - }; - const ShapeState& getShapeState(int index) { return _shapeStates.at(index); } - uint32_t getGeometryCounter() const { return _deleteGeometryCounter; } - const QMap& getRenderItems() const { return _modelMeshRenderItemsMap; } + BlendShapeOperator getModelBlendshapeOperator() const { return _modelBlendshapeOperator; } void renderDebugMeshBoxes(gpu::Batch& batch, bool forward); @@ -425,10 +430,12 @@ protected: bool _snappedToRegistrationPoint; /// are we currently snapped to a registration point glm::vec3 _registrationPoint = glm::vec3(0.5f); /// the point in model space our center is snapped to - std::vector _meshStates; + std::vector _shapeStates; void updateShapeStatesFromRig(); + std::vector _meshStates; + virtual void initJointStates(); void setScaleInternal(const glm::vec3& scale); @@ -471,10 +478,7 @@ protected: static AbstractViewStateInterface* _viewState; QVector> _modelMeshRenderItems; - QMap _modelMeshRenderItemsMap; render::ItemIDs _modelMeshRenderItemIDs; - using ShapeInfo = struct { int meshIndex; uint32_t deformerIndex{ hfm::UNDEFINED_KEY }; }; - std::vector _modelMeshRenderItemShapes; std::vector _modelMeshMaterialNames; bool _addedToScene { false }; // has been added to scene diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp index 186f9e682a..1b8d1e7b69 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ b/libraries/render-utils/src/SoftAttachmentModel.cpp @@ -41,37 +41,37 @@ void SoftAttachmentModel::updateClusterMatrices() { _needsUpdateClusterMatrices = false; - const HFMModel& hfmModel = getHFMModel(); - for (int i = 0; i < (int) _meshStates.size(); i++) { - MeshState& state = _meshStates[i]; - const HFMMesh& mesh = hfmModel.meshes.at(i); - int meshIndex = i; - for (int j = 0; j < mesh.clusters.size(); j++) { - const HFMCluster& cluster = mesh.clusters.at(j); + for (int skinDeformerIndex = 0; skinDeformerIndex < (int)_meshStates.size(); skinDeformerIndex++) { + MeshState& state = _meshStates[skinDeformerIndex]; + auto numClusters = state.getNumClusters(); + for (uint32_t clusterIndex = 0; clusterIndex < numClusters; clusterIndex++) { + const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(skinDeformerIndex, clusterIndex); - int clusterIndex = j; // TODO: cache these look-ups as an optimization - int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); - glm::mat4 jointMatrix; + int jointIndexOverride = getJointIndexOverride(cbmov.jointIndex); + auto rig = &_rigOverride; if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) { - jointMatrix = _rigOverride.getJointTransform(jointIndexOverride); - } else { - jointMatrix = _rig.getJointTransform(cluster.jointIndex); + rig = &_rig; } + if (_useDualQuaternionSkinning) { - glm::mat4 m; - glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, m); - state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(m); - } else { - glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, state.clusterMatrices[j]); + auto jointPose = rig->getJointPose(cbmov.jointIndex); + Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans()); + Transform clusterTransform; + Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform); + state.clusterDualQuaternions[clusterIndex] = Model::TransformDualQuaternion(clusterTransform); + } + else { + auto jointMatrix = rig->getJointTransform(cbmov.jointIndex); + glm_mat4u_mul(jointMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[clusterIndex]); } } } // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); - if (modelBlender->shouldComputeBlendshapes() && hfmModel.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (modelBlender->shouldComputeBlendshapes() && getHFMModel().hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } diff --git a/tools/vhacd-util/src/VHACDUtil.cpp b/tools/vhacd-util/src/VHACDUtil.cpp index 3410d35e6a..f0eb94a1cf 100644 --- a/tools/vhacd-util/src/VHACDUtil.cpp +++ b/tools/vhacd-util/src/VHACDUtil.cpp @@ -348,7 +348,7 @@ bool vhacd::VHACDUtil::computeVHACD(HFMModel& hfmModel, if (_verbose) { qDebug() << "mesh" << meshIndex << ": " - << " parts =" << mesh.parts.size() << " clusters =" << mesh.clusters.size() + << " parts =" << mesh.parts.size() << " vertices =" << numVertices; } ++meshIndex;