diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 4adad0d938..ee5e397592 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1047,6 +1047,7 @@ void Avatar::setModelURLFinished(bool success) { static std::shared_ptr allocateAttachmentModel(bool isSoft, RigPointer rigOverride) { if (isSoft) { // cast to std::shared_ptr + // TODO: re-enable cauterization for the SoftAttachmentModel when this is MyAvatar return std::dynamic_pointer_cast(std::make_shared(std::make_shared(), nullptr, rigOverride)); } else { return std::make_shared(std::make_shared()); diff --git a/interface/src/avatar/CauterizedMeshPartPayload.cpp b/interface/src/avatar/CauterizedMeshPartPayload.cpp index e073b2cedf..a7db9608fe 100644 --- a/interface/src/avatar/CauterizedMeshPartPayload.cpp +++ b/interface/src/avatar/CauterizedMeshPartPayload.cpp @@ -44,6 +44,9 @@ void CauterizedMeshPartPayload::updateTransformForSkinnedCauterizedMesh(const Tr _cauterizedTransform = _transform; } } + } else { + _worldBound = _localBound; + _worldBound.transform(_drawTransform); } } @@ -51,10 +54,10 @@ void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::S // Still relying on the raw data from the model const Model::MeshState& state = _model->getMeshState(_meshIndex); SkeletonModel* skeleton = static_cast(_model); - bool canCauterize = (renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE); + bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE) && skeleton->getEnableCauterization(); if (state.clusterBuffer) { - if (canCauterize && skeleton->getCauterizeBones()) { + if (useCauterizedMesh) { const Model::MeshState& cState = skeleton->getCauterizeMeshState(_meshIndex); batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, cState.clusterBuffer); } else { @@ -62,7 +65,7 @@ void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::S } batch.setModelTransform(_transform); } else { - if (canCauterize && skeleton->getCauterizeBones()) { + if (useCauterizedMesh) { batch.setModelTransform(_cauterizedTransform); } else { batch.setModelTransform(_transform); diff --git a/interface/src/avatar/CauterizedModel.cpp b/interface/src/avatar/CauterizedModel.cpp index 5c06412d9c..30566e357d 100644 --- a/interface/src/avatar/CauterizedModel.cpp +++ b/interface/src/avatar/CauterizedModel.cpp @@ -9,9 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -//#include -//#include - #include "CauterizedModel.h" #include @@ -21,7 +18,8 @@ #include "CauterizedMeshPartPayload.h" -CauterizedModel::CauterizedModel(RigPointer rig, QObject* parent) : Model(rig, parent) { +CauterizedModel::CauterizedModel(RigPointer rig, QObject* parent) : + Model(rig, parent) { } CauterizedModel::~CauterizedModel() { @@ -32,15 +30,64 @@ void CauterizedModel::deleteGeometry() { _cauterizeMeshStates.clear(); } -// Called within Model::simulate call, below. -void CauterizedModel::updateRig(float deltaTime, glm::mat4 parentTransform) { - Model::updateRig(deltaTime, parentTransform); - _needsUpdateClusterMatrices = true; +bool CauterizedModel::updateGeometry() { + bool needsFullUpdate = Model::updateGeometry(); + if (_isCauterized && needsFullUpdate) { + assert(_cauterizeMeshStates.empty()); + const FBXGeometry& fbxGeometry = getFBXGeometry(); + foreach (const FBXMesh& mesh, fbxGeometry.meshes) { + Model::MeshState state; + state.clusterMatrices.resize(mesh.clusters.size()); + _cauterizeMeshStates.append(state); + } + } + return needsFullUpdate; } void CauterizedModel::createVisibleRenderItemSet() { - // Temporary HACK: use base class method for now - Model::createVisibleRenderItemSet(); + if (_isCauterized) { + assert(isLoaded()); + const auto& meshes = _renderGeometry->getMeshes(); + + // all of our mesh vectors must match in size + if ((int)meshes.size() != _meshStates.size()) { + qCDebug(renderlogging) << "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(_modelMeshRenderItemsSet.isEmpty()); + + _modelMeshRenderItemsSet.clear(); + + Transform transform; + transform.setTranslation(_translation); + transform.setRotation(_rotation); + + Transform offset; + offset.setScale(_scale); + offset.postTranslate(_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(); + for (uint32_t i = 0; i < numMeshes; i++) { + const auto& mesh = meshes.at(i); + if (!mesh) { + continue; + } + + // Create the render payloads + int numParts = (int)mesh->getNumParts(); + for (int partIndex = 0; partIndex < numParts; partIndex++) { + auto ptr = std::make_shared(this, i, partIndex, shapeID, transform, offset); + _modelMeshRenderItemsSet << std::static_pointer_cast(ptr); + shapeID++; + } + } + } else { + Model::createVisibleRenderItemSet(); + } } void CauterizedModel::createCollisionRenderItemSet() { @@ -48,19 +95,10 @@ void CauterizedModel::createCollisionRenderItemSet() { Model::createCollisionRenderItemSet(); } -bool CauterizedModel::updateGeometry() { - bool needsFullUpdate = Model::updateGeometry(); - if (needsFullUpdate) { - if (_rig->jointStatesEmpty() && getFBXGeometry().joints.size() > 0) { - const FBXGeometry& fbxGeometry = getFBXGeometry(); - foreach (const FBXMesh& mesh, fbxGeometry.meshes) { - Model::MeshState state; - state.clusterMatrices.resize(mesh.clusters.size()); - _cauterizeMeshStates.append(state); - } - } - } - return needsFullUpdate; +// Called within Model::simulate call, below. +void CauterizedModel::updateRig(float deltaTime, glm::mat4 parentTransform) { + Model::updateRig(deltaTime, parentTransform); + _needsUpdateClusterMatrices = true; } void CauterizedModel::updateClusterMatrices() { @@ -147,90 +185,71 @@ void CauterizedModel::updateClusterMatrices() { } void CauterizedModel::updateRenderItems() { - // Temporary HACK: use base class method for now - Model::updateRenderItems(); -} - -#ifdef FOO -// TODO: finish implementing this -void CauterizedModel::updateRenderItems() { - if (!_addedToScene) { - return; - } - - glm::vec3 scale = getScale(); - if (_collisionGeometry) { - // _collisionGeometry is already scaled - scale = glm::vec3(1.0f); - } - _needsUpdateClusterMatrices = true; - _renderItemsNeedUpdate = false; - - // queue up this work for later processing, at the end of update and just before rendering. - // the application will ensure only the last lambda is actually invoked. - void* key = (void*)this; - std::weak_ptr weakSelf = shared_from_this(); - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf, scale]() { - - // do nothing, if the model has already been destroyed. - auto self = weakSelf.lock(); - if (!self) { + if (_isCauterized) { + if (!_addedToScene) { return; } - render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - - Transform modelTransform; - modelTransform.setTranslation(self->getTranslation()); - modelTransform.setRotation(self->getRotation()); - - Transform scaledModelTransform(modelTransform); - scaledModelTransform.setScale(scale); - - uint32_t deleteGeometryCounter = self->getGeometryCounter(); - - // TODO: handle two cases: - // (a) our payloads are of type ModelMeshPartPayload - // (b) our payloads are of type ModelMeshPartPayload - render::PendingChanges pendingChanges; - QList keys = self->getRenderItems().keys(); - foreach (auto itemID, keys) { - pendingChanges.updateItem(itemID, [modelTransform, deleteGeometryCounter](CauterizedMeshPartPayload& data) { - if (data._model && data._model->isLoaded()) { - if (!data.hasStartedFade() && data._model->getGeometry()->areTexturesLoaded()) { - data.startFade(); - } - // Ensure the model geometry was not reset between frames - if (deleteGeometryCounter == data._model->getGeometryCounter()) { - // lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box. - data._model->updateClusterMatrices(); - - // update the model transform and bounding box for this render item. - const Model::MeshState& state = data._model->getMeshState(data._meshIndex); - CauterizedModel* cModel = static_cast(data._model); - const Model::MeshState& cState = cModel->_cauterizeMeshStates.at(data._meshIndex); - data.updateTransformForSkinnedCauterizedMesh(modelTransform, state.clusterMatrices, cState.clusterMatrices); - } - } - }); + glm::vec3 scale = getScale(); + if (_collisionGeometry) { + // _collisionGeometry is already scaled + scale = glm::vec3(1.0f); } + _needsUpdateClusterMatrices = true; + _renderItemsNeedUpdate = false; - /* - // collision mesh does not share the same unit scale as the FBX file's mesh: only apply offset - Transform collisionMeshOffset; - collisionMeshOffset.setIdentity(); - foreach (auto itemID, self->_collisionRenderItems.keys()) { - pendingChanges.updateItem(itemID, [scaledModelTransform, collisionMeshOffset](MeshPartPayload& data) { - // update the model transform for this render item. - data.updateTransform(scaledModelTransform, collisionMeshOffset); - }); - } - */ + // queue up this work for later processing, at the end of update and just before rendering. + // the application will ensure only the last lambda is actually invoked. + void* key = (void*)this; + std::weak_ptr weakSelf = shared_from_this(); + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf, scale]() { + // do nothing, if the model has already been destroyed. + auto self = weakSelf.lock(); + if (!self) { + return; + } - scene->enqueuePendingChanges(pendingChanges); - }); + render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); + + Transform modelTransform; + modelTransform.setTranslation(self->getTranslation()); + modelTransform.setRotation(self->getRotation()); + + Transform scaledModelTransform(modelTransform); + scaledModelTransform.setScale(scale); + + uint32_t deleteGeometryCounter = self->getGeometryCounter(); + + render::PendingChanges pendingChanges; + QList keys = self->getRenderItems().keys(); + foreach (auto itemID, keys) { + pendingChanges.updateItem(itemID, [modelTransform, deleteGeometryCounter](CauterizedMeshPartPayload& data) { + if (data._model && data._model->isLoaded()) { + if (!data.hasStartedFade() && data._model->getGeometry()->areTexturesLoaded()) { + data.startFade(); + } + // Ensure the model geometry was not reset between frames + if (deleteGeometryCounter == data._model->getGeometryCounter()) { + // lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box. + data._model->updateClusterMatrices(); + + // update the model transform and bounding box for this render item. + const Model::MeshState& state = data._model->getMeshState(data._meshIndex); + CauterizedModel* cModel = static_cast(data._model); + assert(data._meshIndex < cModel->_cauterizeMeshStates.size()); + const Model::MeshState& cState = cModel->_cauterizeMeshStates.at(data._meshIndex); + data.updateTransformForSkinnedCauterizedMesh(modelTransform, state.clusterMatrices, cState.clusterMatrices); + } + } + }); + } + + scene->enqueuePendingChanges(pendingChanges); + }); + } else { + Model::updateRenderItems(); + } } -#endif // FOO const Model::MeshState& CauterizedModel::getCauterizeMeshState(int index) const { assert(index < _meshStates.size()); diff --git a/interface/src/avatar/CauterizedModel.h b/interface/src/avatar/CauterizedModel.h index 12a9723dd4..01e0b13650 100644 --- a/interface/src/avatar/CauterizedModel.h +++ b/interface/src/avatar/CauterizedModel.h @@ -22,19 +22,22 @@ public: CauterizedModel(RigPointer rig, QObject* parent); virtual ~CauterizedModel(); - void deleteGeometry() override; - virtual void updateRig(float deltaTime, glm::mat4 parentTransform) override; + void flagAsCauterized() { _isCauterized = true; } + bool getIsCauterized() const { return _isCauterized; } - void setCauterizeBones(bool flag) { _cauterizeBones = flag; } - bool getCauterizeBones() const { return _cauterizeBones; } + void setEnableCauterization(bool flag) { _enableCauterization = flag; } + bool getEnableCauterization() const { return _enableCauterization; } const std::unordered_set& getCauterizeBoneSet() const { return _cauterizeBoneSet; } void setCauterizeBoneSet(const std::unordered_set& boneSet) { _cauterizeBoneSet = boneSet; } + void deleteGeometry() override; + bool updateGeometry() override; + void createVisibleRenderItemSet() override; void createCollisionRenderItemSet() override; - bool updateGeometry() override; + virtual void updateRig(float deltaTime, glm::mat4 parentTransform) override; virtual void updateClusterMatrices() override; void updateRenderItems() override; @@ -43,7 +46,8 @@ public: protected: std::unordered_set _cauterizeBoneSet; QVector _cauterizeMeshStates; - bool _cauterizeBones { false }; + bool _isCauterized { false }; + bool _enableCauterization { false }; }; #endif // hifi_CauterizedModel_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 488752b309..dd95c5963d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -116,12 +116,12 @@ MyAvatar::MyAvatar(RigPointer rig) : _hmdAtRestDetector(glm::vec3(0), glm::quat()) { using namespace recording; + _skeletonModel->flagAsCauterized(); for (int i = 0; i < MAX_DRIVE_KEYS; i++) { _driveKeys[i] = 0.0f; } - // Necessary to select the correct slot using SlotType = void(MyAvatar::*)(const glm::vec3&, bool, const glm::quat&, bool); @@ -1592,7 +1592,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) { // toggle using the cauterizedBones depending on where the camera is and the rendering pass type. const bool shouldDrawHead = shouldRenderHead(renderArgs); if (shouldDrawHead != _prevShouldDrawHead) { - _skeletonModel->setCauterizeBones(!shouldDrawHead); + _skeletonModel->setEnableCauterization(!shouldDrawHead); } _prevShouldDrawHead = shouldDrawHead; } diff --git a/interface/src/avatar/SoftAttachmentModel.cpp b/interface/src/avatar/SoftAttachmentModel.cpp index 530801007e..da7ca0b87d 100644 --- a/interface/src/avatar/SoftAttachmentModel.cpp +++ b/interface/src/avatar/SoftAttachmentModel.cpp @@ -38,7 +38,6 @@ int SoftAttachmentModel::getJointIndexOverride(int i) const { // virtual // use the _rigOverride matrices instead of the Model::_rig void SoftAttachmentModel::updateClusterMatrices() { - // adebug TODO: this needs work? if (!_needsUpdateClusterMatrices) { return; } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 52eb006b9f..57498abff9 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -370,6 +370,9 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transf _worldBound += clusterBound; } _worldBound.transform(transform); + } else { + _worldBound = _localBound; + _worldBound.transform(_drawTransform); } }