Octree.h 9.7 KB

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