diff --git a/libraries/render/src/render/DrawSceneOctree.cpp b/libraries/render/src/render/DrawSceneOctree.cpp index 2cfa0e190a..1a89aa3275 100644 --- a/libraries/render/src/render/DrawSceneOctree.cpp +++ b/libraries/render/src/render/DrawSceneOctree.cpp @@ -34,9 +34,7 @@ const gpu::PipelinePointer DrawSceneOctree::getDrawCellBoundsPipeline() { gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); - - _drawBoundPosLoc = program->getUniforms().findLocation("inBoundPos"); - _drawBoundDimLoc = program->getUniforms().findLocation("inBoundDim"); + _drawCellLocationLoc = program->getUniforms().findLocation("inCellLocation"); auto state = std::make_shared(); @@ -69,10 +67,7 @@ void DrawSceneOctree::run(const SceneContextPointer& sceneContext, if (!_cells) { _cells = std::make_shared(); } - /* if (!_octreeInfo) { - _octreeInfo = std::make_shared();; - }*/ - + const auto& inCells = scene->getSpatialTree()._cells; _cells->resize(inCells.size() * sizeof(AABox)); AABox* cellAABox = reinterpret_cast (_cells->editData()); @@ -102,15 +97,9 @@ void DrawSceneOctree::run(const SceneContextPointer& sceneContext, // bind the one gpu::Pipeline we need batch.setPipeline(getDrawCellBoundsPipeline()); - AABox* cellAABox = reinterpret_cast (_cells->editData()); - - const unsigned int VEC3_ADRESS_OFFSET = 3; const auto& inCells = scene->getSpatialTree()._cells; for (int i = 0; i < nbCells; i++) { - batch._glUniform3fv(_drawBoundPosLoc, 1, (const float*) (cellAABox + i)); - batch._glUniform3fv(_drawBoundDimLoc, 1, ((const float*)(cellAABox + i)) + VEC3_ADRESS_OFFSET); - auto& cellLoc = inCells[i].getlocation(); glm::ivec4 cellLocation(cellLoc.pos.x, cellLoc.pos.y, cellLoc.pos.z, cellLoc.depth); diff --git a/libraries/render/src/render/DrawSceneOctree.h b/libraries/render/src/render/DrawSceneOctree.h index 409dfae42c..1b9bef12de 100644 --- a/libraries/render/src/render/DrawSceneOctree.h +++ b/libraries/render/src/render/DrawSceneOctree.h @@ -18,8 +18,6 @@ namespace render { class DrawSceneOctree { - int _drawBoundPosLoc; - int _drawBoundDimLoc; int _drawCellLocationLoc; gpu::PipelinePointer _drawCellBoundsPipeline; gpu::BufferPointer _cells; diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 46793d1ec3..7b164a91eb 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -191,6 +191,7 @@ inline QDebug operator<<(QDebug debug, const ItemFilter& me) { } using ItemID = uint32_t; +using ItemCell = int32_t; class Item { public: @@ -198,6 +199,7 @@ public: typedef ItemID ID; static const ID INVALID_ITEM_ID = 0; + static const ItemCell INVALID_CELL = -1; // Bound is the AABBox fully containing this item typedef AABox Bound; @@ -292,12 +294,16 @@ public: // Main scene / item managment interface Reset/Update/Kill void resetPayload(const PayloadPointer& payload); + void resetCell(ItemCell cell) { _cell = cell; } void update(const UpdateFunctorPointer& updateFunctor) { _payload->update(updateFunctor); } // Communicate update to the payload - void kill() { _payload.reset(); _key._flags.reset(); } // Kill means forget the payload and key + void kill() { _payload.reset(); _key._flags.reset(); _cell = INVALID_CELL; } // Kill means forget the payload and key and cell // Check heuristic key const ItemKey& getKey() const { return _key; } + // Check spatial cell + const ItemCell& getCell() const { return _cell; } + // Payload Interface // Get the bound of the item expressed in world space (or eye space depending on the key.isWorldSpace()) @@ -318,6 +324,7 @@ public: protected: PayloadPointer _payload; ItemKey _key; + ItemCell _cell{ INVALID_CELL }; friend class Scene; }; diff --git a/libraries/render/src/render/Octree.cpp b/libraries/render/src/render/Octree.cpp index a162ee3a3f..0b638db3ae 100644 --- a/libraries/render/src/render/Octree.cpp +++ b/libraries/render/src/render/Octree.cpp @@ -67,7 +67,7 @@ Octree::Location Octree::Location::evalFromRange(const Coord3& minCoord, const C } } -Octree::Indices Octree::indexAllocatedCellPath(const Locations& path) const { +Octree::Indices Octree::indexConcreteCellPath(const Locations& path) const { Index currentIndex = ROOT; Indices cellPath(1, currentIndex); @@ -105,7 +105,7 @@ Octree::Index Octree::allocateCell(Index parent, const Location& location) { Octree::Indices Octree::indexCellPath(const Locations& path) { // First through the aallocated cells - Indices cellPath = indexAllocatedCellPath(path); + Indices cellPath = indexConcreteCellPath(path); // Catch up from the last allocated cell on the path auto currentIndex = cellPath.back(); @@ -131,34 +131,86 @@ Octree::Index Octree::allocateBrick() { return brickIdx; } -Octree::Index Octree::accessCellBrick(const Location& loc, const CellBrickAccessor& accessor) { - auto cellId = indexCell(loc); - auto cell = editCell(cellId); +Octree::Index Octree::accessCellBrick(Index cellID, const CellBrickAccessor& accessor, bool createBrick) { + assert(cellID != INVALID); + auto cell = editCell(cellID); if (!cell.asBrick()) { + if (!createBrick) { + return INVALID; + } cell.setBrick(allocateBrick()); } // access the brick - auto& brick = _bricks[cell.brick()]; + auto brickID = cell.brick(); + auto& brick = _bricks[brickID]; // execute the accessor - accessor(brick, cell.brick()); + accessor(brick, brickID); - return cell.brick(); + return brickID; } -void ItemSpatialTree::insert(const ItemBounds& items) { - for (auto& item : items) { - if (!item.bound.isNull()) { - auto cellIdx = indexCell(evalLocation(item.bound)); - - accessCellBrick(evalLocation(item.bound), [&] (Brick& brick, Octree::Index cellID) { - brick.items.push_back(item.id); - }); +Octree::Locations ItemSpatialTree::evalLocations(const ItemBounds& bounds) const { + Locations locations; + locations.reserve(bounds.size()); + for (auto& bound : bounds) { + if (!bound.bound.isNull()) { + locations.emplace_back(evalLocation(bound.bound)); + } else { + locations.emplace_back(Location()); } } + return locations; +} + +ItemSpatialTree::Index ItemSpatialTree::insertItem(const Location& location, const ItemID& item) { + // Go to the cell + auto cellIdx = indexCell(location); + + // Add the item to the brick (and a brick if needed) + accessCellBrick(cellIdx, [&](Brick& brick, Octree::Index cellID) { + brick.items.push_back(item); + }, true); + + return cellIdx; +} + +bool ItemSpatialTree::removeItem(Index cellIdx, const ItemID& item) { + auto success = false; + + // Access the brick at the cell (without createing new ones) + auto brickIdx = accessCellBrick(cellIdx, [&](Brick& brick, Octree::Index brickID) { + // remove the item from the list + brick.items.erase(std::find(brick.items.begin(), brick.items.end(), item)); + success = true; + }, false); // do not create brick! + + return success; +} + +ItemSpatialTree::Index ItemSpatialTree::resetItem(Index oldCell, const Location& location, const ItemID& item) { + // do we know about this item ? + if (oldCell == Item::INVALID_CELL) { + auto newCell = insertItem(location, item); + return newCell; + } else { + auto newCell = indexCell(location); + + accessCellBrick(newCell, [&](Brick& brick, Octree::Index brickID) { + // insert the item only if the new cell is different from the previous one + if (newCell != oldCell) { + brick.items.push_back(item); + } + }, true); + + // now we know where the cell has been added and where it was, + // if different then go clean the previous cell + if (newCell != oldCell) { + removeItem(oldCell, item); + } + + return newCell; + } } -void ItemSpatialTree::erase(const ItemBounds& items) { - -} \ No newline at end of file diff --git a/libraries/render/src/render/Octree.h b/libraries/render/src/render/Octree.h index 7ee4910358..7d3cce9267 100644 --- a/libraries/render/src/render/Octree.h +++ b/libraries/render/src/render/Octree.h @@ -144,7 +144,7 @@ namespace render { using Locations = Location::vector; // Cell or Brick Indexing - using Index = int32_t; + using Index = ItemCell; // int32_t static const Index INVALID = -1; static const Index ROOT = 0; using Indices = std::vector; @@ -194,9 +194,9 @@ namespace render { Indices indexCellPath(const Locations& path); Index indexCell(const Location& loc) { return indexCellPath(Location::pathTo(loc)).back(); } - // Same as indexCellPath except that NO cells are allocated, + // Same as indexCellPath except that NO cells are allocated, only the COncrete cells previously allocated // the returned indices stops at the last existing cell on the requested path. - Indices indexAllocatedCellPath(const Locations& path) const; + Indices indexConcreteCellPath(const Locations& path) const; // Reach a concrete cell const Cell& getCell(Index index) const { @@ -209,7 +209,10 @@ namespace render { // Let s talk about the Cell Bricks now using CellBrickAccessor = std::function; - Index accessCellBrick(const Location& loc, const CellBrickAccessor& accessor); + // acces a cell (must be concrete), then call the brick accessor if the brick exists ( or is just created if authorized to) + // This returns the Brick index + Index accessCellBrick(Index cellID, const CellBrickAccessor& accessor, bool createBrick = true); + const Brick& getBrick(Index index) const { assert(index < _bricks.size()); @@ -258,19 +261,22 @@ namespace render { } + // Bound to Location AABox evalBound(const Location& loc) const { float cellWidth = getCellWidth(loc.depth); return AABox(evalPos(loc.pos, cellWidth), cellWidth); } - Location evalLocation(const AABox& bound) const { return Location::evalFromRange(evalCoord(bound.getMinimumPoint()), evalCoord(bound.getMaximumPoint())); } + Locations evalLocations(const ItemBounds& bounds) const; + + // Managing itemsInserting items in cells + Index insertItem(const Location& location, const ItemID& item); + bool removeItem(Index cellIdx, const ItemID& item); + Index resetItem(Index oldCell, const Location& location, const ItemID& item); ItemSpatialTree() {} - - void insert(const ItemBounds& items); - void erase(const ItemBounds& items); }; } diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index 1458e6fcf8..241f23e290 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -129,22 +129,28 @@ void Scene::processPendingChangesQueue() { } void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) { - auto resetID = ids.begin(); - auto resetPayload = payloads.begin(); - ItemBounds itemBounds; - itemBounds.reserve(ids.size()); - - for (;resetID != ids.end(); resetID++, resetPayload++) { - auto& item = _items[(*resetID)]; + + auto& resetPayload = payloads.begin(); + for (auto resetID : ids) { + // Access the true item + auto& item = _items[resetID]; auto oldKey = item.getKey(); + auto oldCell = item.getCell(); + + // Reset the item with a new payload item.resetPayload(*resetPayload); - _masterBucketMap.reset((*resetID), oldKey, item.getKey()); + // Reset the item in the Bucket map + _masterBucketMap.reset(resetID, oldKey, item.getKey()); - itemBounds.emplace_back(ItemBound((*resetID), item.getBound())); + // Reset the item in the spatial tree + auto newCellLocation = _masterSpatialTree.evalLocation(item.getBound()); + auto newCell = _masterSpatialTree.resetItem(oldCell, newCellLocation, resetID); + item.resetCell(newCell); + + // next loop + resetPayload++; } - - _masterSpatialTree.insert(itemBounds); } void Scene::removeItems(const ItemIDs& ids) { diff --git a/libraries/render/src/render/SceneOctree.slh b/libraries/render/src/render/SceneOctree.slh new file mode 100644 index 0000000000..d3fa36cf0f --- /dev/null +++ b/libraries/render/src/render/SceneOctree.slh @@ -0,0 +1,76 @@ + +<@if not RENDER_OCTREE_SLH@> +<@def RENDER_OCTREE_SLH@> + +const float _size = 32768.0; +const float _invSize = 1.0 / _size; +const vec3 _origin = vec3(-16384.0); + +float getSize() { return _size; } +vec3 getOrigin() { return _origin; } + +const int MAX_DEPTH = 15; +const float DEPTH_DIM[16] = float[16]( + 1.0, + 2.0, + 4.0, + 8.0, + 16.0, + 32.0, + 64.0, + 128.0, + 256.0, + 512.0, + 1024.0, + 2048.0, + 4096.0, + 8192.0, + 16384.0, + 32768.0 ); +const float INV_DEPTH_DIM[16] = float[16]( + 1.0, + 1.0 / 2.0, + 1.0 / 4.0, + 1.0 / 8.0, + 1.0 / 16.0, + 1.0 / 32.0, + 1.0 / 64.0, + 1.0 / 128.0, + 1.0 / 256.0, + 1.0 / 512.0, + 1.0 / 1024.0, + 1.0 / 2048.0, + 1.0 / 4096.0, + 1.0 / 8192.0, + 1.0 / 16384.0, + 1.0 / 32768.0 ); + +int getDepthDimension(int depth) { return 1 << depth; } +float getDepthDimensionf(int depth) { return DEPTH_DIM[depth]; } +float getInvDepthDimension(int depth) { return INV_DEPTH_DIM[depth]; } + +float getCellWidth(int depth) { return _size * getInvDepthDimension(depth); } +float getInvCellWidth(int depth) { return getDepthDimensionf(depth) * _invSize; } + +vec3 evalPos(ivec3 coord, int depth = MAX_DEPTH) { + return getOrigin() + vec3(coord) * getCellWidth(depth); +} +vec3 evalPosDepthWidth(ivec3 coord, float cellWidth) { + return getOrigin() + vec3(coord) * cellWidth; +} + +vec4 evalBound(ivec4 loc) { + float cellWidth = getCellWidth(loc.w); + return vec4(evalPosDepthWidth(loc.xyz, cellWidth), cellWidth); +} + + +<@endif@> diff --git a/libraries/render/src/render/drawCellBounds.slv b/libraries/render/src/render/drawCellBounds.slv index e5ff6c6939..13b0c465d5 100644 --- a/libraries/render/src/render/drawCellBounds.slv +++ b/libraries/render/src/render/drawCellBounds.slv @@ -19,56 +19,8 @@ <@include gpu/Color.slh@> <$declareColorWheel()$> - -const float _size = 32768.0; -const float _invSize = 1.0 / _size; -const vec3 _origin = vec3(-16384.0); - -float getSize() { return _size; } -vec3 getOrigin() { return _origin; } - -const int MAX_DEPTH = 15; -const float INV_DEPTH_DIM[16] = float[16]( - 1.0, - 1.0 / 2.0, - 1.0 / 4.0, - 1.0 / 8.0, - 1.0 / 16.0, - 1.0 / 32.0, - 1.0 / 64.0, - 1.0 / 128.0, - 1.0 / 256.0, - 1.0 / 512.0, - 1.0 / 1024.0, - 1.0 / 2048.0, - 1.0 / 4096.0, - 1.0 / 8192.0, - 1.0 / 16384.0, - 1.0 / 32768.0 ); - -int getDepthDimension(int depth) { return 1 << depth; } -float getInvDepthDimension(int depth) { return INV_DEPTH_DIM[depth]; } - -float getCellWidth(int depth) { return _size * getInvDepthDimension(depth); } -float getInvCellWidth(int depth) { return float(getDepthDimension(depth)) * _invSize; } - -vec3 evalPos(ivec3 coord, int depth = MAX_DEPTH) { - return getOrigin() + vec3(coord) * getCellWidth(depth); -} -vec3 evalPos(ivec3 coord, float cellWidth) { - return getOrigin() + vec3(coord) * cellWidth; -} - -vec4 evalBound(ivec4 loc) { - float cellWidth = getCellWidth(loc.w); - return vec4(evalPos(loc.xyz, cellWidth), cellWidth); -} -!> - -uniform vec3 inBoundPos; -uniform vec3 inBoundDim; uniform ivec4 inCellLocation; out vec4 varColor; @@ -101,7 +53,9 @@ void main(void) { ); vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; - pos.xyz = inBoundPos + inBoundDim * pos.xyz; + vec4 cellBound = evalBound(inCellLocation); + + pos.xyz = cellBound.xyz + vec3(cellBound.w) * pos.xyz; // standard transform TransformCamera cam = getTransformCamera();