diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 99bd4d5758..4f4c528abf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2294,7 +2294,7 @@ void Application::initializeGL() { #ifndef Q_OS_ANDROID _renderEngine->addJob("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED); #endif - _renderEngine->addJob("RenderMainView", cullFunctor, !DISABLE_DEFERRED); + _renderEngine->addJob("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0); #ifdef Q_OS_OSX DeadlockWatchdogThread::resume(); diff --git a/interface/src/Application_render.cpp b/interface/src/Application_render.cpp index 1231e5834b..e1f198eed2 100644 --- a/interface/src/Application_render.cpp +++ b/interface/src/Application_render.cpp @@ -178,7 +178,7 @@ public: render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID }; namespace render { - template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); } + template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); } template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); } template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) { if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) { diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 5db34c9441..6b8e370689 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -19,8 +19,9 @@ using RenderArgsPointer = std::shared_ptr; void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) { - task.addJob("RenderShadowTask", cullFunctor); - const auto items = task.addJob("FetchCullSort", cullFunctor); + + task.addJob("RenderShadowTask", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1); + const auto items = task.addJob("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1); assert(items.canCast()); if (!isDeferred) { task.addJob("Forward", items); @@ -205,7 +206,7 @@ public: void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) { const auto cachedArg = task.addJob("SecondaryCamera"); - const auto items = task.addJob("FetchCullSort", cullFunctor); + const auto items = task.addJob("FetchCullSort", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1); assert(items.canCast()); if (!isDeferred) { task.addJob("Forward", items); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4ab741e32c..d2a9e798f8 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include "MyHead.h" #include "MySkeletonModel.h" @@ -503,11 +504,42 @@ void MyAvatar::updateEyeContactTarget(float deltaTime) { extern QByteArray avatarStateToFrame(const AvatarData* _avatar); extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); +void MyAvatar::beParentOfChild(SpatiallyNestablePointer newChild) const { + _cauterizationNeedsUpdate = true; + SpatiallyNestable::beParentOfChild(newChild); +} + +void MyAvatar::forgetChild(SpatiallyNestablePointer newChild) const { + _cauterizationNeedsUpdate = true; + SpatiallyNestable::forgetChild(newChild); +} + +void MyAvatar::updateChildCauterization(SpatiallyNestablePointer object) { + if (object->getNestableType() == NestableType::Entity) { + EntityItemPointer entity = std::static_pointer_cast(object); + entity->setCauterized(!_prevShouldDrawHead); + } +} + void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); animateScaleChanges(deltaTime); + if (_cauterizationNeedsUpdate) { + const std::unordered_set& headBoneSet = _skeletonModel->getCauterizeBoneSet(); + forEachChild([&](SpatiallyNestablePointer object) { + bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end(); + if (isChildOfHead) { + updateChildCauterization(object); + object->forEachDescendant([&](SpatiallyNestablePointer descendant) { + updateChildCauterization(descendant); + }); + } + }); + _cauterizationNeedsUpdate = false; + } + { PerformanceTimer perfTimer("transform"); bool stepAction = false; @@ -1067,7 +1099,7 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) { } void MyAvatar::setEnableMeshVisible(bool isEnabled) { - _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene()); + _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE); } void MyAvatar::setEnableInverseKinematics(bool isEnabled) { @@ -1417,8 +1449,9 @@ void MyAvatar::clearJointsData() { void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { Avatar::setSkeletonModelURL(skeletonModelURL); - _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene()); + _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE); _headBoneSet.clear(); + _cauterizationNeedsUpdate = true; emit skeletonChanged(); } @@ -1762,7 +1795,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, void MyAvatar::setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visible) { if (model->isActive() && model->isRenderable()) { - model->setVisibleInScene(visible, scene); + model->setVisibleInScene(visible, scene, render::ItemKey::TAG_BITS_NONE); } } @@ -1790,6 +1823,8 @@ void MyAvatar::initHeadBones() { } q.pop(); } + + _cauterizationNeedsUpdate = true; } QUrl MyAvatar::getAnimGraphOverrideUrl() const { @@ -1860,6 +1895,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); initAnimGraph(); _isAnimatingScale = true; + _cauterizationNeedsUpdate = true; } if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) { @@ -1948,6 +1984,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) { + _cauterizationNeedsUpdate = true; _skeletonModel->setEnableCauterization(!shouldDrawHead); for (int i = 0; i < _attachmentData.size(); i++) { @@ -1957,7 +1994,8 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) { _attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) { - _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene()); + _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(), + render::ItemKey::TAG_BITS_NONE); } } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index ed391f750a..97e82b87f5 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -633,6 +633,11 @@ signals: private slots: void leaveDomain(); + +protected: + virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override; + virtual void forgetChild(SpatiallyNestablePointer newChild) const override; + private: bool requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& positionOut); @@ -812,6 +817,8 @@ private: bool _enableDebugDrawIKChains { false }; bool _enableDebugDrawDetailedCollision { false }; + mutable bool _cauterizationNeedsUpdate; // do we need to scan children and update their "cauterized" state? + AudioListenerMode _audioListenerMode; glm::vec3 _customListenPosition; glm::quat _customListenOrientation; @@ -849,6 +856,8 @@ private: // height of user in sensor space, when standing erect. ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; + void updateChildCauterization(SpatiallyNestablePointer object); + // max unscaled forward movement speed ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; }; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 310dbf78d8..4847650163 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -86,7 +86,8 @@ void ModelOverlay::update(float deltatime) { } if (_visibleDirty) { _visibleDirty = false; - _model->setVisibleInScene(getVisible(), scene); + // don't show overlays in mirrors + _model->setVisibleInScene(getVisible(), scene, render::ItemKey::TAG_BITS_0); } if (_drawInFrontDirty) { _drawInFrontDirty = false; @@ -120,8 +121,10 @@ void ModelOverlay::removeFromScene(Overlay::Pointer overlay, const render::Scene } void ModelOverlay::setVisible(bool visible) { - Overlay::setVisible(visible); - _visibleDirty = true; + if (visible != getVisible()) { + Overlay::setVisible(visible); + _visibleDirty = true; + } } void ModelOverlay::setDrawInFront(bool drawInFront) { diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 60ba90e568..08c776c426 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -106,7 +106,7 @@ private: bool _jointMappingCompleted { false }; QVector _jointMapping; // domain is index into model-joints, range is index into animation-joints - bool _visibleDirty { false }; + bool _visibleDirty { true }; bool _drawInFrontDirty { false }; bool _drawInHUDDirty { false }; diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 449ac62998..f99ced0021 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -44,6 +44,13 @@ namespace render { } else { builder.withViewSpace(); } + + if (!overlay->getVisible()) { + builder.withInvisible(); + } + + builder.withTagBits(render::ItemKey::TAG_BITS_0); // Only draw overlays in main view + return builder.build(); } template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) { diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 500a24763d..86635cd3bf 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -50,7 +50,7 @@ const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f); namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) { - return ItemKey::Builder::opaqueShape().withTypeMeta(); + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); } template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) { return static_pointer_cast(avatar)->getBounds(); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index fb9aba636b..aca2f4d35b 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -159,10 +159,10 @@ Item::Bound EntityRenderer::getBound() { ItemKey EntityRenderer::getKey() { if (isTransparent()) { - return ItemKey::Builder::transparentShape().withTypeMeta(); + return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); } - return ItemKey::Builder::opaqueShape().withTypeMeta(); + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); } uint32_t EntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) { @@ -185,7 +185,12 @@ void EntityRenderer::render(RenderArgs* args) { emit requestRenderUpdate(); } - if (_visible) { + auto& renderMode = args->_renderMode; + bool cauterized = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && + renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE && + _cauterized); + + if (_visible && !cauterized) { doRender(args); } } @@ -366,6 +371,7 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa _moving = entity->isMovingRelativeToParent(); _visible = entity->getVisible(); + _cauterized = entity->getCauterized(); _needsRenderUpdate = false; }); } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 8eb82e2c6e..f8685df5da 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -124,6 +124,7 @@ protected: bool _isFading{ _entitiesShouldFadeFunction() }; bool _prevIsTransparent { false }; bool _visible { false }; + bool _cauterized { false }; bool _moving { false }; bool _needsRenderUpdate { false }; // Only touched on the rendering thread diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 9fcb7640ef..137203f475 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1013,9 +1013,9 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) { if (didVisualGeometryRequestSucceed) { - _itemKey = ItemKey::Builder().withTypeMeta(); + _itemKey = ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); } else { - _itemKey = ItemKey::Builder().withTypeMeta().withTypeShape(); + _itemKey = ItemKey::Builder().withTypeMeta().withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); } } @@ -1334,11 +1334,16 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce entity->updateModelBounds(); entity->stopModelOverrideIfNoParent(); - if (model->isVisible() != _visible) { + // Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint) + uint32_t viewTaskBits = _cauterized ? + render::ItemKey::TAG_BITS_1 : // draw in every view except the main one (view zero) + render::ItemKey::TAG_BITS_ALL; // draw in all views + + if (model->isVisible() != _visible || model->getViewTagBits() != viewTaskBits) { // FIXME: this seems like it could be optimized if we tracked our last known visible state in // the renderable item. As it stands now the model checks it's visible/invisible state // so most of the time we don't do anything in this function. - model->setVisibleInScene(_visible, scene); + model->setVisibleInScene(_visible, scene, viewTaskBits); } // TODO? early exit here when not visible? diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 2059487426..af95878213 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -147,9 +147,9 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn ItemKey ParticleEffectEntityRenderer::getKey() { if (_visible) { - return ItemKey::Builder::transparentShape(); + return ItemKey::Builder::transparentShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); } else { - return ItemKey::Builder().withInvisible().build(); + return ItemKey::Builder().withInvisible().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build(); } } diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 4d223669b4..42110170a0 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -112,7 +112,7 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity) } ItemKey PolyLineEntityRenderer::getKey() { - return ItemKey::Builder::transparentShape().withTypeMeta(); + return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); } ShapeKey PolyLineEntityRenderer::getShapeKey() { diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index b43944f26a..04f07c5bd3 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -269,7 +269,7 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe ItemKey ZoneEntityRenderer::getKey() { - return ItemKey::Builder().withTypeMeta().build(); + return ItemKey::Builder().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1).build(); } bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 4c398b8a29..701701ea34 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -470,6 +470,9 @@ public: static QString _marketplacePublicKey; static void retrieveMarketplacePublicKey(); + void setCauterized(bool value) { _cauterized = value; } + bool getCauterized() const { return _cauterized; } + signals: void requestRenderUpdate(); @@ -623,6 +626,7 @@ protected: quint64 _lastUpdatedAccelerationTimestamp { 0 }; quint64 _lastUpdatedQueryAACubeTimestamp { 0 }; + bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera }; #endif // hifi_EntityItem_h diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index c22e99cbbc..4b5b06ab0b 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -67,7 +67,7 @@ public: typedef render::Payload AnimDebugDrawPayload; namespace render { - template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::opaqueShape() : ItemKey::Builder::opaqueShape().withInvisible()); } + template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::opaqueShape() : ItemKey::Builder::opaqueShape().withInvisible()).withTagBits(ItemKey::TAG_BITS_ALL); } template <> const Item::Bound payloadGetBound(const AnimDebugDrawData::Pointer& data) { return data->_bound; } template <> void payloadRender(const AnimDebugDrawData::Pointer& data, RenderArgs* args) { data->render(args); diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index efca0c3267..54dfd96a00 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -249,7 +249,7 @@ void CauterizedModel::updateRenderItems() { data.updateTransformForCauterizedMesh(renderTransform); data.setEnableCauterization(enableCauterization); - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, render::ItemKey::TAG_BITS_ALL); data.setLayer(isLayeredInFront, isLayeredInHUD); data.setShapeKey(invalidatePayloadShapeKey, isWireframe); }); diff --git a/libraries/render-utils/src/LightPayload.cpp b/libraries/render-utils/src/LightPayload.cpp index 09334faa13..79e0c1d94d 100644 --- a/libraries/render-utils/src/LightPayload.cpp +++ b/libraries/render-utils/src/LightPayload.cpp @@ -18,9 +18,13 @@ namespace render { template <> const ItemKey payloadGetKey(const LightPayload::Pointer& payload) { ItemKey::Builder builder; builder.withTypeLight(); - if (!payload || !payload->isVisible()) { - builder.withInvisible(); + builder.withTagBits(ItemKey::TAG_BITS_ALL); + if (payload) { + if (!payload->isVisible()) { + builder.withInvisible(); + } } + return builder.build(); } @@ -87,6 +91,7 @@ namespace render { template <> const ItemKey payloadGetKey(const KeyLightPayload::Pointer& payload) { ItemKey::Builder builder; builder.withTypeLight(); + builder.withTagBits(ItemKey::TAG_BITS_ALL); if (!payload || !payload->isVisible()) { builder.withInvisible(); } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index c506887fc4..9655b60a78 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -71,10 +71,20 @@ void MeshPartPayload::updateMaterial(graphics::MaterialPointer drawMaterial) { _drawMaterial = drawMaterial; } -ItemKey MeshPartPayload::getKey() const { +void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) { ItemKey::Builder builder; builder.withTypeShape(); + if (!isVisible) { + builder.withInvisible(); + } + + builder.withTagBits(tagBits); + + if (isLayered) { + builder.withLayered(); + } + if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); if (matKey.isTranslucent()) { @@ -82,7 +92,11 @@ ItemKey MeshPartPayload::getKey() const { } } - return builder.build(); + _itemKey = builder.build(); +} + +ItemKey MeshPartPayload::getKey() const { + return _itemKey; } Item::Bound MeshPartPayload::getBound() const { @@ -389,7 +403,7 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render _worldBound.transform(boundTransform); } -void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) { +void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) { ItemKey::Builder builder; builder.withTypeShape(); @@ -397,6 +411,8 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) { builder.withInvisible(); } + builder.withTagBits(tagBits); + if (isLayered) { builder.withLayered(); } @@ -415,10 +431,6 @@ void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) { _itemKey = builder.build(); } -ItemKey ModelMeshPartPayload::getKey() const { - return _itemKey; -} - void ModelMeshPartPayload::setLayer(bool isLayeredInFront, bool isLayeredInHUD) { if (isLayeredInFront) { _layer = Item::LAYER_3D_FRONT; diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 8160b9f009..21f9dc2e68 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -33,6 +33,8 @@ public: typedef render::Payload Payload; typedef Payload::DataPointer Pointer; + virtual void updateKey(bool isVisible, bool isLayered, uint8_t tagBits); + virtual void updateMeshPart(const std::shared_ptr& drawMesh, int partIndex); virtual void notifyLocationChanged() {} @@ -70,6 +72,9 @@ public: size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; } int getMaterialTextureCount() { return _drawMaterial ? _drawMaterial->getTextureCount() : 0; } bool hasTextureInfo() const { return _drawMaterial ? _drawMaterial->hasTextureInfo() : false; } + +protected: + render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() }; }; namespace render { @@ -94,16 +99,15 @@ public: using TransformType = glm::mat4; #endif + void updateKey(bool isVisible, bool isLayered, uint8_t tagBits) override; void updateClusterBuffer(const std::vector& clusterTransforms); void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform); // Render Item interface - render::ItemKey getKey() const override; int getLayer() const; render::ShapeKey getShapeKey() const override; // shape interface void render(RenderArgs* args) override; - void setKey(bool isVisible, bool isLayered); void setLayer(bool isLayeredInFront, bool isLayeredInHUD); void setShapeKey(bool invalidateShapeKey, bool isWireframe); @@ -126,7 +130,6 @@ private: void initCache(const ModelPointer& model); gpu::BufferPointer _blendedVertexBuffer; - render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() }; render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() }; int _layer { render::Item::LAYER_3D }; }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b0763c0fb3..b9ccc28c01 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -268,6 +268,7 @@ void Model::updateRenderItems() { bool isWireframe = self->isWireframe(); bool isVisible = self->isVisible(); + uint8_t viewTagBits = self->getViewTagBits(); bool isLayeredInFront = self->isLayeredInFront(); bool isLayeredInHUD = self->isLayeredInHUD(); @@ -280,8 +281,10 @@ void Model::updateRenderItems() { bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); - transaction.updateItem(itemID, [modelTransform, clusterTransforms, invalidatePayloadShapeKey, - isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + transaction.updateItem(itemID, [modelTransform, clusterTransforms, + invalidatePayloadShapeKey, isWireframe, isVisible, + viewTagBits, isLayeredInFront, + isLayeredInHUD](ModelMeshPartPayload& data) { data.updateClusterBuffer(clusterTransforms); Transform renderTransform = modelTransform; @@ -297,7 +300,7 @@ void Model::updateRenderItems() { } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); data.setLayer(isLayeredInFront, isLayeredInHUD); data.setShapeKey(invalidatePayloadShapeKey, isWireframe); }); @@ -681,22 +684,25 @@ void Model::calculateTriangleSets() { } } -void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene) { - if (_isVisible != isVisible) { +void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits) { + if (_isVisible != isVisible || _viewTagBits != viewTagBits) { _isVisible = isVisible; + _viewTagBits = viewTagBits; bool isLayeredInFront = _isLayeredInFront; bool isLayeredInHUD = _isLayeredInHUD; render::Transaction transaction; foreach (auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + isLayeredInHUD](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + isLayeredInHUD](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); }); } scene->enqueueTransaction(transaction); @@ -709,18 +715,21 @@ void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& _isLayeredInFront = isLayeredInFront; bool isVisible = _isVisible; + uint8_t viewTagBits = _viewTagBits; bool isLayeredInHUD = _isLayeredInHUD; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + isLayeredInHUD](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + isLayeredInHUD](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } @@ -733,18 +742,21 @@ void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& sce _isLayeredInHUD = isLayeredInHUD; bool isVisible = _isVisible; + uint8_t viewTagBits = _viewTagBits; bool isLayeredInFront = _isLayeredInFront; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + isLayeredInHUD](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, + isLayeredInHUD](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 027d52ecfd..ca0904f334 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -86,7 +86,7 @@ public: const QUrl& getURL() const { return _url; } // new Scene/Engine rendering support - void setVisibleInScene(bool isVisible, const render::ScenePointer& scene); + void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits); void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene); void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene); bool needsFixupInScene() const; @@ -104,6 +104,7 @@ public: bool isRenderable() const; bool isVisible() const { return _isVisible; } + uint8_t getViewTagBits() const { return _viewTagBits; } bool isLayeredInFront() const { return _isLayeredInFront; } bool isLayeredInHUD() const { return _isLayeredInHUD; } @@ -396,6 +397,7 @@ protected: QUrl _url; bool _isVisible; + uint8_t _viewTagBits{ render::ItemKey::TAG_BITS_ALL }; gpu::Buffers _blendedVertexBuffers; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index d83dfd73a5..19a3f4ed73 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -200,7 +200,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con }); } -void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) { +void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&) { return true; }; // Prepare the ShapePipeline @@ -216,7 +216,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende task.addJob("ShadowSetup"); for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { - const auto setupOutput = task.addJob("ShadowCascadeSetup", i); + const auto setupOutput = task.addJob("ShadowCascadeSetup", i, tagBits, tagMask); const auto shadowFilter = setupOutput.getN(1); // CPU jobs: @@ -264,7 +264,7 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow && _cascadeIndexgetCascadeCount()) { - output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); + output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered().withTagBits(_tagBits, _tagMask); globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR); diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index d8d4c624e7..33e0ad4daa 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -48,7 +48,7 @@ public: using JobModel = render::Task::Model; RenderShadowTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00); void configure(const Config& configuration); }; @@ -67,12 +67,14 @@ public: using Outputs = render::VaryingSet3; using JobModel = render::Job::ModelO; - RenderShadowCascadeSetup(unsigned int cascadeIndex) : _cascadeIndex{ cascadeIndex } {} + RenderShadowCascadeSetup(unsigned int cascadeIndex, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00) : _cascadeIndex{ cascadeIndex }, _tagBits(tagBits), _tagMask(tagMask) {} void run(const render::RenderContextPointer& renderContext, Outputs& output); private: unsigned int _cascadeIndex; + uint8_t _tagBits{ 0x00 }; + uint8_t _tagMask{ 0x00 }; }; class RenderShadowCascadeTeardown { diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index dc6c66e058..19924b4ddc 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -14,7 +14,7 @@ #include "RenderDeferredTask.h" #include "RenderForwardTask.h" -void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) { +void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits, uint8_t tagMask) { // auto items = input.get(); // Shadows use an orthographic projection because they are linked to sunlights @@ -28,9 +28,9 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render: const auto threshold = 1e-3f; return relativeBoundRadius > threshold; return true; - }); + }, tagBits, tagMask); - const auto items = task.addJob("FetchCullSort", cullFunctor); + const auto items = task.addJob("FetchCullSort", cullFunctor, tagBits, tagMask); assert(items.canCast()); if (isDeferred) { diff --git a/libraries/render-utils/src/RenderViewTask.h b/libraries/render-utils/src/RenderViewTask.h index eb61f56eab..5da3d18474 100644 --- a/libraries/render-utils/src/RenderViewTask.h +++ b/libraries/render-utils/src/RenderViewTask.h @@ -23,7 +23,7 @@ public: RenderViewTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00); }; diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 70331cdb47..8d99c3e8f2 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -61,7 +61,7 @@ void render::cullItems(const RenderContextPointer& renderContext, const CullFunc details._rendered += (int)outItems.size(); } -void FetchNonspatialItems::run(const RenderContextPointer& renderContext, ItemBounds& outItems) { +void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemBounds& outItems) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); auto& scene = renderContext->_scene; @@ -72,7 +72,9 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, ItemBo outItems.reserve(items.size()); for (auto& id : items) { auto& item = scene->getItem(id); - outItems.emplace_back(ItemBound(id, item.getBound())); + if (filter.test(item.getKey())) { + outItems.emplace_back(ItemBound(id, item.getBound())); + } } } diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 486c4f4cdf..4461537109 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -24,8 +24,8 @@ namespace render { class FetchNonspatialItems { public: - using JobModel = Job::ModelO; - void run(const RenderContextPointer& renderContext, ItemBounds& outItems); + using JobModel = Job::ModelIO; + void run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemBounds& outItems); }; class FetchSpatialTreeConfig : public Job::Config { diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index 036c7d3a99..612dba076b 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -34,6 +34,21 @@ const int Item::LAYER_3D = 1; const int Item::LAYER_3D_FRONT = 2; const int Item::LAYER_3D_HUD = 3; +const uint8_t ItemKey::TAG_BITS_ALL { 0xFF }; +const uint8_t ItemKey::TAG_BITS_NONE { 0x00 }; +const uint8_t ItemKey::TAG_BITS_0 { 0x01 }; +const uint8_t ItemKey::TAG_BITS_1 { 0x02 }; +const uint8_t ItemKey::TAG_BITS_2 { 0x04 }; +const uint8_t ItemKey::TAG_BITS_3 { 0x08 }; +const uint8_t ItemKey::TAG_BITS_4 { 0x10 }; +const uint8_t ItemKey::TAG_BITS_5 { 0x20 }; +const uint8_t ItemKey::TAG_BITS_6 { 0x40 }; +const uint8_t ItemKey::TAG_BITS_7 { 0x80 }; + +const uint32_t ItemKey::KEY_TAG_BITS_MASK = ((uint32_t) ItemKey::TAG_BITS_ALL) << FIRST_TAG_BIT; + + + void Item::Status::Value::setScale(float scale) { _scale = (std::numeric_limits::max() -1) * 0.5f * (1.0f + std::max(std::min(scale, 1.0f), 0.0f)); } diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index e977c95fa0..ff4b3a0458 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -38,25 +38,62 @@ class Context; // Key is the KEY to filter Items and create specialized lists class ItemKey { public: - enum FlagBit { + // 8 tags are available to organize the items and filter them against as fields of the ItemKey. + // TAG & TAG_BITS are defined from several bits in the Key. + // An Item can be tagged and filtering can rely on the tags to keep or exclude items + // ItemKey are not taged by default + enum Tag : uint8_t { + TAG_0 = 0, // 8 Tags + TAG_1, + TAG_2, + TAG_3, + TAG_4, + TAG_5, + TAG_6, + TAG_7, + + NUM_TAGS + }; + // Tag bits are derived from the Tag enum + const static uint8_t TAG_BITS_ALL; + const static uint8_t TAG_BITS_NONE; + const static uint8_t TAG_BITS_0; + const static uint8_t TAG_BITS_1; + const static uint8_t TAG_BITS_2; + const static uint8_t TAG_BITS_3; + const static uint8_t TAG_BITS_4; + const static uint8_t TAG_BITS_5; + const static uint8_t TAG_BITS_6; + const static uint8_t TAG_BITS_7; + + enum FlagBit : uint32_t { TYPE_SHAPE = 0, // Item is a Shape TYPE_LIGHT, // Item is a Light TYPE_META, // Item is a Meta: meanning it s used to represent a higher level object, potentially represented by other render items + TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work... VIEW_SPACE, // Transformed in view space, and not in world space DYNAMIC, // Dynamic and bound will change unlike static item DEFORMED, // Deformed within bound, not solid - INVISIBLE, // Visible or not? could be just here to cast shadow + INVISIBLE, // Visible or not in the scene? SHADOW_CASTER, // Item cast shadows - PICKABLE, // Item can be picked/selected LAYERED, // Item belongs to one of the layers different from the default layer - SMALLER, + FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against + LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS, + + __SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells) NUM_FLAGS, // Not a valid flag }; typedef std::bitset Flags; + // All the bits touching tag bits sets to true + const static uint32_t KEY_TAG_BITS_MASK; + static uint32_t evalTagBitsWithKeyBits(uint8_t tagBits, const uint32_t keyBits) { + return (keyBits & ~KEY_TAG_BITS_MASK) | (((uint32_t)tagBits) << FIRST_TAG_BIT); + } + // The key is the Flags Flags _flags; @@ -84,9 +121,12 @@ public: Builder& withDeformed() { _flags.set(DEFORMED); return (*this); } Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); } Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); } - Builder& withPickable() { _flags.set(PICKABLE); return (*this); } Builder& withLayered() { _flags.set(LAYERED); return (*this); } + Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); } + // Set ALL the tags in one call using the Tag bits + Builder& withTagBits(uint8_t tagBits) { _flags = evalTagBitsWithKeyBits(tagBits, _flags.to_ulong()); return (*this); } + // Convenient standard keys that we will keep on using all over the place static Builder opaqueShape() { return Builder().withTypeShape(); } static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); } @@ -116,14 +156,15 @@ public: bool isShadowCaster() const { return _flags[SHADOW_CASTER]; } - bool isPickable() const { return _flags[PICKABLE]; } - bool isLayered() const { return _flags[LAYERED]; } bool isSpatial() const { return !isLayered(); } + bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; } + uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); } + // Probably not public, flags used by the scene - bool isSmall() const { return _flags[SMALLER]; } - void setSmaller(bool smaller) { (smaller ? _flags.set(SMALLER) : _flags.reset(SMALLER)); } + bool isSmall() const { return _flags[__SMALLER]; } + void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); } bool operator==(const ItemKey& key) { return (_flags == key._flags); } bool operator!=(const ItemKey& key) { return (_flags != key._flags); } @@ -177,11 +218,14 @@ public: Builder& withNoShadowCaster() { _value.reset(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); } Builder& withShadowCaster() { _value.set(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); } - Builder& withPickable() { _value.set(ItemKey::PICKABLE); _mask.set(ItemKey::PICKABLE); return (*this); } - Builder& withoutLayered() { _value.reset(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); } Builder& withLayered() { _value.set(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); } + Builder& withoutTag(ItemKey::Tag tagIndex) { _value.reset(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } + Builder& withTag(ItemKey::Tag tagIndex) { _value.set(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } + // Set ALL the tags in one call using the Tag bits and the Tag bits touched + Builder& withTagBits(uint8_t tagBits, uint8_t tagMask) { _value = ItemKey::evalTagBitsWithKeyBits(tagBits, _value.to_ulong()); _mask = ItemKey::evalTagBitsWithKeyBits(tagMask, _mask.to_ulong()); return (*this); } + Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); } // Convenient standard keys that we will keep on using all over the place diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index d7294fa2bd..7f60d5bb52 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -17,19 +17,21 @@ using namespace render; -void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor) { +void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; }; // CPU jobs: // Fetch and cull the items from the scene - const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered(); + const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered().withTagBits(tagBits, tagMask); const auto spatialFilter = render::Varying(filter); const auto spatialSelection = task.addJob("FetchSceneSelection", spatialFilter); const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, spatialFilter).asVarying(); const auto culledSpatialSelection = task.addJob("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM); // Overlays are not culled - const auto nonspatialSelection = task.addJob("FetchOverlaySelection"); + const ItemFilter overlayfilter = ItemFilter::Builder().withVisible().withTagBits(tagBits, tagMask); + const auto nonspatialFilter = render::Varying(overlayfilter); + const auto nonspatialSelection = task.addJob("FetchOverlaySelection", nonspatialFilter); // Multi filter visible items into different buckets const int NUM_SPATIAL_FILTERS = 4; diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index b25480ae3a..8c9f2e7304 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -36,7 +36,7 @@ public: RenderFetchCullSortTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00); }; #endif // hifi_RenderFetchCullSortTask_h