diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 81eee6b3a7..ab4ae02a8e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -62,7 +62,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(); + return ItemKey::Builder::opaqueShape().withTypeMeta(); } template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) { return static_pointer_cast(avatar)->getBounds(); @@ -74,6 +74,15 @@ namespace render { avatarPtr->render(args, qApp->getCamera()->getPosition()); } } + template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems) { + auto avatarPtr = static_pointer_cast(avatar); + if (avatarPtr->getSkeletonModel()) { + auto metaSubItems = avatarPtr->getSkeletonModel()->fetchRenderItemIDs(); + subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end()); + return (uint32_t) metaSubItems.size(); + } + return 0; + } } static uint64_t timeProcessingJoints = 0; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index d03a8e9a54..d370402865 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -32,6 +32,7 @@ namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar); template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar); template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args); + template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems); } static const float SCALING_RATIO = .05f; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 359b050803..be9ef08c0b 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -15,21 +15,21 @@ namespace render { template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload) { - if (payload && payload->entity) { - if (payload->entity->getType() == EntityTypes::Light) { - return ItemKey::Builder::light(); + if (payload && payload->_entity) { + if (payload->_entity->getType() == EntityTypes::Light) { + return ItemKey::Builder::light().withTypeMeta(); } - if (payload && payload->entity->isTransparent()) { - return ItemKey::Builder::transparentShape(); + if (payload && payload->_entity->isTransparent()) { + return ItemKey::Builder::transparentShape().withTypeMeta(); } } - return ItemKey::Builder::opaqueShape(); + return ItemKey::Builder::opaqueShape().withTypeMeta(); } template <> const Item::Bound payloadGetBound(const RenderableEntityItemProxy::Pointer& payload) { - if (payload && payload->entity) { + if (payload && payload->_entity) { bool success; - auto result = payload->entity->getAABox(success); + auto result = payload->_entity->getAABox(success); if (!success) { return render::Item::Bound(); } @@ -39,11 +39,19 @@ namespace render { } template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args) { if (args) { - if (payload && payload->entity && payload->entity->getVisible()) { - payload->entity->render(args); + if (payload && payload->_entity && payload->_entity->getVisible()) { + payload->_entity->render(args); } } } + template <> uint32_t metaFetchMetaSubItems(const RenderableEntityItemProxy::Pointer& payload, ItemIDs& subItems) { + auto metaID = payload->_metaID; + if (Item::isValidID(metaID)) { + subItems.emplace_back(metaID); + return 1; + } + return 0; + } } void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status::Getters& statusGetters) { diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index ec65bab1c8..98271ddbbb 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -36,17 +36,19 @@ void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status: class RenderableEntityItemProxy { public: - RenderableEntityItemProxy(EntityItemPointer entity) : entity(entity) { } + RenderableEntityItemProxy(EntityItemPointer entity, render::ItemID metaID) : _entity(entity), _metaID(metaID) { } typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - EntityItemPointer entity; + EntityItemPointer _entity; + render::ItemID _metaID; }; namespace render { template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload); template <> const Item::Bound payloadGetBound(const RenderableEntityItemProxy::Pointer& payload); template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args); + template <> uint32_t metaFetchMetaSubItems(const RenderableEntityItemProxy::Pointer& payload, ItemIDs& subItems); } // Mixin class for implementing basic single item rendering @@ -55,7 +57,7 @@ public: bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { _myItem = scene->allocateID(); - auto renderData = std::make_shared(self); + auto renderData = std::make_shared(self, _myItem); auto renderPayload = std::make_shared(renderData); render::Item::Status::Getters statusGetters; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 55c766c267..945726255c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -194,7 +194,7 @@ public: namespace render { template <> const ItemKey payloadGetKey(const RenderableModelEntityItemMeta::Pointer& payload) { - return ItemKey::Builder::opaqueShape(); + return ItemKey::Builder::opaqueShape().withTypeMeta(); } template <> const Item::Bound payloadGetBound(const RenderableModelEntityItemMeta::Pointer& payload) { @@ -216,6 +216,15 @@ namespace render { } } } + template <> uint32_t metaFetchMetaSubItems(const RenderableModelEntityItemMeta::Pointer& payload, ItemIDs& subItems) { + auto modelEntity = std::static_pointer_cast(payload->entity); + if (modelEntity->hasModel()) { + auto metaSubItems = modelEntity->getModelNotSafe()->fetchRenderItemIDs(); + subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end()); + return (uint32_t) metaSubItems.size(); + } + return 0; + } } bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr scene, @@ -473,6 +482,10 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } } +ModelPointer RenderableModelEntityItem::getModelNotSafe() { + return _model; +} + ModelPointer RenderableModelEntityItem::getModel(QSharedPointer renderer) { if (!renderer) { return nullptr; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 93d48c6085..bac2118326 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -52,6 +52,7 @@ public: BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const override; ModelPointer getModel(QSharedPointer renderer); + ModelPointer getModelNotSafe(); virtual bool needsToCallUpdate() const override; virtual void update(const quint64& now) override; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 3a3095458c..14391b9f16 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -673,6 +673,7 @@ bool Model::addToScene(std::shared_ptr scene, hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent(); verticesCount += renderItem.get()->getVerticesCount(); _modelMeshRenderItems.insert(item, renderPayload); + _modelMeshRenderItemIDs.emplace_back(item); } somethingAdded = !_modelMeshRenderItems.empty(); @@ -695,6 +696,7 @@ void Model::removeFromScene(std::shared_ptr scene, render::Pendin foreach (auto item, _modelMeshRenderItems.keys()) { pendingChanges.removeItem(item); } + _modelMeshRenderItemIDs.clear(); _modelMeshRenderItems.clear(); _modelMeshRenderItemsSet.clear(); @@ -1301,6 +1303,10 @@ AABox Model::getRenderableMeshBound() const { } } +const render::ItemIDs& Model::fetchRenderItemIDs() const { + return _modelMeshRenderItemIDs; +} + void Model::createRenderItemSet() { if (_collisionGeometry) { if (_collisionRenderItemsSet.empty()) { @@ -1479,6 +1485,7 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) { { Lock lock(_mutex); + _modelsRequiringBlends.insert(model); } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 55806b27e1..a11d6d511e 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -105,6 +105,7 @@ public: void setRenderItemsNeedUpdate() { _renderItemsNeedUpdate = true; } bool getRenderItemsNeedUpdate() { return _renderItemsNeedUpdate; } AABox getRenderableMeshBound() const; + const render::ItemIDs& fetchRenderItemIDs() const; bool maybeStartBlender(); @@ -389,6 +390,8 @@ protected: QSet> _modelMeshRenderItemsSet; QMap _modelMeshRenderItems; + render::ItemIDs _modelMeshRenderItemIDs; + bool _addedToScene { false }; // has been added to scene bool _needsFixupInScene { true }; // needs to be removed/re-added to scene bool _needsReload { true }; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index f8cd112007..e0192b5f85 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -53,14 +53,15 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { ShapePlumberPointer shapePlumber = std::make_shared(); initDeferredPipelines(*shapePlumber); - // Extract opaques / transparents / lights / overlays - const auto opaques = items[0]; - const auto transparents = items[1]; - const auto lights = items[2]; - const auto overlayOpaques = items[3]; - const auto overlayTransparents = items[4]; - const auto background = items[5]; - const auto spatialSelection = items[6]; + // Extract opaques / transparents / lights / metas / overlays / background + const auto opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; + const auto transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; + const auto lights = items[RenderFetchCullSortTask::LIGHT]; + const auto metas = items[RenderFetchCullSortTask::META]; + const auto overlayOpaques = items[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; + const auto overlayTransparents = items[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; + const auto background = items[RenderFetchCullSortTask::BACKGROUND]; + const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION]; // Prepare deferred, generate the shared Deferred Frame Transform const auto deferredFrameTransform = addJob("DeferredFrameTransform"); @@ -158,6 +159,11 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { // Debugging stages { + + + // Bounds do not draw on stencil buffer, so they must come last + addJob("DrawMetaBounds", metas); + // Debugging Deferred buffer job const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); addJob("DebugDeferredBuffer", debugFramebuffers); diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index c7a3433c96..45a32c1aaf 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -24,8 +24,6 @@ #include -#include -#include #include "nop_frag.h" using namespace render; @@ -36,13 +34,15 @@ RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) { ShapePlumberPointer shapePlumber = std::make_shared(); initForwardPipelines(*shapePlumber); - // Extract opaques / transparents / lights / overlays - const auto opaques = items[0]; - const auto transparents = items[1]; - const auto lights = items[2]; - const auto overlayOpaques = items[3]; - const auto overlayTransparents = items[4]; - const auto background = items[5]; + // Extract opaques / transparents / lights / metas / overlays / background + const auto opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; + const auto transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; + const auto lights = items[RenderFetchCullSortTask::LIGHT]; + const auto metas = items[RenderFetchCullSortTask::META]; + const auto overlayOpaques = items[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; + const auto overlayTransparents = items[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; + const auto background = items[RenderFetchCullSortTask::BACKGROUND]; + const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION]; const auto framebuffer = addJob("PrepareFramebuffer"); @@ -180,57 +180,4 @@ void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderCo args->_batch = nullptr; } -const gpu::PipelinePointer DrawBounds::getPipeline() { - if (!_boundsPipeline) { - auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); - auto ps = gpu::Shader::createPixel(std::string(drawItemBounds_frag)); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - gpu::Shader::BindingSet slotBindings; - gpu::Shader::makeProgram(*program, slotBindings); - - _cornerLocation = program->getUniforms().findLocation("inBoundPos"); - _scaleLocation = program->getUniforms().findLocation("inBoundDim"); - - auto state = std::make_shared(); - state->setDepthTest(true, false, gpu::LESS_EQUAL); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); - - _boundsPipeline = gpu::Pipeline::create(program, state); - } - return _boundsPipeline; -} - -void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, - const Inputs& items) { - RenderArgs* args = renderContext->args; - - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - args->_batch = &batch; - - // Setup projection - glm::mat4 projMat; - Transform viewMat; - args->getViewFrustum().evalProjectionMatrix(projMat); - args->getViewFrustum().evalViewTransform(viewMat); - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - batch.setModelTransform(Transform()); - - // Bind program - batch.setPipeline(getPipeline()); - assert(_cornerLocation >= 0); - assert(_scaleLocation >= 0); - - // Render bounds - for (const auto& item : items) { - batch._glUniform3fv(_cornerLocation, 1, (const float*)(&item.bound.getCorner())); - batch._glUniform3fv(_scaleLocation, 1, (const float*)(&item.bound.getScale())); - - static const int NUM_VERTICES_PER_CUBE = 24; - batch.draw(gpu::LINES, NUM_VERTICES_PER_CUBE, 0); - } - }); -} diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index a957f7493e..62cbca4382 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -68,25 +68,4 @@ public: const Inputs& background); }; -class DrawBounds { -public: - class Config : public render::JobConfig { - public: - Config() : JobConfig(false) {} - }; - - using Inputs = render::ItemBounds; - using JobModel = render::Job::ModelI; - - void configure(const Config& configuration) {} - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, - const Inputs& items); - -private: - const gpu::PipelinePointer getPipeline(); - gpu::PipelinePointer _boundsPipeline; - int _cornerLocation { -1 }; - int _scaleLocation { -1 }; -}; - #endif // hifi_RenderForwardTask_h diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 56729083dd..1a709ed102 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -170,7 +170,6 @@ namespace render { for (size_t i = 0; i < NUM_FILTERS; i++) { if (_filters[i].test(itemKey)) { outItems[i].template edit().emplace_back(itemBound); - break; } } } diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 1c9a92c511..2829c6f8e7 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -19,6 +19,10 @@ #include #include + +#include +#include + using namespace render; void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, int maxDrawnItems) { @@ -134,3 +138,59 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext auto config = std::static_pointer_cast(renderContext->jobConfig); config->setNumDrawn((int)inLights.size()); } + +const gpu::PipelinePointer DrawBounds::getPipeline() { + if (!_boundsPipeline) { + auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); + auto ps = gpu::Shader::createPixel(std::string(drawItemBounds_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + _cornerLocation = program->getUniforms().findLocation("inBoundPos"); + _scaleLocation = program->getUniforms().findLocation("inBoundDim"); + + auto state = std::make_shared(); + state->setDepthTest(true, false, gpu::LESS_EQUAL); + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + _boundsPipeline = gpu::Pipeline::create(program, state); + } + return _boundsPipeline; +} + +void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const Inputs& items) { + RenderArgs* args = renderContext->args; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + // Setup projection + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + // Bind program + batch.setPipeline(getPipeline()); + assert(_cornerLocation >= 0); + assert(_scaleLocation >= 0); + + // Render bounds + for (const auto& item : items) { + batch._glUniform3fv(_cornerLocation, 1, (const float*)(&item.bound.getCorner())); + batch._glUniform3fv(_scaleLocation, 1, (const float*)(&item.bound.getScale())); + + static const int NUM_VERTICES_PER_CUBE = 24; + batch.draw(gpu::LINES, NUM_VERTICES_PER_CUBE, 0); + } + }); +} + diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index aa564980c4..27f07921c3 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -50,6 +50,27 @@ protected: int _maxDrawn; // initialized by Config }; +class DrawBounds { +public: + class Config : public render::JobConfig { + public: + Config() : JobConfig(false) {} + }; + + using Inputs = render::ItemBounds; + using JobModel = render::Job::ModelI; + + void configure(const Config& configuration) {} + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + const Inputs& items); + +private: + const gpu::PipelinePointer getPipeline(); + gpu::PipelinePointer _boundsPipeline; + int _cornerLocation { -1 }; + int _scaleLocation { -1 }; +}; + } #endif // hifi_render_DrawTask_h diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 9a65b48021..551b48fd7d 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -38,6 +38,7 @@ public: enum FlagBit { 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 @@ -72,6 +73,7 @@ public: Builder& withTypeShape() { _flags.set(TYPE_SHAPE); return (*this); } Builder& withTypeLight() { _flags.set(TYPE_LIGHT); return (*this); } + Builder& withTypeMeta() { _flags.set(TYPE_META); return (*this); } Builder& withTransparent() { _flags.set(TRANSLUCENT); return (*this); } Builder& withViewSpace() { _flags.set(VIEW_SPACE); return (*this); } Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); } @@ -91,6 +93,7 @@ public: bool isShape() const { return _flags[TYPE_SHAPE]; } bool isLight() const { return _flags[TYPE_LIGHT]; } + bool isMeta() const { return _flags[TYPE_META]; } bool isOpaque() const { return !_flags[TRANSLUCENT]; } bool isTransparent() const { return _flags[TRANSLUCENT]; } @@ -150,6 +153,7 @@ public: Builder& withTypeShape() { _value.set(ItemKey::TYPE_SHAPE); _mask.set(ItemKey::TYPE_SHAPE); return (*this); } Builder& withTypeLight() { _value.set(ItemKey::TYPE_LIGHT); _mask.set(ItemKey::TYPE_LIGHT); return (*this); } + Builder& withTypeMeta() { _value.set(ItemKey::TYPE_META); _mask.set(ItemKey::TYPE_META); return (*this); } Builder& withOpaque() { _value.reset(ItemKey::TRANSLUCENT); _mask.set(ItemKey::TRANSLUCENT); return (*this); } Builder& withTransparent() { _value.set(ItemKey::TRANSLUCENT); _mask.set(ItemKey::TRANSLUCENT); return (*this); } @@ -179,6 +183,7 @@ public: static Builder opaqueShape() { return Builder().withTypeShape().withOpaque().withWorldSpace(); } static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); } static Builder light() { return Builder().withTypeLight(); } + static Builder meta() { return Builder().withTypeMeta(); } static Builder background() { return Builder().withViewSpace().withLayered(); } static Builder opaqueShapeLayered() { return Builder().withTypeShape().withOpaque().withWorldSpace().withLayered(); } static Builder transparentShapeLayered() { return Builder().withTypeShape().withTransparent().withWorldSpace().withLayered(); } @@ -210,6 +215,25 @@ inline QDebug operator<<(QDebug debug, const ItemFilter& me) { using ItemID = uint32_t; using ItemCell = int32_t; +// A few typedefs for standard containers of ItemIDs +using ItemIDs = std::vector; +using ItemIDSet = std::set; + +// Handy type to just pass the ID and the bound of an item +class ItemBound { + public: + ItemBound(ItemID id) : id(id) { } + ItemBound(ItemID id, const AABox& bound) : id(id), bound(bound) { } + + ItemID id; + AABox bound; +}; + +// many Item Bounds in a vector +using ItemBounds = std::vector; + +// Item is the proxy to a bounded "object" in the scene +// An item is described by its Key class Item { public: typedef std::vector Vector; @@ -295,6 +319,8 @@ public: virtual const ShapeKey getShapeKey() const = 0; + virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const = 0; + ~PayloadInterface() {} // Status interface is local to the base class @@ -313,6 +339,9 @@ public: Item() {} ~Item() {} + // Item exists if it has a valid payload + bool exist() const { return (bool)(_payload); } + // Main scene / item managment interface reset/update/kill void resetPayload(const PayloadPointer& payload); void resetCell(ItemCell cell = INVALID_CELL, bool _small = false) { _cell = cell; _key.setSmaller(_small); } @@ -339,6 +368,9 @@ public: // Shape Type Interface const ShapeKey getShapeKey() const { return _payload->getShapeKey(); } + // Meta Type Interface + uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return _payload->fetchMetaSubItems(subItems); } + // Access the status const StatusPointer& getStatus() const { return _payload->getStatus(); } @@ -370,10 +402,7 @@ inline QDebug operator<<(QDebug debug, const Item& item) { return debug; } -// THe Payload class is the real Payload to be used -// THis allow anything to be turned into a Payload as long as the required interface functions are available -// When creating a new kind of payload from a new "stuff" class then you need to create specialized version for "stuff" -// of the Payload interface +// Item shared interface supported by the payload template const ItemKey payloadGetKey(const std::shared_ptr& payloadData) { return ItemKey(); } template const Item::Bound payloadGetBound(const std::shared_ptr& payloadData) { return Item::Bound(); } template int payloadGetLayer(const std::shared_ptr& payloadData) { return 0; } @@ -385,6 +414,14 @@ template void payloadRender(const std::shared_ptr& payloadData, Ren // implying that the shape will setup its own pipeline without the use of the ShapeKey. template const ShapeKey shapeGetShapeKey(const std::shared_ptr& payloadData) { return ShapeKey::Builder::ownPipeline(); } +// Meta Type Interface +// Meta items act as the grouping object for several sub items (typically shapes). +template uint32_t metaFetchMetaSubItems(const std::shared_ptr& payloadData, ItemIDs& subItems) { return 0; } + +// THe Payload class is the real Payload to be used +// THis allow anything to be turned into a Payload as long as the required interface functions are available +// When creating a new kind of payload from a new "stuff" class then you need to create specialized version for "stuff" +// of the Payload interface template class Payload : public Item::PayloadInterface { public: typedef std::shared_ptr DataPointer; @@ -403,6 +440,9 @@ public: // Shape Type interface virtual const ShapeKey getShapeKey() const override { return shapeGetShapeKey(_data); } + // Meta Type Interface + virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const override { return metaFetchMetaSubItems(_data, subItems); } + protected: DataPointer _data; @@ -450,22 +490,6 @@ template <> const Item::Bound payloadGetBound(const FooPointer& foo) { typedef Item::PayloadPointer PayloadPointer; typedef std::vector< PayloadPointer > Payloads; -// A few typedefs for standard containers of ItemIDs -using ItemIDs = std::vector; -using ItemIDSet = std::set; - -// Handy type to just pass the ID and the bound of an item -class ItemBound { -public: - ItemBound(ItemID id) : id(id) { } - ItemBound(ItemID id, const AABox& bound) : id(id), bound(bound) { } - - ItemID id; - AABox bound; -}; -// many Item Bounds in a vector -using ItemBounds = std::vector; - // A map of items by ShapeKey to optimize rendering pipeline assignments using ShapeBounds = std::unordered_map; diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index 3195d8c5f8..69c415dffd 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -29,33 +29,41 @@ RenderFetchCullSortTask::RenderFetchCullSortTask(CullFunctor cullFunctor) { const auto nonspatialSelection = addJob("FetchOverlaySelection"); // Multi filter visible items into different buckets - const int NUM_FILTERS = 3; + const int NUM_SPATIAL_FILTERS = 4; + const int NUM_NON_SPATIAL_FILTERS = 3; const int OPAQUE_SHAPE_BUCKET = 0; const int TRANSPARENT_SHAPE_BUCKET = 1; const int LIGHT_BUCKET = 2; + const int META_BUCKET = 3; const int BACKGROUND_BUCKET = 2; - MultiFilterItem::ItemFilterArray spatialFilters = { { + MultiFilterItem::ItemFilterArray spatialFilters = { { ItemFilter::Builder::opaqueShape(), ItemFilter::Builder::transparentShape(), - ItemFilter::Builder::light() + ItemFilter::Builder::light(), + ItemFilter::Builder::meta() } }; - MultiFilterItem::ItemFilterArray nonspatialFilters = { { + MultiFilterItem::ItemFilterArray nonspatialFilters = { { ItemFilter::Builder::opaqueShape(), ItemFilter::Builder::transparentShape(), ItemFilter::Builder::background() } }; - const auto filteredSpatialBuckets = addJob>("FilterSceneSelection", culledSpatialSelection, spatialFilters).get::ItemBoundsArray>(); - const auto filteredNonspatialBuckets = addJob>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters).get::ItemBoundsArray>(); + const auto filteredSpatialBuckets = + addJob>("FilterSceneSelection", culledSpatialSelection, spatialFilters) + .get::ItemBoundsArray>(); + const auto filteredNonspatialBuckets = + addJob>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters) + .get::ItemBoundsArray>(); // Extract opaques / transparents / lights / overlays const auto opaques = addJob("DepthSortOpaque", filteredSpatialBuckets[OPAQUE_SHAPE_BUCKET]); const auto transparents = addJob("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto lights = filteredSpatialBuckets[LIGHT_BUCKET]; + const auto metas = filteredSpatialBuckets[META_BUCKET]; const auto overlayOpaques = addJob("DepthSortOverlayOpaque", filteredNonspatialBuckets[OPAQUE_SHAPE_BUCKET]); const auto overlayTransparents = addJob("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET]; setOutput(Output{{ - opaques, transparents, lights, overlayOpaques, overlayTransparents, background, spatialSelection }}); + opaques, transparents, lights, metas, overlayOpaques, overlayTransparents, background, spatialSelection }}); } diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index bea45247b0..1af74939c9 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -19,7 +19,21 @@ class RenderFetchCullSortTask : public render::Task { public: - using Output = std::array; + + enum Buckets { + OPAQUE_SHAPE = 0, + TRANSPARENT_SHAPE, + LIGHT, + META, + OVERLAY_OPAQUE_SHAPE, + OVERLAY_TRANSPARENT_SHAPE, + BACKGROUND, + SPATIAL_SELECTION, + + NUM_BUCKETS + }; + + using Output = std::array; using JobModel = ModelO; RenderFetchCullSortTask(render::CullFunctor cullFunctor); diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index 95fef3e9f0..076879ae25 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -58,7 +58,7 @@ ItemID Scene::allocateID() { return _IDAllocator.fetch_add(1); } -bool Scene::isAllocatedID(const ItemID& id) { +bool Scene::isAllocatedID(const ItemID& id) const { return Item::isValidID(id) && (id < _numAllocatedItems.load()); } diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 13475d0556..f2f8403dc9 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -61,7 +61,7 @@ public: ItemID allocateID(); // Check that the ID is valid and allocated for this scene, this a threadsafe call - bool isAllocatedID(const ItemID& id); + bool isAllocatedID(const ItemID& id) const; // THis is the total number of allocated items, this a threadsafe call size_t getNumItems() const { return _numAllocatedItems.load(); } @@ -78,6 +78,9 @@ public: // WARNING, There is No check on the validity of the ID, so this could return a bad Item const Item& getItem(const ItemID& id) const { return _items[id]; } + // Same as getItem, checking if the id is valid + const Item getItemSafe(const ItemID& id) const { if (isAllocatedID(id)) { return _items[id]; } else { return Item(); } } + // Access the spatialized items const ItemSpatialTree& getSpatialTree() const { return _masterSpatialTree; } diff --git a/scripts/developer/utilities/render/debugDeferredLighting.js b/scripts/developer/utilities/render/debugDeferredLighting.js index b32a924c10..625f71f8a4 100644 --- a/scripts/developer/utilities/render/debugDeferredLighting.js +++ b/scripts/developer/utilities/render/debugDeferredLighting.js @@ -13,7 +13,7 @@ var qml = Script.resolvePath('deferredLighting.qml'); var window = new OverlayWindow({ title: 'Lighting', source: qml, - width: 400, height:220, + width: 400, height:280, }); window.setPosition(Window.innerWidth - 420, 50); window.closed.connect(function() { Script.stop(); }); diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 4901be8e03..26dbc1f2bc 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -74,7 +74,7 @@ Column { Column { spacing: 10 Repeater { - model: [ "Tone Mapping exposure:ToneMapping:exposure:5.0:-5.0" + model: [ "Tone Mapping Exposure:ToneMapping:exposure:5.0:-5.0" ] ConfigSlider { label: qsTr(modelData.split(":")[0]) @@ -88,7 +88,7 @@ Column { Row { Label { - text: "Debug Framebuffer" + text: "Tone Mapping Curve" anchors.left: root.left } @@ -109,6 +109,7 @@ Column { } Row { id: framebuffer + spacing: 10 Label { text: "Debug Framebuffer" @@ -156,5 +157,14 @@ Column { onCurrentIndexChanged: { framebuffer.setDebugMode(currentIndex) } } } + + Row { + id: metas + CheckBox { + text: "Draw Meta Bounds" + checked: Render.getConfig("DrawMetaBounds")["enabled"] + onCheckedChanged: { Render.getConfig("DrawMetaBounds")["enabled"] = checked } + } + } }