diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 568b492b46..d6b753c734 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -818,20 +818,8 @@ void MyAvatar::simulate(float deltaTime, bool inView) { if (_cauterizationNeedsUpdate) { _cauterizationNeedsUpdate = false; - // Redisplay cauterized entities that are no longer children of the avatar. - auto cauterizedChild = _cauterizedChildrenOfHead.begin(); - if (cauterizedChild != _cauterizedChildrenOfHead.end()) { - auto children = getChildren(); - while (cauterizedChild != _cauterizedChildrenOfHead.end()) { - if (!children.contains(*cauterizedChild)) { - updateChildCauterization(*cauterizedChild, false); - cauterizedChild = _cauterizedChildrenOfHead.erase(cauterizedChild); - } else { - ++cauterizedChild; - } - } - } - + auto objectsToUncauterize = _cauterizedChildrenOfHead; + _cauterizedChildrenOfHead.clear(); // Update cauterization of entities that are children of the avatar. auto headBoneSet = _skeletonModel->getCauterizeBoneSet(); forEachChild([&](SpatiallyNestablePointer object) { @@ -843,15 +831,19 @@ void MyAvatar::simulate(float deltaTime, bool inView) { updateChildCauterization(descendant, !_prevShouldDrawHead); }); _cauterizedChildrenOfHead.insert(object); - } else if (_cauterizedChildrenOfHead.find(object) != _cauterizedChildrenOfHead.end()) { - // Redisplay cauterized children that are not longer children of the head. - updateChildCauterization(object, false); + objectsToUncauterize.erase(object); + } else if (objectsToUncauterize.find(object) == objectsToUncauterize.end()) { + objectsToUncauterize.insert(object); object->forEachDescendant([&](SpatiallyNestablePointer descendant) { - updateChildCauterization(descendant, false); + objectsToUncauterize.insert(descendant); }); - _cauterizedChildrenOfHead.erase(object); } }); + + // Redisplay cauterized entities that are no longer children of the avatar. + for (auto cauterizedChild = objectsToUncauterize.begin(); cauterizedChild != objectsToUncauterize.end(); cauterizedChild++) { + updateChildCauterization(*cauterizedChild, false); + } } { diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 3a56521702..fb6fbad2ac 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -166,7 +166,10 @@ ShapeKey EntityRenderer::getShapeKey() { } render::hifi::Tag EntityRenderer::getTagMask() const { - return _isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW; + render::hifi::Tag mask = render::hifi::TAG_NONE; + mask = (render::hifi::Tag)(mask | (!_cauterized * render::hifi::TAG_MAIN_VIEW)); + mask = (render::hifi::Tag)(mask | (_isVisibleInSecondaryCamera * render::hifi::TAG_SECONDARY_VIEW)); + return mask; } render::hifi::Layer EntityRenderer::getHifiRenderLayer() const { @@ -215,12 +218,7 @@ void EntityRenderer::render(RenderArgs* args) { emit requestRenderUpdate(); } - auto& renderMode = args->_renderMode; - bool cauterized = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && - renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE && - _cauterized); - - if (_visible && !cauterized) { + if (_visible && (args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || !_cauterized)) { doRender(args); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index f921f6eca6..bfbbe12ea6 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1066,13 +1066,6 @@ ItemKey ModelEntityRenderer::getKey() { return _itemKey; } -render::hifi::Tag ModelEntityRenderer::getTagMask() const { - // Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint) - return _cauterized ? - (_isVisibleInSecondaryCamera ? render::hifi::TAG_SECONDARY_VIEW : render::hifi::TAG_NONE) : - Parent::getTagMask(); // calculate which views to be shown in -} - uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) { if (_model) { auto metaSubItems = _model->fetchRenderItemIDs(); @@ -1409,6 +1402,10 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce model->setVisibleInScene(_visible, scene); } + if (model->isCauterized() != _cauterized) { + model->setCauterized(_cauterized, scene); + } + render::hifi::Tag tagMask = getTagMask(); if (model->getTagMask() != tagMask) { model->setTagMask(tagMask, scene); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 2fd1041c5f..ee6e7d0b04 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -161,8 +161,6 @@ protected: virtual void doRender(RenderArgs* args) override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; - render::hifi::Tag getTagMask() const override; - void setIsVisibleInSecondaryCamera(bool value) override; void setRenderLayer(RenderLayer value) override; void setPrimitiveMode(PrimitiveMode value) override; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 8a50c39da9..a532064b6c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3007,6 +3007,26 @@ void EntityItem::setPrimitiveMode(PrimitiveMode value) { } } +bool EntityItem::getCauterized() const { + return resultWithReadLock([&] { + return _cauterized; + }); +} + +void EntityItem::setCauterized(bool value) { + bool changed = false; + withWriteLock([&] { + if (_cauterized != value) { + changed = true; + _cauterized = value; + } + }); + + if (changed) { + emit requestRenderUpdate(); + } +} + bool EntityItem::getIgnorePickIntersection() const { return resultWithReadLock([&] { return _ignorePickIntersection; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index c57fd16a2e..29a1a8d73c 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -303,6 +303,9 @@ public: bool getCanCastShadow() const; void setCanCastShadow(bool value); + void setCauterized(bool value); + bool getCauterized() const; + inline bool isVisible() const { return getVisible(); } inline bool isInvisible() const { return !getVisible(); } @@ -530,9 +533,6 @@ public: static QString _marketplacePublicKey; static void retrieveMarketplacePublicKey(); - void setCauterized(bool value) { _cauterized = value; } - bool getCauterized() const { return _cauterized; } - float getBoundingRadius() const { return _boundingRadius; } void setSpaceIndex(int32_t index); int32_t getSpaceIndex() const { return _spaceIndex; } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index b1104b8aad..2634784f3a 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -416,7 +416,7 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMo void ModelMeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); - if (!args) { + if (!args || (args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && _cauterized)) { return; } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index deae91dda9..641fc81487 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -107,6 +107,7 @@ public: void render(RenderArgs* args) override; void setShapeKey(bool invalidateShapeKey, PrimitiveMode primitiveMode, bool useDualQuaternionSkinning); + void setCauterized(bool cauterized) { _cauterized = cauterized; } // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) override; @@ -138,6 +139,8 @@ private: gpu::BufferPointer _meshBlendshapeBuffer; int _meshNumVertices; render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() }; + bool _cauterized { false }; + }; namespace render { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 6b33012adf..ac47b48c5f 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -224,6 +224,7 @@ void Model::updateRenderItems() { PrimitiveMode primitiveMode = self->getPrimitiveMode(); auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags(); + bool cauterized = self->isCauterized(); render::Transaction transaction; for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) { @@ -237,7 +238,7 @@ void Model::updateRenderItems() { bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, - invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) { + invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions); } else { @@ -261,6 +262,7 @@ void Model::updateRenderItems() { } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); + data.setCauterized(cauterized); data.updateKey(renderItemKeyGlobalFlags); data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); }); @@ -922,6 +924,23 @@ bool Model::isGroupCulled() const { return _renderItemKeyGlobalFlags.isSubMetaCulled(); } +void Model::setCauterized(bool cauterized, const render::ScenePointer& scene) { + if (Model::isCauterized() != cauterized) { + _cauterized = cauterized; + if (!scene) { + _needsFixupInScene = true; + return; + } + render::Transaction transaction; + foreach (auto item, _modelMeshRenderItemsMap.keys()) { + transaction.updateItem(item, [cauterized](ModelMeshPartPayload& data) { + data.setCauterized(cauterized); + }); + } + scene->enqueueTransaction(transaction); + } +} + const render::ItemKey Model::getRenderItemKeyGlobalFlags() const { return _renderItemKeyGlobalFlags; } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 3c207c982c..1431b5e3f9 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -126,6 +126,9 @@ public: void setHifiRenderLayer(render::hifi::Layer layer, const render::ScenePointer& scene = nullptr); + bool isCauterized() const { return _cauterized; } + void setCauterized(bool value, const render::ScenePointer& scene); + // Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model. const render::ItemKey getRenderItemKeyGlobalFlags() const; @@ -502,6 +505,7 @@ protected: // For this to work, a Meta RI must exists and knows about the RIs of this Model. // render::ItemKey _renderItemKeyGlobalFlags; + bool _cauterized { false }; bool shouldInvalidatePayloadShapeKey(int meshIndex); diff --git a/libraries/render-utils/src/RenderHifi.h b/libraries/render-utils/src/RenderHifi.h index c489a0ad1d..8d3fe7e4d1 100644 --- a/libraries/render-utils/src/RenderHifi.h +++ b/libraries/render-utils/src/RenderHifi.h @@ -23,9 +23,9 @@ namespace render { // Tag is the alias names of render::ItemKey::Tag combinations used in the Hifi Render Engine enum Tag : uint8_t { - TAG_NONE = render::ItemKey::TAG_BITS_NONE, // No Tags at all - TAG_MAIN_VIEW = render::ItemKey::TAG_BITS_0, // Main view - TAG_SECONDARY_VIEW = render::ItemKey::TAG_BITS_1, // Secondary View + TAG_NONE = render::ItemKey::TAG_BITS_NONE, // No Tags at all + TAG_MAIN_VIEW = render::ItemKey::TAG_BITS_0, // Main view + TAG_SECONDARY_VIEW = render::ItemKey::TAG_BITS_1, // Secondary View TAG_ALL_VIEWS = TAG_MAIN_VIEW | TAG_SECONDARY_VIEW, // All views }; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 5456453d8a..a261deefb8 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -58,10 +58,6 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); } - // FIXME: calling this here before the zones/lights are drawn during the deferred/forward passes means we're actually using the frames from the previous draw - // Fetch the current frame stacks from all the stages - // Starting with the Light Frame genreated in previous tasks - const auto setupOutput = task.addJob("ShadowSetup", input); const auto queryResolution = setupOutput.getN(1); const auto shadowFrame = setupOutput.getN(3); @@ -99,7 +95,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { char jobName[64]; sprintf(jobName, "ShadowCascadeSetup%d", i); - const auto cascadeSetupOutput = task.addJob(jobName, shadowFrame, i, tagBits, tagMask); + const auto cascadeSetupOutput = task.addJob(jobName, shadowFrame, i, shadowCasterReceiverFilter); const auto shadowFilter = cascadeSetupOutput.getN(0); auto antiFrustum = render::Varying(ViewFrustumPointer()); cascadeFrustums[i] = cascadeSetupOutput.getN(1); @@ -452,8 +448,7 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon const auto globalShadow = shadowFrame->_objects[0]; if (globalShadow && _cascadeIndex < globalShadow->getCascadeCount()) { - // Second item filter is to filter items to keep in shadow frustum computation (here we need to keep shadow receivers) - output.edit0() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask); + output.edit0() = _filter; // Set the keylight render args auto& cascade = globalShadow->getCascade(_cascadeIndex); @@ -551,7 +546,6 @@ void CullShadowBounds::run(const render::RenderContextPointer& renderContext, co assert(lightStage); const auto globalLightDir = currentKeyLight->getDirection(); auto castersFilter = render::ItemFilter::Builder(filter).withShadowCaster().build(); - const auto& receiversFilter = filter; for (auto& inItems : inShapes) { auto key = inItems.first; @@ -570,7 +564,7 @@ void CullShadowBounds::run(const render::RenderContextPointer& renderContext, co if (castersFilter.test(shapeKey)) { outItems->second.emplace_back(item); outBounds += item.bound; - } else if (receiversFilter.test(shapeKey)) { + } else { // Receivers are not rendered but they still increase the bounds of the shadow scene // although only in the direction of the light direction so as to have a correct far // distance without decreasing the near distance. @@ -585,7 +579,7 @@ void CullShadowBounds::run(const render::RenderContextPointer& renderContext, co if (castersFilter.test(shapeKey)) { outItems->second.emplace_back(item); outBounds += item.bound; - } else if (receiversFilter.test(shapeKey)) { + } else { // Receivers are not rendered but they still increase the bounds of the shadow scene // although only in the direction of the light direction so as to have a correct far // distance without decreasing the near distance. diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 7e7d59763e..4dc6f3073f 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -134,15 +134,13 @@ public: using Outputs = render::VaryingSet3; using JobModel = render::Job::ModelIO; - RenderShadowCascadeSetup(unsigned int cascadeIndex, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00) : - _cascadeIndex(cascadeIndex), _tagBits(tagBits), _tagMask(tagMask) {} + RenderShadowCascadeSetup(unsigned int cascadeIndex, render::ItemFilter filter) : _cascadeIndex(cascadeIndex), _filter(filter) {} void run(const render::RenderContextPointer& renderContext, const Inputs& input, Outputs& output); private: unsigned int _cascadeIndex; - uint8_t _tagBits { 0x00 }; - uint8_t _tagMask { 0x00 }; + render::ItemFilter _filter; }; class RenderShadowCascadeTeardown { diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index b5c98e3428..78e9909222 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -61,7 +61,7 @@ namespace render { class Args { public: - enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE }; + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE }; enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD }; enum DebugFlags { RENDER_DEBUG_NONE = 0, diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index 1b1e4a5d8f..0b475614a1 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -39,7 +39,7 @@ public: RenderFetchCullSortTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask); }; #endif // hifi_RenderFetchCullSortTask_h diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 4d97f43e6a..866698adeb 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -68,19 +68,28 @@ const QUuid SpatiallyNestable::getParentID() const { void SpatiallyNestable::setParentID(const QUuid& parentID) { bumpAncestorChainRenderableVersion(); + bool success = false; + auto parent = getParentPointer(success); + bool parentChanged = false; _idLock.withWriteLock([&] { if (_parentID != parentID) { + parentChanged = true; _parentID = parentID; _parentKnowsMe = false; } }); + if (parentChanged && success && parent) { + parent->recalculateChildCauterization(); + } + if (!_parentKnowsMe) { - bool success = false; - auto parent = getParentPointer(success); + success = false; + parent = getParentPointer(success); if (success && parent) { bumpAncestorChainRenderableVersion(); parent->updateQueryAACube(); + parent->recalculateChildCauterization(); } } } @@ -175,8 +184,9 @@ void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { void SpatiallyNestable::setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; - auto parent = _parent.lock(); - if (parent) { + bool success = false; + auto parent = getParentPointer(success); + if (success && parent) { parent->recalculateChildCauterization(); } }