Octree.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Scene/Common.h>
  7. #include <AnKi/Math.h>
  8. #include <AnKi/Collision/Aabb.h>
  9. #include <AnKi/Util/WeakArray.h>
  10. #include <AnKi/Util/Enum.h>
  11. #include <AnKi/Util/ObjectAllocator.h>
  12. #include <AnKi/Util/List.h>
  13. #include <AnKi/Util/Tracer.h>
  14. namespace anki {
  15. // Forward
  16. class OctreePlaceable;
  17. class ThreadHive;
  18. class ThreadHiveSemaphore;
  19. /// @addtogroup scene
  20. /// @{
  21. /// Callback to determine if an octree node is visible.
  22. using OctreeNodeVisibilityTestCallback = Bool (*)(void* userData, const Aabb& box);
  23. /// Octree debug drawer.
  24. class OctreeDebugDrawer
  25. {
  26. public:
  27. virtual void drawCube(const Aabb& box, const Vec4& color) = 0;
  28. };
  29. /// Octree for visibility tests.
  30. class Octree
  31. {
  32. friend class OctreePlaceable;
  33. public:
  34. Octree(SceneAllocator<U8> alloc)
  35. : m_alloc(alloc)
  36. {
  37. }
  38. Octree(const Octree&) = delete; // Non-copyable
  39. ~Octree();
  40. Octree& operator=(const Octree&) = delete; // Non-copyable
  41. void init(const Vec3& sceneAabbMin, const Vec3& sceneAabbMax, U32 maxDepth);
  42. /// Place or re-place an element in the tree.
  43. /// @note It's thread-safe against place and remove methods.
  44. void place(const Aabb& volume, OctreePlaceable* placeable, Bool updateActualSceneBounds);
  45. /// Place the placeable somewhere where it's always visible.
  46. /// @note It's thread-safe against place and remove methods.
  47. void placeAlwaysVisible(OctreePlaceable* placeable);
  48. /// Remove an element from the tree.
  49. /// @note It's thread-safe against place and remove methods.
  50. void remove(OctreePlaceable& placeable);
  51. /// Gather visible placeables.
  52. /// @param frustumPlanes The frustum planes to test against.
  53. /// @param testId A unique index for this test.
  54. /// @param testCallback A ptr to a function that will be used to perform an additional test to the box of the
  55. /// Octree node. Can be nullptr.
  56. /// @param testCallbackUserData Parameter to the testCallback. Can be nullptr.
  57. /// @param out The output of the tests.
  58. /// @note It's thread-safe against other gatherVisible calls.
  59. void gatherVisible(const Plane frustumPlanes[6], U32 testId, OctreeNodeVisibilityTestCallback testCallback,
  60. void* testCallbackUserData, DynamicArrayAuto<void*>& out)
  61. {
  62. gatherVisibleRecursive(frustumPlanes, testId, testCallback, testCallbackUserData, m_rootLeaf, out);
  63. }
  64. /// Similar to gatherVisible but it spawns ThreadHive tasks.
  65. void gatherVisibleParallel(const Plane frustumPlanes[6], U32 testId, OctreeNodeVisibilityTestCallback testCallback,
  66. void* testCallbackUserData, DynamicArrayAuto<void*>* out, ThreadHive& hive,
  67. ThreadHiveSemaphore* waitSemaphore, ThreadHiveSemaphore*& signalSemaphore);
  68. /// Walk the tree.
  69. /// @tparam TTestAabbFunc The lambda that will test an Aabb. Signature of lambda: Bool(*)(const Aabb& leafBox)
  70. /// @tparam TNewPlaceableFunc The lambda to do something with a visible placeable.
  71. /// Signature: void(*)(void* placeableUserData).
  72. /// @param testId The test index.
  73. /// @param testFunc See TTestAabbFunc.
  74. /// @param newPlaceableFunc See TNewPlaceableFunc.
  75. template<typename TTestAabbFunc, typename TNewPlaceableFunc>
  76. void walkTree(U32 testId, TTestAabbFunc testFunc, TNewPlaceableFunc newPlaceableFunc)
  77. {
  78. ANKI_ASSERT(m_rootLeaf);
  79. walkTreeInternal(*m_rootLeaf, testId, testFunc, newPlaceableFunc);
  80. }
  81. /// Debug draw.
  82. void debugDraw(OctreeDebugDrawer& drawer) const
  83. {
  84. ANKI_ASSERT(m_rootLeaf);
  85. debugDrawRecursive(*m_rootLeaf, drawer);
  86. }
  87. /// Get the bounds of the scene as calculated by the objects that were placed inside the Octree.
  88. void getActualSceneBounds(Vec3& min, Vec3& max) const
  89. {
  90. LockGuard<Mutex> lock(m_globalMtx);
  91. ANKI_ASSERT(m_actualSceneAabbMin.x() < MAX_F32);
  92. ANKI_ASSERT(m_actualSceneAabbMax.x() > MIN_F32);
  93. min = m_actualSceneAabbMin;
  94. max = m_actualSceneAabbMax;
  95. }
  96. private:
  97. class GatherParallelCtx;
  98. class GatherParallelTaskCtx;
  99. /// List node.
  100. class PlaceableNode : public IntrusiveListEnabled<PlaceableNode>
  101. {
  102. public:
  103. OctreePlaceable* m_placeable = nullptr;
  104. #if ANKI_ENABLE_ASSERTIONS
  105. ~PlaceableNode()
  106. {
  107. m_placeable = nullptr;
  108. }
  109. #endif
  110. };
  111. /// Octree leaf.
  112. /// @warning Keept its size as small as possible.
  113. class Leaf
  114. {
  115. public:
  116. IntrusiveList<PlaceableNode> m_placeables;
  117. Vec3 m_aabbMin;
  118. Vec3 m_aabbMax;
  119. Array<Leaf*, 8> m_children = {};
  120. #if ANKI_ENABLE_ASSERTIONS
  121. ~Leaf()
  122. {
  123. ANKI_ASSERT(m_placeables.isEmpty());
  124. m_children = {};
  125. m_aabbMin = m_aabbMax = Vec3(0.0f);
  126. }
  127. #endif
  128. Bool hasChildren() const
  129. {
  130. return m_children[0] != nullptr || m_children[1] != nullptr || m_children[2] != nullptr
  131. || m_children[3] != nullptr || m_children[4] != nullptr || m_children[5] != nullptr
  132. || m_children[6] != nullptr || m_children[7] != nullptr;
  133. }
  134. };
  135. /// Used so that OctreePlaceable knows which leafs it belongs to.
  136. class LeafNode : public IntrusiveListEnabled<LeafNode>
  137. {
  138. public:
  139. Leaf* m_leaf = nullptr;
  140. #if ANKI_ENABLE_ASSERTIONS
  141. ~LeafNode()
  142. {
  143. m_leaf = nullptr;
  144. }
  145. #endif
  146. };
  147. /// P: Stands for positive and N: Negative
  148. enum class LeafMask : U8
  149. {
  150. PX_PY_PZ = 1 << 0,
  151. PX_PY_NZ = 1 << 1,
  152. PX_NY_PZ = 1 << 2,
  153. PX_NY_NZ = 1 << 3,
  154. NX_PY_PZ = 1 << 4,
  155. NX_PY_NZ = 1 << 5,
  156. NX_NY_PZ = 1 << 6,
  157. NX_NY_NZ = 1 << 7,
  158. NONE = 0,
  159. ALL = PX_PY_PZ | PX_PY_NZ | PX_NY_PZ | PX_NY_NZ | NX_PY_PZ | NX_PY_NZ | NX_NY_PZ | NX_NY_NZ,
  160. RIGHT = PX_PY_PZ | PX_PY_NZ | PX_NY_PZ | PX_NY_NZ,
  161. LEFT = NX_PY_PZ | NX_PY_NZ | NX_NY_PZ | NX_NY_NZ,
  162. TOP = PX_PY_PZ | PX_PY_NZ | NX_PY_PZ | NX_PY_NZ,
  163. BOTTOM = PX_NY_PZ | PX_NY_NZ | NX_NY_PZ | NX_NY_NZ,
  164. FRONT = PX_PY_PZ | PX_NY_PZ | NX_PY_PZ | NX_NY_PZ,
  165. BACK = PX_PY_NZ | PX_NY_NZ | NX_PY_NZ | NX_NY_NZ,
  166. };
  167. ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS_FRIEND(LeafMask)
  168. SceneAllocator<U8> m_alloc;
  169. U32 m_maxDepth = 0;
  170. Vec3 m_sceneAabbMin = Vec3(0.0f);
  171. Vec3 m_sceneAabbMax = Vec3(0.0f);
  172. mutable Mutex m_globalMtx;
  173. ObjectAllocatorSameType<Leaf, 256> m_leafAlloc;
  174. ObjectAllocatorSameType<LeafNode, 128> m_leafNodeAlloc;
  175. ObjectAllocatorSameType<PlaceableNode, 256> m_placeableNodeAlloc;
  176. Leaf* m_rootLeaf = nullptr;
  177. U32 m_placeableCount = 0;
  178. /// Compute the min of the scene bounds based on what is placed inside the octree.
  179. Vec3 m_actualSceneAabbMin = Vec3(MAX_F32);
  180. Vec3 m_actualSceneAabbMax = Vec3(MIN_F32);
  181. Leaf* newLeaf()
  182. {
  183. return m_leafAlloc.newInstance(m_alloc);
  184. }
  185. void releaseLeaf(Leaf* leaf)
  186. {
  187. m_leafAlloc.deleteInstance(m_alloc, leaf);
  188. }
  189. PlaceableNode* newPlaceableNode(OctreePlaceable* placeable)
  190. {
  191. ANKI_ASSERT(placeable);
  192. PlaceableNode* out = m_placeableNodeAlloc.newInstance(m_alloc);
  193. out->m_placeable = placeable;
  194. return out;
  195. }
  196. void releasePlaceableNode(PlaceableNode* placeable)
  197. {
  198. m_placeableNodeAlloc.deleteInstance(m_alloc, placeable);
  199. }
  200. LeafNode* newLeafNode(Leaf* leaf)
  201. {
  202. ANKI_ASSERT(leaf);
  203. LeafNode* out = m_leafNodeAlloc.newInstance(m_alloc);
  204. out->m_leaf = leaf;
  205. return out;
  206. }
  207. void releaseLeafNode(LeafNode* node)
  208. {
  209. m_leafNodeAlloc.deleteInstance(m_alloc, node);
  210. }
  211. void placeRecursive(const Aabb& volume, OctreePlaceable* placeable, Leaf* parent, U32 depth);
  212. static Bool volumeTotallyInsideLeaf(const Aabb& volume, const Leaf& leaf);
  213. static void computeChildAabb(LeafMask child, const Vec3& parentAabbMin, const Vec3& parentAabbMax,
  214. const Vec3& parentAabbCenter, Vec3& childAabbMin, Vec3& childAabbMax);
  215. /// Remove a placeable from the tree.
  216. void removeInternal(OctreePlaceable& placeable);
  217. static void gatherVisibleRecursive(const Plane frustumPlanes[6], U32 testId,
  218. OctreeNodeVisibilityTestCallback testCallback, void* testCallbackUserData,
  219. Leaf* leaf, DynamicArrayAuto<void*>& out);
  220. /// ThreadHive callback.
  221. static void gatherVisibleTaskCallback(void* ud, U32 threadId, ThreadHive& hive, ThreadHiveSemaphore* sem);
  222. void gatherVisibleParallelTask(U32 threadId, ThreadHive& hive, ThreadHiveSemaphore* sem,
  223. GatherParallelTaskCtx& taskCtx);
  224. /// Remove a leaf.
  225. void cleanupRecursive(Leaf* leaf, Bool& canDeleteLeafUponReturn);
  226. /// Cleanup the tree.
  227. void cleanupInternal();
  228. /// Debug draw.
  229. void debugDrawRecursive(const Leaf& leaf, OctreeDebugDrawer& drawer) const;
  230. template<typename TTestAabbFunc, typename TNewPlaceableFunc>
  231. void walkTreeInternal(Leaf& leaf, U32 testId, TTestAabbFunc testFunc, TNewPlaceableFunc newPlaceableFunc);
  232. };
  233. /// An entity that can be placed in octrees.
  234. class OctreePlaceable
  235. {
  236. friend class Octree;
  237. public:
  238. void* m_userData = nullptr;
  239. OctreePlaceable() = default;
  240. OctreePlaceable(const OctreePlaceable&) = delete; // Non-copyable
  241. OctreePlaceable& operator=(const OctreePlaceable&) = delete; // Non-copyable
  242. void reset()
  243. {
  244. m_visitedMask.setNonAtomically(0);
  245. }
  246. private:
  247. Atomic<U64> m_visitedMask = {0u};
  248. IntrusiveList<Octree::LeafNode> m_leafs; ///< A list of leafs this placeable belongs.
  249. /// Check if already visited.
  250. /// @note It's thread-safe.
  251. Bool alreadyVisited(U32 testId)
  252. {
  253. ANKI_ASSERT(testId < 64);
  254. const U64 testMask = U64(1u) << U64(testId);
  255. const U64 prev = m_visitedMask.fetchOr(testMask);
  256. return !!(testMask & prev);
  257. }
  258. };
  259. template<typename TTestAabbFunc, typename TNewPlaceableFunc>
  260. inline void Octree::walkTreeInternal(Leaf& leaf, U32 testId, TTestAabbFunc testFunc, TNewPlaceableFunc newPlaceableFunc)
  261. {
  262. // Visit the placeables that belong to that leaf
  263. for(PlaceableNode& placeableNode : leaf.m_placeables)
  264. {
  265. if(!placeableNode.m_placeable->alreadyVisited(testId))
  266. {
  267. ANKI_ASSERT(placeableNode.m_placeable->m_userData);
  268. newPlaceableFunc(placeableNode.m_placeable->m_userData);
  269. }
  270. }
  271. Aabb aabb;
  272. U visibleLeafs = 0;
  273. (void)visibleLeafs;
  274. for(Leaf* child : leaf.m_children)
  275. {
  276. if(child)
  277. {
  278. aabb.setMin(child->m_aabbMin);
  279. aabb.setMax(child->m_aabbMax);
  280. if(testFunc(aabb))
  281. {
  282. ++visibleLeafs;
  283. walkTreeInternal(*child, testId, testFunc, newPlaceableFunc);
  284. }
  285. }
  286. }
  287. ANKI_TRACE_INC_COUNTER(OCTREE_VISIBLE_LEAFS, visibleLeafs);
  288. }
  289. /// @}
  290. } // end namespace anki