ToyMaker Game Engine 0.0.2
ToyMaker is a game engine developed and maintained by Zoheb Shujauddin.
Loading...
Searching...
No Matches
octree.hpp
Go to the documentation of this file.
1
10
11#ifndef TOYMAKERENGINE_SPATIALQUERYOCTREE_H
12#define TOYMAKERENGINE_SPATIALQUERYOCTREE_H
13
14#include <memory>
15#include <array>
16#include <algorithm>
17
18#include "types.hpp"
19#include "../core/ecs_world.hpp"
20
21namespace ToyMaker {
22 class Octree;
23
29 class OctreeNode: public std::enable_shared_from_this<OctreeNode> {
30 public:
37 using Octant = uint8_t;
38
43 using Depth = uint8_t;
44
49 using Address = uint64_t;
50
56 RIGHT=0x1,
57 TOP=0x2,
58 FRONT=0x4,
59 };
60
65 static constexpr uint8_t knDepthBits { 5 };
66
72 static constexpr uint8_t kDepthBitOffset { sizeof(Address)*8 - knDepthBits };
73
78 static constexpr uint8_t knRouteBits { (kDepthBitOffset/3) * 3};
79
84 static constexpr Depth kMaxDepthInclusive {std::min(
85 1 + knRouteBits/3,
86 1 + (1<<knDepthBits)
87 )}; // +1 as depth 0 needs no bits
88
93 static constexpr Address kNoAddress { 0x0 };
94
102 static Address MakeAddress(Octant childOctant, Address parentAddress);
103
110 static Depth GetDepth(Address address);
111
123 static Octant ToGrowthDirection(Octant octant);
124
137 static Octant ToOctant(Octant growthDirection);
138
145 static Octant GetOctant(Address address);
146
153 static Address GetBaseRouteMask(Depth baseDepth);
154
162 static Address GetBaseRoute(Address address, Depth baseDepth);
163
171 static Octant GetOctantAt(Address address, Depth depth);
172
184 static Address GrowAddress(Address address, Address rootAddress);
185
196 static Address ShrinkAddress(Address address, Depth depthRemoved);
197
206 static bool SharesBranch(Address one, Address two);
207
213 DEPTH_MASK = -(1ull << kDepthBitOffset), //< Mask for the most significant knDepthBits of the address; mask corresponding to the depth section of the address.
214 ROUTE_MASK = ~(-(1ull << knRouteBits)), //< Mask for the least significant knRouteBits of the address; mask corresponding to the route section of the address.
215 };
216 static_assert(DEPTH_MASK != 0 && "Depth mask cannot be zero");
217 static_assert(ROUTE_MASK != 0 && "Route mask cannot be zero");
218 static_assert(knDepthBits + kDepthBitOffset == sizeof(Address)*8 && "sum of depth bits and depth offset must add up to the size of the address in bits");
219 static_assert(kDepthBitOffset >= knRouteBits && "There must be at least as many bits in the depth bit offset as those used to make the route");
220 static_assert(kNoAddress == 0 && "NoAddress must correspond with 0");
221
229 static std::shared_ptr<OctreeNode> CreateRootNode(
230 uint8_t subdivisionThreshold, AxisAlignedBounds boundRegion
231 );
232
240 static std::shared_ptr<OctreeNode> GrowTreeAndCreateRoot(
241 std::shared_ptr<OctreeNode> oldRoot,
242 const AxisAlignedBounds& regionToCover
243 );
244
248
256 std::vector<std::pair<EntityID, AxisAlignedBounds>> findAllMemberEntities(InteractionLayerMask interactionMask=std::numeric_limits<InteractionLayerMask>::max()) const;
257
266 std::vector<std::pair<EntityID, AxisAlignedBounds>> findEntitiesOverlappingCoarse(
267 const AxisAlignedBounds& searchBounds,
268 InteractionLayerMask interactionMask=std::numeric_limits<InteractionLayerMask>::max()
269 ) const;
270
278 std::vector<std::pair<EntityID, AxisAlignedBounds>> findEntitiesOverlappingCoarse(
279 const Ray& searchRay,
280 InteractionLayerMask interactionMask=std::numeric_limits<InteractionLayerMask>::max()
281 ) const;
282
288 uint8_t getChildCount() const;
289
295 Address getAddress() const { return mAddress; }
296
303
312 Address insertEntity(EntityID entityID, const AxisAlignedBounds& entityWorldBounds);
313
321 std::shared_ptr<OctreeNode> removeEntity(EntityID entityID, Address entityAddressHint=kNoAddress);
322
330 std::shared_ptr<OctreeNode> getNode(Address octantAddress);
331
339 std::shared_ptr<OctreeNode> nextNodeInAddress(Address octantAddress);
340
349 std::shared_ptr<OctreeNode> getSmallestNodeContaining(const AxisAlignedBounds& entityWorldBounds);
350
358 std::shared_ptr<OctreeNode> findCandidateRoot();
359
366 Address getBaseRoute(Address address) const;
367
373 Depth getDepth() const;
374
380 Octant getOctant() const;
381
388 Octant nextOctant(Address address) const;
389
395
396 private:
397
407 Address octantAddress,
408 uint8_t subdivisionThreshold,
409 AxisAlignedBounds worldBounds,
410 std::shared_ptr<OctreeNode> parent
411 ):
412 mAddress { octantAddress },
413 mSubdivisionThreshold { subdivisionThreshold },
414 mWorldBounds { worldBounds },
415 mParent { parent }
416 {}
417
424
430
435 uint8_t mSubdivisionThreshold { 40 };
436
442
447 std::weak_ptr<OctreeNode> mParent {};
448
455 std::array<std::shared_ptr<OctreeNode>, 8> mChildren {};
456
461 std::map<EntityID, AxisAlignedBounds> mEntities{};
462
463 public:
464
470 inline InteractionLayerMask getInteractionLayers() const { return mWorldBounds.getInteractionLayers(); }
471 };
472
490 class Octree {
491 public:
492
500 static constexpr float kMaxDimensionRatio { 20.f };
501
506 using EntityAddressPair = std::pair<EntityID, OctreeNode::Address>;
507
514 Octree(uint8_t subdivisionThreshold, const AxisAlignedBounds& totalWorldBounds):
515 mRootNode { OctreeNode::CreateRootNode(subdivisionThreshold, totalWorldBounds) }
516 {}
517
521
530 inline std::vector<std::pair<EntityID, AxisAlignedBounds>> findAllMemberEntities(InteractionLayerMask layerMask=std::numeric_limits<InteractionLayerMask>::max()) const {
531 return mRootNode->findAllMemberEntities(layerMask);
532 }
533
542 inline std::vector<std::pair<EntityID, AxisAlignedBounds>> findEntitiesOverlappingCoarse(
543 const AxisAlignedBounds& searchBounds,
544 InteractionLayerMask layerMask=std::numeric_limits<InteractionLayerMask>::max()
545 ) const {
546 return mRootNode->findEntitiesOverlappingCoarse(searchBounds, layerMask);
547 }
548
555 std::vector<std::pair<EntityID, AxisAlignedBounds>> findEntitiesOverlappingCoarse(
556 const Ray& searchRay,
557 InteractionLayerMask layerMask=std::numeric_limits<InteractionLayerMask>::max()
558 ) const;
559
566 void insertEntity(EntityID entityID, const AxisAlignedBounds& entityWorldBounds);
567
573 void removeEntity(EntityID entityID);
574
575 private:
580 std::shared_ptr<OctreeNode> mRootNode;
581
586 std::map<EntityID, OctreeNode::Address> mEntityAddresses {};
587 };
588
589}
590
591#endif
An object containing a coarse simplified representation, AABB, of spatially queryable objects.
Definition types.hpp:1322
A single node of an octree, representing a single octant of the 8 that make up its parent region.
Definition octree.hpp:29
static Address MakeAddress(Octant childOctant, Address parentAddress)
Prepends the address of a child octant to the address of its parent in order to make the child's addr...
Definition octree.cpp:69
static std::shared_ptr< OctreeNode > CreateRootNode(uint8_t subdivisionThreshold, AxisAlignedBounds boundRegion)
Produces a node for the root of an octree that encloses the region to be divided.
Definition octree.cpp:32
void shrinkTreeAndBecomeRoot()
Trims the addresses of this node and its children (and consequently their entities) such that this no...
Definition octree.cpp:439
AxisAlignedBounds getWorldBounds() const
Retrieves the AABB representing the region this node covers.
Definition octree.hpp:302
static Address GetBaseRouteMask(Depth baseDepth)
Gets a bit mask covering the first 3*depth bits based on a given depth value.
Definition octree.cpp:88
std::weak_ptr< OctreeNode > mParent
The parent of this node, which this node is an octant of.
Definition octree.hpp:447
static bool SharesBranch(Address one, Address two)
Tests whether two nodes are present on the same branch of an octree (or in other words,...
Definition octree.cpp:124
static std::shared_ptr< OctreeNode > GrowTreeAndCreateRoot(std::shared_ptr< OctreeNode > oldRoot, const AxisAlignedBounds &regionToCover)
Expands an octree such that it encloses a previously unmapped region, and creates a node to be used a...
Definition octree.cpp:457
OctantSpecifier
Mask values which, when applied to the octant value, tell you which sub-region of the parent region t...
Definition octree.hpp:55
Depth getDepth() const
The depth of this node relative to the root of the Octree it is a part of.
Definition octree.cpp:321
static Octant ToOctant(Octant growthDirection)
Converts a growth direction to its corresponding octant.
Definition octree.cpp:84
static constexpr Address kNoAddress
A special value reserved for the absence of an address, as in the root node of the Octree.
Definition octree.hpp:93
std::shared_ptr< OctreeNode > removeEntity(EntityID entityID, Address entityAddressHint=kNoAddress)
Removes an entity situated at a node at some address (or on a descendant node).
Definition octree.cpp:223
uint8_t getChildCount() const
Gets the number of active child octants this octant has.
Definition octree.cpp:603
static Octant GetOctant(Address address)
Returns the 3 bits representing just this node's octant value, relative to its own parent.
Definition octree.cpp:65
static constexpr Depth kMaxDepthInclusive
The total depth representable given the value range of the depth-section of the address,...
Definition octree.hpp:84
void recomputeInteractionLayers()
Add up interaction layer set of child octants and entities to make this octant's new interaction set.
Definition octree.cpp:212
static constexpr uint8_t kDepthBitOffset
(Computed) The number of bits by which to shift the address right in order to retrieve the depth valu...
Definition octree.hpp:72
Address getAddress() const
Gets the address value for this node.
Definition octree.hpp:295
std::shared_ptr< OctreeNode > getSmallestNodeContaining(const AxisAlignedBounds &entityWorldBounds)
Gets the node whose region just encompasses the bounds provided as input.
Definition octree.cpp:289
static Octant GetOctantAt(Address address, Depth depth)
Gets the octant corresponding to a specific depth within an address.
Definition octree.cpp:61
uint8_t mSubdivisionThreshold
The number of member entities a node (or its descendant) may have, beyond which the node's subdivisio...
Definition octree.hpp:435
uint64_t Address
The full address of this node, where every three bits right-to-left represent the octant in the hiera...
Definition octree.hpp:49
uint8_t Octant
A number representing the portion of the parent region represented by this node.
Definition octree.hpp:37
std::shared_ptr< OctreeNode > nextNodeInAddress(Address octantAddress)
Gets the child node corresponding to the next node in the argument's route section relative to the th...
Definition octree.cpp:264
std::array< std::shared_ptr< OctreeNode >, 8 > mChildren
An array of up to 8 child nodes maintained by this node, where each index corresponds to one possible...
Definition octree.hpp:455
static constexpr uint8_t knRouteBits
The number of bits of the address, starting from the right, representing the route to follow in the O...
Definition octree.hpp:78
std::map< EntityID, AxisAlignedBounds > mEntities
The member entities of this node.
Definition octree.hpp:461
std::shared_ptr< OctreeNode > findCandidateRoot()
Gets the smallest node, this node or a descendant, whose region encompasses all entities remaining in...
Definition octree.cpp:301
std::vector< std::pair< EntityID, AxisAlignedBounds > > findAllMemberEntities(InteractionLayerMask interactionMask=std::numeric_limits< InteractionLayerMask >::max()) const
Retrieves all entities in this octant and its descendants.
Definition octree.cpp:333
OctreeNode(Address octantAddress, uint8_t subdivisionThreshold, AxisAlignedBounds worldBounds, std::shared_ptr< OctreeNode > parent)
Constructs a new OctreeNode.
Definition octree.hpp:406
AxisAlignedBounds mWorldBounds
The region, as an AABB, encompassed by this node.
Definition octree.hpp:441
Address mAddress
The address of this node, where kNoAddress is the address of the root node of an octree.
Definition octree.hpp:429
static Address GrowAddress(Address address, Address rootAddress)
Adds root-address' route to address' route.
Definition octree.cpp:96
static constexpr uint8_t knDepthBits
The number of bits on the left hand side of a node address giving the depth of this node.
Definition octree.hpp:65
Address getBaseRoute(Address address) const
Gets the route section of the address up to the current node's depth.
Definition octree.cpp:317
static Address GetBaseRoute(Address address, Depth baseDepth)
Gets the value of the route section of an address up to some specified depth.
Definition octree.cpp:92
InteractionLayerMask getInteractionLayers() const
Gets a list of layers entities under this octant belong to, for which they will participate in spatia...
Definition octree.hpp:470
Octant getOctant() const
Gets the octant value of this node relative to its parent.
Definition octree.cpp:325
static Octant ToGrowthDirection(Octant octant)
Maps an octant to its corresponding growth direction.
Definition octree.cpp:80
Octant nextOctant(Address address) const
Fetches the octant of the next node in the route section of the argument address.
Definition octree.cpp:329
AddressMasks
Mask values for retrieving the different sections of an Address.
Definition octree.hpp:212
uint8_t Depth
The depth of this node relative to the overall octree; the number of hops to go from this node up to ...
Definition octree.hpp:43
std::shared_ptr< OctreeNode > getNode(Address octantAddress)
Gets a descendant of this node (or this node itself) by its address.
Definition octree.cpp:273
static Address ShrinkAddress(Address address, Depth depthRemoved)
Shrinks an address according to the depth removed.
Definition octree.cpp:113
std::vector< std::pair< EntityID, AxisAlignedBounds > > findEntitiesOverlappingCoarse(const AxisAlignedBounds &searchBounds, InteractionLayerMask interactionMask=std::numeric_limits< InteractionLayerMask >::max()) const
Retrieves all entities that intersect with the region described by searchBounds.
Definition octree.cpp:360
static Depth GetDepth(Address address)
Gets the depth value of a node based on its address.
Definition octree.cpp:57
Address insertEntity(EntityID entityID, const AxisAlignedBounds &entityWorldBounds)
Adds an entity to this node or its subtree, per its configuration and the bounds of the object.
Definition octree.cpp:129
A data structure used for speeding up spatial queries about 3-dimensional objects in the scene.
Definition octree.hpp:490
std::map< EntityID, OctreeNode::Address > mEntityAddresses
A mapping of entity IDs to their addresses computed at entity insertion (and recomputed when the octr...
Definition octree.hpp:586
std::pair< EntityID, OctreeNode::Address > EntityAddressPair
An entity-id node-address pair indicating the address at which some entity known by the entity is pre...
Definition octree.hpp:506
void insertEntity(EntityID entityID, const AxisAlignedBounds &entityWorldBounds)
Inserts an entity into the octree.
Definition octree.cpp:611
static constexpr float kMaxDimensionRatio
The maximum possible ratio between two dimensions of the region enclosed by the octree.
Definition octree.hpp:500
std::vector< std::pair< EntityID, AxisAlignedBounds > > findEntitiesOverlappingCoarse(const AxisAlignedBounds &searchBounds, InteractionLayerMask layerMask=std::numeric_limits< InteractionLayerMask >::max()) const
Retrieve all entities that intersect with the region described by searchBounds.
Definition octree.hpp:542
Octree(uint8_t subdivisionThreshold, const AxisAlignedBounds &totalWorldBounds)
Constructs a new octree which encapsulates the bounds specified in the argument.
Definition octree.hpp:514
void removeEntity(EntityID entityID)
Removes an entity from the octree, based on its cached node address.
Definition octree.cpp:664
std::shared_ptr< OctreeNode > mRootNode
The root node of the octree.
Definition octree.hpp:580
std::vector< std::pair< EntityID, AxisAlignedBounds > > findAllMemberEntities(InteractionLayerMask layerMask=std::numeric_limits< InteractionLayerMask >::max()) const
Retrieves all entities in this octant and its descendants.
Definition octree.hpp:530
ToyMaker Engine's implementation of an ECS system.
std::uint64_t EntityID
A single unsigned integer used as a name for an entity managed by an ECS system.
Definition ecs_world.hpp:68
uint16_t InteractionLayerMask
Bit field where each bit represents an interaction layer – a physics/spatial layer that can trigger o...
Definition types.hpp:57
Namespace containing all class definitions and functions related to the ToyMaker engine.
Definition application.hpp:25
Classes and structs representing data related to the engine's spatial query system (the precursor to ...
A set of numbers describing a ray with its source at some finite point in the world,...
Definition types.hpp:447