Sector.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. #include "anki/scene/Sector.h"
  2. #include "anki/scene/Spatial.h"
  3. #include "anki/scene/SceneNode.h"
  4. #include "anki/scene/Renderable.h"
  5. #include "anki/scene/Light.h"
  6. #include "anki/scene/Visibility.h"
  7. #include "anki/scene/Frustumable.h"
  8. #include "anki/scene/Scene.h"
  9. #include "anki/core/Logger.h"
  10. #include "anki/renderer/Renderer.h"
  11. #include "anki/core/ThreadPool.h"
  12. namespace anki {
  13. //==============================================================================
  14. // Misc =
  15. //==============================================================================
  16. //==============================================================================
  17. struct DistanceSortFunctor
  18. {
  19. Vec3 origin;
  20. Bool operator()(SceneNode* a, SceneNode* b)
  21. {
  22. ANKI_ASSERT(a->getSpatial() != nullptr && b->getSpatial() != nullptr);
  23. F32 dist0 = origin.getDistanceSquared(
  24. a->getSpatial()->getSpatialOrigin());
  25. F32 dist1 = origin.getDistanceSquared(
  26. b->getSpatial()->getSpatialOrigin());
  27. return dist0 < dist1;
  28. }
  29. };
  30. //==============================================================================
  31. struct MaterialSortFunctor
  32. {
  33. Bool operator()(SceneNode* a, SceneNode* b)
  34. {
  35. ANKI_ASSERT(a->getRenderable() != nullptr
  36. && b->getRenderable() != nullptr);
  37. return a->getRenderable()->getRenderableMaterial()
  38. < b->getRenderable()->getRenderableMaterial();
  39. }
  40. };
  41. //==============================================================================
  42. struct DistanceSortJob: ThreadJob
  43. {
  44. U nodesCount;
  45. VisibilityTestResults::Container::iterator nodes;
  46. Vec3 origin;
  47. void operator()(U threadId, U threadsCount)
  48. {
  49. DistanceSortFunctor comp;
  50. comp.origin = origin;
  51. std::sort(nodes, nodes + nodesCount, comp);
  52. }
  53. };
  54. //==============================================================================
  55. struct MaterialSortJob: ThreadJob
  56. {
  57. U nodesCount;
  58. VisibilityTestResults::Container::iterator nodes;
  59. void operator()(U threadId, U threadsCount)
  60. {
  61. std::sort(nodes, nodes + nodesCount, MaterialSortFunctor());
  62. }
  63. };
  64. //==============================================================================
  65. // Portal =
  66. //==============================================================================
  67. //==============================================================================
  68. Portal::Portal()
  69. {
  70. sectors[0] = sectors[1] = nullptr;
  71. open = true;
  72. }
  73. //==============================================================================
  74. // Sector =
  75. //==============================================================================
  76. //==============================================================================
  77. Sector::Sector(SectorGroup* group_, const Aabb& box)
  78. : group(group_), octree(this, box, 3),
  79. portals(group->getScene().getAllocator())
  80. {
  81. // Reserve some space for portals
  82. portals.reserve(AVERAGE_PORTALS_PER_SECTOR);
  83. }
  84. //==============================================================================
  85. Bool Sector::placeSceneNode(SceneNode* sn)
  86. {
  87. // XXX Optimize
  88. if(!sn->getSpatial()->getAabb().collide(octree.getRoot().getAabb()))
  89. {
  90. return false;
  91. }
  92. octree.placeSceneNode(sn);
  93. return true;
  94. }
  95. //==============================================================================
  96. void Sector::addNewPortal(Portal* portal)
  97. {
  98. ANKI_ASSERT(portal);
  99. ANKI_ASSERT(
  100. std::find(portals.begin(), portals.end(), portal) == portals.end()
  101. && "Portal found in the container");
  102. portals.push_back(portal);
  103. }
  104. //==============================================================================
  105. void Sector::removePortal(Portal* portal)
  106. {
  107. ANKI_ASSERT(portal);
  108. SceneVector<Portal*>::iterator it =
  109. std::find(portals.begin(), portals.end(), portal);
  110. ANKI_ASSERT(it != portals.end());
  111. portals.erase(it);
  112. }
  113. //==============================================================================
  114. // SectorGroup =
  115. //==============================================================================
  116. //==============================================================================
  117. SectorGroup::SectorGroup(Scene* scene_)
  118. : scene(scene_),
  119. sectors(scene->getAllocator()),
  120. portals(scene->getAllocator())
  121. {
  122. ANKI_ASSERT(scene != nullptr);
  123. }
  124. //==============================================================================
  125. SectorGroup::~SectorGroup()
  126. {
  127. for(Sector* sector : sectors)
  128. {
  129. ANKI_DELETE(sector, scene->getAllocator());
  130. }
  131. for(Portal* portal : portals)
  132. {
  133. ANKI_DELETE(portal, scene->getAllocator());
  134. }
  135. }
  136. //==============================================================================
  137. Sector* SectorGroup::createNewSector(const Aabb& aabb)
  138. {
  139. Sector* out = ANKI_NEW(Sector, scene->getAllocator(), this, aabb);
  140. sectors.push_back(out);
  141. return out;
  142. }
  143. //==============================================================================
  144. Portal* SectorGroup::createNewPortal(Sector* a, Sector* b,
  145. const Obb& collisionShape)
  146. {
  147. ANKI_ASSERT(a && b);
  148. Portal* out = ANKI_NEW_0(Portal, scene->getAllocator());
  149. out->sectors[0] = a;
  150. out->sectors[1] = b;
  151. out->shape = collisionShape;
  152. portals.push_back(out);
  153. a->addNewPortal(out);
  154. b->addNewPortal(out);
  155. return out;
  156. }
  157. //==============================================================================
  158. void SectorGroup::placeSceneNode(SceneNode* sn)
  159. {
  160. ANKI_ASSERT(sn != nullptr);
  161. Spatial* sp = sn->getSpatial();
  162. ANKI_ASSERT(sp);
  163. const Vec3& spPos = sp->getSpatialOrigin();
  164. // Find the candidates first. Sectors overlap, chose the smaller(??!!??)
  165. Sector* sector = nullptr;
  166. for(Sector* s : sectors)
  167. {
  168. // Find if the spatia's position is inside the sector
  169. Bool inside = true;
  170. for(U i = 0; i < 3; i++)
  171. {
  172. if(spPos[i] > s->getAabb().getMax()[i]
  173. || spPos[i] < s->getAabb().getMin()[i])
  174. {
  175. inside = false;
  176. continue;
  177. }
  178. }
  179. if(!inside)
  180. {
  181. // continue
  182. }
  183. else
  184. {
  185. // No other candidate?
  186. if(sector == nullptr)
  187. {
  188. sector = s;
  189. }
  190. else
  191. {
  192. // Other candidata so chose the smaller
  193. F32 lengthSqA = (sector->getAabb().getMax()
  194. - sector->getAabb().getMin()).getLengthSquared();
  195. F32 lengthSqB = (s->getAabb().getMax()
  196. - s->getAabb().getMin()).getLengthSquared();
  197. if(lengthSqB < lengthSqA)
  198. {
  199. sector = s;
  200. }
  201. }
  202. } // end if inside
  203. }
  204. // Ask the octree to place it
  205. if(sector != nullptr)
  206. {
  207. sector->octree.placeSceneNode(sn);
  208. }
  209. else
  210. {
  211. ANKI_LOGW("Spatial outside all sectors");
  212. }
  213. }
  214. //==============================================================================
  215. void SectorGroup::doVisibilityTests(SceneNode& sn, VisibilityTest test,
  216. Renderer* r)
  217. {
  218. // Set all sectors to not visible
  219. for(Sector* sector : sectors)
  220. {
  221. sector->visibleBy = VB_NONE;
  222. }
  223. doVisibilityTestsInternal(sn, test, r, VB_CAMERA);
  224. }
  225. //==============================================================================
  226. void SectorGroup::doVisibilityTestsInternal(SceneNode& sn, VisibilityTest test,
  227. Renderer* r, VisibleBy visibleBy)
  228. {
  229. Frustumable* fr = sn.getFrustumable();
  230. ANKI_ASSERT(fr != nullptr && "sn should be frustumable");
  231. fr->visible = nullptr;
  232. Spatial* sp = sn.getSpatial();
  233. ANKI_ASSERT(sp != nullptr && "sn should be spatial as well");
  234. // sn is not placed in any octree
  235. if(sp->getOctreeNode() == nullptr)
  236. {
  237. return;
  238. }
  239. //
  240. // Find the visible sectors
  241. //
  242. SceneFrameVector<Sector*> visibleSectors(scene->getFrameAllocator());
  243. // Find the sector that contains the frustumable
  244. Sector& containerSector = sp->getOctreeNode()->getOctree().getSector();
  245. containerSector.visibleBy |= visibleBy;
  246. visibleSectors.push_back(&containerSector);
  247. // Loop all sector portals and add other sectors
  248. for(Portal* portal : containerSector.portals)
  249. {
  250. if(ANKI_UNLIKELY(!portal->open))
  251. {
  252. continue;
  253. }
  254. // Get the "other" sector of that portal
  255. Sector* testAgainstSector;
  256. if(portal->sectors[0] == &containerSector)
  257. {
  258. testAgainstSector = portal->sectors[1];
  259. }
  260. else
  261. {
  262. ANKI_ASSERT(portal->sectors[1] == &containerSector);
  263. testAgainstSector = portal->sectors[0];
  264. }
  265. ANKI_ASSERT(testAgainstSector != nullptr);
  266. // Search if portal is in the container from another portal
  267. SceneVector<Sector*>::iterator it = std::find(visibleSectors.begin(),
  268. visibleSectors.end(), testAgainstSector);
  269. if(it == visibleSectors.end())
  270. {
  271. // Not found so test the portal
  272. // Portal is visible
  273. if(fr->insideFrustum(portal->shape))
  274. {
  275. /*if(r == nullptr || r->doVisibilityTests(portal->shape))*/
  276. {
  277. testAgainstSector->visibleBy |= visibleBy;
  278. visibleSectors.push_back(testAgainstSector);
  279. }
  280. }
  281. }
  282. }
  283. //
  284. // For all visible sectors do the tests
  285. //
  286. // Create a few VisibilityTestResults to pass to every octree
  287. SceneVector<VisibilityTestResults> testResults(scene->getFrameAllocator());
  288. testResults.resize(visibleSectors.size(),
  289. VisibilityTestResults(scene->getFrameAllocator()));
  290. U renderablesCount = 0;
  291. U lightsCount = 0;
  292. // Run tests for every octree
  293. for(U i = 0; i < visibleSectors.size(); i++)
  294. {
  295. Sector* sector = visibleSectors[i];
  296. sector->octree.doVisibilityTests(sn, test, testResults[i]);
  297. renderablesCount += testResults[i].renderables.size();
  298. lightsCount += testResults[i].lights.size();
  299. }
  300. // If you don't want lights then the octree should do tests with them
  301. ANKI_ASSERT(!((test & VT_LIGHTS) == 0 && lightsCount != 0));
  302. // Same as ^
  303. ANKI_ASSERT(!((test & VT_RENDERABLES) == 0 && renderablesCount != 0));
  304. //
  305. // Combine test results and try doing renderer tests
  306. //
  307. // Create the visibility container
  308. VisibilityTestResults* visible =
  309. ANKI_NEW(VisibilityTestResults, scene->getFrameAllocator(),
  310. scene->getFrameAllocator());
  311. // Set the sizes to save some moves
  312. visible->renderables.reserve(renderablesCount);
  313. visible->lights.reserve(lightsCount);
  314. // Iterate previous test results and append to the combined one
  315. if(r == nullptr)
  316. {
  317. for(VisibilityTestResults& testResult : testResults)
  318. {
  319. visible->renderables.insert(
  320. visible->renderables.end(),
  321. testResult.renderables.begin(),
  322. testResult.renderables.end());
  323. visible->lights.insert(
  324. visible->lights.end(),
  325. testResult.lights.begin(),
  326. testResult.lights.end());
  327. }
  328. }
  329. else
  330. {
  331. for(VisibilityTestResults& testResult : testResults)
  332. {
  333. // First the renderables
  334. for(SceneNode* renderable : testResult.renderables)
  335. {
  336. if(r->doVisibilityTests(
  337. renderable->getSpatial()->getOptimalCollisionShape()))
  338. {
  339. visible->renderables.push_back(renderable);
  340. }
  341. }
  342. // Then the lights
  343. for(SceneNode* light : testResult.lights)
  344. {
  345. if(r->doVisibilityTests(
  346. light->getSpatial()->getOptimalCollisionShape()))
  347. {
  348. visible->lights.push_back(light);
  349. }
  350. }
  351. }
  352. }
  353. // The given frustumable is finished
  354. fr->visible = visible;
  355. //
  356. // Sort
  357. //
  358. ThreadPool& threadPool = ThreadPoolSingleton::get();
  359. // Sort the renderables in a another thread
  360. DistanceSortJob dsjob;
  361. dsjob.nodes = visible->renderables.begin();
  362. dsjob.nodesCount = visible->renderables.size();
  363. dsjob.origin = sp->getSpatialOrigin();
  364. threadPool.assignNewJob(0, &dsjob);
  365. // The rest of the jobs are dummy
  366. Array<ThreadJobDummy, ThreadPool::MAX_THREADS> dummyjobs;
  367. for(U i = 1; i < threadPool.getThreadsCount(); i++)
  368. {
  369. threadPool.assignNewJob(i, &dummyjobs[i]);
  370. }
  371. // Sort the lights in the main thread
  372. std::sort(visible->lights.begin(),
  373. visible->lights.end(), DistanceSortFunctor{sp->getSpatialOrigin()});
  374. threadPool.waitForAllJobsToFinish();
  375. //
  376. // Continue by testing the lights
  377. //
  378. for(SceneNode* lsn : visible->lights)
  379. {
  380. Light* l = lsn->getLight();
  381. ANKI_ASSERT(l != nullptr);
  382. if(l->getShadowEnabled())
  383. {
  384. ANKI_ASSERT(lsn->getFrustumable() != nullptr);
  385. doVisibilityTestsInternal(*lsn,
  386. (VisibilityTest)(VT_RENDERABLES | VT_ONLY_SHADOW_CASTERS),
  387. nullptr, VB_LIGHT);
  388. }
  389. }
  390. }
  391. } // end namespace anki