diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8a35ec21a0..c3ea0b0af0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -672,7 +672,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : initializeGL(); // Start rendering - _renderEngine->addTask(make_shared()); + _renderEngine->addTask(make_shared(LODManager::shouldRender)); _renderEngine->registerScene(_main3DScene); _offscreenContext->makeCurrent(); @@ -3826,7 +3826,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se auto renderInterface = DependencyManager::get(); auto renderContext = renderInterface->getRenderContext(); - renderArgs->_shouldRender = LODManager::shouldRender; renderArgs->_viewFrustum = getDisplayViewFrustum(); renderContext.setArgs(renderArgs); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index f7a4a9d913..2a8d3352b0 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1291,12 +1291,13 @@ void EntityTree::remapIDs() { recurseTreeWithOperator(&theOperator); } -bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues) { +bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, + bool skipThoseWithBadParents) { if (! entityDescription.contains("Entities")) { entityDescription["Entities"] = QVariantList(); } QScriptEngine scriptEngine; - RecurseOctreeToMapOperator theOperator(entityDescription, element, &scriptEngine, skipDefaultValues); + RecurseOctreeToMapOperator theOperator(entityDescription, element, &scriptEngine, skipDefaultValues, skipThoseWithBadParents); recurseTreeWithOperator(&theOperator); return true; } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 63bd53120f..b1d8a31254 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -199,7 +199,8 @@ public: void remapIDs(); - virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues) override; + virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, + bool skipThoseWithBadParents) override; virtual bool readFromMap(QVariantMap& entityDescription) override; float getContentsLargestDimension(); diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.cpp b/libraries/entities/src/RecurseOctreeToMapOperator.cpp index 81465bfaf5..e930d5ef5f 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.cpp +++ b/libraries/entities/src/RecurseOctreeToMapOperator.cpp @@ -16,12 +16,14 @@ RecurseOctreeToMapOperator::RecurseOctreeToMapOperator(QVariantMap& map, OctreeElementPointer top, QScriptEngine* engine, - bool skipDefaultValues) : + bool skipDefaultValues, + bool skipThoseWithBadParents) : RecurseOctreeOperator(), _map(map), _top(top), _engine(engine), - _skipDefaultValues(skipDefaultValues) + _skipDefaultValues(skipDefaultValues), + _skipThoseWithBadParents(skipThoseWithBadParents) { // if some element "top" was given, only save information for that element and its children. if (_top) { @@ -47,6 +49,10 @@ bool RecurseOctreeToMapOperator::postRecursion(OctreeElementPointer element) { QVariantList entitiesQList = qvariant_cast(_map["Entities"]); entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) { + if (_skipThoseWithBadParents && !entityItem->isParentIDValid()) { + return; // we weren't able to resolve a parent from _parentID, so don't save this entity. + } + EntityItemProperties properties = entityItem->getProperties(); QScriptValue qScriptValues; if (_skipDefaultValues) { diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.h b/libraries/entities/src/RecurseOctreeToMapOperator.h index 35c7f1b6a9..c64cf91b61 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.h +++ b/libraries/entities/src/RecurseOctreeToMapOperator.h @@ -13,7 +13,8 @@ class RecurseOctreeToMapOperator : public RecurseOctreeOperator { public: - RecurseOctreeToMapOperator(QVariantMap& map, OctreeElementPointer top, QScriptEngine* engine, bool skipDefaultValues); + RecurseOctreeToMapOperator(QVariantMap& map, OctreeElementPointer top, QScriptEngine* engine, bool skipDefaultValues, + bool skipThoseWithBadParents); bool preRecursion(OctreeElementPointer element); bool postRecursion(OctreeElementPointer element); private: @@ -22,4 +23,5 @@ public: QScriptEngine* _engine; bool _withinTop; bool _skipDefaultValues; + bool _skipThoseWithBadParents; }; diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index bdad5682a9..a685c2580c 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1919,7 +1919,7 @@ void Octree::writeToJSONFile(const char* fileName, OctreeElementPointer element, entityDescription["Version"] = (int) expectedVersion; // store the entity data - bool entityDescriptionSuccess = writeToMap(entityDescription, top, true); + bool entityDescriptionSuccess = writeToMap(entityDescription, top, true, true); if (!entityDescriptionSuccess) { qCritical("Failed to convert Entities to QVariantMap while saving to json."); return; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 789d0f5600..0939ae37f6 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -304,7 +304,8 @@ public: void writeToFile(const char* filename, OctreeElementPointer element = NULL, QString persistAsFileType = "svo"); void writeToJSONFile(const char* filename, OctreeElementPointer element = NULL, bool doGzip = false); void writeToSVOFile(const char* filename, OctreeElementPointer element = NULL); - virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues) = 0; + virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, + bool skipThoseWithBadParents) = 0; // Octree importers bool readFromFile(const char* filename); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 3419adafe8..fa15abe086 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -71,7 +71,9 @@ void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const Ren _toneMappingEffect.render(renderContext->getArgs()); } -RenderDeferredTask::RenderDeferredTask() : Task() { +RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) : Task() { + cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; }; + // Prepare the ShapePipelines ShapePlumberPointer shapePlumber = std::make_shared(); initDeferredPipelines(*shapePlumber); @@ -80,7 +82,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { auto fetchedOpaques = addJob("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { context->getItemsConfig().opaque.numFeed = count; })); - auto culledOpaques = addJob>("CullOpaque", fetchedOpaques); + auto culledOpaques = addJob>("CullOpaque", fetchedOpaques, cullFunctor); auto opaques = addJob("DepthSortOpaque", culledOpaques); // CPU only, create the list of renderedTransparents items @@ -90,7 +92,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { context->getItemsConfig().transparent.numFeed = count; } )); - auto culledTransparents = addJob>("CullTransparent", fetchedTransparents); + auto culledTransparents = addJob>("CullTransparent", fetchedTransparents, cullFunctor); auto transparents = addJob("DepthSortTransparent", culledTransparents, DepthSortItems(false)); // GPU Jobs: Start preparing the deferred and lighting buffer @@ -111,7 +113,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _occlusionJobIndex = (int)_jobs.size() - 1; // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. - addJob("DrawLight"); + addJob("DrawLight", cullFunctor); // DeferredBuffer is complete, now let's shade it into the LightingBuffer addJob("RenderDeferred"); @@ -186,6 +188,7 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend setAntialiasingStatus(renderContext->getFxaaStatus()); setToneMappingExposure(renderContext->getTone().exposure); setToneMappingToneCurve(renderContext->getTone().toneCurve); + // TODO: Allow runtime manipulation of culling ShouldRenderFunctor renderContext->getArgs()->_context->syncCache(); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 4fe0c75198..3c195f3492 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -12,10 +12,10 @@ #ifndef hifi_RenderDeferredTask_h #define hifi_RenderDeferredTask_h -#include "render/Engine.h" - #include "gpu/Pipeline.h" +#include "render/DrawTask.h" + #include "ToneMappingEffect.h" class SetupDeferred { @@ -113,15 +113,8 @@ public: class RenderDeferredTask : public render::Task { public: - RenderDeferredTask(); + RenderDeferredTask(render::CullFunctor cullFunctor); - int _drawDebugDeferredBufferIndex; - int _drawStatusJobIndex; - int _drawHitEffectJobIndex; - int _occlusionJobIndex; - int _antialiasingJobIndex; - int _toneMappingJobIndex; - void setDrawDebugDeferredBuffer(int draw) { enableJob(_drawDebugDeferredBufferIndex, draw >= 0); } bool doDrawDebugDeferredBuffer() const { return getEnableJob(_drawDebugDeferredBufferIndex); } @@ -147,6 +140,14 @@ public: int getToneMappingToneCurve() const; virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + +protected: + int _drawDebugDeferredBufferIndex; + int _drawStatusJobIndex; + int _drawHitEffectJobIndex; + int _occlusionJobIndex; + int _antialiasingJobIndex; + int _toneMappingJobIndex; }; #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index bc1c17e0d0..b5d6934350 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -78,7 +78,9 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const }); } -RenderShadowTask::RenderShadowTask() : Task() { +RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) : Task() { + cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; }; + // Prepare the ShapePipeline ShapePlumberPointer shapePlumber = std::make_shared(); { @@ -105,7 +107,7 @@ RenderShadowTask::RenderShadowTask() : Task() { auto fetchedItems = addJob("FetchShadowMap"); // CPU: Cull against KeyLight frustum (nearby viewing camera) - auto culledItems = addJob>("CullShadowMap", fetchedItems); + auto culledItems = addJob>("CullShadowMap", fetchedItems, cullFunctor); // CPU: Sort by pipeline auto sortedShapes = addJob("PipelineSortShadowSort", culledItems); @@ -143,6 +145,7 @@ void RenderShadowTask::run(const SceneContextPointer& sceneContext, const render // Set the keylight frustum args->_viewFrustum = globalLight->shadow.getFrustum().get(); + // TODO: Allow runtime manipulation of culling ShouldRenderFunctor for (auto job : _jobs) { job.run(sceneContext, renderContext); diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 4853022359..add021994a 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -15,7 +15,6 @@ #include #include -#include #include class ViewFrustum; @@ -33,7 +32,7 @@ protected: class RenderShadowTask : public render::Task { public: - RenderShadowTask(); + RenderShadowTask(render::CullFunctor shouldRender); void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); }; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 68e1841345..191cb693fd 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -20,14 +20,15 @@ using namespace render; -void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { +void render::cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details, + const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { assert(renderContext->getArgs()); assert(renderContext->getArgs()->_viewFrustum); RenderArgs* args = renderContext->getArgs(); - auto renderDetails = renderContext->getArgs()->_details._item; + ViewFrustum* frustum = args->_viewFrustum; - renderDetails->_considered += inItems.size(); + details._considered += inItems.size(); // Culling / LOD for (auto item : inItems) { @@ -41,24 +42,24 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont bool outOfView; { PerformanceTimer perfTimer("boxInFrustum"); - outOfView = args->_viewFrustum->boxInFrustum(item.bounds) == ViewFrustum::OUTSIDE; + outOfView = frustum->boxInFrustum(item.bounds) == ViewFrustum::OUTSIDE; } if (!outOfView) { bool bigEnoughToRender; { PerformanceTimer perfTimer("shouldRender"); - bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, item.bounds) : true; + bigEnoughToRender = cullFunctor(args, item.bounds); } if (bigEnoughToRender) { outItems.emplace_back(item); // One more Item to render } else { - renderDetails->_tooSmall++; + details._tooSmall++; } } else { - renderDetails->_outOfView++; + details._outOfView++; } } - renderDetails->_rendered += outItems.size(); + details._rendered += outItems.size(); } struct ItemBound { @@ -202,10 +203,10 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext RenderArgs* args = renderContext->getArgs(); + auto& details = args->_details.edit(RenderDetails::OTHER_ITEM); ItemIDsBounds culledItems; culledItems.reserve(inItems.size()); - args->_details.pointTo(RenderDetails::OTHER_ITEM); - cullItems(sceneContext, renderContext, inItems, culledItems); + cullItems(renderContext, _cullFunctor, details, inItems, culledItems); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 5ad1bbf8d4..684d8bf4ea 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -19,7 +19,10 @@ namespace render { -void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); +using CullFunctor = std::function; + +void cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details, + const ItemIDsBounds& inItems, ItemIDsBounds& outItems); void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems); void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); @@ -41,14 +44,20 @@ public: template class CullItems { public: + CullItems(CullFunctor cullFunctor) : _cullFunctor{ cullFunctor } {} + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { + const auto& args = renderContext->getArgs(); + auto& details = args->_details.edit(T); outItems.clear(); outItems.reserve(inItems.size()); - renderContext->getArgs()->_details.pointTo(T); - render::cullItems(sceneContext, renderContext, inItems, outItems); + render::cullItems(renderContext, _cullFunctor, details, inItems, outItems); } using JobModel = Task::Job::ModelIO, ItemIDsBounds, ItemIDsBounds>; + +protected: + CullFunctor _cullFunctor; }; class DepthSortItems { @@ -62,8 +71,12 @@ public: class DrawLight { public: + DrawLight(CullFunctor cullFunctor) : _cullFunctor{ cullFunctor } {} void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); using JobModel = Task::Job::Model; + +protected: + CullFunctor _cullFunctor; }; class PipelineSortShapes { diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index e5dfd5f8ea..7012c78c8f 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -56,34 +56,25 @@ public: Item _translucent; Item _other; - Item* _item = &_other; - - void pointTo(Type type) { + Item& edit(Type type) { switch (type) { case OPAQUE_ITEM: - _item = &_opaque; - break; + return _opaque; case SHADOW_ITEM: - _item = &_shadow; - break; + return _shadow; case TRANSLUCENT_ITEM: - _item = &_translucent; - break; + return _translucent; case OTHER_ITEM: - _item = &_other; - break; + default: + return _other; } } }; class RenderArgs { public: - typedef std::function ShoudRenderFunctor; - enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE }; - enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT }; - enum DebugFlags { RENDER_DEBUG_NONE = 0, RENDER_DEBUG_HULLS = 1 @@ -97,8 +88,7 @@ public: RenderMode renderMode = DEFAULT_RENDER_MODE, RenderSide renderSide = MONO, DebugFlags debugFlags = RENDER_DEBUG_NONE, - gpu::Batch* batch = nullptr, - ShoudRenderFunctor shouldRender = nullptr) : + gpu::Batch* batch = nullptr) : _context(context), _renderer(renderer), _viewFrustum(viewFrustum), @@ -107,8 +97,7 @@ public: _renderMode(renderMode), _renderSide(renderSide), _debugFlags(debugFlags), - _batch(batch), - _shouldRender(shouldRender) { + _batch(batch) { } std::shared_ptr _context = nullptr; @@ -123,7 +112,6 @@ public: RenderSide _renderSide = MONO; DebugFlags _debugFlags = RENDER_DEBUG_NONE; gpu::Batch* _batch = nullptr; - ShoudRenderFunctor _shouldRender; std::shared_ptr _whiteTexture; diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index dc38671091..75783fa6d5 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -118,6 +118,8 @@ public: void die() { _isDead = true; } bool isDead() const { return _isDead; } + bool isParentIDValid() const { bool success = false; getParentPointer(success); return success; } + protected: const NestableType _nestableType; // EntityItem or an AvatarData QUuid _id;