LightNode.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. // Copyright (C) 2009-2020, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <anki/scene/LightNode.h>
  6. #include <anki/scene/SceneGraph.h>
  7. #include <anki/scene/components/LensFlareComponent.h>
  8. #include <anki/scene/components/MoveComponent.h>
  9. #include <anki/scene/components/SpatialComponent.h>
  10. #include <anki/scene/components/FrustumComponent.h>
  11. #include <anki/resource/ResourceManager.h>
  12. #include <anki/shaders/include/ClusteredShadingTypes.h>
  13. namespace anki
  14. {
  15. /// Feedback component.
  16. class LightNode::MovedFeedbackComponent : public SceneComponent
  17. {
  18. public:
  19. MovedFeedbackComponent()
  20. : SceneComponent(SceneComponentType::NONE)
  21. {
  22. }
  23. Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated) override
  24. {
  25. updated = false;
  26. const MoveComponent& move = node.getComponentAt<MoveComponent>(0);
  27. if(move.getTimestamp() == node.getGlobalTimestamp())
  28. {
  29. // Move updated
  30. static_cast<LightNode&>(node).onMoveUpdate(move);
  31. }
  32. return Error::NONE;
  33. }
  34. };
  35. /// Feedback component.
  36. class LightNode::LightChangedFeedbackComponent : public SceneComponent
  37. {
  38. public:
  39. LightChangedFeedbackComponent()
  40. : SceneComponent(SceneComponentType::NONE)
  41. {
  42. }
  43. Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated) override
  44. {
  45. updated = false;
  46. LightComponent& light = node.getFirstComponentOfType<LightComponent>();
  47. if(light.getTimestamp() == node.getGlobalTimestamp())
  48. {
  49. // Shape updated
  50. static_cast<LightNode&>(node).onShapeUpdate(light);
  51. }
  52. return Error::NONE;
  53. }
  54. };
  55. LightNode::LightNode(SceneGraph* scene, CString name)
  56. : SceneNode(scene, name)
  57. {
  58. }
  59. LightNode::~LightNode()
  60. {
  61. }
  62. Error LightNode::initCommon(LightComponentType lightType)
  63. {
  64. CString texFname;
  65. switch(lightType)
  66. {
  67. case LightComponentType::POINT:
  68. texFname = "engine_data/LightBulb.ankitex";
  69. break;
  70. case LightComponentType::SPOT:
  71. texFname = "engine_data/SpotLight.ankitex";
  72. break;
  73. default:
  74. ANKI_ASSERT(0);
  75. }
  76. ANKI_CHECK(getResourceManager().loadResource(texFname, m_dbgTex));
  77. return m_dbgDrawer.init(&getResourceManager());
  78. }
  79. void LightNode::frameUpdateCommon()
  80. {
  81. // Update frustum comps shadow info
  82. const LightComponent& lc = getFirstComponentOfType<LightComponent>();
  83. const Bool castsShadow = lc.getShadowEnabled();
  84. const Error err = iterateComponentsOfType<FrustumComponent>([&](FrustumComponent& frc) -> Error {
  85. if(castsShadow)
  86. {
  87. frc.setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag::SHADOW_CASTERS);
  88. }
  89. else
  90. {
  91. frc.setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag::NONE);
  92. }
  93. return Error::NONE;
  94. });
  95. (void)err;
  96. }
  97. void LightNode::onMoveUpdateCommon(const MoveComponent& move)
  98. {
  99. // Update the spatial
  100. SpatialComponent& sp = getFirstComponentOfType<SpatialComponent>();
  101. sp.markForUpdate();
  102. sp.setSpatialOrigin(move.getWorldTransform().getOrigin());
  103. // Update the lens flare
  104. LensFlareComponent* lf = tryGetFirstComponentOfType<LensFlareComponent>();
  105. if(lf)
  106. {
  107. lf->setWorldPosition(move.getWorldTransform().getOrigin());
  108. }
  109. // Update light component
  110. getFirstComponentOfType<LightComponent>().updateWorldTransform(move.getWorldTransform());
  111. }
  112. Error LightNode::loadLensFlare(const CString& filename)
  113. {
  114. ANKI_ASSERT(tryGetFirstComponentOfType<LensFlareComponent>() == nullptr);
  115. LensFlareComponent* flareComp = newComponent<LensFlareComponent>(this);
  116. const Error err = flareComp->init(filename);
  117. if(err)
  118. {
  119. ANKI_ASSERT(!"TODO: Remove component");
  120. return err;
  121. }
  122. return Error::NONE;
  123. }
  124. void LightNode::drawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
  125. {
  126. for(const void* plight : userData)
  127. {
  128. const LightNode& self = *static_cast<const LightNode*>(plight);
  129. const LightComponent& lcomp = self.getFirstComponentOfType<LightComponent>();
  130. const Bool enableDepthTest = ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DEPTH_TEST_ON);
  131. if(enableDepthTest)
  132. {
  133. ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::LESS);
  134. }
  135. else
  136. {
  137. ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::ALWAYS);
  138. }
  139. Vec3 color = lcomp.getDiffuseColor().xyz();
  140. color /= max(max(color.x(), color.y()), color.z());
  141. self.m_dbgDrawer.drawBillboardTexture(
  142. ctx.m_projectionMatrix, ctx.m_viewMatrix, lcomp.getTransform().getOrigin().xyz(), color.xyz1(),
  143. ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON),
  144. self.m_dbgTex->getGrTextureView(), ctx.m_sampler, Vec2(0.75f), *ctx.m_stagingGpuAllocator,
  145. ctx.m_commandBuffer);
  146. // Restore state
  147. if(!enableDepthTest)
  148. {
  149. ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::LESS);
  150. }
  151. }
  152. }
  153. PointLightNode::PointLightNode(SceneGraph* scene, CString name)
  154. : LightNode(scene, name)
  155. {
  156. }
  157. PointLightNode::~PointLightNode()
  158. {
  159. m_shadowData.destroy(getAllocator());
  160. }
  161. Error PointLightNode::init()
  162. {
  163. ANKI_CHECK(initCommon(LightComponentType::POINT));
  164. // Move component
  165. newComponent<MoveComponent>();
  166. // Feedback component
  167. newComponent<MovedFeedbackComponent>();
  168. // Light component
  169. LightComponent* lc = newComponent<LightComponent>(LightComponentType::POINT, getSceneGraph().getNewUuid());
  170. lc->setDrawCallback(drawCallback, static_cast<LightNode*>(this));
  171. // Feedback component
  172. newComponent<LightChangedFeedbackComponent>();
  173. // Spatial component
  174. newComponent<SpatialComponent>(this, &m_sphereW);
  175. return Error::NONE;
  176. }
  177. void PointLightNode::onMoveUpdate(const MoveComponent& move)
  178. {
  179. onMoveUpdateCommon(move);
  180. // Update the frustums
  181. U32 count = 0;
  182. Error err = iterateComponentsOfType<FrustumComponent>([&](FrustumComponent& fr) -> Error {
  183. Transform trf = m_shadowData[count].m_localTrf;
  184. trf.setOrigin(move.getWorldTransform().getOrigin());
  185. fr.setTransform(trf);
  186. ++count;
  187. return Error::NONE;
  188. });
  189. (void)err;
  190. m_sphereW.setCenter(move.getWorldTransform().getOrigin());
  191. }
  192. void PointLightNode::onShapeUpdate(LightComponent& light)
  193. {
  194. Error err = iterateComponentsOfType<FrustumComponent>([&](FrustumComponent& fr) -> Error {
  195. fr.setFar(light.getRadius());
  196. return Error::NONE;
  197. });
  198. (void)err;
  199. m_sphereW.setRadius(light.getRadius());
  200. }
  201. Error PointLightNode::frameUpdate(Second prevUpdateTime, Second crntTime)
  202. {
  203. if(getFirstComponentOfType<LightComponent>().getShadowEnabled() && m_shadowData.isEmpty())
  204. {
  205. m_shadowData.create(getAllocator(), 6);
  206. const F32 ang = toRad(90.0f);
  207. const F32 dist = m_sphereW.getRadius();
  208. const F32 zNear = LIGHT_FRUSTUM_NEAR_PLANE;
  209. Mat3 rot;
  210. rot = Mat3(Euler(0.0, -PI / 2.0, 0.0)) * Mat3(Euler(0.0, 0.0, PI));
  211. m_shadowData[0].m_localTrf.setRotation(Mat3x4(Vec3(0.0f), rot));
  212. rot = Mat3(Euler(0.0, PI / 2.0, 0.0)) * Mat3(Euler(0.0, 0.0, PI));
  213. m_shadowData[1].m_localTrf.setRotation(Mat3x4(Vec3(0.0f), rot));
  214. rot = Mat3(Euler(PI / 2.0, 0.0, 0.0));
  215. m_shadowData[2].m_localTrf.setRotation(Mat3x4(Vec3(0.0f), rot));
  216. rot = Mat3(Euler(-PI / 2.0, 0.0, 0.0));
  217. m_shadowData[3].m_localTrf.setRotation(Mat3x4(Vec3(0.0f), rot));
  218. rot = Mat3(Euler(0.0, PI, 0.0)) * Mat3(Euler(0.0, 0.0, PI));
  219. m_shadowData[4].m_localTrf.setRotation(Mat3x4(Vec3(0.0f), rot));
  220. rot = Mat3(Euler(0.0, 0.0, PI));
  221. m_shadowData[5].m_localTrf.setRotation(Mat3x4(Vec3(0.0f), rot));
  222. const Vec4& origin = getFirstComponentOfType<MoveComponent>().getWorldTransform().getOrigin();
  223. for(U32 i = 0; i < 6; i++)
  224. {
  225. Transform trf = m_shadowData[i].m_localTrf;
  226. trf.setOrigin(origin);
  227. FrustumComponent* frc = newComponent<FrustumComponent>(this, FrustumType::PERSPECTIVE);
  228. frc->setPerspective(zNear, dist, ang, ang);
  229. frc->setTransform(trf);
  230. }
  231. }
  232. frameUpdateCommon();
  233. return Error::NONE;
  234. }
  235. SpotLightNode::SpotLightNode(SceneGraph* scene, CString name)
  236. : LightNode(scene, name)
  237. {
  238. }
  239. Error SpotLightNode::init()
  240. {
  241. ANKI_CHECK(initCommon(LightComponentType::SPOT));
  242. // Move component
  243. newComponent<MoveComponent>();
  244. // Feedback component
  245. newComponent<MovedFeedbackComponent>();
  246. // Light component
  247. LightComponent* lc = newComponent<LightComponent>(LightComponentType::SPOT, getSceneGraph().getNewUuid());
  248. lc->setDrawCallback(drawCallback, static_cast<LightNode*>(this));
  249. // Feedback component
  250. newComponent<LightChangedFeedbackComponent>();
  251. // Frustum component
  252. FrustumComponent* fr = newComponent<FrustumComponent>(this, FrustumType::PERSPECTIVE);
  253. fr->setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag::NONE);
  254. // Spatial component
  255. newComponent<SpatialComponent>(this, &fr->getPerspectiveBoundingShape());
  256. return Error::NONE;
  257. }
  258. void SpotLightNode::onMoveUpdate(const MoveComponent& move)
  259. {
  260. // Update the frustums
  261. Error err = iterateComponentsOfType<FrustumComponent>([&](FrustumComponent& fr) -> Error {
  262. fr.setTransform(move.getWorldTransform());
  263. return Error::NONE;
  264. });
  265. (void)err;
  266. onMoveUpdateCommon(move);
  267. }
  268. void SpotLightNode::onShapeUpdate(LightComponent& light)
  269. {
  270. // Update the frustum first
  271. FrustumComponent& frc = getFirstComponentOfType<FrustumComponent>();
  272. frc.setPerspective(LIGHT_FRUSTUM_NEAR_PLANE, light.getDistance(), light.getOuterAngle(), light.getOuterAngle());
  273. // Mark the spatial for update
  274. SpatialComponent& sp = getFirstComponentOfType<SpatialComponent>();
  275. sp.markForUpdate();
  276. }
  277. Error SpotLightNode::frameUpdate(Second prevUpdateTime, Second crntTime)
  278. {
  279. frameUpdateCommon();
  280. return Error::NONE;
  281. }
  282. class DirectionalLightNode::FeedbackComponent : public SceneComponent
  283. {
  284. public:
  285. FeedbackComponent()
  286. : SceneComponent(SceneComponentType::NONE)
  287. {
  288. }
  289. Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated) override
  290. {
  291. const MoveComponent& move = node.getComponentAt<MoveComponent>(0);
  292. if(move.getTimestamp() == node.getGlobalTimestamp())
  293. {
  294. // Move updated
  295. LightComponent& lightc = node.getFirstComponentOfType<LightComponent>();
  296. lightc.updateWorldTransform(move.getWorldTransform());
  297. SpatialComponent& spatialc = node.getFirstComponentOfType<SpatialComponent>();
  298. spatialc.setSpatialOrigin(move.getWorldTransform().getOrigin());
  299. spatialc.markForUpdate();
  300. }
  301. return Error::NONE;
  302. }
  303. };
  304. DirectionalLightNode::DirectionalLightNode(SceneGraph* scene, CString name)
  305. : SceneNode(scene, name)
  306. {
  307. }
  308. Error DirectionalLightNode::init()
  309. {
  310. newComponent<MoveComponent>();
  311. newComponent<FeedbackComponent>();
  312. LightComponent* lc = newComponent<LightComponent>(LightComponentType::DIRECTIONAL, getSceneGraph().getNewUuid());
  313. lc->setDrawCallback(drawCallback, this);
  314. SpatialComponent* spatialc = newComponent<SpatialComponent>(this, &m_boundingBox);
  315. // Make the bounding box large enough so it will always be visible. Because of that don't update the octree bounds
  316. m_boundingBox.setMin(getSceneGraph().getSceneMin());
  317. m_boundingBox.setMax(getSceneGraph().getSceneMax());
  318. spatialc->setUpdateOctreeBounds(false);
  319. return Error::NONE;
  320. }
  321. } // end namespace anki