Merge pull request #7319 from samcake/red

Supporting RenderItems being added Outside the RenderSpatialTree volume
This commit is contained in:
Brad Hefta-Gaub 2016-03-11 08:34:50 -08:00
commit d5c8e69c48
3 changed files with 65 additions and 13 deletions

View file

@ -96,6 +96,9 @@ void Scene::processPendingChangesQueue() {
// removes // removes
removeItems(consolidatedPendingChanges._removedItems); removeItems(consolidatedPendingChanges._removedItems);
// Update the numItemsAtomic counter AFTER the pending changes went through
_numAllocatedItems.exchange(maxID);
// ready to go back to rendering activities // ready to go back to rendering activities
_itemsMutex.unlock(); _itemsMutex.unlock();
} }

View file

@ -264,12 +264,33 @@ Octree::Index Octree::accessCellBrick(Index cellID, const CellBrickAccessor& acc
return brickID; return brickID;
} }
Octree::Location ItemSpatialTree::evalLocation(const AABox& bound, Coord3f& minCoordf, Coord3f& maxCoordf) const {
minCoordf = evalCoordf(bound.getMinimumPoint());
maxCoordf = evalCoordf(bound.getMaximumPoint());
// If the bound crosses any of the octree volume limit, then return root cell
if ( (minCoordf.x < 0.0f)
|| (minCoordf.y < 0.0f)
|| (minCoordf.z < 0.0f)
|| (maxCoordf.x >= _size)
|| (maxCoordf.y >= _size)
|| (maxCoordf.z >= _size)) {
return Location();
}
Coord3 minCoord(minCoordf);
Coord3 maxCoord(maxCoordf);
return Location::evalFromRange(minCoord, maxCoord);
}
Octree::Locations ItemSpatialTree::evalLocations(const ItemBounds& bounds) const { Octree::Locations ItemSpatialTree::evalLocations(const ItemBounds& bounds) const {
Locations locations; Locations locations;
Coord3f minCoordf, maxCoordf;
locations.reserve(bounds.size()); locations.reserve(bounds.size());
for (auto& bound : bounds) { for (auto& bound : bounds) {
if (!bound.bound.isNull()) { if (!bound.bound.isNull()) {
locations.emplace_back(evalLocation(bound.bound)); locations.emplace_back(evalLocation(bound.bound, minCoordf, maxCoordf));
} else { } else {
locations.emplace_back(Location()); locations.emplace_back(Location());
} }
@ -344,11 +365,8 @@ bool ItemSpatialTree::removeItem(Index cellIdx, const ItemKey& key, const ItemID
ItemSpatialTree::Index ItemSpatialTree::resetItem(Index oldCell, const ItemKey& oldKey, const AABox& bound, const ItemID& item, ItemKey& newKey) { ItemSpatialTree::Index ItemSpatialTree::resetItem(Index oldCell, const ItemKey& oldKey, const AABox& bound, const ItemID& item, ItemKey& newKey) {
auto newCell = INVALID_CELL; auto newCell = INVALID_CELL;
if (!newKey.isViewSpace()) { if (!newKey.isViewSpace()) {
auto minCoordf = evalCoordf(bound.getMinimumPoint()); Coord3f minCoordf, maxCoordf;
auto maxCoordf = evalCoordf(bound.getMaximumPoint()); auto location = evalLocation(bound, minCoordf, maxCoordf);
Coord3 minCoord(minCoordf);
Coord3 maxCoord(maxCoordf);
auto location = Location::evalFromRange(minCoord, maxCoord);
// Compare range size vs cell location size and tag itemKey accordingly // Compare range size vs cell location size and tag itemKey accordingly
// If Item bound fits in sub cell then tag as small // If Item bound fits in sub cell then tag as small
@ -403,7 +421,21 @@ ItemSpatialTree::Index ItemSpatialTree::resetItem(Index oldCell, const ItemKey&
int Octree::select(CellSelection& selection, const FrustumSelector& selector) const { int Octree::select(CellSelection& selection, const FrustumSelector& selector) const {
Index cellID = ROOT_CELL; Index cellID = ROOT_CELL;
return selectTraverse(cellID, selection, selector); auto cell = getConcreteCell(cellID);
int numSelectedsIn = (int)selection.size();
// Always include the root cell partially containing potentially outer objects
selectCellBrick(cellID, selection, false);
// then traverse deeper
for (int i = 0; i < NUM_OCTANTS; i++) {
Index subCellID = cell.child((Link)i);
if (subCellID != INVALID_CELL) {
selectTraverse(subCellID, selection, selector);
}
}
return (int)selection.size() - numSelectedsIn;
} }

View file

@ -117,7 +117,6 @@ namespace render {
return depth; return depth;
} }
class Location { class Location {
void assertValid() { void assertValid() {
assert((pos.x >= 0) && (pos.y >= 0) && (pos.z >= 0)); assert((pos.x >= 0) && (pos.y >= 0) && (pos.z >= 0));
@ -157,6 +156,7 @@ namespace render {
// Eval the location best fitting the specified range // Eval the location best fitting the specified range
static Location evalFromRange(const Coord3& minCoord, const Coord3& maxCoord, Depth rangeDepth = MAX_DEPTH); static Location evalFromRange(const Coord3& minCoord, const Coord3& maxCoord, Depth rangeDepth = MAX_DEPTH);
// Eval the intersection test against a frustum // Eval the intersection test against a frustum
enum Intersection { enum Intersection {
Outside = 0, Outside = 0,
@ -367,7 +367,7 @@ namespace render {
// An octree of Items organizing them efficiently for culling // An octree of Items organizing them efficiently for culling
// The octree only cares about the bound & the key of an item to store it a the right cell location // The octree only cares about the bound & the key of an item to store it a the right cell location
class ItemSpatialTree : public Octree { class ItemSpatialTree : public Octree {
float _size { 32768.0f }; float _size{ 32768.0f };
float _invSize { 1.0f / _size }; float _invSize { 1.0f / _size };
glm::vec3 _origin { -16384.0f }; glm::vec3 _origin { -16384.0f };
@ -398,10 +398,26 @@ namespace render {
return getOrigin() + glm::vec3(coord) * cellWidth; return getOrigin() + glm::vec3(coord) * cellWidth;
} }
// Clamp a 3D relative position to make sure it is in the valid range space of the octree
glm::vec3 clampRelPosToTreeRange(const glm::vec3& pos) const {
const float EPSILON = 0.0001f;
return glm::vec3(
std::min(std::max(pos.x, 0.0f), _size - EPSILON),
std::min(std::max(pos.y, 0.0f), _size - EPSILON),
std::min(std::max(pos.z, 0.0f), _size - EPSILON));
}
// Eval an integer cell coordinate (at the specified deepth) from a given 3d position
// If the 3D position is out of the octree volume, then the position is clamped
// so the integer coordinate is meaningfull
Coord3 evalCoord(const glm::vec3& pos, Depth depth = Octree::METRIC_COORD_DEPTH) const { Coord3 evalCoord(const glm::vec3& pos, Depth depth = Octree::METRIC_COORD_DEPTH) const {
auto npos = (pos - getOrigin()); auto npos = clampRelPosToTreeRange((pos - getOrigin()));
return Coord3(npos * getInvCellWidth(depth)); // Truncate fractional part return Coord3(npos * getInvCellWidth(depth)); // Truncate fractional part
} }
// Eval a real cell coordinate (at the specified deepth) from a given 3d position
// Position is NOT clamped to the boundaries of the octree so beware of conversion to a Coord3!
Coord3f evalCoordf(const glm::vec3& pos, Depth depth = Octree::METRIC_COORD_DEPTH) const { Coord3f evalCoordf(const glm::vec3& pos, Depth depth = Octree::METRIC_COORD_DEPTH) const {
auto npos = (pos - getOrigin()); auto npos = (pos - getOrigin());
return Coord3f(npos * getInvCellWidth(depth)); return Coord3f(npos * getInvCellWidth(depth));
@ -412,9 +428,10 @@ namespace render {
float cellWidth = getCellWidth(loc.depth); float cellWidth = getCellWidth(loc.depth);
return AABox(evalPos(loc.pos, cellWidth), cellWidth); return AABox(evalPos(loc.pos, cellWidth), cellWidth);
} }
Location evalLocation(const AABox& bound) const {
return Location::evalFromRange(evalCoord(bound.getMinimumPoint()), evalCoord(bound.getMaximumPoint())); // Eval the cell location for a given arbitrary Bound,
} // if the Bound crosses any of the Octree planes then the root cell is returned
Location evalLocation(const AABox& bound, Coord3f& minCoordf, Coord3f& maxCoordf) const;
Locations evalLocations(const ItemBounds& bounds) const; Locations evalLocations(const ItemBounds& bounds) const;
// Managing itemsInserting items in cells // Managing itemsInserting items in cells