CapsuleLightDelegate.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Atom/Feature/CoreLights/CapsuleLightFeatureProcessorInterface.h>
  9. #include <Atom/RPI.Public/Scene.h>
  10. #include <AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h>
  11. #include <CoreLights/CapsuleLightDelegate.h>
  12. namespace AZ::Render
  13. {
  14. CapsuleLightDelegate::CapsuleLightDelegate(LmbrCentral::CapsuleShapeComponentRequests* shapeBus, EntityId entityId, bool isVisible)
  15. : LightDelegateBase<CapsuleLightFeatureProcessorInterface>(entityId, isVisible)
  16. , m_capsuleShapeBus(shapeBus)
  17. {
  18. InitBase(entityId);
  19. }
  20. float CapsuleLightDelegate::CalculateAttenuationRadius(float lightThreshold) const
  21. {
  22. // Calculate the radius at which the irradiance will be equal to lightThreshold.
  23. lightThreshold = AZStd::max<float>(lightThreshold, 0.001f); // prevent divide by zero.
  24. // This equation is based off of the integration of a line segment against a perpendicular normal pointing at the center of the
  25. // line segment from some distance away.
  26. float scale = GetTransform().GetUniformScale();
  27. float h = GetInteriorHeight() * scale;
  28. float t2 = lightThreshold * lightThreshold;
  29. float h2 = h * h;
  30. float h4 = h2 * h2;
  31. float radius = Sqrt(((-h2 / 4.0f) + Sqrt((h4 / 16.0f) + (4.0f / t2))) / 2.0f);
  32. float intensity = GetPhotometricValue().GetCombinedIntensity(PhotometricUnit::Candela);
  33. return radius * intensity;
  34. }
  35. void CapsuleLightDelegate::HandleShapeChanged()
  36. {
  37. if (GetLightHandle().IsValid())
  38. {
  39. const auto endpoints = m_capsuleShapeBus->GetCapsulePoints();
  40. GetFeatureProcessor()->SetCapsuleLineSegment(GetLightHandle(), endpoints.m_begin, endpoints.m_end);
  41. float scale = GetTransform().GetUniformScale();
  42. float radius = m_capsuleShapeBus->GetRadius();
  43. GetFeatureProcessor()->SetCapsuleRadius(GetLightHandle(), scale * radius);
  44. }
  45. }
  46. float CapsuleLightDelegate::GetSurfaceArea() const
  47. {
  48. float scale = GetTransform().GetUniformScale();
  49. float radius = m_capsuleShapeBus->GetRadius();
  50. float capsArea = 4.0f * Constants::Pi * radius * radius; // both caps make a sphere
  51. float sideArea = 2.0f * Constants::Pi * radius * GetInteriorHeight(); // cylindrical area of capsule
  52. return (capsArea + sideArea) * scale * scale;
  53. }
  54. void CapsuleLightDelegate::DrawDebugDisplay(
  55. const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const
  56. {
  57. if (isSelected)
  58. {
  59. const auto [radius, height] = CalculateCapsuleVisualizationDimensions();
  60. debugDisplay.SetColor(color);
  61. debugDisplay.DrawWireCapsule(
  62. transform.GetTranslation(), transform.GetBasisZ(), radius, AZ::GetMax(height - 2.0f * radius, 0.0f));
  63. }
  64. }
  65. float CapsuleLightDelegate::GetInteriorHeight() const
  66. {
  67. return m_capsuleShapeBus->GetHeight() - m_capsuleShapeBus->GetRadius() * 2.0f;
  68. }
  69. void CapsuleLightDelegate::SetAffectsGI(bool affectsGI)
  70. {
  71. if (GetLightHandle().IsValid())
  72. {
  73. GetFeatureProcessor()->SetAffectsGI(GetLightHandle(), affectsGI);
  74. }
  75. }
  76. void CapsuleLightDelegate::SetAffectsGIFactor(float affectsGIFactor)
  77. {
  78. if (GetLightHandle().IsValid())
  79. {
  80. GetFeatureProcessor()->SetAffectsGIFactor(GetLightHandle(), affectsGIFactor);
  81. }
  82. }
  83. Aabb CapsuleLightDelegate::GetLocalVisualizationBounds() const
  84. {
  85. const auto [radius, height] = CalculateCapsuleVisualizationDimensions();
  86. const AZ::Vector3 translationOffset = m_shapeBus ? m_shapeBus->GetTranslationOffset() : AZ::Vector3::CreateZero();
  87. return Aabb::CreateFromMinMax(
  88. AZ::Vector3(-radius, -radius, AZ::GetMin(-radius, -height * 0.5f)) + translationOffset,
  89. AZ::Vector3(radius, radius, AZ::GetMax(radius, height * 0.5f)) + translationOffset);
  90. }
  91. float CapsuleLightDelegate::GetEffectiveSolidAngle() const
  92. {
  93. return PhotometricValue::OmnidirectionalSteradians;
  94. }
  95. CapsuleLightDelegate::CapsuleVisualizationDimensions CapsuleLightDelegate::CalculateCapsuleVisualizationDimensions() const
  96. {
  97. // Attenuation radius shape is just a capsule with the same internal height, but a radius of the attenuation radius.
  98. const float radius = GetConfig()->m_attenuationRadius;
  99. const float scale = GetTransform().GetUniformScale();
  100. const float height = m_capsuleShapeBus->GetHeight() * scale;
  101. return CapsuleLightDelegate::CapsuleVisualizationDimensions{ radius, height };
  102. }
  103. } // namespace AZ::Render