Merge pull request #7218 from zzmp/fix/resort-in-octree

Fix item key lookup on updated items in scene
This commit is contained in:
samcake 2016-03-08 17:48:51 -08:00
commit bfed0304c3
15 changed files with 309 additions and 385 deletions

View file

@ -231,23 +231,19 @@ bool Overlays::editOverlay(unsigned int id, const QVariant& properties) {
Overlay::Pointer thisOverlay = getOverlay(id); Overlay::Pointer thisOverlay = getOverlay(id);
if (thisOverlay) { if (thisOverlay) {
thisOverlay->setProperties(properties.toMap());
if (thisOverlay->is3D()) { if (thisOverlay->is3D()) {
render::ItemKey oldItemKey = render::payloadGetKey(thisOverlay); auto itemID = thisOverlay->getRenderItemID();
if (render::Item::isValidID(itemID)) {
thisOverlay->setProperties(properties.toMap()); render::ScenePointer scene = qApp->getMain3DScene();
const render::Item& item = scene->getItem(itemID);
render::ItemKey itemKey = render::payloadGetKey(thisOverlay); if (item.getKey() != render::payloadGetKey(thisOverlay)) {
if (itemKey != oldItemKey) {
auto itemID = thisOverlay->getRenderItemID();
if (render::Item::isValidID(itemID)) {
render::ScenePointer scene = qApp->getMain3DScene();
render::PendingChanges pendingChanges; render::PendingChanges pendingChanges;
pendingChanges.resortItem(itemID, oldItemKey, itemKey); pendingChanges.updateItem(itemID);
scene->enqueuePendingChanges(pendingChanges); scene->enqueuePendingChanges(pendingChanges);
} }
} }
} else {
thisOverlay->setProperties(properties.toMap());
} }
return true; return true;
@ -601,4 +597,4 @@ float Overlays::width() const {
float Overlays::height() const { float Overlays::height() const {
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
return offscreenUi->getWindow()->size().height(); return offscreenUi->getWindow()->size().height();
} }

View file

@ -10,27 +10,30 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "RenderDeferredTask.h"
#include <PerfStat.h> #include <PerfStat.h>
#include <PathUtils.h> #include <PathUtils.h>
#include <RenderArgs.h> #include <RenderArgs.h>
#include <ViewFrustum.h> #include <ViewFrustum.h>
#include <gpu/Context.h> #include <gpu/Context.h>
#include <render/CullTask.h>
#include <render/SortTask.h>
#include <render/DrawTask.h>
#include <render/DrawStatus.h>
#include <render/DrawSceneOctree.h>
#include "DebugDeferredBuffer.h" #include "DebugDeferredBuffer.h"
#include "DeferredLightingEffect.h" #include "DeferredLightingEffect.h"
#include "FramebufferCache.h" #include "FramebufferCache.h"
#include "HitEffect.h" #include "HitEffect.h"
#include "TextureCache.h" #include "TextureCache.h"
#include "render/DrawTask.h"
#include "render/DrawStatus.h"
#include "render/DrawSceneOctree.h"
#include "AmbientOcclusionEffect.h" #include "AmbientOcclusionEffect.h"
#include "AntialiasingEffect.h" #include "AntialiasingEffect.h"
#include "ToneMappingEffect.h" #include "ToneMappingEffect.h"
#include "RenderDeferredTask.h"
using namespace render; using namespace render;
extern void initStencilPipeline(gpu::PipelinePointer& pipeline); extern void initStencilPipeline(gpu::PipelinePointer& pipeline);
@ -54,34 +57,42 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
// CPU jobs: // CPU jobs:
// Fetch and cull the items from the scene // Fetch and cull the items from the scene
auto sceneFilter = ItemFilter::Builder::visibleWorldItems().withoutLayered(); auto spatialFilter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
const auto sceneSelection = addJob<FetchSpatialTree>("FetchSceneSelection", sceneFilter); const auto spatialSelection = addJob<FetchSpatialTree>("FetchSceneSelection", spatialFilter);
const auto culledSceneSelection = addJob<CullSpatialSelection>("CullSceneSelection", sceneSelection, cullFunctor, RenderDetails::ITEM, sceneFilter); const auto culledSpatialSelection = addJob<CullSpatialSelection>("CullSceneSelection", spatialSelection, cullFunctor, RenderDetails::ITEM, spatialFilter);
// Overlays are not culled
const auto nonspatialSelection = addJob<FetchNonspatialItems>("FetchOverlaySelection");
// Multi filter visible items into different buckets // Multi filter visible items into different buckets
const int NUM_FILTERS = 3; const int NUM_FILTERS = 3;
const int OPAQUE_SHAPE_BUCKET = 0; const int OPAQUE_SHAPE_BUCKET = 0;
const int TRANSPARENT_SHAPE_BUCKET = 1; const int TRANSPARENT_SHAPE_BUCKET = 1;
const int LIGHT_BUCKET = 2; const int LIGHT_BUCKET = 2;
MultiFilterItem<NUM_FILTERS>::ItemFilterArray triageFilters = { { const int BACKGROUND_BUCKET = 2;
MultiFilterItem<NUM_FILTERS>::ItemFilterArray spatialFilters = { {
ItemFilter::Builder::opaqueShape(), ItemFilter::Builder::opaqueShape(),
ItemFilter::Builder::transparentShape(), ItemFilter::Builder::transparentShape(),
ItemFilter::Builder::light() ItemFilter::Builder::light()
} }; } };
const auto filteredItemsBuckets = addJob<MultiFilterItem<NUM_FILTERS>>("FilterSceneSelection", culledSceneSelection, triageFilters).get<MultiFilterItem<NUM_FILTERS>::ItemBoundsArray>(); MultiFilterItem<NUM_FILTERS>::ItemFilterArray nonspatialFilters = { {
ItemFilter::Builder::opaqueShape(),
ItemFilter::Builder::transparentShape(),
ItemFilter::Builder::background()
} };
const auto filteredSpatialBuckets = addJob<MultiFilterItem<NUM_FILTERS>>("FilterSceneSelection", culledSpatialSelection, spatialFilters).get<MultiFilterItem<NUM_FILTERS>::ItemBoundsArray>();
const auto filteredNonspatialBuckets = addJob<MultiFilterItem<NUM_FILTERS>>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters).get<MultiFilterItem<NUM_FILTERS>::ItemBoundsArray>();
// Extract / Sort opaques / Transparents / Lights / Overlays // Extract / Sort opaques / Transparents / Lights / Overlays
const auto opaques = addJob<DepthSortItems>("DepthSortOpaque", filteredItemsBuckets[OPAQUE_SHAPE_BUCKET]); const auto opaques = addJob<DepthSortItems>("DepthSortOpaque", filteredSpatialBuckets[OPAQUE_SHAPE_BUCKET]);
const auto transparents = addJob<DepthSortItems>("DepthSortTransparent", filteredItemsBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto transparents = addJob<DepthSortItems>("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
const auto lights = filteredItemsBuckets[LIGHT_BUCKET]; const auto lights = filteredSpatialBuckets[LIGHT_BUCKET];
// Overlays are not culled because we want to make sure they are seen const auto overlayOpaques = addJob<DepthSortItems>("DepthSortOverlayOpaque", filteredNonspatialBuckets[OPAQUE_SHAPE_BUCKET]);
// Could be considered a bug in the current cullfunctor const auto overlayTransparents = addJob<DepthSortItems>("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
const auto overlayOpaques = addJob<FetchItems>("FetchOverlayOpaque", ItemFilter::Builder::opaqueShapeLayered()); const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET];
const auto fetchedOverlayOpaques = addJob<FetchItems>("FetchOverlayTransparents", ItemFilter::Builder::transparentShapeLayered());
const auto overlayTransparents = addJob<DepthSortItems>("DepthSortTransparentOverlay", fetchedOverlayOpaques, DepthSortItems(false));
// GPU Jobs: Start preparing the deferred and lighting buffer // GPU jobs: Start preparing the deferred and lighting buffer
addJob<PrepareDeferred>("PrepareDeferred"); addJob<PrepareDeferred>("PrepareDeferred");
// Render opaque objects in DeferredBuffer // Render opaque objects in DeferredBuffer
@ -91,7 +102,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
addJob<DrawStencilDeferred>("DrawOpaqueStencil"); addJob<DrawStencilDeferred>("DrawOpaqueStencil");
// Use Stencil and start drawing background in Lighting buffer // Use Stencil and start drawing background in Lighting buffer
addJob<DrawBackgroundDeferred>("DrawBackgroundDeferred"); addJob<DrawBackgroundDeferred>("DrawBackgroundDeferred", background);
// AO job // AO job
addJob<AmbientOcclusionEffect>("AmbientOcclusion"); addJob<AmbientOcclusionEffect>("AmbientOcclusion");
@ -123,8 +134,8 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
// Scene Octree Debuging job // Scene Octree Debuging job
{ {
addJob<DrawSceneOctree>("DrawSceneOctree", sceneSelection); addJob<DrawSceneOctree>("DrawSceneOctree", spatialSelection);
addJob<DrawItemSelection>("DrawItemSelection", sceneSelection); addJob<DrawItemSelection>("DrawItemSelection", spatialSelection);
} }
// Status icon rendering job // Status icon rendering job
@ -170,9 +181,9 @@ void DrawDeferred::run(const SceneContextPointer& sceneContext, const RenderCont
RenderArgs* args = renderContext->args; RenderArgs* args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
batch.setViewportTransform(args->_viewport); batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport); batch.setStateScissorRect(args->_viewport);
args->_batch = &batch;
config->setNumDrawn((int)inItems.size()); config->setNumDrawn((int)inItems.size());
emit config->numDrawnChanged(); emit config->numDrawnChanged();
@ -222,7 +233,8 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
// Render the items // Render the items
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch; args->_batch = &batch;
args->_whiteTexture = DependencyManager::get<TextureCache>()->getWhiteTexture(); batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
glm::mat4 projMat; glm::mat4 projMat;
Transform viewMat; Transform viewMat;
@ -231,14 +243,10 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
batch.setProjectionTransform(projMat); batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat); batch.setViewTransform(viewMat);
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
batch.setResourceTexture(0, args->_whiteTexture);
renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn);
args->_batch = nullptr;
}); });
args->_batch = nullptr;
args->_whiteTexture.reset();
} }
} }
@ -276,20 +284,10 @@ void DrawStencilDeferred::run(const SceneContextPointer& sceneContext, const Ren
args->_batch = nullptr; args->_batch = nullptr;
} }
void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems) {
assert(renderContext->args); assert(renderContext->args);
assert(renderContext->args->_viewFrustum); assert(renderContext->args->_viewFrustum);
// render backgrounds
auto& scene = sceneContext->_scene;
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::background());
ItemBounds inItems;
inItems.reserve(items.size());
for (auto id : items) {
inItems.emplace_back(id);
}
RenderArgs* args = renderContext->args; RenderArgs* args = renderContext->args;
doInBatch(args->_context, [&](gpu::Batch& batch) { doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch; args->_batch = &batch;

View file

@ -12,9 +12,8 @@
#ifndef hifi_RenderDeferredTask_h #ifndef hifi_RenderDeferredTask_h
#define hifi_RenderDeferredTask_h #define hifi_RenderDeferredTask_h
#include "gpu/Pipeline.h" #include <gpu/Pipeline.h>
#include <render/CullTask.h>
#include "render/DrawTask.h"
class SetupDeferred { class SetupDeferred {
public: public:
@ -85,9 +84,9 @@ protected:
class DrawBackgroundDeferred { class DrawBackgroundDeferred {
public: public:
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemBounds& inItems);
using JobModel = render::Job::Model<DrawBackgroundDeferred>; using JobModel = render::Job::ModelI<DrawBackgroundDeferred, render::ItemBounds>;
}; };
class DrawOverlay3DConfig : public render::Job::Config { class DrawOverlay3DConfig : public render::Job::Config {

View file

@ -9,16 +9,20 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "RenderShadowTask.h"
#include <gpu/Context.h> #include <gpu/Context.h>
#include <ViewFrustum.h> #include <ViewFrustum.h>
#include "render/Context.h" #include <render/Context.h>
#include <render/CullTask.h>
#include <render/SortTask.h>
#include <render/DrawTask.h>
#include "DeferredLightingEffect.h" #include "DeferredLightingEffect.h"
#include "FramebufferCache.h" #include "FramebufferCache.h"
#include "RenderShadowTask.h"
#include "model_shadow_vert.h" #include "model_shadow_vert.h"
#include "skin_model_shadow_vert.h" #include "skin_model_shadow_vert.h"
@ -28,7 +32,7 @@
using namespace render; using namespace render;
void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext,
const render::ShapesIDsBounds& inShapes) { const render::ShapeBounds& inShapes) {
assert(renderContext->args); assert(renderContext->args);
assert(renderContext->args->_viewFrustum); assert(renderContext->args->_viewFrustum);
@ -104,20 +108,18 @@ RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) : Task(std::make_sha
skinProgram, state); skinProgram, state);
} }
// CPU: Fetch shadow-casting opaques // CPU jobs:
const auto fetchedItems = addJob<FetchItems>("FetchShadowMap"); // Fetch and cull the items from the scene
auto shadowFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
const auto shadowSelection = addJob<FetchSpatialTree>("FetchShadowSelection", shadowFilter);
const auto culledShadowSelection = addJob<CullSpatialSelection>("CullShadowSelection", shadowSelection, cullFunctor, RenderDetails::SHADOW, shadowFilter);
// CPU: Cull against KeyLight frustum (nearby viewing camera) // Sort
const auto culledItems = addJob<CullItems<RenderDetails::SHADOW>>("CullShadowMap", fetchedItems, cullFunctor); const auto sortedPipelines = addJob<PipelineSortShapes>("PipelineSortShadowSort", culledShadowSelection);
const auto sortedShapes = addJob<DepthSortShapes>("DepthSortShadowMap", sortedPipelines);
// CPU: Sort by pipeline // GPU jobs: Render to shadow map
const auto sortedShapes = addJob<PipelineSortShapes>("PipelineSortShadowSort", culledItems); addJob<RenderShadowMap>("RenderShadowMap", sortedShapes, shapePlumber);
// CPU: Sort front to back
const auto shadowShapes = addJob<DepthSortShapes>("DepthSortShadowMap", sortedShapes);
// GPU: Render to shadow map
addJob<RenderShadowMap>("RenderShadowMap", shadowShapes, shapePlumber);
} }
void RenderShadowTask::configure(const Config& configuration) { void RenderShadowTask::configure(const Config& configuration) {

View file

@ -15,17 +15,17 @@
#include <gpu/Framebuffer.h> #include <gpu/Framebuffer.h>
#include <gpu/Pipeline.h> #include <gpu/Pipeline.h>
#include <render/DrawTask.h> #include <render/CullTask.h>
class ViewFrustum; class ViewFrustum;
class RenderShadowMap { class RenderShadowMap {
public: public:
using JobModel = render::Job::ModelI<RenderShadowMap, render::ShapesIDsBounds>; using JobModel = render::Job::ModelI<RenderShadowMap, render::ShapeBounds>;
RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext,
const render::ShapesIDsBounds& inShapes); const render::ShapeBounds& inShapes);
protected: protected:
render::ShapePlumberPointer _shapePlumber; render::ShapePlumberPointer _shapePlumber;

View file

@ -62,99 +62,21 @@ void render::cullItems(const RenderContextPointer& renderContext, const CullFunc
details._rendered += (int)outItems.size(); details._rendered += (int)outItems.size();
} }
struct ItemBoundSort { void FetchNonspatialItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemBounds& outItems) {
float _centerDepth = 0.0f;
float _nearDepth = 0.0f;
float _farDepth = 0.0f;
ItemID _id = 0;
AABox _bounds;
ItemBoundSort() {}
ItemBoundSort(float centerDepth, float nearDepth, float farDepth, ItemID id, const AABox& bounds) : _centerDepth(centerDepth), _nearDepth(nearDepth), _farDepth(farDepth), _id(id), _bounds(bounds) {}
};
struct FrontToBackSort {
bool operator() (const ItemBoundSort& left, const ItemBoundSort& right) {
return (left._centerDepth < right._centerDepth);
}
};
struct BackToFrontSort {
bool operator() (const ItemBoundSort& left, const ItemBoundSort& right) {
return (left._centerDepth > right._centerDepth);
}
};
void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems) {
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
auto& scene = sceneContext->_scene;
RenderArgs* args = renderContext->args;
// Allocate and simply copy
outItems.clear();
outItems.reserve(inItems.size());
// Make a local dataset of the center distance and closest point distance
std::vector<ItemBoundSort> itemBoundSorts;
itemBoundSorts.reserve(outItems.size());
for (auto itemDetails : inItems) {
auto item = scene->getItem(itemDetails.id);
auto bound = itemDetails.bound; // item.getBound();
float distance = args->_viewFrustum->distanceToCamera(bound.calcCenter());
itemBoundSorts.emplace_back(ItemBoundSort(distance, distance, distance, itemDetails.id, bound));
}
// sort against Z
if (frontToBack) {
FrontToBackSort frontToBackSort;
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), frontToBackSort);
} else {
BackToFrontSort backToFrontSort;
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), backToFrontSort);
}
// FInally once sorted result to a list of itemID
for (auto& item : itemBoundSorts) {
outItems.emplace_back(ItemBound(item._id, item._bounds));
}
}
void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems);
}
void FetchItems::configure(const Config& config) {
}
void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemBounds& outItems) {
assert(renderContext->args); assert(renderContext->args);
assert(renderContext->args->_viewFrustum); assert(renderContext->args->_viewFrustum);
auto& scene = sceneContext->_scene; auto& scene = sceneContext->_scene;
outItems.clear(); outItems.clear();
const auto& bucket = scene->getMasterBucket(); const auto& items = scene->getNonspatialSet();
const auto& items = bucket.find(_filter); outItems.reserve(items.size());
if (items != bucket.end()) { for (auto& id : items) {
outItems.reserve(items->second.size()); auto& item = scene->getItem(id);
for (auto& id : items->second) { outItems.emplace_back(ItemBound(id, item.getBound()));
auto& item = scene->getItem(id);
outItems.emplace_back(ItemBound(id, item.getBound()));
}
} }
std::static_pointer_cast<Config>(renderContext->jobConfig)->numItems = (int)outItems.size();
} }
void FetchSpatialTree::configure(const Config& config) { void FetchSpatialTree::configure(const Config& config) {
_justFrozeFrustum = _justFrozeFrustum || (config.freezeFrustum && !_freezeFrustum); _justFrozeFrustum = _justFrozeFrustum || (config.freezeFrustum && !_freezeFrustum);
_freezeFrustum = config.freezeFrustum; _freezeFrustum = config.freezeFrustum;

View file

@ -21,52 +21,13 @@ namespace render {
void cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details, void cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details,
const ItemBounds& inItems, ItemBounds& outItems); const ItemBounds& inItems, ItemBounds& outItems);
void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems);
class FetchItemsConfig : public Job::Config { class FetchNonspatialItems {
Q_OBJECT
Q_PROPERTY(int numItems READ getNumItems)
public: public:
int getNumItems() { return numItems; } using JobModel = Job::ModelO<FetchNonspatialItems, ItemBounds>;
int numItems{ 0 };
};
class FetchItems {
public:
using Config = FetchItemsConfig;
using JobModel = Job::ModelO<FetchItems, ItemBounds, Config>;
FetchItems() {}
FetchItems(const ItemFilter& filter) : _filter(filter) {}
ItemFilter _filter{ ItemFilter::Builder::opaqueShape().withoutLayered() };
void configure(const Config& config);
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemBounds& outItems); void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemBounds& outItems);
}; };
template<RenderDetails::Type T>
class CullItems {
public:
using JobModel = Job::ModelIO<CullItems<T>, ItemBounds, ItemBounds>;
CullItems(CullFunctor cullFunctor) : _cullFunctor{ cullFunctor } {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
const auto& args = renderContext->args;
auto& details = args->_details.edit(T);
outItems.clear();
outItems.reserve(inItems.size());
render::cullItems(renderContext, _cullFunctor, details, inItems, outItems);
}
protected:
CullFunctor _cullFunctor;
};
class FetchSpatialTreeConfig : public Job::Config { class FetchSpatialTreeConfig : public Job::Config {
Q_OBJECT Q_OBJECT
Q_PROPERTY(int numItems READ getNumItems) Q_PROPERTY(int numItems READ getNumItems)
@ -209,28 +170,19 @@ namespace render {
outItems[i].template edit<ItemBounds>().clear(); outItems[i].template edit<ItemBounds>().clear();
} }
// For each item, filter it into the buckets // For each item, filter it into one bucket
for (auto itemBound : inItems) { for (auto itemBound : inItems) {
auto& item = scene->getItem(itemBound.id); auto& item = scene->getItem(itemBound.id);
auto itemKey = item.getKey(); auto itemKey = item.getKey();
for (size_t i = 0; i < NUM_FILTERS; i++) { for (size_t i = 0; i < NUM_FILTERS; i++) {
if (_filters[i].test(itemKey)) { if (_filters[i].test(itemKey)) {
outItems[i].template edit<ItemBounds>().emplace_back(itemBound); outItems[i].template edit<ItemBounds>().emplace_back(itemBound);
break;
} }
} }
} }
} }
}; };
class DepthSortItems {
public:
using JobModel = Job::ModelIO<DepthSortItems, ItemBounds, ItemBounds>;
bool _frontToBack;
DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems);
};
} }
#endif // hifi_render_CullTask_h; #endif // hifi_render_CullTask_h;

View file

@ -73,38 +73,3 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext
args->_batch = nullptr; args->_batch = nullptr;
}); });
} }
void PipelineSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ShapesIDsBounds& outShapes) {
auto& scene = sceneContext->_scene;
outShapes.clear();
for (const auto& item : inItems) {
auto key = scene->getItem(item.id).getShapeKey();
auto outItems = outShapes.find(key);
if (outItems == outShapes.end()) {
outItems = outShapes.insert(std::make_pair(key, ItemBounds{})).first;
outItems->second.reserve(inItems.size());
}
outItems->second.push_back(item);
}
for (auto& items : outShapes) {
items.second.shrink_to_fit();
}
}
void DepthSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapesIDsBounds& inShapes, ShapesIDsBounds& outShapes) {
outShapes.clear();
outShapes.reserve(inShapes.size());
for (auto& pipeline : inShapes) {
auto& inItems = pipeline.second;
auto outItems = outShapes.find(pipeline.first);
if (outItems == outShapes.end()) {
outItems = outShapes.insert(std::make_pair(pipeline.first, ItemBounds{})).first;
}
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems->second);
}
}

View file

@ -13,10 +13,6 @@
#define hifi_render_DrawTask_h #define hifi_render_DrawTask_h
#include "Engine.h" #include "Engine.h"
#include "CullTask.h"
#include "ShapePipeline.h"
#include "gpu/Batch.h"
namespace render { namespace render {
@ -31,22 +27,6 @@ public:
protected: protected:
}; };
class PipelineSortShapes {
public:
using JobModel = Job::ModelIO<PipelineSortShapes, ItemBounds, ShapesIDsBounds>;
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ShapesIDsBounds& outShapes);
};
class DepthSortShapes {
public:
using JobModel = Job::ModelIO<DepthSortShapes, ShapesIDsBounds, ShapesIDsBounds>;
bool _frontToBack;
DepthSortShapes(bool frontToBack = true) : _frontToBack(frontToBack) {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapesIDsBounds& inShapes, ShapesIDsBounds& outShapes);
};
} }
#endif // hifi_render_DrawTask_h #endif // hifi_render_DrawTask_h

View file

@ -63,6 +63,13 @@ void Item::PayloadInterface::addStatusGetters(const Status::Getters& getters) {
} }
} }
void Item::update(const UpdateFunctorPointer& updateFunctor) {
if (updateFunctor) {
_payload->update(updateFunctor);
}
_key = _payload->getKey();
}
void Item::resetPayload(const PayloadPointer& payload) { void Item::resetPayload(const PayloadPointer& payload) {
if (!payload) { if (!payload) {
kill(); kill();

View file

@ -112,6 +112,7 @@ public:
bool isPickable() const { return _flags[PICKABLE]; } bool isPickable() const { return _flags[PICKABLE]; }
bool isLayered() const { return _flags[LAYERED]; } bool isLayered() const { return _flags[LAYERED]; }
bool isSpatial() const { return !isLayered(); }
// Probably not public, flags used by the scene // Probably not public, flags used by the scene
bool isSmall() const { return _flags[SMALLER]; } bool isSmall() const { return _flags[SMALLER]; }
@ -312,11 +313,11 @@ public:
Item() {} Item() {}
~Item() {} ~Item() {}
// Main scene / item managment interface Reset/Update/Kill // Main scene / item managment interface reset/update/kill
void resetPayload(const PayloadPointer& payload); void resetPayload(const PayloadPointer& payload);
void resetCell(ItemCell cell, bool _small) { _cell = cell; _key.setSmaller(_small); } void resetCell(ItemCell cell = INVALID_CELL, bool _small = false) { _cell = cell; _key.setSmaller(_small); }
void update(const UpdateFunctorPointer& updateFunctor) { _payload->update(updateFunctor); } // Communicate update to the payload void update(const UpdateFunctorPointer& updateFunctor); // communicate update to payload
void kill() { _payload.reset(); _key._flags.reset(); _cell = INVALID_CELL; } // Kill means forget the payload and key and cell void kill() { _payload.reset(); resetCell(); _key._flags.reset(); } // forget the payload, key, cell
// Check heuristic key // Check heuristic key
const ItemKey& getKey() const { return _key; } const ItemKey& getKey() const { return _key; }
@ -464,7 +465,7 @@ public:
using ItemBounds = std::vector<ItemBound>; using ItemBounds = std::vector<ItemBound>;
// A map of items by ShapeKey to optimize rendering pipeline assignments // A map of items by ShapeKey to optimize rendering pipeline assignments
using ShapesIDsBounds = std::unordered_map<ShapeKey, ItemBounds, ShapeKey::Hash, ShapeKey::KeyEqual>; using ShapeBounds = std::unordered_map<ShapeKey, ItemBounds, ShapeKey::Hash, ShapeKey::KeyEqual>;
} }

View file

@ -15,59 +15,11 @@
using namespace render; using namespace render;
void ItemBucketMap::insert(const ItemID& id, const ItemKey& key) {
// Insert the itemID in every bucket where it filters true
for (auto& bucket : (*this)) {
if (bucket.first.test(key)) {
bucket.second.insert(id);
}
}
}
void ItemBucketMap::erase(const ItemID& id, const ItemKey& key) {
// Remove the itemID in every bucket where it filters true
for (auto& bucket : (*this)) {
if (bucket.first.test(key)) {
bucket.second.erase(id);
}
}
}
void ItemBucketMap::reset(const ItemID& id, const ItemKey& oldKey, const ItemKey& newKey) {
// Reset the itemID in every bucket,
// Remove from the buckets where oldKey filters true AND newKey filters false
// Insert into the buckets where newKey filters true
for (auto& bucket : (*this)) {
if (bucket.first.test(oldKey)) {
if (!bucket.first.test(newKey)) {
bucket.second.erase(id);
}
} else if (bucket.first.test(newKey)) {
bucket.second.insert(id);
}
}
}
void ItemBucketMap::allocateStandardOpaqueTranparentBuckets() {
(*this)[ItemFilter::Builder::opaqueShape().withoutLayered()];
(*this)[ItemFilter::Builder::transparentShape().withoutLayered()];
(*this)[ItemFilter::Builder::light()];
(*this)[ItemFilter::Builder::background()];
(*this)[ItemFilter::Builder::opaqueShape().withLayered()];
(*this)[ItemFilter::Builder::transparentShape().withLayered()];
}
void PendingChanges::resetItem(ItemID id, const PayloadPointer& payload) { void PendingChanges::resetItem(ItemID id, const PayloadPointer& payload) {
_resetItems.push_back(id); _resetItems.push_back(id);
_resetPayloads.push_back(payload); _resetPayloads.push_back(payload);
} }
void PendingChanges::resortItem(ItemID id, ItemKey oldKey, ItemKey newKey) {
_resortItems.push_back(id);
_resortOldKeys.push_back(oldKey);
_resortNewKeys.push_back(newKey);
}
void PendingChanges::removeItem(ItemID id) { void PendingChanges::removeItem(ItemID id) {
_removedItems.push_back(id); _removedItems.push_back(id);
} }
@ -80,9 +32,6 @@ void PendingChanges::updateItem(ItemID id, const UpdateFunctorPointer& functor)
void PendingChanges::merge(PendingChanges& changes) { void PendingChanges::merge(PendingChanges& changes) {
_resetItems.insert(_resetItems.end(), changes._resetItems.begin(), changes._resetItems.end()); _resetItems.insert(_resetItems.end(), changes._resetItems.begin(), changes._resetItems.end());
_resetPayloads.insert(_resetPayloads.end(), changes._resetPayloads.begin(), changes._resetPayloads.end()); _resetPayloads.insert(_resetPayloads.end(), changes._resetPayloads.begin(), changes._resetPayloads.end());
_resortItems.insert(_resortItems.end(), changes._resortItems.begin(), changes._resortItems.end());
_resortOldKeys.insert(_resortOldKeys.end(), changes._resortOldKeys.begin(), changes._resortOldKeys.end());
_resortNewKeys.insert(_resortNewKeys.end(), changes._resortNewKeys.begin(), changes._resortNewKeys.end());
_removedItems.insert(_removedItems.end(), changes._removedItems.begin(), changes._removedItems.end()); _removedItems.insert(_removedItems.end(), changes._removedItems.begin(), changes._removedItems.end());
_updatedItems.insert(_updatedItems.end(), changes._updatedItems.begin(), changes._updatedItems.end()); _updatedItems.insert(_updatedItems.end(), changes._updatedItems.begin(), changes._updatedItems.end());
_updateFunctors.insert(_updateFunctors.end(), changes._updateFunctors.begin(), changes._updateFunctors.end()); _updateFunctors.insert(_updateFunctors.end(), changes._updateFunctors.begin(), changes._updateFunctors.end());
@ -92,7 +41,6 @@ Scene::Scene(glm::vec3 origin, float size) :
_masterSpatialTree(origin, size) _masterSpatialTree(origin, size)
{ {
_items.push_back(Item()); // add the itemID #0 to nothing _items.push_back(Item()); // add the itemID #0 to nothing
_masterBucketMap.allocateStandardOpaqueTranparentBuckets();
} }
ItemID Scene::allocateID() { ItemID Scene::allocateID() {
@ -133,7 +81,6 @@ void Scene::processPendingChangesQueue() {
// capture anything coming from the pendingChanges // capture anything coming from the pendingChanges
resetItems(consolidatedPendingChanges._resetItems, consolidatedPendingChanges._resetPayloads); resetItems(consolidatedPendingChanges._resetItems, consolidatedPendingChanges._resetPayloads);
updateItems(consolidatedPendingChanges._updatedItems, consolidatedPendingChanges._updateFunctors); updateItems(consolidatedPendingChanges._updatedItems, consolidatedPendingChanges._updateFunctors);
resortItems(consolidatedPendingChanges._resortItems, consolidatedPendingChanges._resortOldKeys, consolidatedPendingChanges._resortNewKeys);
removeItems(consolidatedPendingChanges._removedItems); removeItems(consolidatedPendingChanges._removedItems);
// ready to go back to rendering activities // ready to go back to rendering activities
@ -141,7 +88,6 @@ void Scene::processPendingChangesQueue() {
} }
void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) { void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) {
auto resetPayload = payloads.begin(); auto resetPayload = payloads.begin();
for (auto resetID : ids) { for (auto resetID : ids) {
// Access the true item // Access the true item
@ -153,28 +99,20 @@ void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) {
item.resetPayload(*resetPayload); item.resetPayload(*resetPayload);
auto newKey = item.getKey(); auto newKey = item.getKey();
// Update the item's container
// Reset the item in the Bucket map assert((oldKey.isSpatial() == newKey.isSpatial()) || oldKey._flags.none());
_masterBucketMap.reset(resetID, oldKey, newKey); if (newKey.isSpatial()) {
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), resetID, newKey);
// Reset the item in the spatial tree item.resetCell(newCell, newKey.isSmall());
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), resetID, newKey); } else {
item.resetCell(newCell, newKey.isSmall()); _masterNonspatialSet.insert(resetID);
}
// next loop // next loop
resetPayload++; resetPayload++;
} }
} }
void Scene::resortItems(const ItemIDs& ids, ItemKeys& oldKeys, ItemKeys& newKeys) {
auto resortID = ids.begin();
auto oldKey = oldKeys.begin();
auto newKey = newKeys.begin();
for (; resortID != ids.end(); resortID++, oldKey++, newKey++) {
_masterBucketMap.reset(*resortID, *oldKey, *newKey);
}
}
void Scene::removeItems(const ItemIDs& ids) { void Scene::removeItems(const ItemIDs& ids) {
for (auto removedID :ids) { for (auto removedID :ids) {
// Access the true item // Access the true item
@ -182,11 +120,12 @@ void Scene::removeItems(const ItemIDs& ids) {
auto oldCell = item.getCell(); auto oldCell = item.getCell();
auto oldKey = item.getKey(); auto oldKey = item.getKey();
// Remove from Bucket map // Remove the item
_masterBucketMap.erase(removedID, item.getKey()); if (oldKey.isSpatial()) {
_masterSpatialTree.removeItem(oldCell, oldKey, removedID);
// Remove from spatial tree } else {
_masterSpatialTree.removeItem(oldCell, oldKey, removedID); _masterNonspatialSet.erase(removedID);
}
// Kill it // Kill it
item.kill(); item.kill();
@ -202,14 +141,30 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) {
auto oldCell = item.getCell(); auto oldCell = item.getCell();
auto oldKey = item.getKey(); auto oldKey = item.getKey();
// Update it // Update the item
_items[updateID].update((*updateFunctor)); item.update((*updateFunctor));
auto newKey = item.getKey(); auto newKey = item.getKey();
// Update the citem in the spatial tree if needed // Update the item's container
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), updateID, newKey); if (oldKey.isSpatial() == newKey.isSpatial()) {
item.resetCell(newCell, newKey.isSmall()); if (newKey.isSpatial()) {
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), updateID, newKey);
item.resetCell(newCell, newKey.isSmall());
}
} else {
if (newKey.isSpatial()) {
_masterNonspatialSet.erase(updateID);
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), updateID, newKey);
item.resetCell(newCell, newKey.isSmall());
} else {
_masterSpatialTree.removeItem(oldCell, oldKey, updateID);
item.resetCell();
_masterNonspatialSet.insert(updateID);
}
}
// next loop // next loop
updateFunctor++; updateFunctor++;

View file

@ -17,21 +17,6 @@
namespace render { namespace render {
// A map of ItemIDSets allowing to create bucket lists of items which are filtered according to their key
class ItemBucketMap : public std::map<ItemFilter, ItemIDSet, ItemFilter::Less> {
public:
ItemBucketMap() {}
void insert(const ItemID& id, const ItemKey& key);
void erase(const ItemID& id, const ItemKey& key);
void reset(const ItemID& id, const ItemKey& oldKey, const ItemKey& newKey);
// standard builders allocating the main buckets
void allocateStandardOpaqueTranparentBuckets();
};
class Engine; class Engine;
class PendingChanges { class PendingChanges {
@ -40,7 +25,6 @@ public:
~PendingChanges() {} ~PendingChanges() {}
void resetItem(ItemID id, const PayloadPointer& payload); void resetItem(ItemID id, const PayloadPointer& payload);
void resortItem(ItemID id, ItemKey oldKey, ItemKey newKey);
void removeItem(ItemID id); void removeItem(ItemID id);
template <class T> void updateItem(ItemID id, std::function<void(T&)> func) { template <class T> void updateItem(ItemID id, std::function<void(T&)> func) {
@ -48,14 +32,12 @@ public:
} }
void updateItem(ItemID id, const UpdateFunctorPointer& functor); void updateItem(ItemID id, const UpdateFunctorPointer& functor);
void updateItem(ItemID id) { updateItem(id, nullptr); }
void merge(PendingChanges& changes); void merge(PendingChanges& changes);
ItemIDs _resetItems; ItemIDs _resetItems;
Payloads _resetPayloads; Payloads _resetPayloads;
ItemIDs _resortItems;
ItemKeys _resortOldKeys;
ItemKeys _resortNewKeys;
ItemIDs _removedItems; ItemIDs _removedItems;
ItemIDs _updatedItems; ItemIDs _updatedItems;
UpdateFunctors _updateFunctors; UpdateFunctors _updateFunctors;
@ -75,27 +57,27 @@ public:
Scene(glm::vec3 origin, float size); Scene(glm::vec3 origin, float size);
~Scene() {} ~Scene() {}
/// This call is thread safe, can be called from anywhere to allocate a new ID // This call is thread safe, can be called from anywhere to allocate a new ID
ItemID allocateID(); ItemID allocateID();
/// Enqueue change batch to the scene // Enqueue change batch to the scene
void enqueuePendingChanges(const PendingChanges& pendingChanges); void enqueuePendingChanges(const PendingChanges& pendingChanges);
// Process the penging changes equeued // Process the penging changes equeued
void processPendingChangesQueue(); void processPendingChangesQueue();
/// Access a particular item form its ID // Access a particular item form its ID
/// WARNING, There is No check on the validity of the ID, so this could return a bad Item // 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]; } const Item& getItem(const ItemID& id) const { return _items[id]; }
size_t getNumItems() const { return _items.size(); } size_t getNumItems() const { return _items.size(); }
/// Access the main bucketmap of items // Access the spatialized items
const ItemBucketMap& getMasterBucket() const { return _masterBucketMap; }
/// Access the item spatial tree
const ItemSpatialTree& getSpatialTree() const { return _masterSpatialTree; } const ItemSpatialTree& getSpatialTree() const { return _masterSpatialTree; }
// Access non-spatialized items (overlays, backgrounds)
const ItemIDSet& getNonspatialSet() const { return _masterNonspatialSet; }
protected: protected:
// Thread safe elements that can be accessed from anywhere // Thread safe elements that can be accessed from anywhere
std::atomic<unsigned int> _IDAllocator{ 1 }; // first valid itemID will be One std::atomic<unsigned int> _IDAllocator{ 1 }; // first valid itemID will be One
@ -106,12 +88,10 @@ protected:
// database of items is protected for editing by a mutex // database of items is protected for editing by a mutex
std::mutex _itemsMutex; std::mutex _itemsMutex;
Item::Vector _items; Item::Vector _items;
ItemBucketMap _masterBucketMap;
ItemSpatialTree _masterSpatialTree; ItemSpatialTree _masterSpatialTree;
ItemIDSet _masterNonspatialSet;
void resetItems(const ItemIDs& ids, Payloads& payloads); void resetItems(const ItemIDs& ids, Payloads& payloads);
void resortItems(const ItemIDs& ids, ItemKeys& oldKeys, ItemKeys& newKeys);
void removeItems(const ItemIDs& ids); void removeItems(const ItemIDs& ids);
void updateItems(const ItemIDs& ids, UpdateFunctors& functors); void updateItems(const ItemIDs& ids, UpdateFunctors& functors);

View file

@ -0,0 +1,120 @@
//
// CullTask.cpp
// render/src/render
//
// Created by Sam Gateau on 2/2/16.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "SortTask.h"
#include "ShapePipeline.h"
#include <assert.h>
#include <ViewFrustum.h>
using namespace render;
struct ItemBoundSort {
float _centerDepth = 0.0f;
float _nearDepth = 0.0f;
float _farDepth = 0.0f;
ItemID _id = 0;
AABox _bounds;
ItemBoundSort() {}
ItemBoundSort(float centerDepth, float nearDepth, float farDepth, ItemID id, const AABox& bounds) : _centerDepth(centerDepth), _nearDepth(nearDepth), _farDepth(farDepth), _id(id), _bounds(bounds) {}
};
struct FrontToBackSort {
bool operator() (const ItemBoundSort& left, const ItemBoundSort& right) {
return (left._centerDepth < right._centerDepth);
}
};
struct BackToFrontSort {
bool operator() (const ItemBoundSort& left, const ItemBoundSort& right) {
return (left._centerDepth > right._centerDepth);
}
};
void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems) {
assert(renderContext->args);
assert(renderContext->args->_viewFrustum);
auto& scene = sceneContext->_scene;
RenderArgs* args = renderContext->args;
// Allocate and simply copy
outItems.clear();
outItems.reserve(inItems.size());
// Make a local dataset of the center distance and closest point distance
std::vector<ItemBoundSort> itemBoundSorts;
itemBoundSorts.reserve(outItems.size());
for (auto itemDetails : inItems) {
auto item = scene->getItem(itemDetails.id);
auto bound = itemDetails.bound; // item.getBound();
float distance = args->_viewFrustum->distanceToCamera(bound.calcCenter());
itemBoundSorts.emplace_back(ItemBoundSort(distance, distance, distance, itemDetails.id, bound));
}
// sort against Z
if (frontToBack) {
FrontToBackSort frontToBackSort;
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), frontToBackSort);
} else {
BackToFrontSort backToFrontSort;
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), backToFrontSort);
}
// Finally once sorted result to a list of itemID
for (auto& item : itemBoundSorts) {
outItems.emplace_back(ItemBound(item._id, item._bounds));
}
}
void PipelineSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ShapeBounds& outShapes) {
auto& scene = sceneContext->_scene;
outShapes.clear();
for (const auto& item : inItems) {
auto key = scene->getItem(item.id).getShapeKey();
auto outItems = outShapes.find(key);
if (outItems == outShapes.end()) {
outItems = outShapes.insert(std::make_pair(key, ItemBounds{})).first;
outItems->second.reserve(inItems.size());
}
outItems->second.push_back(item);
}
for (auto& items : outShapes) {
items.second.shrink_to_fit();
}
}
void DepthSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapeBounds& inShapes, ShapeBounds& outShapes) {
outShapes.clear();
outShapes.reserve(inShapes.size());
for (auto& pipeline : inShapes) {
auto& inItems = pipeline.second;
auto outItems = outShapes.find(pipeline.first);
if (outItems == outShapes.end()) {
outItems = outShapes.insert(std::make_pair(pipeline.first, ItemBounds{})).first;
}
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems->second);
}
}
void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems);
}

View file

@ -0,0 +1,47 @@
//
// SortTask.h
// render/src/render
//
// Created by Zach Pomerantz on 2/26/2016.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_render_SortTask_h
#define hifi_render_SortTask_h
#include "Engine.h"
namespace render {
void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems);
class PipelineSortShapes {
public:
using JobModel = Job::ModelIO<PipelineSortShapes, ItemBounds, ShapeBounds>;
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ShapeBounds& outShapes);
};
class DepthSortShapes {
public:
using JobModel = Job::ModelIO<DepthSortShapes, ShapeBounds, ShapeBounds>;
bool _frontToBack;
DepthSortShapes(bool frontToBack = true) : _frontToBack(frontToBack) {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapeBounds& inShapes, ShapeBounds& outShapes);
};
class DepthSortItems {
public:
using JobModel = Job::ModelIO<DepthSortItems, ItemBounds, ItemBounds>;
bool _frontToBack;
DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {}
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems);
};
}
#endif // hifi_render_SortTask_h;