VisibilityTester.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #include <boost/foreach.hpp>
  2. #include "VisibilityTester.h"
  3. #include "Scene.h"
  4. #include "ModelNode.h"
  5. #include "SkinNode.h"
  6. #include "ModelPatchNode.h"
  7. #include "rsrc/Material.h"
  8. #include "cln/Sphere.h"
  9. #include "PointLight.h"
  10. #include "SpotLight.h"
  11. #include "core/parallel/Manager.h"
  12. #include "core/Logger.h"
  13. //==============================================================================
  14. // Destructor =
  15. //==============================================================================
  16. VisibilityTester::~VisibilityTester()
  17. {}
  18. //==============================================================================
  19. // CmpDistanceFromOrigin::operator() =
  20. //==============================================================================
  21. bool VisibilityTester::CmpDistanceFromOrigin::operator()(const SceneNode* a,
  22. const SceneNode* b) const
  23. {
  24. return (a->getWorldTransform().getOrigin() - o).getLengthSquared() <
  25. (b->getWorldTransform().getOrigin() - o).getLengthSquared();
  26. }
  27. //==============================================================================
  28. // Constructor =
  29. //==============================================================================
  30. VisibilityTester::VisibilityTester(Scene& scene_):
  31. scene(scene_)
  32. {}
  33. //==============================================================================
  34. // test =
  35. //==============================================================================
  36. void VisibilityTester::test(Camera& cam)
  37. {
  38. //
  39. // Set all nodes to not visible
  40. //
  41. BOOST_FOREACH(SceneNode* node, scene.getAllNodes())
  42. {
  43. node->disableFlag(SceneNode::SNF_VISIBLE);
  44. }
  45. //
  46. // Collect the lights for the main cam
  47. //
  48. cam.getVisiblePointLights().clear();
  49. cam.getVisibleSpotLights().clear();
  50. BOOST_FOREACH(Light* light, scene.getLights())
  51. {
  52. if(!light->isFlagEnabled(SceneNode::SNF_ACTIVE))
  53. {
  54. continue;
  55. }
  56. switch(light->getLightType())
  57. {
  58. // Point
  59. case Light::LT_POINT:
  60. {
  61. PointLight* pointl = static_cast<PointLight*>(light);
  62. Sphere sphere(pointl->getWorldTransform().getOrigin(),
  63. pointl->getRadius());
  64. if(cam.insideFrustum(sphere))
  65. {
  66. cam.getVisiblePointLights().push_back(pointl);
  67. pointl->enableFlag(SceneNode::SNF_VISIBLE);
  68. }
  69. break;
  70. }
  71. // Spot
  72. case Light::LT_SPOT:
  73. {
  74. SpotLight* spotl = static_cast<SpotLight*>(light);
  75. if(cam.insideFrustum(*(spotl->getCamera().
  76. getVisibilityCollisionShapeWorldSpace())))
  77. {
  78. cam.getVisibleSpotLights().push_back(spotl);
  79. spotl->enableFlag(SceneNode::SNF_VISIBLE);
  80. spotl->getCamera().enableFlag(SceneNode::SNF_VISIBLE);
  81. }
  82. break;
  83. }
  84. } // end switch
  85. } // end for all lights
  86. //
  87. // Get the renderables for the main cam
  88. //
  89. getRenderableNodes(false, cam, cam);
  90. //
  91. // For every spot light camera collect the renderable nodes
  92. //
  93. BOOST_FOREACH(SpotLight* spot, cam.getVisibleSpotLights())
  94. {
  95. getRenderableNodes(true, spot->getCamera(), *spot);
  96. }
  97. }
  98. //==============================================================================
  99. // test =
  100. //==============================================================================
  101. template<typename Type>
  102. bool VisibilityTester::test(const Type& tested, const Camera& cam)
  103. {
  104. return cam.insideFrustum(*tested.getVisibilityCollisionShapeWorldSpace());
  105. }
  106. //==============================================================================
  107. // getRenderableNodes =
  108. //==============================================================================
  109. void VisibilityTester::getRenderableNodes(bool skipShadowless,
  110. const Camera& cam, VisibilityInfo& storage)
  111. {
  112. storage.getVisibleMsRenderableNodes().clear();
  113. storage.getVisibleBsRenderableNodes().clear();
  114. // Run in parallel
  115. VisJobParameters jobParameters;
  116. jobParameters.cam = &cam;
  117. jobParameters.skipShadowless = skipShadowless;
  118. jobParameters.visibilityInfo = &storage;
  119. jobParameters.scene = &scene;
  120. jobParameters.msRenderableNodesMtx = &msRenderableNodesMtx;
  121. jobParameters.bsRenderableNodesMtx = &bsRenderableNodesMtx;
  122. for(uint i = 0;
  123. i < parallel::ManagerSingleton::get().getThreadsNum(); i++)
  124. {
  125. parallel::ManagerSingleton::get().assignNewJob(i,
  126. getRenderableNodesJobCallback, jobParameters);
  127. }
  128. parallel::ManagerSingleton::get().waitForAllJobsToFinish();
  129. //
  130. // Sort the renderables from closest to the camera to the farthest
  131. //
  132. std::sort(storage.getVisibleMsRenderableNodes().begin(),
  133. storage.getVisibleMsRenderableNodes().end(),
  134. CmpDistanceFromOrigin(cam.getWorldTransform().getOrigin()));
  135. std::sort(storage.getVisibleBsRenderableNodes().begin(),
  136. storage.getVisibleBsRenderableNodes().end(),
  137. CmpDistanceFromOrigin(cam.getWorldTransform().getOrigin()));
  138. }
  139. //==============================================================================
  140. // getRenderableNodesJobCallback =
  141. //==============================================================================
  142. void VisibilityTester::getRenderableNodesJobCallback(
  143. parallel::JobParameters& data,
  144. const parallel::Job& job)
  145. {
  146. VisJobParameters& jobParameters = static_cast<VisJobParameters&>(data);
  147. uint id = job.getId();
  148. uint threadsNum = job.getManager().getThreadsNum();
  149. const Camera& cam = *jobParameters.cam;
  150. bool skipShadowless = jobParameters.skipShadowless;
  151. VisibilityInfo& visibilityInfo = *jobParameters.visibilityInfo;
  152. Scene& scene = *jobParameters.scene;
  153. boost::mutex& msRenderableNodesMtx = *jobParameters.msRenderableNodesMtx;
  154. boost::mutex& bsRenderableNodesMtx = *jobParameters.bsRenderableNodesMtx;
  155. uint count, from, to;
  156. size_t nodesSize;
  157. boost::array<const RenderableNode*, Scene::MAX_VISIBLE_NODES> msVisibles,
  158. bsVisibles;
  159. uint msI = 0, bsI = 0;
  160. //
  161. // ModelNodes
  162. //
  163. nodesSize = scene.getModelNodes().size();
  164. count = nodesSize / threadsNum;
  165. from = count * id;
  166. to = count * (id + 1);
  167. if(id == threadsNum - 1) // The last job will get the rest
  168. {
  169. to = nodesSize;
  170. }
  171. for(uint i = from; i < to; i++)
  172. {
  173. ModelNode* node = scene.getModelNodes()[i];
  174. if(!node->isFlagEnabled(SceneNode::SNF_ACTIVE))
  175. {
  176. continue;
  177. }
  178. // Skip if the ModeNode is not visible
  179. if(!test(*node, cam))
  180. {
  181. continue;
  182. }
  183. node->enableFlag(SceneNode::SNF_VISIBLE);
  184. // If visible test every patch individually
  185. BOOST_FOREACH(ModelPatchNode* modelPatchNode,
  186. node->getModelPatchNodes())
  187. {
  188. if(!modelPatchNode->isFlagEnabled(SceneNode::SNF_ACTIVE))
  189. {
  190. continue;
  191. }
  192. // Skip shadowless
  193. if(skipShadowless &&
  194. !modelPatchNode->getMaterialRuntime().getCastShadow())
  195. {
  196. continue;
  197. }
  198. // Test if visible by main camera
  199. if(test(*modelPatchNode, cam))
  200. {
  201. if(modelPatchNode->getMaterialRuntime().
  202. getRenderInBledingStage())
  203. {
  204. bsVisibles[bsI++] = modelPatchNode;
  205. }
  206. else
  207. {
  208. msVisibles[msI++] = modelPatchNode;
  209. }
  210. modelPatchNode->enableFlag(SceneNode::SNF_VISIBLE);
  211. }
  212. }
  213. }
  214. //
  215. // SkinNodes
  216. //
  217. nodesSize = scene.getSkinNodes().size();
  218. count = nodesSize / threadsNum;
  219. from = count * id;
  220. to = count * (id + 1);
  221. if(id == threadsNum - 1) // The last job will get the rest
  222. {
  223. to = nodesSize;
  224. }
  225. for(uint i = from; i < to; i++)
  226. {
  227. SkinNode* node = scene.getSkinNodes()[i];
  228. if(!node->isFlagEnabled(SceneNode::SNF_ACTIVE))
  229. {
  230. continue;
  231. }
  232. // Skip if the SkinNode is not visible
  233. if(!test(*node, cam))
  234. {
  235. continue;
  236. }
  237. node->enableFlag(SceneNode::SNF_VISIBLE);
  238. // Put all the patches into the visible container
  239. BOOST_FOREACH(SkinPatchNode* patchNode,
  240. node->getPatchNodes())
  241. {
  242. if(!patchNode->isFlagEnabled(SceneNode::SNF_ACTIVE))
  243. {
  244. continue;
  245. }
  246. // Skip shadowless
  247. if(skipShadowless &&
  248. !patchNode->getMaterialRuntime().getCastShadow())
  249. {
  250. continue;
  251. }
  252. if(patchNode->getMaterialRuntime().getRenderInBledingStage())
  253. {
  254. bsVisibles[bsI++] = patchNode;
  255. }
  256. else
  257. {
  258. msVisibles[msI++] = patchNode;
  259. }
  260. patchNode->enableFlag(SceneNode::SNF_VISIBLE);
  261. }
  262. }
  263. //
  264. // Copy the temps to the global
  265. //
  266. {
  267. boost::mutex::scoped_lock lock(bsRenderableNodesMtx);
  268. for(uint i = 0; i < bsI; i++)
  269. {
  270. visibilityInfo.getVisibleBsRenderableNodes().push_back(
  271. bsVisibles[i]);
  272. }
  273. }
  274. {
  275. boost::mutex::scoped_lock lock(msRenderableNodesMtx);
  276. for(uint i = 0; i < msI; i++)
  277. {
  278. visibilityInfo.getVisibleMsRenderableNodes().push_back(
  279. msVisibles[i]);
  280. }
  281. }
  282. }