GradientSampler.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. #pragma once
  9. #include <AzCore/Math/Vector3.h>
  10. #include <AzCore/Component/EntityId.h>
  11. #include <AzCore/Debug/Profiler.h>
  12. #include <AzCore/Outcome/Outcome.h>
  13. #include <AzCore/Memory/Memory.h>
  14. #include <AzCore/RTTI/ReflectContext.h>
  15. #include <AzCore/RTTI/RTTI.h>
  16. #include <AzCore/Serialization/EditContextConstants.inl>
  17. #include <GradientSignal/Ebuses/GradientRequestBus.h>
  18. #include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
  19. #include <GradientSignal/Util.h>
  20. #include <SurfaceData/SurfaceDataSystemRequestBus.h>
  21. namespace GradientSignal
  22. {
  23. struct GradientSampleParams;
  24. class GradientSampler final
  25. {
  26. public:
  27. AZ_CLASS_ALLOCATOR(GradientSampler, AZ::SystemAllocator);
  28. AZ_RTTI(GradientSampler, "{3768D3A6-BF70-4ABC-B4EC-73C75A886916}");
  29. static void Reflect(AZ::ReflectContext* context);
  30. inline float GetValue(const GradientSampleParams& sampleParams) const;
  31. inline void GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const;
  32. bool IsEntityInHierarchy(const AZ::EntityId& entityId) const;
  33. //! Given a dirty region for a gradient, transform the dirty region in world space based on the gradient transform settings.
  34. AZ::Aabb TransformDirtyRegion(const AZ::Aabb& dirtyRegion) const;
  35. AZ::EntityId m_gradientId;
  36. //! Entity that owns the gradientSampler itself, used by the gradient previewer
  37. AZ::EntityId m_ownerEntityId;
  38. float m_opacity = 1.0f;
  39. bool m_invertInput = false;
  40. bool m_enableTransform = false;
  41. AZ::Vector3 m_translate = AZ::Vector3::CreateZero();
  42. AZ::Vector3 m_scale = AZ::Vector3::CreateOne();
  43. AZ::Vector3 m_rotate = AZ::Vector3::CreateZero();
  44. //embedded levels controls
  45. bool m_enableLevels = false;
  46. float m_inputMid = 1.0f;
  47. float m_inputMin = 0.0f;
  48. float m_inputMax = 1.0f;
  49. float m_outputMin = 0.0f;
  50. float m_outputMax = 1.0f;
  51. bool ValidateGradientEntityId();
  52. private:
  53. AZ::Matrix3x4 GetTransformMatrix() const;
  54. // Pass-through for UIElement attribute
  55. GradientSampler* GetSampler();
  56. AZ::u32 ChangeNotify() const;
  57. bool AreLevelSettingsDisabled() const;
  58. bool AreTransformSettingsDisabled() const;
  59. AZ::Outcome<void, AZStd::string> ValidatePotentialEntityId(void* newValue, const AZ::Uuid& valueType) const;
  60. };
  61. namespace GradientSamplerUtil
  62. {
  63. AZ_INLINE bool AreLevelParamsSet(const GradientSampler& sampler)
  64. {
  65. return sampler.m_inputMid != 1.0f || sampler.m_inputMin != 0.0f || sampler.m_inputMax != 1.0f || sampler.m_outputMin != 0.0f || sampler.m_outputMax != 1.0f;
  66. }
  67. AZ_INLINE bool AreTransformParamsSet(const GradientSampler& sampler)
  68. {
  69. static const AZ::Vector3 zero3 = AZ::Vector3::CreateZero();
  70. static const AZ::Vector3 one3 = AZ::Vector3::CreateOne();
  71. return sampler.m_translate != zero3 || sampler.m_rotate != zero3 || sampler.m_scale != one3;
  72. }
  73. }
  74. inline AZ::Matrix3x4 GradientSampler::GetTransformMatrix() const
  75. {
  76. if (m_enableTransform)
  77. {
  78. AZ::Matrix3x4 matrix3x4;
  79. matrix3x4.SetFromEulerDegrees(m_rotate);
  80. matrix3x4.MultiplyByScale(m_scale);
  81. matrix3x4.SetTranslation(m_translate);
  82. return matrix3x4;
  83. }
  84. else
  85. {
  86. return AZ::Matrix3x4::CreateIdentity();
  87. }
  88. }
  89. inline float GradientSampler::GetValue(const GradientSampleParams& sampleParams) const
  90. {
  91. if (m_opacity <= 0.0f || !m_gradientId.IsValid())
  92. {
  93. return 0.0f;
  94. }
  95. GradientSampleParams sampleParamsTransformed(sampleParams);
  96. //apply transform if set
  97. if (m_enableTransform && GradientSamplerUtil::AreTransformParamsSet(*this))
  98. {
  99. // We use the inverse here because we're going from world space to gradient space.
  100. AZ::Matrix3x4 matrix3x4 = GetTransformMatrix().GetInverseFull();
  101. sampleParamsTransformed.m_position = matrix3x4 * sampleParamsTransformed.m_position;
  102. }
  103. float output = 0.0f;
  104. {
  105. if (GradientRequestBus::HasReentrantEBusUseThisThread())
  106. {
  107. AZ_ErrorOnce("GradientSignal", false, "Detected cyclic dependencies with gradient entity references on entity id %s",
  108. m_gradientId.ToString().c_str());
  109. }
  110. else
  111. {
  112. GradientRequestBus::EventResult(output, m_gradientId, &GradientRequestBus::Events::GetValue, sampleParamsTransformed);
  113. if (m_invertInput)
  114. {
  115. output = 1.0f - output;
  116. }
  117. //apply levels if set
  118. if (m_enableLevels && GradientSamplerUtil::AreLevelParamsSet(*this))
  119. {
  120. output = GetLevels(output, m_inputMid, m_inputMin, m_inputMax, m_outputMin, m_outputMax);
  121. }
  122. }
  123. }
  124. return output * m_opacity;
  125. }
  126. inline void GradientSampler::GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const
  127. {
  128. auto ClearOutputValues = [](AZStd::span<float> outValues)
  129. {
  130. // If we don't have a valid gradient (or it is fully transparent), clear out all the output values.
  131. AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
  132. };
  133. if (m_opacity <= 0.0f || !m_gradientId.IsValid())
  134. {
  135. ClearOutputValues(outValues);
  136. return;
  137. }
  138. AZStd::vector<AZ::Vector3> transformedPositions;
  139. bool useTransformedPositions = false;
  140. // apply transform if set
  141. if (m_enableTransform && GradientSamplerUtil::AreTransformParamsSet(*this))
  142. {
  143. // We use the inverse here because we're going from world space to gradient space.
  144. AZ::Matrix3x4 matrix3x4 = GetTransformMatrix().GetInverseFull();
  145. useTransformedPositions = true;
  146. transformedPositions.resize(positions.size());
  147. for (size_t index = 0; index < positions.size(); index++)
  148. {
  149. transformedPositions[index] = matrix3x4 * positions[index];
  150. }
  151. }
  152. {
  153. if (GradientRequestBus::HasReentrantEBusUseThisThread())
  154. {
  155. AZ_ErrorOnce(
  156. "GradientSignal", false, "Detected cyclic dependencies with gradient entity references on entity id %s",
  157. m_gradientId.ToString().c_str());
  158. ClearOutputValues(outValues);
  159. return;
  160. }
  161. else
  162. {
  163. GradientRequestBus::Event(
  164. m_gradientId, &GradientRequestBus::Events::GetValues, useTransformedPositions ? transformedPositions : positions,
  165. outValues);
  166. }
  167. }
  168. // Perform any post-fetch transformations on the gradient values (invert, levels, opacity).
  169. for (auto& outValue : outValues)
  170. {
  171. if (m_invertInput)
  172. {
  173. outValue = 1.0f - outValue;
  174. }
  175. // apply levels if set
  176. if (m_enableLevels && GradientSamplerUtil::AreLevelParamsSet(*this))
  177. {
  178. outValue = GetLevels(outValue, m_inputMid, m_inputMin, m_inputMax, m_outputMin, m_outputMax);
  179. }
  180. outValue = outValue * m_opacity;
  181. }
  182. }
  183. }