FrustumComponent.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright (C) 2009-2022, 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/Components/FrustumComponent.h>
  6. #include <AnKi/Scene/SceneNode.h>
  7. #include <AnKi/Collision/Functions.h>
  8. namespace anki {
  9. ANKI_SCENE_COMPONENT_STATICS(FrustumComponent)
  10. FrustumComponent::FrustumComponent(SceneNode* node)
  11. : SceneComponent(node, getStaticClassId())
  12. , m_node(node)
  13. , m_shapeMarkedForUpdate(true)
  14. , m_trfMarkedForUpdate(true)
  15. , m_miscMarkedForUpdate(true)
  16. {
  17. ANKI_ASSERT(&m_perspective.m_far == &m_ortho.m_far);
  18. ANKI_ASSERT(node);
  19. // Set some default values
  20. setFrustumType(FrustumType::kPerspective);
  21. for(U i = 0; i < m_misc.m_maxLodDistances.getSize(); ++i)
  22. {
  23. const F32 dist = (m_common.m_far - m_common.m_near) / F32(kMaxLodCount + 1);
  24. m_misc.m_maxLodDistances[i] = m_common.m_near + dist * F32(i + 1);
  25. }
  26. updateInternal();
  27. }
  28. FrustumComponent::~FrustumComponent()
  29. {
  30. m_coverageBuff.m_depthMap.destroy(m_node->getMemoryPool());
  31. }
  32. Bool FrustumComponent::updateInternal()
  33. {
  34. ANKI_ASSERT(m_frustumType != FrustumType::kCount);
  35. Bool updated = false;
  36. for(U32 i = kPrevMatrixHistory - 1; i != 0; --i)
  37. {
  38. m_prevViewProjMats[i] = m_prevViewProjMats[i - 1];
  39. m_prevViewMats[i] = m_prevViewMats[i - 1];
  40. m_prevProjMats[i] = m_prevProjMats[i - 1];
  41. }
  42. m_prevViewProjMats[0] = m_viewProjMat;
  43. m_prevViewMats[0] = m_viewMat;
  44. m_prevProjMats[0] = m_projMat;
  45. // Update the shape
  46. if(m_shapeMarkedForUpdate)
  47. {
  48. updated = true;
  49. // Fix user data
  50. if(!ANKI_SCENE_ASSERT(m_common.m_far - m_common.m_near > 1.0_cm))
  51. {
  52. setFrustumType(m_frustumType);
  53. }
  54. if(m_frustumType == FrustumType::kPerspective)
  55. {
  56. m_projMat = Mat4::calculatePerspectiveProjectionMatrix(m_perspective.m_fovX, m_perspective.m_fovY,
  57. m_perspective.m_near, m_perspective.m_far);
  58. computeEdgesOfFrustum(m_perspective.m_far, m_perspective.m_fovX, m_perspective.m_fovY,
  59. &m_perspective.m_edgesL[0]);
  60. // Planes
  61. F32 c, s; // cos & sine
  62. sinCos(kPi + m_perspective.m_fovX / 2.0f, s, c);
  63. // right
  64. m_viewPlanesL[FrustumPlaneType::kRight] = Plane(Vec4(c, 0.0f, s, 0.0f), 0.0f);
  65. // left
  66. m_viewPlanesL[FrustumPlaneType::kLeft] = Plane(Vec4(-c, 0.0f, s, 0.0f), 0.0f);
  67. sinCos((kPi + m_perspective.m_fovY) * 0.5f, s, c);
  68. // bottom
  69. m_viewPlanesL[FrustumPlaneType::kBottom] = Plane(Vec4(0.0f, s, c, 0.0f), 0.0f);
  70. // top
  71. m_viewPlanesL[FrustumPlaneType::kTop] = Plane(Vec4(0.0f, -s, c, 0.0f), 0.0f);
  72. // near
  73. m_viewPlanesL[FrustumPlaneType::kNear] = Plane(Vec4(0.0f, 0.0f, -1.0, 0.0f), m_perspective.m_near);
  74. // far
  75. m_viewPlanesL[FrustumPlaneType::kFar] = Plane(Vec4(0.0f, 0.0f, 1.0, 0.0f), -m_perspective.m_far);
  76. }
  77. else
  78. {
  79. m_projMat = Mat4::calculateOrthographicProjectionMatrix(m_ortho.m_right, m_ortho.m_left, m_ortho.m_top,
  80. m_ortho.m_bottom, m_ortho.m_near, m_ortho.m_far);
  81. // OBB
  82. const Vec4 c((m_ortho.m_right + m_ortho.m_left) * 0.5f, (m_ortho.m_top + m_ortho.m_bottom) * 0.5f,
  83. -(m_ortho.m_far + m_ortho.m_near) * 0.5f, 0.0f);
  84. const Vec4 e = Vec4(m_ortho.m_right, m_ortho.m_top, -m_ortho.m_far, 0.0f) - c;
  85. m_ortho.m_obbL = Obb(c, Mat3x4::getIdentity(), e);
  86. // Planes
  87. m_viewPlanesL[FrustumPlaneType::kLeft] = Plane(Vec4(1.0f, 0.0f, 0.0f, 0.0f), m_ortho.m_left);
  88. m_viewPlanesL[FrustumPlaneType::kRight] = Plane(Vec4(-1.0f, 0.0f, 0.0f, 0.0f), -m_ortho.m_right);
  89. m_viewPlanesL[FrustumPlaneType::kNear] = Plane(Vec4(0.0f, 0.0f, -1.0f, 0.0f), m_ortho.m_near);
  90. m_viewPlanesL[FrustumPlaneType::kFar] = Plane(Vec4(0.0f, 0.0f, 1.0f, 0.0f), -m_ortho.m_far);
  91. m_viewPlanesL[FrustumPlaneType::kTop] = Plane(Vec4(0.0f, -1.0f, 0.0f, 0.0f), -m_ortho.m_top);
  92. m_viewPlanesL[FrustumPlaneType::kBottom] = Plane(Vec4(0.0f, 1.0f, 0.0f, 0.0f), m_ortho.m_bottom);
  93. }
  94. }
  95. // Update transform related things
  96. if(m_trfMarkedForUpdate)
  97. {
  98. updated = true;
  99. m_viewMat = Mat3x4(m_trf.getInverse());
  100. }
  101. // Fixup the misc data
  102. if(m_miscMarkedForUpdate)
  103. {
  104. updated = true;
  105. const F32 frustumFraction = (m_common.m_far - m_common.m_near) / 100.0f;
  106. for(U32 i = 0; i < m_misc.m_shadowCascadeCount; ++i)
  107. {
  108. if(!ANKI_SCENE_ASSERT(m_misc.m_shadowCascadeDistances[i] > m_common.m_near
  109. && m_misc.m_shadowCascadeDistances[i] <= m_common.m_far))
  110. {
  111. m_misc.m_shadowCascadeDistances[i] =
  112. clamp(m_misc.m_shadowCascadeDistances[i], m_common.m_near + kEpsilonf, m_common.m_far);
  113. }
  114. if(i != 0
  115. && !ANKI_SCENE_ASSERT(m_misc.m_shadowCascadeDistances[i - 1] < m_misc.m_shadowCascadeDistances[i]))
  116. {
  117. m_misc.m_shadowCascadeDistances[i] = m_misc.m_shadowCascadeDistances[i - 1] + frustumFraction;
  118. }
  119. }
  120. for(U32 i = 0; i < m_misc.m_maxLodDistances.getSize(); ++i)
  121. {
  122. if(!ANKI_SCENE_ASSERT(m_misc.m_maxLodDistances[i] > m_common.m_near
  123. && m_misc.m_maxLodDistances[i] <= m_common.m_far))
  124. {
  125. m_misc.m_maxLodDistances[i] =
  126. clamp(m_misc.m_maxLodDistances[i], m_common.m_near + kEpsilonf, m_common.m_far);
  127. }
  128. if(i != 0 && !ANKI_SCENE_ASSERT(m_misc.m_maxLodDistances[i - 1] < m_misc.m_maxLodDistances[i]))
  129. {
  130. m_misc.m_maxLodDistances[i] = m_misc.m_maxLodDistances[i - 1] + frustumFraction;
  131. }
  132. }
  133. }
  134. // Updates that are affected by transform & shape updates
  135. if(updated)
  136. {
  137. m_viewProjMat = m_projMat * Mat4(m_viewMat, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
  138. m_shapeMarkedForUpdate = false;
  139. m_trfMarkedForUpdate = false;
  140. m_miscMarkedForUpdate = false;
  141. if(m_frustumType == FrustumType::kPerspective)
  142. {
  143. m_perspective.m_edgesW[0] = m_trf.getOrigin();
  144. m_perspective.m_edgesW[1] = m_trf.transform(m_perspective.m_edgesL[0]);
  145. m_perspective.m_edgesW[2] = m_trf.transform(m_perspective.m_edgesL[1]);
  146. m_perspective.m_edgesW[3] = m_trf.transform(m_perspective.m_edgesL[2]);
  147. m_perspective.m_edgesW[4] = m_trf.transform(m_perspective.m_edgesL[3]);
  148. m_perspective.m_hull = ConvexHullShape(&m_perspective.m_edgesW[0], m_perspective.m_edgesW.getSize());
  149. }
  150. else
  151. {
  152. m_ortho.m_obbW = m_ortho.m_obbL.getTransformed(m_trf);
  153. }
  154. for(FrustumPlaneType planeId : EnumIterable<FrustumPlaneType>())
  155. {
  156. m_viewPlanesW[planeId] = m_viewPlanesL[planeId].getTransformed(m_trf);
  157. }
  158. }
  159. return updated;
  160. }
  161. void FrustumComponent::fillCoverageBufferCallback(void* userData, F32* depthValues, U32 width, U32 height)
  162. {
  163. ANKI_ASSERT(userData && depthValues && width > 0 && height > 0);
  164. FrustumComponent& self = *static_cast<FrustumComponent*>(userData);
  165. self.m_coverageBuff.m_depthMap.destroy(self.m_node->getMemoryPool());
  166. self.m_coverageBuff.m_depthMap.create(self.m_node->getMemoryPool(), width * height);
  167. memcpy(&self.m_coverageBuff.m_depthMap[0], depthValues, self.m_coverageBuff.m_depthMap.getSizeInBytes());
  168. self.m_coverageBuff.m_depthMapWidth = width;
  169. self.m_coverageBuff.m_depthMapHeight = height;
  170. }
  171. void FrustumComponent::setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag bits)
  172. {
  173. m_flags = FrustumComponentVisibilityTestFlag::kNone;
  174. m_flags |= bits;
  175. #if ANKI_ENABLE_ASSERTIONS
  176. if(!!(m_flags & FrustumComponentVisibilityTestFlag::kRenderComponents)
  177. || !!(m_flags & FrustumComponentVisibilityTestFlag::kShadowCasterRenderComponents))
  178. {
  179. if((m_flags & FrustumComponentVisibilityTestFlag::kRenderComponents)
  180. == (m_flags & FrustumComponentVisibilityTestFlag::kShadowCasterRenderComponents))
  181. {
  182. ANKI_ASSERT(0 && "Cannot have them both");
  183. }
  184. }
  185. // TODO
  186. #endif
  187. }
  188. } // end namespace anki