Octree.h 9.9 KB

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