sceneZoneCullingState.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "scene/culling/sceneZoneCullingState.h"
  24. #include "scene/culling/sceneCullingState.h"
  25. #include "platform/profiler.h"
  26. //-----------------------------------------------------------------------------
  27. template< typename T >
  28. inline SceneZoneCullingState::CullingTestResult SceneZoneCullingState::_testVolumes( T bounds, bool occludersOnly ) const
  29. {
  30. // If we are testing for occlusion only and we don't have any
  31. // occlusion volumes, we can early out here.
  32. if( occludersOnly && !mHaveOccluders )
  33. return CullingTestNegative;
  34. // If we haven't sorted the volumes on this zone state yet,
  35. // do so now.
  36. if( !mHaveSortedVolumes )
  37. _sortVolumes();
  38. // Now go through the volumes in this zone and test them
  39. // against the bounds.
  40. for( CullingVolumeLink* link = mCullingVolumes; link != NULL; link = link->mNext )
  41. {
  42. const SceneCullingVolume& volume = link->mVolume;
  43. if( volume.isOccluder() )
  44. {
  45. if( volume.test( bounds ) )
  46. return CullingTestPositiveByOcclusion;
  47. }
  48. else
  49. {
  50. // If we are testing for occlusion only, we can early out as soon
  51. // as we have reached the first non-inverted volume.
  52. if( occludersOnly )
  53. return CullingTestNegative;
  54. if( volume.test( bounds ) )
  55. return CullingTestPositiveByInclusion;
  56. }
  57. }
  58. return CullingTestNegative;
  59. }
  60. //-----------------------------------------------------------------------------
  61. SceneZoneCullingState::CullingTestResult SceneZoneCullingState::testVolumes( const Box3F& aabb, bool invertedOnly ) const
  62. {
  63. PROFILE_SCOPE( SceneZoneCullingState_testVolumes );
  64. return _testVolumes( aabb, invertedOnly );
  65. }
  66. //-----------------------------------------------------------------------------
  67. SceneZoneCullingState::CullingTestResult SceneZoneCullingState::testVolumes( const OrientedBox3F& obb, bool invertedOnly ) const
  68. {
  69. PROFILE_SCOPE( SceneZoneCullingState_testVolumes_OBB );
  70. return _testVolumes( obb, invertedOnly );
  71. }
  72. //-----------------------------------------------------------------------------
  73. SceneZoneCullingState::CullingTestResult SceneZoneCullingState::testVolumes( const SphereF& sphere, bool invertedOnly ) const
  74. {
  75. PROFILE_SCOPE( SceneZoneCullingState_testVolumes_Sphere );
  76. return _testVolumes( sphere, invertedOnly );
  77. }
  78. //-----------------------------------------------------------------------------
  79. void SceneZoneCullingState::_sortVolumes() const
  80. {
  81. // First do a pass to gather all occlusion volumes. These must be put on the
  82. // list in front of all inclusion volumes. Otherwise, an inclusion volume
  83. // may test positive when in fact an occlusion volume would reject the object.
  84. CullingVolumeLink* occluderHead = NULL;
  85. CullingVolumeLink* occluderTail = NULL;
  86. if( mHaveOccluders )
  87. {
  88. U32 numOccluders = 0;
  89. for( CullingVolumeLink* current = mCullingVolumes, *prev = NULL; current != NULL; )
  90. {
  91. CullingVolumeLink* next = current->mNext;
  92. if( !current->mVolume.isOccluder() )
  93. prev = current;
  94. else
  95. {
  96. // Unlink from list.
  97. if( prev )
  98. prev->mNext = next;
  99. else
  100. mCullingVolumes = next;
  101. // Sort into list.
  102. _insertSorted( occluderHead, occluderTail, current );
  103. ++ numOccluders;
  104. }
  105. current = next;
  106. }
  107. // If we ended up with more inverted (occlusion) volumes than we want,
  108. // chop off any but the first N volumes. Since we have sorted the volumes
  109. // by screen coverage, this will get rid of smallest occlusion volumes.
  110. if( numOccluders > SceneCullingState::smMaxOccludersPerZone )
  111. {
  112. CullingVolumeLink* last = occluderHead;
  113. for( U32 i = 0; i < ( SceneCullingState::smMaxOccludersPerZone - 1 ); ++ i )
  114. last = last->mNext;
  115. // Chop off rest. The links are allocated on the chunker
  116. // and thus will simply disappear when the state gets deleted.
  117. last->mNext = NULL;
  118. occluderTail = last;
  119. }
  120. }
  121. // Now, do a second pass to sort all includer volumes by decreasing screen
  122. // real estate so that when testing against them, we test the larger volumes first
  123. // and the smaller ones later.
  124. CullingVolumeLink* includerHead = NULL;
  125. CullingVolumeLink* includerTail = NULL;
  126. while( mCullingVolumes )
  127. {
  128. CullingVolumeLink* current = mCullingVolumes;
  129. AssertFatal( !current->mVolume.isOccluder(),
  130. "SceneCullingState::ZoneState::_sortFrustums - Occluders must have been filtered out at this point" );
  131. // Unlink from list.
  132. mCullingVolumes = current->mNext;
  133. // Sort into list.
  134. _insertSorted( includerHead, includerTail, current );
  135. }
  136. // Merge the two lists. Put inverted volumes first and
  137. // non-inverted volumes second.
  138. if( occluderHead != NULL )
  139. {
  140. mCullingVolumes = occluderHead;
  141. occluderTail->mNext = includerHead;
  142. }
  143. else
  144. mCullingVolumes = includerHead;
  145. // Done.
  146. mHaveSortedVolumes = true;
  147. }
  148. //-----------------------------------------------------------------------------
  149. void SceneZoneCullingState::_insertSorted( CullingVolumeLink*& head, CullingVolumeLink*& tail, CullingVolumeLink* link )
  150. {
  151. // If first element, just put it in the list
  152. // and return.
  153. if( !head )
  154. {
  155. head = link;
  156. tail = link;
  157. link->mNext = NULL;
  158. return;
  159. }
  160. // Otherwise, search for where to put it.
  161. F32 sortPoint = link->mVolume.getSortPoint();
  162. for( CullingVolumeLink* current = head, *prev = NULL; current != NULL; prev = current, current = current->mNext )
  163. {
  164. F32 currentSortPoint = current->mVolume.getSortPoint();
  165. if( currentSortPoint > sortPoint )
  166. continue;
  167. if( !prev )
  168. head = link;
  169. else
  170. prev->mNext = link;
  171. link->mNext = current;
  172. return;
  173. }
  174. // Smallest frustum in list. Append to end.
  175. tail->mNext = link;
  176. link->mNext = NULL;
  177. tail = link;
  178. }