merging from main

This commit is contained in:
greerdv
2021-04-15 08:18:11 +01:00
2503 changed files with 45147 additions and 527864 deletions
@@ -43,6 +43,7 @@ ly_add_target(
Gem::AtomLyIntegration_CommonFeatures.Public
Gem::LmbrCentral.Static
Gem::GradientSignal.Static
Gem::SurfaceData.Static
Gem::Atom_Feature_Common.Static
Gem::Atom_Bootstrap.Headers
)
@@ -77,6 +77,72 @@ namespace AZ
//! Sets the photometric unit to the one provided and converts the intensity to the photometric unit so actual light intensity remains constant.
virtual void ConvertToIntensityMode(PhotometricUnit intensityMode) = 0;
// Shutters
//! Returns true if shutters are enabled.
virtual bool GetEnableShutters() const = 0;
//! Sets if shutters should be enabled.
virtual void SetEnableShutters(bool enabled) = 0;
//! Returns the inner angle of the shutters in degrees
virtual float GetInnerShutterAngle() const = 0;
//! Sets the inner angle of the shutters in degrees
virtual void SetInnerShutterAngle(float degrees) = 0;
//! Returns the outer angle of the shutters in degrees
virtual float GetOuterShutterAngle() const = 0;
//! Sets the outer angle of the shutters in degrees
virtual void SetOuterShutterAngle(float degrees) = 0;
// Shadows
//! Returns true if shadows are enabled.
virtual bool GetEnableShadow() const = 0;
//! Sets if shadows should be enabled.
virtual void SetEnableShadow(bool enabled) = 0;
//! Returns the maximum width and height of shadowmap.
virtual ShadowmapSize GetShadowmapMaxSize() const = 0;
//! Sets the maximum width and height of shadowmap.
virtual void SetShadowmapMaxSize(ShadowmapSize size) = 0;
//! Returns the filter method of shadows.
virtual ShadowFilterMethod GetShadowFilterMethod() const = 0;
//! Sets the filter method of shadows.
virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0;
//! Gets the width of softening boundary between shadowed area and lit area in degrees.
virtual float GetSofteningBoundaryWidthAngle() const = 0;
//! Sets the width of softening boundary between shadowed area and lit area in degrees.
//! 0 disables softening.
virtual void SetSofteningBoundaryWidthAngle(float degrees) = 0;
//! Gets the sample count to predict boundary of shadow.
virtual uint32_t GetPredictionSampleCount() const = 0;
//! Sets the sample count to predict boundary of shadow. Maximum 16, and should also be
//! less than the filtering sample count.
virtual void SetPredictionSampleCount(uint32_t count) = 0;
//! Gets the sample count for filtering of the shadow boundary.
virtual uint32_t GetFilteringSampleCount() const = 0;
//! Sets the sample count for filtering of the shadow boundary. Maximum 64.
virtual void SetFilteringSampleCount(uint32_t count) = 0;
//! Gets the type of Pcf (percentage-closer filtering) to use.
virtual PcfMethod GetPcfMethod() const = 0;
//! Sets the type of Pcf (percentage-closer filtering) to use.
virtual void SetPcfMethod(PcfMethod method) = 0;
};
//! The EBus for requests to for setting and getting light component properties.
@@ -14,9 +14,9 @@
#include <AzCore/Component/Component.h>
#include <AzCore/Math/Color.h>
#include <AzCore/Serialization/EditContext.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/CoreLightsConstants.h>
#include <AzCore/Serialization/EditContext.h>
namespace AZ
{
@@ -28,6 +28,20 @@ namespace AZ
AZ_RTTI(AZ::Render::AreaLightComponentConfig, "{11C08FED-7F94-4926-8517-46D08E4DD837}", ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
enum class LightType : uint8_t
{
Unknown,
Sphere,
SpotDisk,
Capsule,
Quad,
Polygon,
SimplePoint,
SimpleSpot,
LightTypeCount,
};
static constexpr float CutoffIntensity = 0.1f;
AZ::Color m_color = AZ::Color::CreateOne();
@@ -39,17 +53,50 @@ namespace AZ
bool m_useFastApproximation = false;
AZ::Crc32 m_shapeType;
bool m_enableShutters = false;
LightType m_lightType = LightType::Unknown;
float m_innerShutterAngleDegrees = 35.0f;
float m_outerShutterAngleDegrees = 45.0f;
// Shadows (only used for supported shapes)
bool m_enableShadow = false;
ShadowmapSize m_shadowmapMaxSize = ShadowmapSize::Size256;
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
PcfMethod m_pcfMethod = PcfMethod::BoundarySearch;
float m_boundaryWidthInDegrees = 0.25f;
uint16_t m_predictionSampleCount = 4;
uint16_t m_filteringSampleCount = 12;
// The following functions provide information to an EditContext...
AZStd::vector<Edit::EnumConstant<PhotometricUnit>> GetValidPhotometricUnits() const;
bool RequiresShapeComponent() const;
//! Returns true if m_attenuationRadiusMode is set to LightAttenuationRadiusMode::Automatic
bool IsAttenuationRadiusModeAutomatic() const;
//! Returns true if the shape type is a 2D surface
bool Is2DSurface() const;
//! Returns true if the shape type can emit light from both sides
bool SupportsBothDirections() const;
//! Returns true if the light type supports a faster and less accurate approximation for the lighting algorithm.
bool SupportsFastApproximation() const;
//! Returns true if the light type supports restricting the light beam to an angle
bool SupportsShutters() const;
//! Returns true if the light type supports shutters, but they must be turned on.
bool ShuttersMustBeEnabled() const;
//! Returns true if shutters are turned off
bool ShuttersDisabled() const;
//! Returns true if the light type supports shadows.
bool SupportsShadows() const;
//! Returns true if shadows are turned on
bool ShadowsDisabled() const;
//! Returns characters for a suffix for the light type including a space. " lm" for lumens for example.
const char* GetIntensitySuffix() const;
@@ -65,6 +112,15 @@ namespace AZ
//! Returns the maximum intensity value for UI depending on the m_intensityMode, but users may still type in a greater value depending on GetIntensityMin().
float GetIntensitySoftMax() const;
//! Returns true if shadow filtering is disabled.
bool IsShadowFilteringDisabled() const;
//! Returns true if pcf shadows are disabled.
bool IsShadowPcfDisabled() const;
//! Returns true if pcf boundary search is disabled.
bool IsPcfBoundarySearchDisabled() const;
};
}
}
@@ -22,10 +22,6 @@ namespace AZ
{
static constexpr const char* const AreaLightComponentTypeId = "{744B3961-6242-4461-983F-2817D9D29C30}";
static constexpr const char* const EditorAreaLightComponentTypeId = "{8B605C0C-9027-4E0B-BA8C-19E396F8F262}";
static constexpr const char* const PointLightComponentTypeId = "{0A0E44AB-F583-481F-8AE8-68C4B1F9CD05}";
static constexpr const char* const EditorPointLightComponentTypeId = "{C4D354BE-5247-41FD-9A8D-550C6772EE5B}";
static constexpr const char* const SpotLightComponentTypeId = "{441DF0EC-6B70-451E-AEBE-6452A17BB852}";
static constexpr const char* const EditorSpotLightComponentTypeId = "{9A32D37B-C5D2-43A7-B574-E2EA1CDC7D64}";
static constexpr const char* const DirectionalLightComponentTypeId = "{13054592-2753-46C2-B19E-59670D4CE03D}";
static constexpr const char* const EditorDirectionalLightComponentTypeId = "{45B97527-6E72-411B-BC23-00068CF01580}";
@@ -182,6 +182,13 @@ namespace AZ
//! This sets the sample count for filtering of the shadow boundary.
//! @param count Sample Count for filtering (up to 64)
virtual void SetFilteringSampleCount(uint32_t count) = 0;
//! This gets the type of Pcf (percentage-closer filtering) to use.
virtual PcfMethod GetPcfMethod() const = 0;
//! This sets the type of Pcf (percentage-closer filtering) to use.
//! @param method The Pcf method to use.
virtual void SetPcfMethod(PcfMethod method) = 0;
};
using DirectionalLightRequestBus = EBus<DirectionalLightRequests>;
@@ -117,11 +117,14 @@ namespace AZ
//! It is used only when the pixel is predicted as on the boundary.
uint16_t m_filteringSampleCount = 32;
PcfMethod m_pcfMethod = PcfMethod::BoundarySearch;
bool IsSplitManual() const;
bool IsSplitAutomatic() const;
bool IsCascadeCorrectionDisabled() const;
bool IsShadowFilteringDisabled() const;
bool IsShadowPcfDisabled() const;
bool IsPcfBoundarySearchDisabled() const;
};
} // namespace Render
} // namespace AZ
@@ -1,130 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Component/ComponentBus.h>
#include <AzCore/Math/Color.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/PointLightComponentConfig.h>
namespace AZ
{
namespace Render
{
class PointLightRequests
: public ComponentBus
{
public:
AZ_RTTI(PointLightRequests, "{359BE514-DBEB-4D6A-B283-F8C5E83CD477}");
/// Overrides the default AZ::EBusTraits handler policy to allow one listener only.
static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single;
virtual ~PointLightRequests() {}
/// Gets a point light's color. This value is indepedent from its intensity.
virtual const Color& GetColor() const = 0;
/// Sets a point light's color. This value is indepedent from its intensity.
virtual void SetColor(const Color& color) = 0;
/// Gets a point light's intensity. This value is indepedent from its color.
virtual float GetIntensity() const = 0;
//! Gets a point light's photometric type.
virtual PhotometricUnit GetIntensityMode() const = 0;
/// Sets a point light's intensity. This value is indepedent from its color.
virtual void SetIntensity(float intensity) = 0;
//! Sets a point light's intensity and intensity mode. This value is indepedent from its color.
virtual void SetIntensity(float intensity, PhotometricUnit intensityMode) = 0;
/// Gets the distance at which the point light will no longer affect lighting.
virtual float GetAttenuationRadius() const = 0;
/// Set the distance and which a point light will no longer affect lighitng. Setting this forces the RadiusCalculation to Explicit mode.
virtual void SetAttenuationRadius(float radius) = 0;
/// Gets the size in meters of the sphere representing the light bulb.
virtual float GetBulbRadius() const = 0;
/// Sets the size in meters of the sphere representing the light bulb in meters.
virtual void SetBulbRadius(float bulbSize) = 0;
/*
* If this is set to Automatic, the radius will immediately be recalculated based on the intensity.
* If this is set to Explicit, the radius value will be unchanged from its previous value.
*/
virtual void SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode) = 0;
/// Gets the flag whether attenuation radius calculation is automatic or not.
virtual bool GetAttenuationRadiusIsAutomatic() const = 0;
/// Sets the flag whether attenuation radius calculation is automatic or not.
virtual void SetAttenuationRadiusIsAutomatic(bool flag)
{
SetAttenuationRadiusMode(flag ? LightAttenuationRadiusMode::Automatic : LightAttenuationRadiusMode::Explicit);
}
//! Sets the photometric unit to the one provided and converts the intensity to the photometric unit so actual light intensity remains constant.
virtual void ConvertToIntensityMode(PhotometricUnit intensityMode) = 0;
};
/// The EBus for requests to for setting and getting light component properties.
typedef AZ::EBus<PointLightRequests> PointLightRequestBus;
class PointLightNotifications
: public ComponentBus
{
public:
AZ_RTTI(PointLightNotifications, "{7363728D-E3EE-4AC8-AAA7-C299782763F0}");
virtual ~PointLightNotifications() {}
/**
* Signals that the color of the light changed.
* @param color A reference to the new color of the light.
*/
virtual void OnColorChanged(const Color& /*color*/) { }
/**
* Signals that the intensity of the light changed.
* @param color A reference to the new intensity of the light.
*/
virtual void OnIntensityChanged(float /*intensity*/) { }
/**
* Signals that the color or intensity of the light changed. This is useful when both the color and intensity are need in the same call.
* @param color A reference to the new color of the light.
* @param color A reference to the new intensity of the light.
*/
virtual void OnColorOrIntensityChanged(const Color& /*color*/, float /*intensity*/) { }
/**
* Signals that the attenuation radius of the light changed.
* @param attenuationRadius The distance at which this light no longer affects lighting.
*/
virtual void OnAttenutationRadiusChanged(float /*attenuationRadius*/) { }
/**
* Signals that the bulb size of the light changed.
* @param bulbRadius The size in meters of the sphere representing the light bulb in meters.
*/
virtual void OnBulbRadiusChanged(float /*bulbRadius*/) { }
};
/// The EBus for light notification events.
typedef AZ::EBus<PointLightNotifications> PointLightNotificationBus;
} // namespace Render
} // namespace AZ
@@ -1,113 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Math/Color.h>
#include <AzCore/Math/MathUtils.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/CoreLightsConstants.h>
namespace AZ
{
namespace Render
{
struct PointLightComponentConfig final
: public ComponentConfig
{
AZ_RTTI(PointLightComponentConfig, "{B6FC35BA-D22F-4C20-BFFC-3FE7A48858FA}", ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
static constexpr float DefaultIntensity = 800.0f; // 800 lumes is roughly equivalent to a 60 watt incandescent bulb
static constexpr float DefaultBulbRadius = 0.05f; // 5cm
AZ::Color m_color = AZ::Color::CreateOne();
PhotometricUnit m_intensityMode = PhotometricUnit::Lumen;
float m_intensity = DefaultIntensity;
float m_attenuationRadius = 0.0f;
float m_bulbRadius = DefaultBulbRadius;
LightAttenuationRadiusMode m_attenuationRadiusMode = LightAttenuationRadiusMode::Automatic;
// Not serialized, but used to keep scaled and unscaled properties in sync.
float m_scale = 1.0f;
// These values are used to deal adjusting the brightness and bulb radius based on the transform component's scale
// so that point lights scale concistently with meshes. Not serialized.
float m_unscaledIntensity = DefaultIntensity;
float m_unscaledBulbRadius = DefaultBulbRadius;
//! Updates scale and adjusts the values of intensity and bulb radius based on the new scale and the unscaled values.
void UpdateScale(float newScale)
{
m_scale = newScale;
m_intensity = m_unscaledIntensity;
// Lumens & Candela aren't based on surface area, so scale them.
if (!IsAreaBasedIntensityMode())
{
// Light surface area and brightness increases at scale^2 because of equation of sphere surface area.
m_intensity *= m_scale * m_scale;
}
m_bulbRadius = m_unscaledBulbRadius * m_scale;
}
//! Updates the unscaled intensity based on the current scaled value.
void UpdateUnscaledIntensity()
{
m_unscaledIntensity = m_intensity;
// Lumens & Candela aren't based on surface area, so scale them.
if (!IsAreaBasedIntensityMode())
{
// Light surface area and brightness increases at scale^2 because of equation of sphere surface area.
m_unscaledIntensity /= m_scale * m_scale;
}
}
//! Updates the unscaled bulb radius based on the current scaled value.
void UpdateUnscaledBulbRadius()
{
m_unscaledBulbRadius = m_bulbRadius / m_scale;
}
// Returns true if the intensity mode is an area based light unit (not lumens or candela)
bool IsAreaBasedIntensityMode()
{
return m_intensityMode != PhotometricUnit::Lumen && m_intensityMode != PhotometricUnit::Candela;
}
// Returns the surface area of the light bulb. 4.0 * pi * m_bulbRadius^2
float GetArea()
{
return 4.0f * Constants::Pi * m_bulbRadius * m_bulbRadius;
}
// The following functions provide information to an EditContext...
//! Returns true if m_attenuationRadiusMode is set to LightAttenuationRadiusMode::Automatic
bool IsAttenuationRadiusModeAutomatic() const
{
return m_attenuationRadiusMode == LightAttenuationRadiusMode::Automatic;
}
//! Returns characters for a suffix for the light type including a space. " lm" for lumens for example.
const char* GetIntensitySuffix() const
{
return PhotometricValue::GetTypeSuffix(m_intensityMode);
}
};
}
}
@@ -1,172 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/ComponentBus.h>
#include <AzCore/Math/Color.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/SpotLightComponentConfig.h>
#include <Atom/Feature/CoreLights/ShadowConstants.h>
namespace AZ
{
namespace Render
{
class SpotLightRequests
: public ComponentBus
{
public:
//! Overrides the default AZ::EBusTraits handler policy to allow one listener only.
static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single;
virtual ~SpotLightRequests() = default;
//! Gets a spot light's color. This value is independent from its intensity.
virtual const Color& GetColor() const = 0;
//! Sets a spot light's color. This value is independent from its intensity.
virtual void SetColor(const Color& color) = 0;
//! Gets a spot light's intensity. This value is independent from its color.
virtual float GetIntensity() const = 0;
//! Sets a spot light's intensity. This value is independent from its color.
virtual void SetIntensity(float intensity) = 0;
//! Gets a spot light's bulb radius in meters.
virtual float GetBulbRadius() const = 0;
//! Sets a spot light's bulb radius in meters.
virtual void SetBulbRadius(float bulbRadius) = 0;
//! @return Returns inner cone angle of the spot light in degrees.
virtual float GetInnerConeAngleInDegrees() const = 0;
//! @brief Sets inner cone angle of the spot light in degrees.
virtual void SetInnerConeAngleInDegrees(float degrees) = 0;
//! @return Returns outer cone angle of the spot light in degrees.
virtual float GetOuterConeAngleInDegrees() const = 0;
//! @brief Sets outer cone angle of the spot light in degrees.
virtual void SetOuterConeAngleInDegrees(float degrees) = 0;
//! @return Returns penumbra bias for the falloff curve of the spot light.
virtual float GetPenumbraBias() const = 0;
//! @brief Sets penumbra bias for the falloff curve of the spot light.
virtual void SetPenumbraBias(float penumbraBias) = 0;
//! @return Returns radius attenuation of the spot light.
virtual float GetAttenuationRadius() const = 0;
//! @return Sets radius attenuation of the spot light.
virtual void SetAttenuationRadius(float radius) = 0;
//! @return Returns radius attenuation mode (Auto or Explicit).
virtual LightAttenuationRadiusMode GetAttenuationRadiusMode() const = 0;
//! If this is set to Automatic, the radius will immediately be recalculated based on the intensity.
//! If this is set to Explicit, the radius value will be unchanged from its previous value.
virtual void SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode) = 0;
//! @return the flag whether attenuation radius calculation is automatic or not.
virtual bool GetAttenuationRadiusIsAutomatic() const
{
return (GetAttenuationRadiusMode() == LightAttenuationRadiusMode::Automatic);
}
//! This sets flag whether attenuation radius calculation is automatic or not.
//! @param flag flag whether attenuation radius calculation is automatic or not.
virtual void SetAttenuationRadiusIsAutomatic(bool flag)
{
SetAttenuationRadiusMode(flag ? LightAttenuationRadiusMode::Automatic : LightAttenuationRadiusMode::Explicit);
}
//! @return the flag indicates this light have shadow or not.
virtual bool GetEnableShadow() const = 0;
//! This specify this spot light uses shadow or not.
//! @param enabled true if shadow is used, false otherwise.
virtual void SetEnableShadow(bool enabled) = 0;
//! @return the size of shadowmap (width and height).
virtual ShadowmapSize GetShadowmapSize() const = 0;
//! This specifies the size of shadowmap to size x size.
virtual void SetShadowmapSize(ShadowmapSize size) = 0;
//! This gets the filter method of shadows.
//! @return filter method
virtual ShadowFilterMethod GetShadowFilterMethod() const = 0;
//! This specifies filter method of shadows.
//! @param method Filter method.
virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0;
//! This gets the width of boundary between shadowed area and lit area.
//! The width is given by the angle, and the units are in degrees.
//! @return Boundary width. The degree of the shadowed region is gradually changed on the boundary.
virtual float GetSofteningBoundaryWidthAngle() const = 0;
//! This specifies the width of boundary between shadowed area and lit area.
//! @param width Boundary width. The degree of shadowed is gradually changed on the boundary.
//! If width == 0, softening edge is disabled. Units are in degrees.
virtual void SetSofteningBoundaryWidthAngle(float degrees) = 0;
//! This gets the sample count to predict boundary of shadow.
//! @return Sample Count for prediction of whether the pixel is on the boundary (up to 16)
virtual uint32_t GetPredictionSampleCount() const = 0;
//! This sets the sample count to predict boundary of shadow.
//! @param count Sample count for prediction of whether the pixel is on the boundary (up to 16)
//! This value should be less than or equal to m_filteringSampleCount.
virtual void SetPredictionSampleCount(uint32_t count) = 0;
//! This gets the sample count for filtering of the shadow boundary.
//! @return Sample Count for filtering (up to 64)
virtual uint32_t GetFilteringSampleCount() const = 0;
//! This sets the sample count for filtering of the shadow boundary.
//! @param count Sample Count for filtering (up to 64)
virtual void SetFilteringSampleCount(uint32_t count) = 0;
//! This gets the type of Pcf (percentage-closer filtering) to use.
virtual PcfMethod GetPcfMethod() const = 0;
//! This sets the type of Pcf (percentage-closer filtering) to use.
//! @param method The Pcf method to use.
virtual void SetPcfMethod(PcfMethod method) = 0;
};
/// The EBus for requests to for setting and getting spot light component properties.
typedef AZ::EBus<SpotLightRequests> SpotLightRequestBus;
class SpotLightNotifications
: public ComponentBus
{
public:
virtual ~SpotLightNotifications() = default;
//! @brief Signals that the intensity of the light changed.
virtual void OnIntensityChanged(float intensity) { AZ_UNUSED(intensity); }
//! @brief Signals that the color of the light changed.
virtual void OnColorChanged(const Color& color) { AZ_UNUSED(color); }
//! @brief Signals that the cone angles of the spot light have changed.
virtual void OnConeAnglesChanged(float innerConeAngleDegrees, float outerConeAngleDegrees) { AZ_UNUSED(innerConeAngleDegrees); AZ_UNUSED(outerConeAngleDegrees); }
//! @brief Signals that the attenuation radius has changed.
virtual void OnAttenuationRadiusChanged(float attenuationRadius) { AZ_UNUSED(attenuationRadius); }
//! @brief Signals that the penumbra bias has changed.
virtual void OnPenumbraBiasChanged(float penumbraBias) { AZ_UNUSED(penumbraBias); }
};
//! The EBus for spot light notification events.
typedef AZ::EBus<SpotLightNotifications> SpotLightNotificationBus;
} // namespace Render
} // namespace AZ
@@ -1,62 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Math/Color.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
#include <Atom/Feature/CoreLights/ShadowConstants.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/CoreLightsConstants.h>
namespace AZ
{
namespace Render
{
struct SpotLightComponentConfig final
: ComponentConfig
{
AZ_RTTI(SpotLightComponentConfig, "{20C882C8-615E-4272-93A8-BE9102E6EFED}", ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
AZ::Color m_color = AZ::Color::CreateOne();
float m_intensity = 100.0f;
PhotometricUnit m_intensityMode = PhotometricUnit::Lumen;
float m_bulbRadius = 0.075;
float m_innerConeDegrees = 45.0f;
float m_outerConeDegrees = 55.0f;
float m_attenuationRadius = 20.0f;
float m_penumbraBias = 0.0f;
LightAttenuationRadiusMode m_attenuationRadiusMode = LightAttenuationRadiusMode::Automatic;
bool m_enabledShadow = false;
ShadowmapSize m_shadowmapSize = MaxShadowmapImageSize;
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
PcfMethod m_pcfMethod = PcfMethod::BoundarySearch;
float m_boundaryWidthInDegrees = 0.25f;
uint16_t m_predictionSampleCount = 4;
uint16_t m_filteringSampleCount = 32;
// The following functions provide information to an EditContext...
//! Returns true if m_attenuationRadiusMode is set to LightAttenuationRadiusMode::Automatic
bool IsAttenuationRadiusModeAutomatic() const;
//! Returns characters for a suffix for the light type including a space. " lm" for lumens for example.
const char* GetIntensitySuffix() const;
float GetConeDegrees() const;
bool IsShadowFilteringDisabled() const;
bool IsShadowPcfDisabled() const;
bool IsPcfBoundarySearchDisabled() const;
};
}
}
@@ -60,8 +60,34 @@ namespace AZ
{
public:
virtual void OnModelReady(const Data::Asset<RPI::ModelAsset>& modelAsset, const Data::Instance<RPI::Model>& model) = 0;
virtual void OnModelPreDestroy() {}
/**
* When connecting to this bus if the asset is ready you will immediately get an OnModelReady event
*/
template<class Bus>
struct ConnectionPolicy
: public AZ::EBusConnectionPolicy<Bus>
{
static void Connect(
typename Bus::BusPtr& busPtr,
typename Bus::Context& context,
typename Bus::HandlerNode& handler,
typename Bus::Context::ConnectLockGuard& connectLock,
const typename Bus::BusIdType& id = 0)
{
AZ::EBusConnectionPolicy<Bus>::Connect(busPtr, context, handler, connectLock, id);
Data::Instance<RPI::Model> model;
MeshComponentRequestBus::EventResult(model, id, &MeshComponentRequestBus::Events::GetModel);
if (model &&
model->GetModelAsset().GetStatus() == AZ::Data::AssetData::AssetStatus::Ready)
{
handler->OnModelReady(model->GetModelAsset(), model);
}
}
};
};
using MeshComponentNotificationBus = EBus<MeshComponentNotifications>;
} // namespace Render
} // namespace AZ
@@ -21,7 +21,8 @@ namespace AZ
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<AreaLightComponentConfig, ComponentConfig>()
->Version(3)
->Version(5) // ATOM-14637
->Field("LightType", &AreaLightComponentConfig::m_lightType)
->Field("Color", &AreaLightComponentConfig::m_color)
->Field("IntensityMode", &AreaLightComponentConfig::m_intensityMode)
->Field("Intensity", &AreaLightComponentConfig::m_intensity)
@@ -29,25 +30,89 @@ namespace AZ
->Field("AttenuationRadius", &AreaLightComponentConfig::m_attenuationRadius)
->Field("LightEmitsBothDirections", &AreaLightComponentConfig::m_lightEmitsBothDirections)
->Field("UseFastApproximation", &AreaLightComponentConfig::m_useFastApproximation)
// Shutters
->Field("EnableShutters", &AreaLightComponentConfig::m_enableShutters)
->Field("InnerShutterAngleDegrees", &AreaLightComponentConfig::m_innerShutterAngleDegrees)
->Field("OuterShutterAngleDegrees", &AreaLightComponentConfig::m_outerShutterAngleDegrees)
// Shadows
->Field("Enable Shadow", &AreaLightComponentConfig::m_enableShadow)
->Field("Shadowmap Max Size", &AreaLightComponentConfig::m_shadowmapMaxSize)
->Field("Shadow Filter Method", &AreaLightComponentConfig::m_shadowFilterMethod)
->Field("Softening Boundary Width", &AreaLightComponentConfig::m_boundaryWidthInDegrees)
->Field("Prediction Sample Count", &AreaLightComponentConfig::m_predictionSampleCount)
->Field("Filtering Sample Count", &AreaLightComponentConfig::m_filteringSampleCount)
->Field("Pcf Method", &AreaLightComponentConfig::m_pcfMethod);
;
}
}
AZStd::vector<Edit::EnumConstant<PhotometricUnit>> AreaLightComponentConfig::GetValidPhotometricUnits() const
{
AZStd::vector<Edit::EnumConstant<PhotometricUnit>> enumValues =
{
// Candela & lumen always supported.
Edit::EnumConstant<PhotometricUnit>(PhotometricUnit::Candela, "Candela"),
Edit::EnumConstant<PhotometricUnit>(PhotometricUnit::Lumen, "Lumen"),
};
if (RequiresShapeComponent())
{
// Lights with surface area also support nits and ev100.
enumValues.push_back(Edit::EnumConstant<PhotometricUnit>(PhotometricUnit::Nit, "Nit"));
enumValues.push_back(Edit::EnumConstant<PhotometricUnit>(PhotometricUnit::Ev100Luminance, "Ev100"));
}
return enumValues;
}
bool AreaLightComponentConfig::RequiresShapeComponent() const
{
return m_lightType == LightType::Sphere
|| m_lightType == LightType::SpotDisk
|| m_lightType == LightType::Capsule
|| m_lightType == LightType::Quad
|| m_lightType == LightType::Polygon;
}
bool AreaLightComponentConfig::IsAttenuationRadiusModeAutomatic() const
{
return m_attenuationRadiusMode == LightAttenuationRadiusMode::Automatic;
}
bool AreaLightComponentConfig::Is2DSurface() const
bool AreaLightComponentConfig::SupportsBothDirections() const
{
return m_shapeType == AZ_CRC_CE("DiskShape")
|| m_shapeType == AZ_CRC_CE("QuadShape")
|| m_shapeType == AZ_CRC_CE("PolygonPrism");
return m_lightType == LightType::Quad
|| m_lightType == LightType::Polygon;
}
bool AreaLightComponentConfig::SupportsFastApproximation() const
{
return m_shapeType == AZ_CRC_CE("QuadShape");
return m_lightType == LightType::Quad;
}
bool AreaLightComponentConfig::SupportsShutters() const
{
return m_lightType == LightType::SimpleSpot
|| m_lightType == LightType::SpotDisk;
}
bool AreaLightComponentConfig::ShuttersMustBeEnabled() const
{
return m_lightType == LightType::SpotDisk;
}
bool AreaLightComponentConfig::ShuttersDisabled() const
{
return m_lightType == LightType::SpotDisk && !m_enableShutters;
}
bool AreaLightComponentConfig::SupportsShadows() const
{
return m_shapeType == AZ_CRC_CE("DiskShape");
}
bool AreaLightComponentConfig::ShadowsDisabled() const
{
return !m_enableShadow;
}
const char* AreaLightComponentConfig::GetIntensitySuffix() const
@@ -109,6 +174,26 @@ namespace AZ
}
return 0.0f;
}
bool AreaLightComponentConfig::IsShadowFilteringDisabled() const
{
return (m_shadowFilterMethod == ShadowFilterMethod::None);
}
bool AreaLightComponentConfig::IsShadowPcfDisabled() const
{
return !(m_shadowFilterMethod == ShadowFilterMethod::Pcf ||
m_shadowFilterMethod == ShadowFilterMethod::EsmPcf);
}
bool AreaLightComponentConfig::IsPcfBoundarySearchDisabled() const
{
if (IsShadowPcfDisabled())
{
return true;
}
return m_pcfMethod != PcfMethod::BoundarySearch;
}
}
}
@@ -15,6 +15,8 @@
#include <CoreLights/DiskLightDelegate.h>
#include <CoreLights/PolygonLightDelegate.h>
#include <CoreLights/QuadLightDelegate.h>
#include <CoreLights/SimplePointLightDelegate.h>
#include <CoreLights/SimpleSpotLightDelegate.h>
#include <CoreLights/SphereLightDelegate.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
@@ -31,297 +33,593 @@
#include <LmbrCentral/Shape/PolygonPrismShapeComponentBus.h>
#include <LmbrCentral/Shape/QuadShapeComponentBus.h>
namespace AZ
namespace AZ::Render
{
namespace Render
void AreaLightComponentController::Reflect(ReflectContext* context)
{
void AreaLightComponentController::Reflect(ReflectContext* context)
AreaLightComponentConfig::Reflect(context);
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
AreaLightComponentConfig::Reflect(context);
serializeContext->Class<AreaLightComponentController>()
->Version(1)
->Field("Configuration", &AreaLightComponentController::m_configuration);
}
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<AreaLightComponentController>()
->Version(0)
->Field("Configuration", &AreaLightComponentController::m_configuration);
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<AreaLightRequestBus>("AreaLightRequestBus")
->Event("GetAttenuationRadius", &AreaLightRequestBus::Events::GetAttenuationRadius)
->Event("SetAttenuationRadius", &AreaLightRequestBus::Events::SetAttenuationRadius)
->Event("SetAttenuationRadiusMode", &AreaLightRequestBus::Events::SetAttenuationRadiusMode)
->Event("GetColor", &AreaLightRequestBus::Events::GetColor)
->Event("SetColor", &AreaLightRequestBus::Events::SetColor)
->Event("GetEmitsLightBothDirections", &AreaLightRequestBus::Events::GetLightEmitsBothDirections)
->Event("SetEmitsLightBothDirections", &AreaLightRequestBus::Events::SetLightEmitsBothDirections)
->Event("GetUseFastApproximation", &AreaLightRequestBus::Events::GetUseFastApproximation)
->Event("SetUseFastApproximation", &AreaLightRequestBus::Events::SetUseFastApproximation)
->Event("GetIntensity", &AreaLightRequestBus::Events::GetIntensity)
->Event("SetIntensity", static_cast<void(AreaLightRequestBus::Events::*)(float)>(&AreaLightRequestBus::Events::SetIntensity))
->Event("GetIntensityMode", &AreaLightRequestBus::Events::GetIntensityMode)
->Event("ConvertToIntensityMode", &AreaLightRequestBus::Events::ConvertToIntensityMode)
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
->Event("GetEnableShutters", &AreaLightRequestBus::Events::GetEnableShutters)
->Event("SetEnableShutters", &AreaLightRequestBus::Events::SetEnableShutters)
->Event("GetInnerShutterAngle", &AreaLightRequestBus::Events::GetInnerShutterAngle)
->Event("SetInnerShutterAngle", &AreaLightRequestBus::Events::SetInnerShutterAngle)
->Event("GetOuterShutterAngle", &AreaLightRequestBus::Events::GetOuterShutterAngle)
->Event("SetOuterShutterAngle", &AreaLightRequestBus::Events::SetOuterShutterAngle)
->Event("GetEnableShadow", &AreaLightRequestBus::Events::GetEnableShadow)
->Event("SetEnableShadow", &AreaLightRequestBus::Events::SetEnableShadow)
->Event("GetShadowmapMaxSize", &AreaLightRequestBus::Events::GetShadowmapMaxSize)
->Event("SetShadowmapMaxSize", &AreaLightRequestBus::Events::SetShadowmapMaxSize)
->Event("GetShadowFilterMethod", &AreaLightRequestBus::Events::GetShadowFilterMethod)
->Event("SetShadowFilterMethod", &AreaLightRequestBus::Events::SetShadowFilterMethod)
->Event("GetSofteningBoundaryWidthAngle", &AreaLightRequestBus::Events::GetSofteningBoundaryWidthAngle)
->Event("SetSofteningBoundaryWidthAngle", &AreaLightRequestBus::Events::SetSofteningBoundaryWidthAngle)
->Event("GetPredictionSampleCount", &AreaLightRequestBus::Events::GetPredictionSampleCount)
->Event("SetPredictionSampleCount", &AreaLightRequestBus::Events::SetPredictionSampleCount)
->Event("GetFilteringSampleCount", &AreaLightRequestBus::Events::GetFilteringSampleCount)
->Event("SetFilteringSampleCount", &AreaLightRequestBus::Events::SetFilteringSampleCount)
->Event("GetPcfMethod", &AreaLightRequestBus::Events::GetPcfMethod)
->Event("SetPcfMethod", &AreaLightRequestBus::Events::SetPcfMethod)
->VirtualProperty("AttenuationRadius", "GetAttenuationRadius", "SetAttenuationRadius")
->VirtualProperty("Color", "GetColor", "SetColor")
->VirtualProperty("EmitsLightBothDirections", "GetEmitsLightBothDirections", "SetEmitsLightBothDirections")
->VirtualProperty("UseFastApproximation", "GetUseFastApproximation", "SetUseFastApproximation")
->VirtualProperty("Intensity", "GetIntensity", "SetIntensity")
->VirtualProperty("ShuttersEnabled", "GetEnableShutters", "SetEnableShutters")
->VirtualProperty("InnerShutterAngle", "GetInnerShutterAngle", "SetInnerShutterAngle")
->VirtualProperty("OuterShutterAngle", "GetOuterShutterAngle", "SetOuterShutterAngle")
->VirtualProperty("ShadowsEnabled", "GetEnableShadow", "SetEnableShadow")
->VirtualProperty("ShadowmapMaxSize", "GetShadowmapMaxSize", "SetShadowmapMaxSize")
->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod")
->VirtualProperty("SofteningBoundaryWidthAngle", "GetSofteningBoundaryWidthAngle", "SetSofteningBoundaryWidthAngle")
->VirtualProperty("PredictionSampleCount", "GetPredictionSampleCount", "SetPredictionSampleCount")
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
->VirtualProperty("PcfMethod", "GetPcfMethod", "SetPcfMethod");
;
}
}
void AreaLightComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("AreaLightService"));
}
void AreaLightComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("AreaLightService"));
}
void AreaLightComponentController::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
dependent.push_back(AZ_CRC_CE("ShapeService"));
}
AreaLightComponentController::AreaLightComponentController(const AreaLightComponentConfig& config)
: m_configuration(config)
{
}
void AreaLightComponentController::Activate(EntityId entityId)
{
m_entityId = entityId;
// Used to determine which features are supported.
m_configuration.m_shapeType = 0;
LmbrCentral::ShapeComponentRequestsBus::EventResult(m_configuration.m_shapeType, m_entityId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetShapeType);
VerifyLightTypeAndShapeComponent();
CreateLightShapeDelegate();
if (m_configuration.RequiresShapeComponent() && m_lightShapeDelegate == nullptr)
{
AZ_Error("AreaLightComponentController", false, "AreaLightComponentController activated without having required shape component.");
}
AreaLightRequestBus::Handler::BusConnect(m_entityId);
ConfigurationChanged();
}
void AreaLightComponentController::Deactivate()
{
AreaLightRequestBus::Handler::BusDisconnect(m_entityId);
m_lightShapeDelegate.reset();
}
void AreaLightComponentController::SetConfiguration(const AreaLightComponentConfig& config)
{
m_configuration = config;
VerifyLightTypeAndShapeComponent();
ConfigurationChanged();
}
const AreaLightComponentConfig& AreaLightComponentController::GetConfiguration() const
{
return m_configuration;
}
void AreaLightComponentController::SetVisibiliy(bool isVisible)
{
m_isVisible = isVisible;
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetVisibility(m_isVisible);
if (m_isVisible)
{
behaviorContext->EBus<AreaLightRequestBus>("AreaLightRequestBus")
->Event("GetAttenuationRadius", &AreaLightRequestBus::Events::GetAttenuationRadius)
->Event("SetAttenuationRadius", &AreaLightRequestBus::Events::SetAttenuationRadius)
->Event("SetAttenuationRadiusMode", &AreaLightRequestBus::Events::SetAttenuationRadiusMode)
->Event("GetColor", &AreaLightRequestBus::Events::GetColor)
->Event("SetColor", &AreaLightRequestBus::Events::SetColor)
->Event("GetEmitsLightBothDirections", &AreaLightRequestBus::Events::GetLightEmitsBothDirections)
->Event("SetEmitsLightBothDirections", &AreaLightRequestBus::Events::SetLightEmitsBothDirections)
->Event("GetUseFastApproximation", &AreaLightRequestBus::Events::GetUseFastApproximation)
->Event("SetUseFastApproximation", &AreaLightRequestBus::Events::SetUseFastApproximation)
->Event("GetIntensity", &AreaLightRequestBus::Events::GetIntensity)
->Event("SetIntensity", static_cast<void(AreaLightRequestBus::Events::*)(float)>(&AreaLightRequestBus::Events::SetIntensity))
->Event("GetIntensityMode", &AreaLightRequestBus::Events::GetIntensityMode)
->Event("ConvertToIntensityMode", &AreaLightRequestBus::Events::ConvertToIntensityMode)
->VirtualProperty("AttenuationRadius", "GetAttenuationRadius", "SetAttenuationRadius")
->VirtualProperty("Color", "GetColor", "SetColor")
->VirtualProperty("EmitsLightBothDirections", "GetEmitsLightBothDirections", "SetEmitsLightBothDirections")
->VirtualProperty("UseFastApproximation", "GetUseFastApproximation", "SetUseFastApproximation")
->VirtualProperty("Intensity", "GetIntensity", "SetIntensity")
;
// If the light is made visible, make sure to apply the configuration so all properties as set correctly.
ConfigurationChanged();
}
}
}
void AreaLightComponentController::VerifyLightTypeAndShapeComponent()
{
constexpr Crc32 SphereShapeTypeId = AZ_CRC_CE("Sphere");
constexpr Crc32 DiskShapeTypeId = AZ_CRC_CE("DiskShape");
constexpr Crc32 CapsuleShapeTypeId = AZ_CRC_CE("Capsule");
constexpr Crc32 QuadShapeTypeId = AZ_CRC_CE("QuadShape");
constexpr Crc32 PoylgonShapeTypeId = AZ_CRC_CE("PolygonPrism");
void AreaLightComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
if (m_configuration.m_lightType == AreaLightComponentConfig::LightType::Unknown)
{
provided.push_back(AZ_CRC_CE("AreaLightService"));
}
void AreaLightComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("AreaLightService"));
}
void AreaLightComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC_CE("AreaLightShapeService"));
}
AreaLightComponentController::AreaLightComponentController(const AreaLightComponentConfig& config)
: m_configuration(config)
{
}
void AreaLightComponentController::Activate(EntityId entityId)
{
m_entityId = entityId;
CreateLightShapeDelegate();
AZ_Warning("AreaLightComponentController", m_lightShapeDelegate, "AreaLightComponentController activated without having required component.");
// Used to determine if the shape can be double-sided.
LmbrCentral::ShapeComponentRequestsBus::EventResult(m_configuration.m_shapeType, m_entityId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetShapeType);
AreaLightRequestBus::Handler::BusConnect(m_entityId);
ConfigurationChanged();
}
void AreaLightComponentController::Deactivate()
{
AreaLightRequestBus::Handler::BusDisconnect(m_entityId);
m_lightShapeDelegate.reset();
}
void AreaLightComponentController::SetConfiguration(const AreaLightComponentConfig& config)
{
m_configuration = config;
ConfigurationChanged();
}
const AreaLightComponentConfig& AreaLightComponentController::GetConfiguration() const
{
return m_configuration;
}
void AreaLightComponentController::SetVisibiliy(bool isVisible)
{
m_isVisible = isVisible;
if (m_lightShapeDelegate)
// Light type is unknown, see if it can be determined from a shape component.
switch (m_configuration.m_shapeType)
{
m_lightShapeDelegate->SetVisibility(m_isVisible);
case SphereShapeTypeId:
m_configuration.m_lightType = AreaLightComponentConfig::LightType::Sphere;
break;
case DiskShapeTypeId:
m_configuration.m_lightType = AreaLightComponentConfig::LightType::SpotDisk;
break;
case CapsuleShapeTypeId:
m_configuration.m_lightType = AreaLightComponentConfig::LightType::Capsule;
break;
case QuadShapeTypeId:
m_configuration.m_lightType = AreaLightComponentConfig::LightType::Quad;
break;
case PoylgonShapeTypeId:
m_configuration.m_lightType = AreaLightComponentConfig::LightType::Polygon;
break;
default:
break; // Light type can't be deduced.
}
}
void AreaLightComponentController::ConfigurationChanged()
else if (m_configuration.m_shapeType == Crc32(0))
{
ChromaChanged();
IntensityChanged();
AttenuationRadiusChanged();
AZ_Error("AreaLightComponentController", !m_configuration.RequiresShapeComponent(), "The light type used on this area light requires a corresponding shape component");
}
else
{
// Validate the the light type matches up with shape type if the light type is an area light.
AZ_Error("AreaLightComponentController",
!(m_configuration.m_lightType == AreaLightComponentConfig::LightType::Sphere && m_configuration.m_shapeType != SphereShapeTypeId),
"The light type is a sphere, but the shape component is not.");
AZ_Error("AreaLightComponentController",
!(m_configuration.m_lightType == AreaLightComponentConfig::LightType::SpotDisk && m_configuration.m_shapeType != DiskShapeTypeId),
"The light type is a disk, but the shape component is not.");
AZ_Error("AreaLightComponentController",
!(m_configuration.m_lightType == AreaLightComponentConfig::LightType::Capsule && m_configuration.m_shapeType != CapsuleShapeTypeId),
"The light type is a capsule, but the shape component is not.");
AZ_Error("AreaLightComponentController",
!(m_configuration.m_lightType == AreaLightComponentConfig::LightType::Quad && m_configuration.m_shapeType != QuadShapeTypeId),
"The light type is a quad, but the shape component is not.");
AZ_Error("AreaLightComponentController",
!(m_configuration.m_lightType == AreaLightComponentConfig::LightType::Polygon && m_configuration.m_shapeType != PoylgonShapeTypeId),
"The light type is a polygon, but the shape component is not.");
}
}
if (m_lightShapeDelegate)
void AreaLightComponentController::ConfigurationChanged()
{
ChromaChanged();
IntensityChanged();
AttenuationRadiusChanged();
ShuttersChanged();
ShadowsChanged();
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetLightEmitsBothDirections(m_configuration.m_lightEmitsBothDirections);
m_lightShapeDelegate->SetUseFastApproximation(m_configuration.m_useFastApproximation);
}
}
void AreaLightComponentController::IntensityChanged()
{
AreaLightNotificationBus::Event(m_entityId, &AreaLightNotifications::OnColorOrIntensityChanged, m_configuration.m_color, m_configuration.m_intensity);
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetPhotometricUnit(m_configuration.m_intensityMode);
m_lightShapeDelegate->SetIntensity(m_configuration.m_intensity);
}
}
void AreaLightComponentController::ChromaChanged()
{
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetChroma(m_configuration.m_color);
}
}
void AreaLightComponentController::AttenuationRadiusChanged()
{
if (m_configuration.m_attenuationRadiusMode == LightAttenuationRadiusMode::Automatic)
{
AutoCalculateAttenuationRadius();
}
AreaLightNotificationBus::Event(m_entityId, &AreaLightNotifications::OnAttenutationRadiusChanged, m_configuration.m_attenuationRadius);
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetAttenuationRadius(m_configuration.m_attenuationRadius);
}
}
void AreaLightComponentController::ShuttersChanged()
{
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetEnableShutters(m_configuration.m_enableShutters);
if (m_configuration.m_enableShutters)
{
m_lightShapeDelegate->SetLightEmitsBothDirections(m_configuration.m_lightEmitsBothDirections);
m_lightShapeDelegate->SetUseFastApproximation(m_configuration.m_useFastApproximation);
m_lightShapeDelegate->SetShutterAngles(m_configuration.m_innerShutterAngleDegrees, m_configuration.m_outerShutterAngleDegrees);
}
}
}
void AreaLightComponentController::IntensityChanged()
void AreaLightComponentController::ShadowsChanged()
{
if (m_lightShapeDelegate)
{
AreaLightNotificationBus::Event(m_entityId, &AreaLightNotifications::OnColorOrIntensityChanged, m_configuration.m_color, m_configuration.m_intensity);
if (m_lightShapeDelegate)
m_lightShapeDelegate->SetEnableShadow(m_configuration.m_enableShadow);
if (m_configuration.m_enableShadow)
{
m_lightShapeDelegate->SetPhotometricUnit(m_configuration.m_intensityMode);
m_lightShapeDelegate->SetIntensity(m_configuration.m_intensity);
m_lightShapeDelegate->SetShadowmapMaxSize(m_configuration.m_shadowmapMaxSize);
m_lightShapeDelegate->SetShadowFilterMethod(m_configuration.m_shadowFilterMethod);
m_lightShapeDelegate->SetSofteningBoundaryWidthAngle(m_configuration.m_boundaryWidthInDegrees);
m_lightShapeDelegate->SetPredictionSampleCount(m_configuration.m_predictionSampleCount);
m_lightShapeDelegate->SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
m_lightShapeDelegate->SetPcfMethod(m_configuration.m_pcfMethod);
}
}
}
void AreaLightComponentController::ChromaChanged()
void AreaLightComponentController::AutoCalculateAttenuationRadius()
{
if (m_lightShapeDelegate)
{
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetChroma(m_configuration.m_color);
}
m_configuration.m_attenuationRadius = m_lightShapeDelegate->CalculateAttenuationRadius(AreaLightComponentConfig::CutoffIntensity);
}
}
void AreaLightComponentController::AttenuationRadiusChanged()
{
if (m_configuration.m_attenuationRadiusMode == LightAttenuationRadiusMode::Automatic)
{
AutoCalculateAttenuationRadius();
}
AreaLightNotificationBus::Event(m_entityId, &AreaLightNotifications::OnAttenutationRadiusChanged, m_configuration.m_attenuationRadius);
const Color& AreaLightComponentController::GetColor() const
{
return m_configuration.m_color;
}
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetAttenuationRadius(m_configuration.m_attenuationRadius);
}
}
void AreaLightComponentController::SetColor(const Color& color)
{
m_configuration.m_color = color;
AreaLightNotificationBus::Event(m_entityId, &AreaLightNotifications::OnColorChanged, color);
ChromaChanged();
}
void AreaLightComponentController::AutoCalculateAttenuationRadius()
{
if (m_lightShapeDelegate)
{
m_configuration.m_attenuationRadius = m_lightShapeDelegate->CalculateAttenuationRadius(AreaLightComponentConfig::CutoffIntensity);
}
}
bool AreaLightComponentController::GetLightEmitsBothDirections() const
{
return m_configuration.m_lightEmitsBothDirections;
}
const Color& AreaLightComponentController::GetColor() const
{
return m_configuration.m_color;
}
void AreaLightComponentController::SetLightEmitsBothDirections(bool value)
{
m_configuration.m_lightEmitsBothDirections = value;
}
void AreaLightComponentController::SetColor(const Color& color)
{
m_configuration.m_color = color;
AreaLightNotificationBus::Event(m_entityId, &AreaLightNotifications::OnColorChanged, color);
ChromaChanged();
}
bool AreaLightComponentController::GetUseFastApproximation() const
{
return m_configuration.m_useFastApproximation;
}
bool AreaLightComponentController::GetLightEmitsBothDirections() const
{
return m_configuration.m_lightEmitsBothDirections;
}
void AreaLightComponentController::SetUseFastApproximation(bool value)
{
m_configuration.m_useFastApproximation = value;
}
void AreaLightComponentController::SetLightEmitsBothDirections(bool value)
{
m_configuration.m_lightEmitsBothDirections = value;
}
PhotometricUnit AreaLightComponentController::GetIntensityMode() const
{
return m_configuration.m_intensityMode;
}
bool AreaLightComponentController::GetUseFastApproximation() const
{
return m_configuration.m_useFastApproximation;
}
float AreaLightComponentController::GetIntensity() const
{
return m_configuration.m_intensity;
}
void AreaLightComponentController::SetUseFastApproximation(bool value)
{
m_configuration.m_useFastApproximation = value;
}
void AreaLightComponentController::SetIntensity(float intensity, PhotometricUnit intensityMode)
{
m_configuration.m_intensityMode = intensityMode;
m_configuration.m_intensity = intensity;
PhotometricUnit AreaLightComponentController::GetIntensityMode() const
{
return m_configuration.m_intensityMode;
}
AreaLightNotificationBus::Event(m_entityId, &AreaLightNotifications::OnIntensityChanged, intensity, intensityMode);
IntensityChanged();
}
float AreaLightComponentController::GetIntensity() const
{
return m_configuration.m_intensity;
}
void AreaLightComponentController::SetIntensity(float intensity)
{
m_configuration.m_intensity = intensity;
void AreaLightComponentController::SetIntensity(float intensity, PhotometricUnit intensityMode)
AreaLightNotificationBus::Event(m_entityId, &AreaLightNotifications::OnIntensityChanged, intensity, m_configuration.m_intensityMode);
IntensityChanged();
}
float AreaLightComponentController::GetAttenuationRadius() const
{
return m_configuration.m_attenuationRadius;
}
void AreaLightComponentController::SetAttenuationRadius(float radius)
{
m_configuration.m_attenuationRadius = radius;
m_configuration.m_attenuationRadiusMode = LightAttenuationRadiusMode::Explicit;
AttenuationRadiusChanged();
}
void AreaLightComponentController::SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode)
{
m_configuration.m_attenuationRadiusMode = attenuationRadiusMode;
AttenuationRadiusChanged();
}
void AreaLightComponentController::ConvertToIntensityMode(PhotometricUnit intensityMode)
{
if (m_lightShapeDelegate && m_lightShapeDelegate->GetPhotometricValue().GetType() != intensityMode)
{
m_configuration.m_intensityMode = intensityMode;
m_configuration.m_intensity = intensity;
AreaLightNotificationBus::Event(m_entityId, &AreaLightNotifications::OnIntensityChanged, intensity, intensityMode);
IntensityChanged();
m_configuration.m_intensity = m_lightShapeDelegate->SetPhotometricUnit(intensityMode);
}
}
bool AreaLightComponentController::GetEnableShutters() const
{
return m_configuration.m_enableShutters;
}
void AreaLightComponentController::SetIntensity(float intensity)
void AreaLightComponentController::SetEnableShutters(bool enabled)
{
m_configuration.m_enableShutters = enabled && m_configuration.SupportsShutters();
if (m_lightShapeDelegate)
{
m_configuration.m_intensity = intensity;
AreaLightNotificationBus::Event(m_entityId, &AreaLightNotifications::OnIntensityChanged, intensity, m_configuration.m_intensityMode);
IntensityChanged();
m_lightShapeDelegate->SetEnableShutters(enabled);
}
}
float AreaLightComponentController::GetAttenuationRadius() const
float AreaLightComponentController::GetInnerShutterAngle() const
{
return m_configuration.m_innerShutterAngleDegrees;
}
void AreaLightComponentController::SetInnerShutterAngle(float degrees)
{
m_configuration.m_innerShutterAngleDegrees = degrees;
if (m_lightShapeDelegate)
{
return m_configuration.m_attenuationRadius;
m_lightShapeDelegate->SetShutterAngles(m_configuration.m_innerShutterAngleDegrees, m_configuration.m_outerShutterAngleDegrees);
}
}
void AreaLightComponentController::SetAttenuationRadius(float radius)
float AreaLightComponentController::GetOuterShutterAngle() const
{
return m_configuration.m_outerShutterAngleDegrees;
}
void AreaLightComponentController::SetOuterShutterAngle(float degrees)
{
m_configuration.m_outerShutterAngleDegrees = degrees;
if (m_lightShapeDelegate)
{
m_configuration.m_attenuationRadius = radius;
m_configuration.m_attenuationRadiusMode = LightAttenuationRadiusMode::Explicit;
AttenuationRadiusChanged();
m_lightShapeDelegate->SetShutterAngles(m_configuration.m_innerShutterAngleDegrees, m_configuration.m_outerShutterAngleDegrees);
}
}
void AreaLightComponentController::SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode)
bool AreaLightComponentController::GetEnableShadow() const
{
return m_configuration.m_enableShadow;
}
void AreaLightComponentController::SetEnableShadow(bool enabled)
{
m_configuration.m_enableShadow = enabled && m_configuration.SupportsShadows();
if (m_lightShapeDelegate)
{
m_configuration.m_attenuationRadiusMode = attenuationRadiusMode;
AttenuationRadiusChanged();
m_lightShapeDelegate->SetEnableShadow(enabled);
}
}
void AreaLightComponentController::ConvertToIntensityMode(PhotometricUnit intensityMode)
ShadowmapSize AreaLightComponentController::GetShadowmapMaxSize() const
{
return m_configuration.m_shadowmapMaxSize;
}
void AreaLightComponentController::SetShadowmapMaxSize(ShadowmapSize size)
{
m_configuration.m_shadowmapMaxSize = size;
if (m_lightShapeDelegate)
{
if (m_lightShapeDelegate && m_lightShapeDelegate->GetPhotometricValue().GetType() != intensityMode)
{
m_configuration.m_intensityMode = intensityMode;
m_configuration.m_intensity = m_lightShapeDelegate->SetPhotometricUnit(intensityMode);
}
m_lightShapeDelegate->SetShadowmapMaxSize(size);
}
}
void AreaLightComponentController::HandleDisplayEntityViewport(
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay,
bool isSelected)
ShadowFilterMethod AreaLightComponentController::GetShadowFilterMethod() const
{
return m_configuration.m_shadowFilterMethod;
}
void AreaLightComponentController::SetShadowFilterMethod(ShadowFilterMethod method)
{
m_configuration.m_shadowFilterMethod = method;
if (m_lightShapeDelegate)
{
Transform transform = Transform::CreateIdentity();
TransformBus::EventResult(transform, m_entityId, &TransformBus::Events::GetWorldTM);
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->DrawDebugDisplay(transform, m_configuration.m_color, debugDisplay, isSelected);
}
m_lightShapeDelegate->SetShadowFilterMethod(method);
}
}
void AreaLightComponentController::CreateLightShapeDelegate()
float AreaLightComponentController::GetSofteningBoundaryWidthAngle() const
{
return m_configuration.m_boundaryWidthInDegrees;
}
void AreaLightComponentController::SetSofteningBoundaryWidthAngle(float width)
{
m_configuration.m_boundaryWidthInDegrees = width;
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetSofteningBoundaryWidthAngle(width);
}
}
uint32_t AreaLightComponentController::GetPredictionSampleCount() const
{
return m_configuration.m_predictionSampleCount;
}
void AreaLightComponentController::SetPredictionSampleCount(uint32_t count)
{
m_configuration.m_predictionSampleCount = count;
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetPredictionSampleCount(count);
}
}
uint32_t AreaLightComponentController::GetFilteringSampleCount() const
{
return m_configuration.m_filteringSampleCount;
}
void AreaLightComponentController::SetFilteringSampleCount(uint32_t count)
{
m_configuration.m_filteringSampleCount = count;
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetFilteringSampleCount(count);
}
}
void AreaLightComponentController::HandleDisplayEntityViewport(
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay,
bool isSelected)
{
Transform transform = Transform::CreateIdentity();
TransformBus::EventResult(transform, m_entityId, &TransformBus::Events::GetWorldTM);
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->DrawDebugDisplay(transform, m_configuration.m_color, debugDisplay, isSelected);
}
}
PcfMethod AreaLightComponentController::GetPcfMethod() const
{
return m_configuration.m_pcfMethod;
}
void AreaLightComponentController::SetPcfMethod(PcfMethod method)
{
m_configuration.m_pcfMethod = method;
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetPcfMethod(method);
}
}
void AreaLightComponentController::CreateLightShapeDelegate()
{
switch (m_configuration.m_lightType)
{
// Simple types
case AreaLightComponentConfig::LightType::SimplePoint:
m_lightShapeDelegate = AZStd::make_unique<SimplePointLightDelegate>(m_entityId, m_isVisible);
break;
case AreaLightComponentConfig::LightType::SimpleSpot:
m_lightShapeDelegate = AZStd::make_unique<SimpleSpotLightDelegate>(m_entityId, m_isVisible);
break;
// Area light types
case AreaLightComponentConfig::LightType::Sphere:
{
LmbrCentral::SphereShapeComponentRequests* sphereShapeInterface = LmbrCentral::SphereShapeComponentRequestsBus::FindFirstHandler(m_entityId);
if (sphereShapeInterface)
{
m_lightShapeDelegate = AZStd::make_unique<SphereLightDelegate>(sphereShapeInterface, m_entityId, m_isVisible);
return;
}
break;
}
case AreaLightComponentConfig::LightType::SpotDisk:
{
LmbrCentral::DiskShapeComponentRequests* diskShapeInterface = LmbrCentral::DiskShapeComponentRequestBus::FindFirstHandler(m_entityId);
if (diskShapeInterface)
{
m_lightShapeDelegate = AZStd::make_unique<DiskLightDelegate>(diskShapeInterface, m_entityId, m_isVisible);
return;
}
break;
}
case AreaLightComponentConfig::LightType::Capsule:
{
LmbrCentral::CapsuleShapeComponentRequests* capsuleShapeInterface = LmbrCentral::CapsuleShapeComponentRequestsBus::FindFirstHandler(m_entityId);
if (capsuleShapeInterface)
{
m_lightShapeDelegate = AZStd::make_unique<CapsuleLightDelegate>(capsuleShapeInterface, m_entityId, m_isVisible);
return;
}
break;
}
case AreaLightComponentConfig::LightType::Quad:
{
LmbrCentral::QuadShapeComponentRequests* quadShapeInterface = LmbrCentral::QuadShapeComponentRequestBus::FindFirstHandler(m_entityId);
if (quadShapeInterface)
{
m_lightShapeDelegate = AZStd::make_unique<QuadLightDelegate>(quadShapeInterface, m_entityId, m_isVisible);
return;
}
break;
}
case AreaLightComponentConfig::LightType::Polygon:
{
LmbrCentral::PolygonPrismShapeComponentRequests* polyPrismShapeInterface = LmbrCentral::PolygonPrismShapeComponentRequestBus::FindFirstHandler(m_entityId);
if (polyPrismShapeInterface)
{
m_lightShapeDelegate = AZStd::make_unique<PolygonLightDelegate>(polyPrismShapeInterface, m_entityId, m_isVisible);
return;
}
break;
}
}
}
} // namespace Render
} // namespace AZ
} // namespace AZ::Render
@@ -38,7 +38,7 @@ namespace AZ
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
AreaLightComponentController() = default;
AreaLightComponentController(const AreaLightComponentConfig& config);
@@ -71,15 +71,41 @@ namespace AZ
void SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode) override;
void ConvertToIntensityMode(PhotometricUnit intensityMode) override;
bool GetEnableShutters() const override;
void SetEnableShutters(bool enabled) override;
float GetInnerShutterAngle() const override;
void SetInnerShutterAngle(float degrees) override;
float GetOuterShutterAngle() const override;
void SetOuterShutterAngle(float degrees) override;
bool GetEnableShadow() const override;
void SetEnableShadow(bool enabled) override;
ShadowmapSize GetShadowmapMaxSize() const override;
void SetShadowmapMaxSize(ShadowmapSize size) override;
ShadowFilterMethod GetShadowFilterMethod() const override;
void SetShadowFilterMethod(ShadowFilterMethod method) override;
float GetSofteningBoundaryWidthAngle() const override;
void SetSofteningBoundaryWidthAngle(float width) override;
uint32_t GetPredictionSampleCount() const override;
void SetPredictionSampleCount(uint32_t count) override;
uint32_t GetFilteringSampleCount() const override;
void SetFilteringSampleCount(uint32_t count) override;
PcfMethod GetPcfMethod() const override;
void SetPcfMethod(PcfMethod method) override;
void HandleDisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay,
bool isSelected);
void VerifyLightTypeAndShapeComponent();
void ConfigurationChanged();
void IntensityChanged();
void ChromaChanged();
void AttenuationRadiusChanged();
void ShuttersChanged();
void ShadowsChanged();
//! Handles calculating the attenuation radius when LightAttenuationRadiusMode is auto
void AutoCalculateAttenuationRadius();
@@ -24,7 +24,7 @@ namespace AZ
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<DirectionalLightComponentConfig, ComponentConfig>()
->Version(6)
->Version(7)
->Field("Color", &DirectionalLightComponentConfig::m_color)
->Field("IntensityMode", &DirectionalLightComponentConfig::m_intensityMode)
->Field("Intensity", &DirectionalLightComponentConfig::m_intensity)
@@ -43,7 +43,8 @@ namespace AZ
->Field("SofteningBoundaryWidth", &DirectionalLightComponentConfig::m_boundaryWidth)
->Field("PcfPredictionSampleCount", &DirectionalLightComponentConfig::m_predictionSampleCount)
->Field("PcfFilteringSampleCount", &DirectionalLightComponentConfig::m_filteringSampleCount)
;
->Field("Pcf Method", &DirectionalLightComponentConfig::m_pcfMethod)
;
}
}
@@ -126,5 +127,15 @@ namespace AZ
m_shadowFilterMethod == ShadowFilterMethod::EsmPcf);
}
bool DirectionalLightComponentConfig::IsPcfBoundarySearchDisabled() const
{
if (IsShadowPcfDisabled())
{
return true;
}
return m_pcfMethod != PcfMethod::BoundarySearch;
}
} // namespace Render
} // namespace AZ
@@ -87,6 +87,8 @@ namespace AZ
->Event("SetPredictionSampleCount", &DirectionalLightRequestBus::Events::SetPredictionSampleCount)
->Event("GetFilteringSampleCount", &DirectionalLightRequestBus::Events::GetFilteringSampleCount)
->Event("SetFilteringSampleCount", &DirectionalLightRequestBus::Events::SetFilteringSampleCount)
->Event("GetPcfMethod", &DirectionalLightRequestBus::Events::GetPcfMethod)
->Event("SetPcfMethod", &DirectionalLightRequestBus::Events::SetPcfMethod)
->VirtualProperty("Color", "GetColor", "SetColor")
->VirtualProperty("Intensity", "GetIntensity", "SetIntensity")
->VirtualProperty("AngularDiameter", "GetAngularDiameter", "SetAngularDiameter")
@@ -103,7 +105,8 @@ namespace AZ
->VirtualProperty("SofteningBoundaryWidth", "GetSofteningBoundaryWidth", "SetSofteningBoundaryWidth")
->VirtualProperty("PredictionSampleCount", "GetPredictionSampleCount", "SetPredictionSampleCount")
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
;
->VirtualProperty("PcfMethod", "GetPcfMethod", "SetPcfMethod");
;
}
}
@@ -534,6 +537,7 @@ namespace AZ
SetSofteningBoundaryWidth(m_configuration.m_boundaryWidth);
SetPredictionSampleCount(m_configuration.m_predictionSampleCount);
SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
SetPcfMethod(m_configuration.m_pcfMethod);
// [GFX TODO][ATOM-1726] share config for multiple light (e.g., light ID).
// [GFX TODO][ATOM-2416] adapt to multiple viewports.
@@ -620,6 +624,16 @@ namespace AZ
}
}
PcfMethod DirectionalLightComponentController::GetPcfMethod() const
{
return m_configuration.m_pcfMethod;
}
void DirectionalLightComponentController::SetPcfMethod(PcfMethod method)
{
m_configuration.m_pcfMethod = method;
m_featureProcessor->SetPcfMethod(m_lightHandle, method);
}
} // namespace Render
} // namespace AZ
@@ -86,6 +86,8 @@ namespace AZ
void SetPredictionSampleCount(uint32_t count) override;
uint32_t GetFilteringSampleCount() const override;
void SetFilteringSampleCount(uint32_t count) override;
PcfMethod GetPcfMethod() const override;
void SetPcfMethod(PcfMethod method) override;
private:
friend class EditorDirectionalLightComponent;
@@ -14,62 +14,121 @@
#include <Atom/RPI.Public/Scene.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h>
namespace AZ
namespace AZ::Render
{
namespace Render
DiskLightDelegate::DiskLightDelegate(LmbrCentral::DiskShapeComponentRequests* shapeBus, EntityId entityId, bool isVisible)
: LightDelegateBase<DiskLightFeatureProcessorInterface>(entityId, isVisible)
, m_shapeBus(shapeBus)
{
DiskLightDelegate::DiskLightDelegate(LmbrCentral::DiskShapeComponentRequests* shapeBus, EntityId entityId, bool isVisible)
: LightDelegateBase<DiskLightFeatureProcessorInterface>(entityId, isVisible)
, m_shapeBus(shapeBus)
{
InitBase(entityId);
}
void DiskLightDelegate::SetLightEmitsBothDirections(bool lightEmitsBothDirections)
{
if (GetLightHandle().IsValid())
{
GetFeatureProcessor()->SetLightEmitsBothDirections(GetLightHandle(), lightEmitsBothDirections);
}
}
InitBase(entityId);
}
float DiskLightDelegate::CalculateAttenuationRadius(float lightThreshold) const
{
// Calculate the radius at which the irradiance will be equal to cutoffIntensity.
float intensity = GetPhotometricValue().GetCombinedIntensity(PhotometricUnit::Lumen);
return sqrt(intensity / lightThreshold);
}
float DiskLightDelegate::CalculateAttenuationRadius(float lightThreshold) const
{
// Calculate the radius at which the irradiance will be equal to cutoffIntensity.
float intensity = GetPhotometricValue().GetCombinedIntensity(PhotometricUnit::Lumen);
return sqrt(intensity / lightThreshold);
}
void DiskLightDelegate::HandleShapeChanged()
void DiskLightDelegate::HandleShapeChanged()
{
if (GetLightHandle().IsValid())
{
if (GetLightHandle().IsValid())
{
GetFeatureProcessor()->SetPosition(GetLightHandle(), GetTransform().GetTranslation());
GetFeatureProcessor()->SetDirection(GetLightHandle(), m_shapeBus->GetNormal());
GetFeatureProcessor()->SetDiskRadius(GetLightHandle(), GetRadius());
}
GetFeatureProcessor()->SetPosition(GetLightHandle(), GetTransform().GetTranslation());
GetFeatureProcessor()->SetDirection(GetLightHandle(), m_shapeBus->GetNormal());
GetFeatureProcessor()->SetDiskRadius(GetLightHandle(), GetRadius());
}
}
float DiskLightDelegate::GetSurfaceArea() const
float DiskLightDelegate::GetSurfaceArea() const
{
float radius = GetRadius();
return Constants::Pi * radius * radius;
}
float DiskLightDelegate::GetRadius() const
{
return m_shapeBus->GetRadius() * GetTransform().GetScale().GetMaxElement();
}
void DiskLightDelegate::DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const
{
if (isSelected)
{
float radius = GetRadius();
return Constants::Pi * radius * radius;
}
debugDisplay.SetColor(color);
float DiskLightDelegate::GetRadius() const
// Draw a disk for the attenuation radius
debugDisplay.DrawWireSphere(transform.GetTranslation(), CalculateAttenuationRadius(AreaLightComponentConfig::CutoffIntensity));
}
}
void DiskLightDelegate::SetEnableShutters(bool enabled)
{
Base::SetEnableShutters(enabled);
GetFeatureProcessor()->SetConstrainToConeLight(GetLightHandle(), true);
}
void DiskLightDelegate::SetShutterAngles(float innerAngleDegrees, float outerAngleDegrees)
{
if (GetShuttersEnabled())
{
return m_shapeBus->GetRadius() * GetTransform().GetScale().GetMaxElement();
GetFeatureProcessor()->SetConeAngles(GetLightHandle(), DegToRad(innerAngleDegrees), DegToRad(outerAngleDegrees));
}
}
void DiskLightDelegate::DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const
void DiskLightDelegate::SetEnableShadow(bool enabled)
{
Base::SetEnableShadow(enabled);
GetFeatureProcessor()->SetShadowsEnabled(GetLightHandle(), enabled);
}
void DiskLightDelegate::SetShadowmapMaxSize(ShadowmapSize size)
{
if (GetShadowsEnabled())
{
if (isSelected)
{
debugDisplay.SetColor(color);
// Draw a disk for the attenuation radius
debugDisplay.DrawWireSphere(transform.GetTranslation(), CalculateAttenuationRadius(AreaLightComponentConfig::CutoffIntensity));
}
GetFeatureProcessor()->SetShadowmapMaxResolution(GetLightHandle(), size);
}
} // namespace Render
} // namespace AZ
}
void DiskLightDelegate::SetShadowFilterMethod(ShadowFilterMethod method)
{
if (GetShadowsEnabled())
{
GetFeatureProcessor()->SetShadowFilterMethod(GetLightHandle(), method);
}
}
void DiskLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees)
{
if (GetShadowsEnabled())
{
GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees));
}
}
void DiskLightDelegate::SetPredictionSampleCount(uint32_t count)
{
if (GetShadowsEnabled())
{
GetFeatureProcessor()->SetPredictionSampleCount(GetLightHandle(), count);
}
}
void DiskLightDelegate::SetFilteringSampleCount(uint32_t count)
{
if (GetShadowsEnabled())
{
GetFeatureProcessor()->SetFilteringSampleCount(GetLightHandle(), count);
}
}
void DiskLightDelegate::SetPcfMethod(PcfMethod method)
{
if (GetShadowsEnabled())
{
GetFeatureProcessor()->SetPcfMethod(GetLightHandle(), method);
}
}
} // namespace AZ::Render
@@ -30,16 +30,28 @@ namespace AZ
class DiskLightDelegate final
: public LightDelegateBase<DiskLightFeatureProcessorInterface>
{
using Base = LightDelegateBase<DiskLightFeatureProcessorInterface>;
public:
DiskLightDelegate(LmbrCentral::DiskShapeComponentRequests* shapeBus, EntityId entityId, bool isVisible);
// LightDelegateBase overrides...
void SetLightEmitsBothDirections(bool lightEmitsBothDirections) override;
float GetSurfaceArea() const override;
float GetEffectiveSolidAngle() const override { return PhotometricValue::DirectionalEffectiveSteradians; }
float CalculateAttenuationRadius(float lightThreshold) const override;
void DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const override;
void SetEnableShutters(bool enabled) override;
void SetShutterAngles(float innerAngleDegrees, float outerAngleDegrees) override;
void SetEnableShadow(bool enabled) override;
void SetShadowmapMaxSize(ShadowmapSize size) override;
void SetShadowFilterMethod(ShadowFilterMethod method) override;
void SetSofteningBoundaryWidthAngle(float widthInDegrees) override;
void SetPredictionSampleCount(uint32_t count) override;
void SetFilteringSampleCount(uint32_t count) override;
void SetPcfMethod(PcfMethod method) override;
private:
// LightDelegateBase overrides...
@@ -13,10 +13,17 @@
#include <CoreLights/EditorAreaLightComponent.h>
#include <Atom/RPI.Edit/Common/ColorUtils.h>
#include <AzToolsFramework/Component/EditorComponentAPIBus.h>
#include <AzToolsFramework/API/EntityCompositionRequestBus.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <LmbrCentral/Shape/ShapeComponentBus.h>
#include <LmbrCentral/Shape/EditorShapeComponentBus.h>
#include <LmbrCentral/Shape/SphereShapeComponentBus.h>
#include <LmbrCentral/Shape/DiskShapeComponentBus.h>
#include <LmbrCentral/Shape/CapsuleShapeComponentBus.h>
#include <LmbrCentral/Shape/QuadShapeComponentBus.h>
#include <LmbrCentral/Shape/PolygonPrismShapeComponentBus.h>
namespace AZ
{
@@ -27,65 +34,145 @@ namespace AZ
{
}
void EditorAreaLightComponent::Reflect(AZ::ReflectContext* context)
void EditorAreaLightComponent::Reflect(ReflectContext* context)
{
BaseClass::Reflect(context);
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<EditorAreaLightComponent, BaseClass>()
->Version(1, ConvertToEditorRenderComponentAdapter<1>);
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
if (EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorAreaLightComponent>(
"Area Light", "An Area light emits light emits light from a goemetric shape.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Atom")
->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/Component_Placeholder.svg")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "editor/icons/components/viewport/component_placeholder.png")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://docs.aws.amazon.com/lumberyard/latest/userguide/component-area-light.html")
"Light", "A light which emits from a point or goemetric shape.")
->ClassElement(Edit::ClassElements::EditorData, "")
->Attribute(Edit::Attributes::Category, "Atom")
->Attribute(Edit::Attributes::Icon, "Editor/Icons/Components/Component_Placeholder.svg")
->Attribute(Edit::Attributes::ViewportIcon, "editor/icons/components/viewport/component_placeholder.png")
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(Edit::Attributes::AutoExpand, true)
->Attribute(Edit::Attributes::HelpPageURL, "https://docs.aws.amazon.com/lumberyard/latest/userguide/component-light.html")
;
editContext->Class<AreaLightComponentController>(
"AreaLightComponentController", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &AreaLightComponentController::m_configuration, "Configuration", "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->ClassElement(Edit::ClassElements::EditorData, "")
->Attribute(Edit::Attributes::AutoExpand, true)
->DataElement(Edit::UIHandlers::Default, &AreaLightComponentController::m_configuration, "Configuration", "")
->Attribute(Edit::Attributes::Visibility, Edit::PropertyVisibility::ShowChildrenOnly)
;
editContext->Class<AreaLightComponentConfig>(
"AreaLightComponentConfig", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->DataElement(AZ::Edit::UIHandlers::Color, &AreaLightComponentConfig::m_color, "Color", "Color of the light")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute("ColorEditorConfiguration", AZ::RPI::ColorUtils::GetLinearRgbEditorConfig())
->DataElement(AZ::Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_intensityMode, "Intensity Mode", "Allows specifying which photometric unit to work in.")
->EnumAttribute(PhotometricUnit::Candela, "Candela")
->EnumAttribute(PhotometricUnit::Lumen, "Lumen")
->EnumAttribute(PhotometricUnit::Nit, "Nit")
->EnumAttribute(PhotometricUnit::Ev100Luminance, "Ev100")
->ClassElement(Edit::ClassElements::EditorData, "")
->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_lightType, "Light Type", "Which type of light this component represents.")
->EnumAttribute(AreaLightComponentConfig::LightType::Unknown, "Choose a Light Type")
->EnumAttribute(AreaLightComponentConfig::LightType::Sphere, "Point (Sphere)")
->EnumAttribute(AreaLightComponentConfig::LightType::SimplePoint, "Point (Simple)")
->EnumAttribute(AreaLightComponentConfig::LightType::SpotDisk, "Spot (Disk)")
->EnumAttribute(AreaLightComponentConfig::LightType::SimpleSpot, "Spot (Simple)")
->EnumAttribute(AreaLightComponentConfig::LightType::Capsule, "Capsule")
->EnumAttribute(AreaLightComponentConfig::LightType::Quad, "Quad")
->EnumAttribute(AreaLightComponentConfig::LightType::Polygon, "Polygon")
->DataElement(Edit::UIHandlers::Color, &AreaLightComponentConfig::m_color, "Color", "Color of the light")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute("ColorEditorConfiguration", RPI::ColorUtils::GetLinearRgbEditorConfig())
->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_intensityMode, "Intensity Mode", "Allows specifying which photometric unit to work in.")
->Attribute(AZ::Edit::Attributes::EnumValues, &AreaLightComponentConfig::GetValidPhotometricUnits)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_intensity, "Intensity", "Intensity of the light in the set photometric unit.")
->Attribute(Edit::Attributes::Min, &AreaLightComponentConfig::GetIntensityMin)
->Attribute(Edit::Attributes::Max, &AreaLightComponentConfig::GetIntensityMax)
->Attribute(Edit::Attributes::SoftMin, &AreaLightComponentConfig::GetIntensitySoftMin)
->Attribute(Edit::Attributes::SoftMax, &AreaLightComponentConfig::GetIntensitySoftMax)
->Attribute(Edit::Attributes::Suffix, &AreaLightComponentConfig::GetIntensitySuffix)
->DataElement(AZ::Edit::UIHandlers::CheckBox, &AreaLightComponentConfig::m_lightEmitsBothDirections, "Both Directions", "Whether light should emit from both sides of the surface or just the front")
->Attribute(AZ::Edit::Attributes::Visibility, &AreaLightComponentConfig::Is2DSurface)
->DataElement(AZ::Edit::UIHandlers::CheckBox, &AreaLightComponentConfig::m_useFastApproximation, "Fast Approximation", "Whether the light should use the default high quality linear transformed cosine technique or a faster approximation.")
->Attribute(AZ::Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsFastApproximation)
->ClassElement(AZ::Edit::ClassElements::Group, "Attenuation Radius")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_attenuationRadiusMode, "Mode", "Controls whether the attenation radius is calculated automatically or set explicitly.")
->DataElement(Edit::UIHandlers::CheckBox, &AreaLightComponentConfig::m_lightEmitsBothDirections, "Both Directions", "Whether light should emit from both sides of the surface or just the front")
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsBothDirections)
->DataElement(Edit::UIHandlers::CheckBox, &AreaLightComponentConfig::m_useFastApproximation, "Fast Approximation", "Whether the light should use the default high quality linear transformed cosine technique or a faster approximation.")
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsFastApproximation)
->ClassElement(Edit::ClassElements::Group, "Attenuation Radius")
->Attribute(Edit::Attributes::AutoExpand, true)
->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_attenuationRadiusMode, "Mode", "Controls whether the attenation radius is calculated automatically or set explicitly.")
->EnumAttribute(LightAttenuationRadiusMode::Automatic, "Automatic")
->EnumAttribute(LightAttenuationRadiusMode::Explicit, "Explicit")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
->DataElement(AZ::Edit::UIHandlers::Default, &AreaLightComponentConfig::m_attenuationRadius, "Radius", "The distance at which this light no longer has an affect.")
->Attribute(AZ::Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsAttenuationRadiusModeAutomatic)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
->DataElement(Edit::UIHandlers::Default, &AreaLightComponentConfig::m_attenuationRadius, "Radius", "The distance at which this light no longer has an affect.")
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsAttenuationRadiusModeAutomatic)
->ClassElement(Edit::ClassElements::Group, "Shutters")
->Attribute(Edit::Attributes::AutoExpand, true)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShutters)
->DataElement(Edit::UIHandlers::Default, &AreaLightComponentConfig::m_enableShutters, "Enable Shutters", "Restrict the light to a specific beam angle depending on shape.")
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::ShuttersMustBeEnabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_innerShutterAngleDegrees, "Inner Angle", "The inner angle of the shutters where the light beam begins to be occluded.")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 180.0f)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShutters)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShuttersDisabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_outerShutterAngleDegrees, "Outer Angle", "The outer angle of the shutters where the light beam is completely occluded.")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 180.0f)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShutters)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShuttersDisabled)
->ClassElement(Edit::ClassElements::Group, "Shadows")
->Attribute(Edit::Attributes::AutoExpand, true)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->DataElement(Edit::UIHandlers::Default, &AreaLightComponentConfig::m_enableShadow, "Enable Shadow", "Enable shadow for the light")
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_shadowmapMaxSize, "Shadowmap Size", "Width/Height of shadowmap")
->EnumAttribute(ShadowmapSize::Size256, " 256")
->EnumAttribute(ShadowmapSize::Size512, " 512")
->EnumAttribute(ShadowmapSize::Size1024, "1024")
->EnumAttribute(ShadowmapSize::Size2048, "2048")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled)
->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_shadowFilterMethod, "Shadow Filter Method",
"Filtering method of edge-softening of shadows.\n"
" None: no filtering\n"
" PCF: Percentage-Closer Filtering\n"
" ESM: Exponential Shadow Maps\n"
" ESM+PCF: ESM with a PCF fallback\n"
"For BehaviorContext (or TrackView), None=0, PCF=1, ESM=2, ESM+PCF=3")
->EnumAttribute(ShadowFilterMethod::None, "None")
->EnumAttribute(ShadowFilterMethod::Pcf, "PCF")
->EnumAttribute(ShadowFilterMethod::Esm, "ESM")
->EnumAttribute(ShadowFilterMethod::EsmPcf, "ESM+PCF")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_boundaryWidthInDegrees, "Softening Boundary Width",
"Width of the boundary between shadowed area and lit one. "
"Units are in degrees. "
"If this is 0, softening edge is disabled.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 1.f)
->Attribute(Edit::Attributes::Suffix, " deg")
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsPcfBoundarySearchDisabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_predictionSampleCount, "Prediction Sample Count",
"Sample Count for prediction of whether the pixel is on the boundary. Specific to PCF and ESM+PCF.")
->Attribute(Edit::Attributes::Min, 4)
->Attribute(Edit::Attributes::Max, 16)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsPcfBoundarySearchDisabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_filteringSampleCount, "Filtering Sample Count",
"It is used only when the pixel is predicted to be on the boundary. Specific to PCF and ESM+PCF.")
->Attribute(Edit::Attributes::Min, 4)
->Attribute(Edit::Attributes::Max, 64)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled)
->DataElement(
Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_pcfMethod, "Pcf Method",
"Type of Pcf to use.\n"
" Boundary search: do several taps to first determine if we are on a shadow boundary\n"
" Bicubic: a smooth, fixed-size kernel \n")
->EnumAttribute(PcfMethod::BoundarySearch, "Boundary Search")
->EnumAttribute(PcfMethod::Bicubic, "Bicubic")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled);
;
}
}
@@ -95,8 +182,8 @@ namespace AZ
behaviorContext->Class<EditorAreaLightComponent>()->RequestBus("AreaLightRequestBus");
behaviorContext->ConstantProperty("EditorAreaLightComponentTypeId", BehaviorConstant(Uuid(EditorAreaLightComponentTypeId)))
->Attribute(AZ::Script::Attributes::Module, "render")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
->Attribute(Script::Attributes::Module, "render")
->Attribute(Script::Attributes::Scope, Script::Attributes::ScopeFlags::Automation);
}
}
@@ -119,14 +206,139 @@ namespace AZ
BaseClass::Deactivate();
}
AZ::u32 EditorAreaLightComponent::OnConfigurationChanged()
bool EditorAreaLightComponent::HandleLightTypeChange()
{
if (m_lightType == AreaLightComponentConfig::LightType::Unknown)
{
// Light type is unknown, see if it can be determined from a shape component.
Crc32 shapeType = Crc32(0);
LmbrCentral::ShapeComponentRequestsBus::EventResult(shapeType, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::GetShapeType);
constexpr Crc32 SphereShapeTypeId = AZ_CRC_CE("Sphere");
constexpr Crc32 DiskShapeTypeId = AZ_CRC_CE("DiskShape");
constexpr Crc32 CapsuleShapeTypeId = AZ_CRC_CE("Capsule");
constexpr Crc32 QuadShapeTypeId = AZ_CRC_CE("QuadShape");
constexpr Crc32 PoylgonShapeTypeId = AZ_CRC_CE("PolygonPrism");
switch (shapeType)
{
case SphereShapeTypeId:
m_lightType = AreaLightComponentConfig::LightType::Sphere;
break;
case DiskShapeTypeId:
m_lightType = AreaLightComponentConfig::LightType::SpotDisk;
break;
case CapsuleShapeTypeId:
m_lightType = AreaLightComponentConfig::LightType::Capsule;
break;
case QuadShapeTypeId:
m_lightType = AreaLightComponentConfig::LightType::Quad;
break;
case PoylgonShapeTypeId:
m_lightType = AreaLightComponentConfig::LightType::Polygon;
break;
default:
break; // Light type can't be deduced.
}
}
if (m_lightType == m_controller.m_configuration.m_lightType)
{
// No change, nothing to do
return false;
}
// Update the cached light type.
m_lightType = m_controller.m_configuration.m_lightType;
// componets may be removed or added here, so deactivate now and reactivate the entity when everything is done shifting around.
GetEntity()->Deactivate();
// Check if there is already a shape components and remove it.
for (Component* component : GetEntity()->GetComponents())
{
ComponentDescriptor::DependencyArrayType provided;
ComponentDescriptor* componentDescriptor = nullptr;
EBUS_EVENT_ID_RESULT(componentDescriptor, component->RTTI_GetType(), ComponentDescriptorBus, GetDescriptor);
AZ_Assert(componentDescriptor, "Component class %s descriptor is not created! It must be before you can use it!", component->RTTI_GetTypeName());
componentDescriptor->GetProvidedServices(provided, component);
auto providedItr = AZStd::find(provided.begin(), provided.end(), AZ_CRC_CE("ShapeService"));
if (providedItr != provided.end())
{
AZStd::vector<Component*> componentsToRemove = { component };
AzToolsFramework::EntityCompositionRequests::RemoveComponentsOutcome outcome =
AZ::Failure(AZStd::string("Failed to remove old shape component."));
AzToolsFramework::EntityCompositionRequestBus::BroadcastResult(outcome, &AzToolsFramework::EntityCompositionRequests::RemoveComponents, componentsToRemove);
break;
}
}
// Add a new shape component for light types that require it.
auto addComponentOfType = [&](AZ::Uuid type)
{
AzToolsFramework::EntityCompositionRequests::AddComponentsOutcome outcome =
AZ::Failure(AZStd::string("Failed to add shape component for light type"));
const AZStd::vector<AZ::EntityId> entityList = { GetEntityId() };
AzToolsFramework::EntityCompositionRequestBus::BroadcastResult(outcome, &AzToolsFramework::EntityCompositionRequests::AddComponentsToEntities,
entityList, ComponentTypeList({ type }));
};
switch (m_lightType)
{
case AreaLightComponentConfig::LightType::Sphere:
addComponentOfType(LmbrCentral::EditorSphereShapeComponentTypeId);
break;
case AreaLightComponentConfig::LightType::SpotDisk:
addComponentOfType(LmbrCentral::EditorDiskShapeComponentTypeId);
break;
case AreaLightComponentConfig::LightType::Capsule:
addComponentOfType(LmbrCentral::EditorCapsuleShapeComponentTypeId);
break;
case AreaLightComponentConfig::LightType::Quad:
addComponentOfType(LmbrCentral::EditorQuadShapeComponentTypeId);
break;
case AreaLightComponentConfig::LightType::Polygon:
addComponentOfType(LmbrCentral::EditorPolygonPrismShapeComponentTypeId);
break;
default:
// Some light types don't require a shape, this is ok.
break;
}
GetEntity()->Activate();
// Set more reasonable default values for certain shapes.
switch (m_lightType)
{
case AreaLightComponentConfig::LightType::Sphere:
LmbrCentral::SphereShapeComponentRequestsBus::Event(GetEntityId(), &LmbrCentral::SphereShapeComponentRequests::SetRadius, 0.05f);
break;
case AreaLightComponentConfig::LightType::SpotDisk:
LmbrCentral::DiskShapeComponentRequestBus::Event(GetEntityId(), &LmbrCentral::DiskShapeComponentRequests::SetRadius, 0.05f);
break;
}
return true;
}
u32 EditorAreaLightComponent::OnConfigurationChanged()
{
bool needsFullRefresh = HandleLightTypeChange();
LmbrCentral::EditorShapeComponentRequestsBus::Event(GetEntityId(), &LmbrCentral::EditorShapeComponentRequests::SetShapeColor, m_controller.m_configuration.m_color);
// If photometric unit changes, convert the intensities so the actual intensity doesn't change.
m_controller.ConvertToIntensityMode(m_controller.m_configuration.m_intensityMode);
BaseClass::OnConfigurationChanged();
if (needsFullRefresh)
{
return Edit::PropertyRefreshLevels::EntireTree;
}
return Edit::PropertyRefreshLevels::AttributesAndValues;
}
@@ -52,7 +52,11 @@ namespace AZ
// EditorRenderComponentAdapter overrides...
bool ShouldActivateController() const override;
AZ::u32 OnConfigurationChanged() override;
bool HandleLightTypeChange();
u32 OnConfigurationChanged() override;
AreaLightComponentConfig::LightType m_lightType; // Used to detect when the configuration's light type changes.
};
} // namespace Render
@@ -145,14 +145,14 @@ namespace AZ
->Attribute(Edit::Attributes::Max, 0.1f)
->Attribute(Edit::Attributes::Suffix, " m")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowFilteringDisabled)
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsPcfBoundarySearchDisabled)
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_predictionSampleCount, "Prediction Sample Count",
"Sample Count for prediction of whether the pixel is on the boundary. "
"Specific to PCF and ESM+PCF.")
->Attribute(Edit::Attributes::Min, 4)
->Attribute(Edit::Attributes::Max, 16)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled)
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsPcfBoundarySearchDisabled)
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering Sample Count",
"It is used only when the pixel is predicted as on the boundary. "
"Specific to PCF and ESM+PCF.")
@@ -160,7 +160,17 @@ namespace AZ
->Attribute(Edit::Attributes::Max, 64)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled)
;
->DataElement(
Edit::UIHandlers::ComboBox, &DirectionalLightComponentConfig::m_pcfMethod, "Pcf Method",
"Type of Pcf to use.\n"
" Boundary search: do several taps to first determine if we are on a shadow boundary\n"
" Bicubic: a smooth, fixed-size kernel \n")
->EnumAttribute(PcfMethod::BoundarySearch, "Boundary Search")
->EnumAttribute(PcfMethod::Bicubic, "Bicubic")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled);
;
}
}
@@ -1,206 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <CoreLights/EditorPointLightComponent.h>
#include <Atom/RPI.Edit/Common/ColorUtils.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzCore/Math/IntersectSegment.h>
namespace AZ
{
namespace Render
{
EditorPointLightComponent::EditorPointLightComponent(const PointLightComponentConfig& config)
: BaseClass(config)
{
}
void EditorPointLightComponent::Reflect(AZ::ReflectContext* context)
{
BaseClass::Reflect(context);
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorPointLightComponent, BaseClass>()
->Version(1, ConvertToEditorRenderComponentAdapter<1>);
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorPointLightComponent>(
"Point Light", "A point light emits light in all directions from a single point in space.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Atom")
->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/Component_Placeholder.svg")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "editor/icons/components/viewport/component_placeholder.png")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://docs.aws.amazon.com/lumberyard/latest/userguide/component-point-light.html")
;
editContext->Class<PointLightComponentController>(
"PointLightComponentController", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &PointLightComponentController::m_configuration, "Configuration", "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
editContext->Class<PointLightComponentConfig>(
"PointLightComponentConfig", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->DataElement(AZ::Edit::UIHandlers::Color, &PointLightComponentConfig::m_color, "Color", "Color of the light")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute("ColorEditorConfiguration", AZ::RPI::ColorUtils::GetLinearRgbEditorConfig())
->DataElement(Edit::UIHandlers::ComboBox, &PointLightComponentConfig::m_intensityMode, "Intensity Mode", "Allows specifying light values in candelas or lumens")
->EnumAttribute(PhotometricUnit::Candela, "Candela")
->EnumAttribute(PhotometricUnit::Lumen, "Lumen")
->EnumAttribute(PhotometricUnit::Nit, "Nit")
->EnumAttribute(PhotometricUnit::Ev100Luminance, "Ev100")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
->DataElement(AZ::Edit::UIHandlers::Default, &PointLightComponentConfig::m_intensity, "Intensity", "Intensity of the light")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::Suffix, &PointLightComponentConfig::GetIntensitySuffix)
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(AZ::Edit::UIHandlers::Slider, &PointLightComponentConfig::m_bulbRadius, "Bulb Radius", "The size of the bulb in meters")
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
->Attribute(AZ::Edit::Attributes::Max, 100000.0f)
->Attribute(AZ::Edit::Attributes::SoftMin, 0.01f)
->Attribute(AZ::Edit::Attributes::SoftMax, 1.0f)
->Attribute(AZ::Edit::Attributes::Suffix, " m")
->ClassElement(AZ::Edit::ClassElements::Group, "Attenuation Radius")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &PointLightComponentConfig::m_attenuationRadiusMode, "Mode", "Controls whether the attenation radius is calculated automatically or set explicitly.")
->EnumAttribute(LightAttenuationRadiusMode::Automatic, "Automatic")
->EnumAttribute(LightAttenuationRadiusMode::Explicit, "Explicit")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
->DataElement(AZ::Edit::UIHandlers::Default, &PointLightComponentConfig::m_attenuationRadius, "Radius", "The distance at which this light no longer has an affect.")
->Attribute(AZ::Edit::Attributes::ReadOnly, &PointLightComponentConfig::IsAttenuationRadiusModeAutomatic)
;
}
}
if (auto behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<EditorPointLightComponent>()->RequestBus("PointLightRequestBus");
behaviorContext->ConstantProperty("EditorPointLightComponentTypeId", BehaviorConstant(Uuid(EditorPointLightComponentTypeId)))
->Attribute(AZ::Script::Attributes::Module, "render")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
}
}
void EditorPointLightComponent::Activate()
{
BaseClass::Activate();
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusConnect(GetEntityId());
TransformNotificationBus::Handler::BusConnect(GetEntityId());
AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId());
}
void EditorPointLightComponent::Deactivate()
{
AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusDisconnect();
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
BaseClass::Deactivate();
}
AZStd::tuple<float, Vector3> EditorPointLightComponent::GetRadiusAndPosition() const
{
Vector3 position = Vector3::CreateZero();
AZ::TransformBus::EventResult(position, GetEntityId(), &AZ::TransformBus::Events::GetWorldTranslation);
return AZStd::tuple<float, Vector3>(m_controller.GetBulbRadius(), position);
}
AZStd::tuple<float, Vector3> EditorPointLightComponent::GetViewportRadiusAndPosition(const AzFramework::ViewportInfo& viewportInfo) const
{
const auto [radius, position] = GetRadiusAndPosition();
constexpr float PixelRadius = 10.0f;
const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId);
const float distance = cameraState.m_position.GetDistance(position);
const float screenScale = (distance * cameraState.m_fovOrZoom) / cameraState.m_viewportSize.GetX();
return AZStd::tuple<float, Vector3>(AZ::GetMax(radius, screenScale * PixelRadius), position);
}
void EditorPointLightComponent::DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay)
{
debugDisplay.SetColor(m_controller.GetColor());
// Draw a sphere for the light itself.
auto [sphereSize, position] = GetViewportRadiusAndPosition(viewportInfo);
debugDisplay.DrawWireSphere(position, sphereSize);
// Don't draw extra visualization unless selected.
if (!IsSelected())
{
return;
}
// Draw a sphere for the attenuation radius
debugDisplay.DrawWireSphere(position, m_controller.GetAttenuationRadius());
}
AZ::Aabb EditorPointLightComponent::GetEditorSelectionBoundsViewport(const AzFramework::ViewportInfo& viewportInfo)
{
auto [radius, position] = GetViewportRadiusAndPosition(viewportInfo);
return Aabb::CreateCenterRadius(position, radius);
}
bool EditorPointLightComponent::EditorSelectionIntersectRayViewport(
const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance)
{
auto [radius, position] = GetViewportRadiusAndPosition(viewportInfo);
return AZ::Intersect::IntersectRaySphere(src, dir, position, radius, distance) > 0;
}
void EditorPointLightComponent::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, [[maybe_unused]] const AZ::Transform& world)
{
// Transform scale impacts the bulb radius and intensity of the light, so refresh the values.
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay,
AzToolsFramework::Refresh_Values);
}
AZ::Aabb EditorPointLightComponent::GetWorldBounds()
{
auto [radius, position] = GetRadiusAndPosition();
return Aabb::CreateCenterRadius(position, radius);
}
AZ::Aabb EditorPointLightComponent::GetLocalBounds()
{
return Aabb::CreateCenterRadius(AZ::Vector3::CreateZero(), m_controller.GetBulbRadius());
}
u32 EditorPointLightComponent::OnConfigurationChanged()
{
// Set the intenstiy of the photometric unit in case the controller is disabled. This is needed to correctly convert between photometric units.
m_controller.m_photometricValue.SetIntensity(m_controller.m_configuration.m_intensity);
// If the intensity mode changes in the editor, convert the photometric value and update the intensity
if (m_controller.m_configuration.m_intensityMode != m_controller.m_photometricValue.GetType())
{
m_controller.m_photometricValue.SetArea(m_controller.m_configuration.GetArea());
m_controller.m_photometricValue.ConvertToPhotometricUnit(m_controller.m_configuration.m_intensityMode);
m_controller.m_configuration.m_intensity = m_controller.m_photometricValue.GetIntensity();
}
BaseClass::OnConfigurationChanged();
return Edit::PropertyRefreshLevels::AttributesAndValues;
}
} // namespace Render
} // namespace AZ
@@ -1,74 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzFramework/Visibility/BoundsBus.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <Atom/Feature/Utils/EditorRenderComponentAdapter.h>
#include <CoreLights/PointLightComponent.h>
namespace AZ
{
namespace Render
{
class EditorPointLightComponent final
: public EditorRenderComponentAdapter<PointLightComponentController, PointLightComponent, PointLightComponentConfig>
, private AzToolsFramework::EditorComponentSelectionRequestsBus::Handler
, private AzFramework::EntityDebugDisplayEventBus::Handler
, private TransformNotificationBus::Handler
, public AzFramework::BoundsRequestBus::Handler
{
public:
using BaseClass = EditorRenderComponentAdapter<PointLightComponentController, PointLightComponent, PointLightComponentConfig>;
AZ_EDITOR_COMPONENT(AZ::Render::EditorPointLightComponent, EditorPointLightComponentTypeId, BaseClass);
static void Reflect(AZ::ReflectContext* context);
EditorPointLightComponent() = default;
EditorPointLightComponent(const PointLightComponentConfig& config);
void Activate() override;
void Deactivate() override;
// EntityDebugDisplayEventBus overrides ...
void DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override;
// EditorComponentSelectionRequestsBus overrides ...
bool SupportsEditorRayIntersect() override { return true; }
bool EditorSelectionIntersectRayViewport(
const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) override;
AZ::Aabb GetEditorSelectionBoundsViewport(const AzFramework::ViewportInfo& viewportInfo) override;
// BoundsRequestBus overrides ...
AZ::Aabb GetWorldBounds() override;
AZ::Aabb GetLocalBounds() override;
private:
AZStd::tuple<float, Vector3> GetRadiusAndPosition() const;
// TransformNotificationBus::Handler overrides ...
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
//! Returns a radius for the light relative to the viewport, ensuring the the light will always take up at least a certain amount of
//! screen space for selection and debug drawing
AZStd::tuple<float, Vector3> GetViewportRadiusAndPosition(const AzFramework::ViewportInfo& viewportInfo) const;
//! EditorRenderComponentAdapter overrides ...
u32 OnConfigurationChanged() override;
};
} // namespace Render
} // namespace AZ
@@ -1,261 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <CoreLights/EditorSpotLightComponent.h>
#include <Atom/RPI.Edit/Common/ColorUtils.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <CoreLights/SpotLightComponent.h>
namespace AZ
{
namespace Render
{
EditorSpotLightComponent::EditorSpotLightComponent(const SpotLightComponentConfig& config)
: BaseClass(config)
{
}
void EditorSpotLightComponent::Reflect(AZ::ReflectContext* context)
{
BaseClass::Reflect(context);
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorSpotLightComponent, BaseClass>()
->Version(3, ConvertToEditorRenderComponentAdapter<2>);
if (AZ::EditContext * editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorSpotLightComponent>(
"Spot Light", "A spot light emits light in a cone from a single point in space.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Atom")
->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/Component_Placeholder.svg")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "editor/icons/components/viewport/component_placeholder.png")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://docs.aws.amazon.com/lumberyard/latest/userguide/component-spot-light.html")
;
editContext->Class<SpotLightComponentController>(
"SpotLightComponentController", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &SpotLightComponentController::m_configuration, "Configuration", "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
editContext->Class<SpotLightComponentConfig>(
"SpotLightComponentConfig", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->DataElement(AZ::Edit::UIHandlers::Color, &SpotLightComponentConfig::m_color, "Color", "Color of the light")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute("ColorEditorConfiguration", AZ::RPI::ColorUtils::GetLinearRgbEditorConfig())
->DataElement(Edit::UIHandlers::ComboBox, &SpotLightComponentConfig::m_intensityMode, "Intensity Mode",
"Allows specifying light values in candelas or lumens")
->EnumAttribute(PhotometricUnit::Candela, "Candela")
->EnumAttribute(PhotometricUnit::Lumen, "Lumen")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
->DataElement(AZ::Edit::UIHandlers::Default, &SpotLightComponentConfig::m_intensity, "Intensity", "Intensity of the light")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::Suffix, &SpotLightComponentConfig::GetIntensitySuffix)
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(AZ::Edit::UIHandlers::Slider, &SpotLightComponentConfig::m_bulbRadius, "Bulb Radius",
"Radius of the disk that represents the spot light bulb.")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::SoftMax, 0.25f)
->Attribute(AZ::Edit::Attributes::Suffix, " m")
->ClassElement(AZ::Edit::ClassElements::Group, "Cone Configuration")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &SpotLightComponentConfig::m_innerConeDegrees, "Inner Cone Angle",
"Angle from the direction axis at which this light starts to fall off.")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::Max, &SpotLightComponentConfig::GetConeDegrees)
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(AZ::Edit::UIHandlers::Slider, &SpotLightComponentConfig::m_outerConeDegrees, "Outer Cone Angle",
"Angle from the direction axis at which this light no longer has an effect.")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::Max, &SpotLightComponentConfig::GetConeDegrees)
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(AZ::Edit::UIHandlers::Slider, &SpotLightComponentConfig::m_penumbraBias, "Penumbra Bias",
"Controls biasing the fall off curve of the penumbra towards the inner or outer cone angles.")
->Attribute(AZ::Edit::Attributes::Min, -1.0f)
->Attribute(AZ::Edit::Attributes::Max, 1.0f)
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->ClassElement(AZ::Edit::ClassElements::Group, "Attenuation Radius")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &SpotLightComponentConfig::m_attenuationRadiusMode, "Mode",
"Controls whether the attenuation radius is calculated automatically or set explicitly.")
->EnumAttribute(LightAttenuationRadiusMode::Automatic, "Automatic")
->EnumAttribute(LightAttenuationRadiusMode::Explicit, "Explicit")
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
->DataElement(AZ::Edit::UIHandlers::Default, &SpotLightComponentConfig::m_attenuationRadius, "Radius",
"The distance at which this light no longer has an affect.")
->Attribute(AZ::Edit::Attributes::ReadOnly, &SpotLightComponentConfig::IsAttenuationRadiusModeAutomatic)
->ClassElement(AZ::Edit::ClassElements::Group, "Shadow")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(Edit::UIHandlers::Default, &SpotLightComponentConfig::m_enabledShadow, "Enable Shadow", "Enable shadow for the light")
->DataElement(Edit::UIHandlers::ComboBox, &SpotLightComponentConfig::m_shadowmapSize, "Shadowmap Size", "Width/Height of shadowmap")
->EnumAttribute(ShadowmapSize::Size256, " 256")
->EnumAttribute(ShadowmapSize::Size512, " 512")
->EnumAttribute(ShadowmapSize::Size1024, "1024")
->EnumAttribute(ShadowmapSize::Size2048, "2048")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(Edit::UIHandlers::ComboBox, &SpotLightComponentConfig::m_shadowFilterMethod, "Shadow Filter Method",
"Filtering method of edge-softening of shadows.\n"
" None: no filtering\n"
" PCF: Percentage-Closer Filtering\n"
" ESM: Exponential Shadow Maps\n"
" ESM+PCF: ESM with a PCF fallback\n"
"For BehaviorContext (or TrackView), None=0, PCF=1, ESM=2, ESM+PCF=3")
->EnumAttribute(ShadowFilterMethod::None, "None")
->EnumAttribute(ShadowFilterMethod::Pcf, "PCF")
->EnumAttribute(ShadowFilterMethod::Esm, "ESM")
->EnumAttribute(ShadowFilterMethod::EsmPcf, "ESM+PCF")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(Edit::UIHandlers::Slider, &SpotLightComponentConfig::m_boundaryWidthInDegrees, "Softening Boundary Width",
"Width of the boundary between shadowed area and lit one. "
"Units are in degrees. "
"If this is 0, softening edge is disabled.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 1.f)
->Attribute(Edit::Attributes::Suffix, " deg")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &SpotLightComponentConfig::IsPcfBoundarySearchDisabled)
->DataElement(Edit::UIHandlers::Slider, &SpotLightComponentConfig::m_predictionSampleCount, "Prediction Sample Count",
"Sample Count for prediction of whether the pixel is on the boundary. Specific to PCF and ESM+PCF.")
->Attribute(Edit::Attributes::Min, 4)
->Attribute(Edit::Attributes::Max, 16)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &SpotLightComponentConfig::IsPcfBoundarySearchDisabled)
->DataElement(Edit::UIHandlers::Slider, &SpotLightComponentConfig::m_filteringSampleCount, "Filtering Sample Count",
"It is used only when the pixel is predicted to be on the boundary. Specific to PCF and ESM+PCF.")
->Attribute(Edit::Attributes::Min, 4)
->Attribute(Edit::Attributes::Max, 64)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &SpotLightComponentConfig::IsShadowPcfDisabled)
->DataElement(
Edit::UIHandlers::ComboBox, &SpotLightComponentConfig::m_pcfMethod, "Pcf Method",
"Type of Pcf to use.\n"
" Boundary search: do several taps to first determine if we are on a shadow boundary\n"
" Bicubic: a smooth, fixed-size kernel \n")
->EnumAttribute(PcfMethod::BoundarySearch, "Boundary Search")
->EnumAttribute(PcfMethod::Bicubic, "Bicubic")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::ReadOnly, &SpotLightComponentConfig::IsShadowPcfDisabled);
}
}
if (auto behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<EditorSpotLightComponent>()->RequestBus("SpotLightRequestBus");
behaviorContext->ConstantProperty("EditorSpotLightComponentTypeId", BehaviorConstant(Uuid(EditorSpotLightComponentTypeId)))
->Attribute(AZ::Script::Attributes::Module, "render")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
}
}
void EditorSpotLightComponent::Activate()
{
BaseClass::Activate();
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
}
void EditorSpotLightComponent::Deactivate()
{
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
BaseClass::Deactivate();
}
void EditorSpotLightComponent::DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay)
{
AZ::Transform worldTM;
AZ::TransformBus::EventResult(worldTM, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
const AZ::Vector3 position = worldTM.GetTranslation();
debugDisplay.SetColor(m_controller.GetColor());
// Draw a sphere for the light itself.
const float pixelRadius = 10.0f;
const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId);
const float distance = cameraState.m_position.GetDistance(position);
const float screenScale = (distance * cameraState.m_fovOrZoom) / cameraState.m_viewportSize.GetX();
debugDisplay.DrawWireSphere(position, screenScale * pixelRadius);
// Don't draw extra visualization unless selected.
if (!IsSelected())
{
return;
}
/*
* Draw rays to show the affected volume of the spot light.
* As well as two circle showing inner and outer cone angles.
* Note: the circles will not be drawn if cone are angles go beyond 90 degrees.
*/
worldTM.ExtractScale();
debugDisplay.PushMatrix(worldTM);
debugDisplay.SetColor(m_controller.GetColor());
float outerConeHalfAngle = m_controller.GetOuterConeAngleInDegrees() * 0.5f;
float innerConeHalfAngle = m_controller.GetInnerConeAngleInDegrees() * 0.5f;
const float debugConeHeight = m_controller.GetAttenuationRadius();
const float debugOuterConeRadius = tanf(AZ::DegToRad(outerConeHalfAngle)) * debugConeHeight;
debugDisplay.DrawArrow(Vector3::CreateZero(), Vector3::CreateAxisY() * debugConeHeight * 0.5f, debugConeHeight * 0.2f);
constexpr float rightAngleInDegrees = 90.0f;
if (outerConeHalfAngle < rightAngleInDegrees)
{
// outer cone
debugDisplay.DrawCircle(Vector3::CreateAxisY() * debugConeHeight, debugOuterConeRadius, 1);
}
if (innerConeHalfAngle < rightAngleInDegrees)
{
// inner cone
const float debugInnerConeRadius = tanf(AZ::DegToRad(innerConeHalfAngle)) * debugConeHeight;
debugDisplay.DrawCircle(Vector3::CreateAxisY() * debugConeHeight, debugInnerConeRadius, 1);
}
constexpr int debugRays = 6;
for (int rayIndex = 0; rayIndex < debugRays; ++rayIndex)
{
const float angle = (AZ::Constants::TwoPi / debugRays) * rayIndex;
const Vector3 spotRay = Vector3::CreateAxisY() * debugConeHeight + debugOuterConeRadius * Vector3(sinf(angle), 0.f, cosf(angle));
debugDisplay.DrawLine(Vector3::CreateZero(), spotRay * (outerConeHalfAngle > rightAngleInDegrees ? -1.f : 1.f));
}
debugDisplay.PopMatrix();
}
u32 EditorSpotLightComponent::OnConfigurationChanged()
{
// Set the intenstiy of the photometric unit in case the controller is disabled. This is needed to correctly convert between photometric units.
m_controller.m_photometricValue.SetIntensity(m_controller.m_configuration.m_intensity);
// If the intensity mode changes in the editor, convert the photometric value and update the intensity
if (m_controller.m_configuration.m_intensityMode != m_controller.m_photometricValue.GetType())
{
m_controller.m_photometricValue.ConvertToPhotometricUnit(m_controller.m_configuration.m_intensityMode);
m_controller.m_configuration.m_intensity = m_controller.m_photometricValue.GetIntensity();
}
BaseClass::OnConfigurationChanged();
return Edit::PropertyRefreshLevels::AttributesAndValues;
}
} // namespace Render
} // namespace AZ
@@ -1,49 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <Atom/Feature/Utils/EditorRenderComponentAdapter.h>
#include <CoreLights/SpotLightComponent.h>
namespace AZ
{
namespace Render
{
class EditorSpotLightComponent final
: public EditorRenderComponentAdapter<SpotLightComponentController, SpotLightComponent, SpotLightComponentConfig>
, private AzFramework::EntityDebugDisplayEventBus::Handler
{
public:
using BaseClass = EditorRenderComponentAdapter<SpotLightComponentController, SpotLightComponent, SpotLightComponentConfig>;
AZ_EDITOR_COMPONENT(AZ::Render::EditorSpotLightComponent, EditorSpotLightComponentTypeId, BaseClass);
static void Reflect(AZ::ReflectContext* context);
EditorSpotLightComponent() = default;
EditorSpotLightComponent(const SpotLightComponentConfig& config);
void Activate() override;
void Deactivate() override;
// AzFramework::EntityDebugDisplayEventBus::Handler overrides...
void DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override;
// EditorComponentAdapter overrides...
AZ::u32 OnConfigurationChanged() override;
};
} // namespace Render
} // namespace AZ
@@ -34,20 +34,32 @@ namespace AZ
class LightDelegateBase
: public LightDelegateInterface
, private LmbrCentral::ShapeComponentNotificationsBus::Handler
, private TransformNotificationBus::Handler
{
public:
LightDelegateBase(EntityId entityId, bool isVisible);
virtual ~LightDelegateBase();
// LightDelegateInterface overrides...
virtual void SetChroma(const AZ::Color& chroma) override;
virtual void SetIntensity(float intensity) override;
virtual float SetPhotometricUnit(PhotometricUnit unit) override;
virtual void SetAttenuationRadius(float radius) override;
virtual const PhotometricValue& GetPhotometricValue() const override { return m_photometricValue; };
virtual void SetLightEmitsBothDirections([[maybe_unused]] bool lightEmitsBothDirections) override {};
virtual void SetUseFastApproximation([[maybe_unused]] bool useFastApproximation) override {};
virtual void SetVisibility(bool visibility) override;
void SetChroma(const AZ::Color& chroma) override;
void SetIntensity(float intensity) override;
float SetPhotometricUnit(PhotometricUnit unit) override;
void SetAttenuationRadius(float radius) override;
const PhotometricValue& GetPhotometricValue() const override { return m_photometricValue; };
void SetLightEmitsBothDirections([[maybe_unused]] bool lightEmitsBothDirections) override {};
void SetUseFastApproximation([[maybe_unused]] bool useFastApproximation) override {};
void SetVisibility(bool visibility) override;
void SetEnableShutters(bool enabled) override { m_shuttersEnabled = enabled; };
void SetShutterAngles([[maybe_unused]]float innerAngleDegrees, [[maybe_unused]]float outerAngleDegrees) override {};
void SetEnableShadow(bool enabled) override { m_shadowsEnabled = enabled; };
void SetShadowmapMaxSize([[maybe_unused]] ShadowmapSize size) override {};
void SetShadowFilterMethod([[maybe_unused]] ShadowFilterMethod method) override {};
void SetSofteningBoundaryWidthAngle([[maybe_unused]] float widthInDegrees) override {};
void SetPredictionSampleCount([[maybe_unused]] uint32_t count) override {};
void SetFilteringSampleCount([[maybe_unused]] uint32_t count) override {};
void SetPcfMethod([[maybe_unused]] PcfMethod method) override {};
protected:
void InitBase(EntityId entityId);
@@ -56,11 +68,15 @@ namespace AZ
FeatureProcessorType* GetFeatureProcessor() const { return m_featureProcessor; };
typename FeatureProcessorType::LightHandle GetLightHandle() const { return m_lightHandle; };
const AZ::Transform& GetTransform() const { return m_transform; };
bool GetShuttersEnabled() { return m_shuttersEnabled; };
bool GetShadowsEnabled() { return m_shadowsEnabled; };
virtual void HandleShapeChanged() = 0;
// ShapeComponentNotificationsBus::Handler overrides...
void OnShapeChanged(ShapeChangeReasons changeReason) override;
// TransformNotificationBus::Handler overrides ...
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
private:
FeatureProcessorType* m_featureProcessor = nullptr;
@@ -69,6 +85,8 @@ namespace AZ
LmbrCentral::ShapeComponentRequests* m_shapeBus;
AZ::Transform m_transform;
PhotometricValue m_photometricValue;
bool m_shuttersEnabled = false;
bool m_shadowsEnabled = false;
};
} // namespace Render
} // namespace AZ
@@ -31,6 +31,7 @@ namespace AZ
template <typename FeatureProcessorType>
LightDelegateBase<FeatureProcessorType>::~LightDelegateBase()
{
TransformNotificationBus::Handler::BusDisconnect();
LmbrCentral::ShapeComponentNotificationsBus::Handler::BusDisconnect();
if (m_lightHandle.IsValid())
{
@@ -42,10 +43,21 @@ namespace AZ
void LightDelegateBase<FeatureProcessorType>::InitBase(EntityId entityId)
{
m_photometricValue.SetEffectiveSolidAngle(GetEffectiveSolidAngle());
LmbrCentral::ShapeComponentNotificationsBus::Handler::BusConnect(entityId);
m_shapeBus = LmbrCentral::ShapeComponentRequestsBus::FindFirstHandler(entityId);
TransformBus::EventResult(m_transform, entityId, &TransformBus::Events::GetWorldTM);
OnShapeChanged(ShapeChangeReasons::TransformChanged);
if (m_shapeBus != nullptr)
{
LmbrCentral::ShapeComponentNotificationsBus::Handler::BusConnect(entityId);
OnShapeChanged(ShapeChangeReasons::TransformChanged);
}
else if (m_lightHandle.IsValid())
{
// Only connect to the transform bus if there's no shape bus, otherwise the shape bus handles transforms.
TransformNotificationBus::Handler::BusConnect(entityId);
HandleShapeChanged();
m_featureProcessor->SetRgbIntensity(m_lightHandle, m_photometricValue.GetCombinedRgb<FeatureProcessorType::PhotometricUnitType>());
}
}
template <typename FeatureProcessorType>
@@ -95,6 +107,13 @@ namespace AZ
}
HandleShapeChanged();
}
template <typename FeatureProcessorType>
void LightDelegateBase<FeatureProcessorType>::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world)
{
m_transform = world;
HandleShapeChanged();
}
template <typename FeatureProcessorType>
void LightDelegateBase<FeatureProcessorType>::SetVisibility(bool isVisible)
@@ -14,6 +14,7 @@
#include <AzCore/Component/TransformBus.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
#include <Atom/Feature/CoreLights/ShadowConstants.h>
namespace AzFramework
{
@@ -56,6 +57,31 @@ namespace AZ
virtual void DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const = 0;
//! Turns the visibility of this light on/off.
virtual void SetVisibility(bool visibility) = 0;
// Shutters
// Sets if the light should be restricted to shutter angles.
virtual void SetEnableShutters(bool enabled) = 0;
// Sets the inner and outer angles of the shutters in degrees for where the light
// beam starts to attenuate (inner) to where it is completely occluded (outer).
virtual void SetShutterAngles(float innerAngleDegrees, float outerAngleDegrees) = 0;
// Shadows
//! Sets if shadows should be enabled
virtual void SetEnableShadow(bool enabled) = 0;
//! Sets the maximum resolution of the shadow map
virtual void SetShadowmapMaxSize(ShadowmapSize size) = 0;
//! Sets the filter method for the shadow
virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0;
//! Sets the width of boundary between shadowed area and lit area in degrees.
virtual void SetSofteningBoundaryWidthAngle(float widthInDegrees) = 0;
//! Sets the sample count to predict the boundary of the shadow. Max 16, should be less than filtering sample count.
virtual void SetPredictionSampleCount(uint32_t count) = 0;
//! Sets the sample count for filtering of the shadow boundary, max 64.
virtual void SetFilteringSampleCount(uint32_t count) = 0;
//! Sets the Pcf (Percentage closer filtering) method to use.
virtual void SetPcfMethod(PcfMethod method) = 0;
};
} // namespace Render
} // namespace AZ
@@ -1,44 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <CoreLights/PointLightComponent.h>
namespace AZ
{
namespace Render
{
PointLightComponent::PointLightComponent(const PointLightComponentConfig& config)
: BaseClass(config)
{
}
void PointLightComponent::Reflect(AZ::ReflectContext* context)
{
BaseClass::Reflect(context);
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<PointLightComponent, BaseClass>();
}
if (auto behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<PointLightComponent>()->RequestBus("PointLightRequestBus");
behaviorContext->ConstantProperty("PointLightComponentTypeId", BehaviorConstant(Uuid(PointLightComponentTypeId)))
->Attribute(AZ::Script::Attributes::Module, "render")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common);
}
}
} // namespace Render
} // namespace AZ
@@ -1,38 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzFramework/Components/ComponentAdapter.h>
#include <CoreLights/PointLightComponentController.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/CoreLightsConstants.h>
namespace AZ
{
namespace Render
{
class PointLightComponent final
: public AzFramework::Components::ComponentAdapter<PointLightComponentController, PointLightComponentConfig>
{
public:
using BaseClass = AzFramework::Components::ComponentAdapter<PointLightComponentController, PointLightComponentConfig>;
AZ_COMPONENT(AZ::Render::PointLightComponent, PointLightComponentTypeId, BaseClass);
PointLightComponent() = default;
PointLightComponent(const PointLightComponentConfig& config);
static void Reflect(AZ::ReflectContext* context);
};
} // namespace Render
} // namespace AZ
@@ -1,286 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <CoreLights/PointLightComponentController.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <Atom/RPI.Public/Scene.h>
namespace AZ
{
namespace Render
{
void PointLightComponentConfig::Reflect(ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<PointLightComponentConfig, ComponentConfig>()
->Version(2)
->Field("Color", &PointLightComponentConfig::m_color)
->Field("ColorIntensityMode", &PointLightComponentConfig::m_intensityMode)
->Field("Intensity", &PointLightComponentConfig::m_intensity)
->Field("AttenuationRadiusMode", &PointLightComponentConfig::m_attenuationRadiusMode)
->Field("AttenuationRadius", &PointLightComponentConfig::m_attenuationRadius)
->Field("BulbRadius", &PointLightComponentConfig::m_bulbRadius)
;
}
}
void PointLightComponentController::Reflect(ReflectContext* context)
{
PointLightComponentConfig::Reflect(context);
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<PointLightComponentController>()
->Version(1)
->Field("Configuration", &PointLightComponentController::m_configuration);
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<PointLightRequestBus>("PointLightRequestBus")
->Attribute(AZ::Script::Attributes::Module, "render")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Event("GetAttenuationRadius", &PointLightRequestBus::Events::GetAttenuationRadius)
->Event("SetAttenuationRadius", &PointLightRequestBus::Events::SetAttenuationRadius)
->Event("GetAttenuationRadiusIsAutomatic", &PointLightRequestBus::Events::GetAttenuationRadiusIsAutomatic)
->Event("SetAttenuationRadiusIsAutomatic", &PointLightRequestBus::Events::SetAttenuationRadiusIsAutomatic)
->Event("GetBulbRadius", &PointLightRequestBus::Events::GetBulbRadius)
->Event("SetBulbRadius", &PointLightRequestBus::Events::SetBulbRadius)
->Event("GetColor", &PointLightRequestBus::Events::GetColor)
->Event("SetColor", &PointLightRequestBus::Events::SetColor)
->Event("GetIntensity", &PointLightRequestBus::Events::GetIntensity)
->Event("SetIntensity", static_cast<void(PointLightRequestBus::Events::*)(float)>(&PointLightRequestBus::Events::SetIntensity))
->Event("GetIntensityMode", &PointLightRequestBus::Events::GetIntensityMode)
->Event("ConvertToIntensityMode", &PointLightRequestBus::Events::ConvertToIntensityMode)
->VirtualProperty("AttenuationRadius", "GetAttenuationRadius", "SetAttenuationRadius")
->VirtualProperty("AttenuationRadiusIsAutomatic", "GetAttenuationRadiusIsAutomatic", "SetAttenuationRadiusIsAutomatic")
->VirtualProperty("BulbRadius", "GetBulbRadius", "SetBulbRadius")
->VirtualProperty("Color", "GetColor", "SetColor")
->VirtualProperty("Intensity", "GetIntensity", "SetIntensity")
;
}
}
void PointLightComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("PointLightService", 0x951d2403));
}
void PointLightComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("PointLightService", 0x951d2403));
}
PointLightComponentController::PointLightComponentController(const PointLightComponentConfig& config)
: m_configuration(config)
{
}
void PointLightComponentController::Activate(EntityId entityId)
{
m_entityId = entityId;
m_featureProcessor = RPI::Scene::GetFeatureProcessorForEntity<PointLightFeatureProcessorInterface>(entityId);
AZ_Error("PointLightComponentController", m_featureProcessor, "Could not find a PointLightFeatureProcessorInterface on the scene.");
if (m_featureProcessor)
{
m_lightHandle = m_featureProcessor->AcquireLight();
AZ::Vector3 position = Vector3::CreateZero();
AZ::TransformBus::EventResult(position, entityId, &AZ::TransformBus::Events::GetWorldTranslation);
m_featureProcessor->SetPosition(m_lightHandle, position);
AZ::Vector3 scale = AZ::Vector3::CreateOne();
AZ::TransformBus::EventResult(scale, entityId, &AZ::TransformBus::Events::GetWorldScale);
m_configuration.m_scale = scale.GetMaxElement();
TransformNotificationBus::Handler::BusConnect(m_entityId);
PointLightRequestBus::Handler::BusConnect(m_entityId);
ConfigurationChanged();
}
}
void PointLightComponentController::Deactivate()
{
PointLightRequestBus::Handler::BusDisconnect(m_entityId);
TransformNotificationBus::Handler::BusDisconnect(m_entityId);
if (m_featureProcessor)
{
m_featureProcessor->ReleaseLight(m_lightHandle);
}
m_entityId.SetInvalid();
}
void PointLightComponentController::SetConfiguration(const PointLightComponentConfig& config)
{
m_configuration = config;
ConfigurationChanged();
}
const PointLightComponentConfig& PointLightComponentController::GetConfiguration() const
{
return m_configuration;
}
void PointLightComponentController::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world)
{
m_featureProcessor->SetPosition(m_lightHandle, world.GetTranslation());
if (m_configuration.m_scale != world.GetScale().GetMaxElement())
{
m_configuration.UpdateScale(world.GetScale().GetMaxElement());
BulbRadiusChanged();
ColorIntensityChanged();
}
}
void PointLightComponentController::ConfigurationChanged()
{
m_configuration.UpdateUnscaledIntensity();
m_configuration.UpdateUnscaledBulbRadius();
m_photometricValue = PhotometricValue(m_configuration.m_intensity, m_configuration.m_color, m_configuration.m_intensityMode);
m_photometricValue.SetArea(m_configuration.GetArea());
ColorIntensityChanged();
AttenuationRadiusChanged();
BulbRadiusChanged();
}
void PointLightComponentController::ColorIntensityChanged()
{
PointLightNotificationBus::Event(m_entityId, &PointLightNotifications::OnColorOrIntensityChanged, m_configuration.m_color, m_configuration.m_intensity);
m_photometricValue.SetChroma(m_configuration.m_color);
m_photometricValue.SetIntensity(m_configuration.m_intensity);
m_featureProcessor->SetRgbIntensity(m_lightHandle, m_photometricValue.GetCombinedRgb<PhotometricUnit::Candela>());
}
void PointLightComponentController::AttenuationRadiusChanged()
{
if (m_configuration.m_attenuationRadiusMode == LightAttenuationRadiusMode::Automatic)
{
AutoCalculateAttenuationRadius();
}
PointLightNotificationBus::Event(m_entityId, &PointLightNotifications::OnAttenutationRadiusChanged, m_configuration.m_attenuationRadius);
m_featureProcessor->SetAttenuationRadius(m_lightHandle, m_configuration.m_attenuationRadius);
}
void PointLightComponentController::BulbRadiusChanged()
{
m_photometricValue.SetArea(m_configuration.GetArea());
PointLightNotificationBus::Event(m_entityId, &PointLightNotifications::OnBulbRadiusChanged, m_configuration.m_bulbRadius);
m_featureProcessor->SetBulbRadius(m_lightHandle, m_configuration.m_bulbRadius);
}
void PointLightComponentController::AutoCalculateAttenuationRadius()
{
// Get combined intensity luma from m_photometricValue, then calculate the radius at which the irradiance will be equal to cutoffIntensity.
static const float CutoffIntensity = 0.1f; // Make this configurable later.
float intensity = m_photometricValue.GetCombinedIntensity(PhotometricUnit::Lumen);
m_configuration.m_attenuationRadius = sqrt(intensity / CutoffIntensity);
}
const Color& PointLightComponentController::GetColor() const
{
return m_configuration.m_color;
}
void PointLightComponentController::SetColor(const Color& color)
{
m_configuration.m_color = color;
PointLightNotificationBus::Event(m_entityId, &PointLightNotifications::OnColorChanged, color);
ColorIntensityChanged();
}
float PointLightComponentController::GetIntensity() const
{
return m_configuration.m_intensity;
}
void PointLightComponentController::SetIntensity(float intensity)
{
m_configuration.m_intensity = intensity;
m_configuration.UpdateUnscaledIntensity();
PointLightNotificationBus::Event(m_entityId, &PointLightNotifications::OnIntensityChanged, intensity);
ColorIntensityChanged();
}
void PointLightComponentController::SetIntensity(float intensity, PhotometricUnit intensityMode)
{
m_configuration.m_intensityMode = intensityMode;
SetIntensity(intensity);
}
PhotometricUnit PointLightComponentController::GetIntensityMode() const
{
return m_configuration.m_intensityMode;
}
void PointLightComponentController::ConvertToIntensityMode(PhotometricUnit intensityMode)
{
if (m_configuration.m_intensityMode != intensityMode)
{
m_configuration.m_intensityMode = intensityMode;
m_photometricValue.ConvertToPhotometricUnit(intensityMode);
m_configuration.m_intensity = m_photometricValue.GetIntensity();
m_configuration.UpdateUnscaledIntensity();
}
}
float PointLightComponentController::GetAttenuationRadius() const
{
return m_configuration.m_attenuationRadius;
}
void PointLightComponentController::SetAttenuationRadius(float radius)
{
m_configuration.m_attenuationRadius = radius;
AttenuationRadiusChanged();
}
float PointLightComponentController::GetBulbRadius() const
{
return m_configuration.m_bulbRadius;
}
void PointLightComponentController::SetBulbRadius(float bulbRadius)
{
m_configuration.m_bulbRadius = bulbRadius;
m_configuration.UpdateUnscaledBulbRadius();
BulbRadiusChanged();
}
bool PointLightComponentController::GetAttenuationRadiusIsAutomatic() const
{
return (m_configuration.m_attenuationRadiusMode == LightAttenuationRadiusMode::Automatic);
}
void PointLightComponentController::SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode)
{
m_configuration.m_attenuationRadiusMode = attenuationRadiusMode;
if (attenuationRadiusMode == LightAttenuationRadiusMode::Automatic)
{
AutoCalculateAttenuationRadius();
}
}
} // namespace Render
} // namespace AZ
@@ -1,87 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Math/Color.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
#include <Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/PointLightBus.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/PointLightComponentConfig.h>
namespace AZ
{
namespace Render
{
class PointLightComponentController final
: private TransformNotificationBus::Handler
, public PointLightRequestBus::Handler
{
public:
friend class EditorPointLightComponent;
AZ_TYPE_INFO(AZ::Render::PointLightComponentController, "{23F82E30-2E1F-45FE-A9A7-B15632ED9EBD}");
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
PointLightComponentController() = default;
PointLightComponentController(const PointLightComponentConfig& config);
void Activate(EntityId entityId);
void Deactivate();
void SetConfiguration(const PointLightComponentConfig& config);
const PointLightComponentConfig& GetConfiguration() const;
private:
AZ_DISABLE_COPY(PointLightComponentController);
// TransformNotificationBus::Handler overrides ...
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
// PointLightRequestBus::Handler overrides ...
const Color& GetColor() const override;
void SetColor(const Color& color) override;
float GetIntensity() const override;
PhotometricUnit GetIntensityMode() const override;
void SetIntensity(float intensity) override;
void SetIntensity(float intensity, PhotometricUnit intensityMode) override;
float GetAttenuationRadius() const override;
void SetAttenuationRadius(float radius) override;
bool GetAttenuationRadiusIsAutomatic() const override;
void SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode) override;
float GetBulbRadius() const override;
void SetBulbRadius(float bulbRadius) override;
void ConvertToIntensityMode(PhotometricUnit intensityMode) override;
void ConfigurationChanged();
void ColorIntensityChanged();
void AttenuationRadiusChanged();
void BulbRadiusChanged();
void AutoCalculateAttenuationRadius();
PointLightComponentConfig m_configuration;
PhotometricValue m_photometricValue;
PointLightFeatureProcessorInterface* m_featureProcessor = nullptr;
PointLightFeatureProcessorInterface::LightHandle m_lightHandle;
EntityId m_entityId;
};
} // namespace Render
} // AZ namespace
@@ -0,0 +1,56 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <CoreLights/SimplePointLightDelegate.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/Feature/CoreLights/SimplePointLightFeatureProcessorInterface.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h>
namespace AZ
{
namespace Render
{
SimplePointLightDelegate::SimplePointLightDelegate(EntityId entityId, bool isVisible)
: LightDelegateBase<SimplePointLightFeatureProcessorInterface>(entityId, isVisible)
{
InitBase(entityId);
GetFeatureProcessor()->SetPosition(GetLightHandle(), GetTransform().GetTranslation());
}
float SimplePointLightDelegate::CalculateAttenuationRadius(float lightThreshold) const
{
// Calculate the radius at which the irradiance will be equal to cutoffIntensity.
float intensity = GetPhotometricValue().GetCombinedIntensity(PhotometricUnit::Lumen);
return sqrt(intensity / lightThreshold);
}
float SimplePointLightDelegate::GetSurfaceArea() const
{
return 0.0f;
}
void SimplePointLightDelegate::HandleShapeChanged()
{
GetFeatureProcessor()->SetPosition(GetLightHandle(), GetTransform().GetTranslation());
}
void SimplePointLightDelegate::DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const
{
if (isSelected)
{
debugDisplay.SetColor(color);
// Draw a sphere for the attenuation radius
debugDisplay.DrawWireSphere(transform.GetTranslation(), CalculateAttenuationRadius(AreaLightComponentConfig::CutoffIntensity));
}
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,44 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <CoreLights/LightDelegateBase.h>
#include <AzCore/Component/TransformBus.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <Atom/Feature/CoreLights/SimplePointLightFeatureProcessorInterface.h>
namespace AZ
{
namespace Render
{
class SimplePointLightDelegate final
: public LightDelegateBase<SimplePointLightFeatureProcessorInterface>
{
public:
SimplePointLightDelegate(EntityId entityId, bool isVisible);
// LightDelegateBase overrides...
float CalculateAttenuationRadius(float lightThreshold) const override;
void DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const override;
float GetSurfaceArea() const override;
float GetEffectiveSolidAngle() const override { return PhotometricValue::OmnidirectionalSteradians; }
private:
virtual void HandleShapeChanged();
};
} // namespace Render
} // namespace AZ
@@ -0,0 +1,58 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <CoreLights/SimpleSpotLightDelegate.h>
#include <Atom/RPI.Public/Scene.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h>
namespace AZ::Render
{
SimpleSpotLightDelegate::SimpleSpotLightDelegate(EntityId entityId, bool isVisible)
: LightDelegateBase<SimpleSpotLightFeatureProcessorInterface>(entityId, isVisible)
{
InitBase(entityId);
}
void SimpleSpotLightDelegate::HandleShapeChanged()
{
GetFeatureProcessor()->SetPosition(GetLightHandle(), GetTransform().GetTranslation());
GetFeatureProcessor()->SetDirection(GetLightHandle(), GetTransform().GetBasisZ());
}
float SimpleSpotLightDelegate::CalculateAttenuationRadius(float lightThreshold) const
{
// Calculate the radius at which the irradiance will be equal to cutoffIntensity.
float intensity = GetPhotometricValue().GetCombinedIntensity(PhotometricUnit::Lumen);
return sqrt(intensity / lightThreshold);
}
float SimpleSpotLightDelegate::GetSurfaceArea() const
{
return 0.0f;
}
void SimpleSpotLightDelegate::SetShutterAngles(float innerAngleDegrees, float outerAngleDegrees)
{
GetFeatureProcessor()->SetConeAngles(GetLightHandle(), DegToRad(innerAngleDegrees), DegToRad(outerAngleDegrees));
}
void SimpleSpotLightDelegate::DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const
{
if (isSelected)
{
debugDisplay.SetColor(color);
// Draw a cone for the cone angle and attenuation radius
debugDisplay.DrawCone(transform.GetTranslation(), transform.GetBasisX(), CalculateAttenuationRadius(AreaLightComponentConfig::CutoffIntensity), false);
}
}
} // namespace AZ::Render
@@ -0,0 +1,44 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <CoreLights/LightDelegateBase.h>
#include <AzCore/Component/TransformBus.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <Atom/Feature/CoreLights/SimpleSpotLightFeatureProcessorInterface.h>
namespace AZ
{
namespace Render
{
class SimpleSpotLightDelegate final
: public LightDelegateBase<SimpleSpotLightFeatureProcessorInterface>
{
public:
SimpleSpotLightDelegate(EntityId entityId, bool isVisible);
// LightDelegateBase overrides...
float CalculateAttenuationRadius(float lightThreshold) const override;
void DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const override;
float GetSurfaceArea() const override;
float GetEffectiveSolidAngle() const override { return PhotometricValue::DirectionalEffectiveSteradians; }
void SetShutterAngles(float innerAngleDegrees, float outerAngleDegrees) override;
private:
virtual void HandleShapeChanged();
};
} // namespace Render
} // namespace AZ
@@ -1,44 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <CoreLights/SpotLightComponent.h>
namespace AZ
{
namespace Render
{
SpotLightComponent::SpotLightComponent(const SpotLightComponentConfig& config)
: BaseClass(config)
{
}
void SpotLightComponent::Reflect(AZ::ReflectContext* context)
{
BaseClass::Reflect(context);
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<SpotLightComponent, BaseClass>();
}
if (auto behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<SpotLightComponent>()->RequestBus("SpotLightRequestBus");
behaviorContext->ConstantProperty("SpotLightComponentTypeId", BehaviorConstant(Uuid(SpotLightComponentTypeId)))
->Attribute(AZ::Script::Attributes::Module, "render")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common);
}
}
} // namespace Render
} // namespace AZ
@@ -1,37 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzFramework/Components/ComponentAdapter.h>
#include <CoreLights/SpotLightComponentController.h>
namespace AZ
{
namespace Render
{
class SpotLightComponent final
: public AzFramework::Components::ComponentAdapter<SpotLightComponentController, SpotLightComponentConfig>
{
public:
using BaseClass = AzFramework::Components::ComponentAdapter<SpotLightComponentController, SpotLightComponentConfig>;
AZ_COMPONENT(AZ::Render::SpotLightComponent, SpotLightComponentTypeId, BaseClass);
SpotLightComponent() = default;
SpotLightComponent(const SpotLightComponentConfig& config);
static void Reflect(AZ::ReflectContext* context);
};
} // namespace Render
} // namespace AZ
@@ -1,83 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AtomLyIntegration/CommonFeatures/CoreLights/SpotLightComponentConfig.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
namespace Render
{
void SpotLightComponentConfig::Reflect(ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<SpotLightComponentConfig, ComponentConfig>()
->Version(4)
->Field("Color", &SpotLightComponentConfig::m_color)
->Field("Intensity", &SpotLightComponentConfig::m_intensity)
->Field("IntensityMode", &SpotLightComponentConfig::m_intensityMode)
->Field("Bulb Radius", &SpotLightComponentConfig::m_bulbRadius)
->Field("Inner Cone Angle", &SpotLightComponentConfig::m_innerConeDegrees)
->Field("Outer Cone Angle", &SpotLightComponentConfig::m_outerConeDegrees)
->Field("Attenuation Radius", &SpotLightComponentConfig::m_attenuationRadius)
->Field("Attenuation Radius Mode", &SpotLightComponentConfig::m_attenuationRadiusMode)
->Field("Penumbra Bias", &SpotLightComponentConfig::m_penumbraBias)
->Field("Enabled Shadow", &SpotLightComponentConfig::m_enabledShadow)
->Field("Shadowmap Size", &SpotLightComponentConfig::m_shadowmapSize)
->Field("Shadow Filter Method", &SpotLightComponentConfig::m_shadowFilterMethod)
->Field("Softening Boundary Width", &SpotLightComponentConfig::m_boundaryWidthInDegrees)
->Field("Prediction Sample Count", &SpotLightComponentConfig::m_predictionSampleCount)
->Field("Filtering Sample Count", &SpotLightComponentConfig::m_filteringSampleCount)
->Field("Pcf Method", &SpotLightComponentConfig::m_pcfMethod);
}
}
bool SpotLightComponentConfig::IsAttenuationRadiusModeAutomatic() const
{
return m_attenuationRadiusMode == LightAttenuationRadiusMode::Automatic;
}
const char* SpotLightComponentConfig::GetIntensitySuffix() const
{
return PhotometricValue::GetTypeSuffix(m_intensityMode);
}
float SpotLightComponentConfig::GetConeDegrees() const
{
return (m_enabledShadow && m_shadowmapSize != ShadowmapSize::None) ? MaxSpotLightConeAngleDegreeWithShadow : MaxSpotLightConeAngleDegree;
}
bool SpotLightComponentConfig::IsShadowFilteringDisabled() const
{
return (m_shadowFilterMethod == ShadowFilterMethod::None);
}
bool SpotLightComponentConfig::IsShadowPcfDisabled() const
{
return !(m_shadowFilterMethod == ShadowFilterMethod::Pcf ||
m_shadowFilterMethod == ShadowFilterMethod::EsmPcf);
}
bool SpotLightComponentConfig::IsPcfBoundarySearchDisabled() const
{
if (IsShadowPcfDisabled())
{
return true;
}
return m_pcfMethod != PcfMethod::BoundarySearch;
}
} // namespace Render
} // namespace AZ
@@ -1,434 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <CoreLights/SpotLightComponentController.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <Atom/RPI.Public/Scene.h>
namespace AZ
{
namespace Render
{
void SpotLightComponentController::Reflect(ReflectContext* context)
{
SpotLightComponentConfig::Reflect(context);
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<SpotLightComponentController>()
->Version(3)
->Field("Configuration", &SpotLightComponentController::m_configuration);
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext
->Enum<static_cast<uint32_t>(ShadowFilterMethod::None)>("ShadowFilterMethod_None")
->Enum<static_cast<uint32_t>(ShadowFilterMethod::Pcf)>("ShadowFilterMethod_PCF")
->Enum<static_cast<uint32_t>(ShadowFilterMethod::Esm)>("ShadowFilterMethod_ESM")
->Enum<static_cast<uint32_t>(ShadowFilterMethod::EsmPcf)>("ShadowFilterMethod_ESM_PCF")
->Enum<static_cast<uint32_t>(ShadowmapSize::None)>("ShadowmapSize_None")
->Enum<static_cast<uint32_t>(ShadowmapSize::Size256)>("ShadowmapSize_256")
->Enum<static_cast<uint32_t>(ShadowmapSize::Size512)>("ShadowmapSize_512")
->Enum<static_cast<uint32_t>(ShadowmapSize::Size1024)>("ShadowmapSize_1024")
->Enum<static_cast<uint32_t>(ShadowmapSize::Size2048)>("ShadowmapSize_2045")
;
behaviorContext->EBus<SpotLightRequestBus>("SpotLightRequestBus")
->Attribute(AZ::Script::Attributes::Module, "render")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Event("GetAttenuationRadius", &SpotLightRequestBus::Events::GetAttenuationRadius)
->Event("SetAttenuationRadius", &SpotLightRequestBus::Events::SetAttenuationRadius)
->Event("GetAttenuationRadiusIsAutomatic", &SpotLightRequestBus::Events::GetAttenuationRadiusIsAutomatic)
->Event("SetAttenuationRadiusIsAutomatic", &SpotLightRequestBus::Events::SetAttenuationRadiusIsAutomatic)
->Event("GetColor", &SpotLightRequestBus::Events::GetColor)
->Event("SetColor", &SpotLightRequestBus::Events::SetColor)
->Event("GetIntensity", &SpotLightRequestBus::Events::GetIntensity)
->Event("SetIntensity", &SpotLightRequestBus::Events::SetIntensity)
->Event("GetBulbRadius", &SpotLightRequestBus::Events::GetBulbRadius)
->Event("SetBulbRadius", &SpotLightRequestBus::Events::SetBulbRadius)
->Event("GetInnerConeAngleInDegrees", &SpotLightRequestBus::Events::GetInnerConeAngleInDegrees)
->Event("SetInnerConeAngleInDegrees", &SpotLightRequestBus::Events::SetInnerConeAngleInDegrees)
->Event("GetOuterConeAngleInDegrees", &SpotLightRequestBus::Events::GetOuterConeAngleInDegrees)
->Event("SetOuterConeAngleInDegrees", &SpotLightRequestBus::Events::SetOuterConeAngleInDegrees)
->Event("GetPenumbraBias", &SpotLightRequestBus::Events::GetPenumbraBias)
->Event("SetPenumbraBias", &SpotLightRequestBus::Events::SetPenumbraBias)
->Event("GetEnableShadow", &SpotLightRequestBus::Events::GetEnableShadow)
->Event("SetEnableShadow", &SpotLightRequestBus::Events::SetEnableShadow)
->Event("GetShadowmapSize", &SpotLightRequestBus::Events::GetShadowmapSize)
->Event("SetShadowmapSize", &SpotLightRequestBus::Events::SetShadowmapSize)
->Event("GetShadowFilterMethod", &SpotLightRequestBus::Events::GetShadowFilterMethod)
->Event("SetShadowFilterMethod", &SpotLightRequestBus::Events::SetShadowFilterMethod)
->Event("GetSofteningBoundaryWidthAngle", &SpotLightRequestBus::Events::GetSofteningBoundaryWidthAngle)
->Event("SetSofteningBoundaryWidthAngle", &SpotLightRequestBus::Events::SetSofteningBoundaryWidthAngle)
->Event("GetPredictionSampleCount", &SpotLightRequestBus::Events::GetPredictionSampleCount)
->Event("SetPredictionSampleCount", &SpotLightRequestBus::Events::SetPredictionSampleCount)
->Event("GetFilteringSampleCount", &SpotLightRequestBus::Events::GetFilteringSampleCount)
->Event("SetFilteringSampleCount", &SpotLightRequestBus::Events::SetFilteringSampleCount)
->Event("GetPcfMethod", &SpotLightRequestBus::Events::GetPcfMethod)
->Event("SetPcfMethod", &SpotLightRequestBus::Events::SetPcfMethod)
->VirtualProperty("AttenuationRadius", "GetAttenuationRadius", "SetAttenuationRadius")
->VirtualProperty("AttenuationRadiusIsAutomatic", "GetAttenuationRadiusIsAutomatic", "SetAttenuationRadiusIsAutomatic")
->VirtualProperty("Color", "GetColor", "SetColor")
->VirtualProperty("Intensity", "GetIntensity", "SetIntensity")
->VirtualProperty("InnerConeAngleInDegrees", "GetInnerConeAngleInDegrees", "SetInnerConeAngleInDegrees")
->VirtualProperty("OuterConeAngleInDegrees", "GetOuterConeAngleInDegrees", "SetOuterConeAngleInDegrees")
->VirtualProperty("PenumbraBias", "GetPenumbraBias", "SetPenumbraBias")
->VirtualProperty("EnableShadow", "GetEnableShadow", "SetEnableShadow")
->VirtualProperty("ShadowmapSize", "GetShadowmapSize", "SetShadowmapSize")
->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod")
->VirtualProperty("SofteningBoundaryWidthAngle", "GetSofteningBoundaryWidthAngle", "SetSofteningBoundaryWidthAngle")
->VirtualProperty("PredictionSampleCount", "GetPredictionSampleCount", "SetPredictionSampleCount")
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
->VirtualProperty("PcfMethod", "GetPcfMethod", "SetPcfMethod");
}
}
void SpotLightComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("SpotLightService", 0x3ae7d498));
}
void SpotLightComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("SpotLightService", 0x3ae7d498));
}
SpotLightComponentController::SpotLightComponentController(const SpotLightComponentConfig& config)
: m_configuration(config)
{
}
void SpotLightComponentController::Activate(EntityId entityId)
{
m_entityId = entityId;
m_featureProcessor = RPI::Scene::GetFeatureProcessorForEntity<SpotLightFeatureProcessorInterface>(entityId);
AZ_Error("SpotLightComponentController", m_featureProcessor, "Could not find a SpotLightFeatureProcessorInterface on the scene.");
if (m_featureProcessor)
{
m_lightHandle = m_featureProcessor->AcquireLight();
TransformNotificationBus::Handler::BusConnect(m_entityId);
SpotLightRequestBus::Handler::BusConnect(m_entityId);
ConfigurationChanged();
}
}
void SpotLightComponentController::Deactivate()
{
SpotLightRequestBus::Handler::BusDisconnect(m_entityId);
TransformNotificationBus::Handler::BusDisconnect(m_entityId);
if (m_featureProcessor)
{
m_featureProcessor->ReleaseLight(m_lightHandle);
}
m_entityId.SetInvalid();
}
void SpotLightComponentController::SetConfiguration(const SpotLightComponentConfig& config)
{
m_configuration = config;
ConfigurationChanged();
}
const SpotLightComponentConfig& SpotLightComponentController::GetConfiguration() const
{
return m_configuration;
}
void SpotLightComponentController::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world)
{
m_featureProcessor->SetPosition(m_lightHandle, world.GetTranslation());
const Vector3 forward = Vector3::CreateAxisY();
const Vector3 lightDirection = world.TransformVector(forward);
m_featureProcessor->SetDirection(m_lightHandle, lightDirection);
}
void SpotLightComponentController::ConfigurationChanged()
{
m_photometricValue = PhotometricValue(m_configuration.m_intensity, m_configuration.m_color, m_configuration.m_intensityMode);
m_photometricValue.SetEffectiveSolidAngle(PhotometricValue::DirectionalEffectiveSteradians);
AZ::Transform worldTM;
AZ::TransformBus::EventResult(worldTM, m_entityId, &AZ::TransformBus::Events::GetWorldTM);
OnTransformChanged({}, worldTM);
ColorIntensityChanged();
AttenuationRadiusChanged();
ConeAnglesChanged();
PenumbraBiasChanged();
SetBulbRadius(m_configuration.m_bulbRadius);
SetEnableShadow(m_configuration.m_enabledShadow);
SetShadowmapSize(m_configuration.m_shadowmapSize);
SetShadowFilterMethod(m_configuration.m_shadowFilterMethod);
SetSofteningBoundaryWidthAngle(m_configuration.m_boundaryWidthInDegrees);
SetPredictionSampleCount(m_configuration.m_predictionSampleCount);
SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
SetPcfMethod(m_configuration.m_pcfMethod);
}
void SpotLightComponentController::ColorIntensityChanged()
{
SpotLightNotificationBus::Event(m_entityId, &SpotLightNotifications::OnIntensityChanged, m_configuration.m_intensity);
SpotLightNotificationBus::Event(m_entityId, &SpotLightNotifications::OnColorChanged, m_configuration.m_color);
m_photometricValue.SetChroma(m_configuration.m_color);
m_photometricValue.SetIntensity(m_configuration.m_intensity);
m_featureProcessor->SetRgbIntensity(m_lightHandle, m_photometricValue.GetCombinedRgb<PhotometricUnit::Candela>());
}
void SpotLightComponentController::ConeAnglesChanged()
{
if (m_configuration.m_innerConeDegrees > m_configuration.m_outerConeDegrees)
{
m_configuration.m_innerConeDegrees = m_configuration.m_outerConeDegrees;
}
SpotLightNotificationBus::Event(m_entityId, &SpotLightNotifications::OnConeAnglesChanged, m_configuration.m_innerConeDegrees, m_configuration.m_outerConeDegrees);
m_featureProcessor->SetConeAngles(m_lightHandle, m_configuration.m_innerConeDegrees, m_configuration.m_outerConeDegrees);
}
void SpotLightComponentController::AttenuationRadiusChanged()
{
if (m_configuration.m_attenuationRadiusMode == LightAttenuationRadiusMode::Automatic)
{
AutoCalculateAttenuationRadius();
}
SpotLightNotificationBus::Event(m_entityId, &SpotLightNotifications::OnAttenuationRadiusChanged, m_configuration.m_attenuationRadius);
m_featureProcessor->SetAttenuationRadius(m_lightHandle, m_configuration.m_attenuationRadius);
}
void SpotLightComponentController::PenumbraBiasChanged()
{
SpotLightNotificationBus::Event(m_entityId, &SpotLightNotifications::OnPenumbraBiasChanged, m_configuration.m_penumbraBias);
m_featureProcessor->SetPenumbraBias(m_lightHandle, m_configuration.m_penumbraBias);
}
void SpotLightComponentController::AutoCalculateAttenuationRadius()
{
// Get combined intensity luma from m_photometricValue, then calculate the radius at which the irradiance will be equal to cutoffIntensity.
static const float CutoffIntensity = 0.1f; // Make this configurable later.
float intensity = m_photometricValue.GetCombinedIntensity(PhotometricUnit::Lumen);
m_configuration.m_attenuationRadius = sqrt(intensity / CutoffIntensity);
}
const Color& SpotLightComponentController::GetColor() const
{
return m_configuration.m_color;
}
void SpotLightComponentController::SetColor(const Color& color)
{
m_configuration.m_color = color;
ColorIntensityChanged();
}
float SpotLightComponentController::GetIntensity() const
{
return m_configuration.m_intensity;
}
void SpotLightComponentController::SetIntensity(float intensity)
{
m_configuration.m_intensity = intensity;
ColorIntensityChanged();
}
float SpotLightComponentController::GetBulbRadius() const
{
return m_configuration.m_bulbRadius;
}
void SpotLightComponentController::SetBulbRadius(float bulbRadius)
{
m_configuration.m_bulbRadius = bulbRadius;
m_featureProcessor->SetBulbRadius(m_lightHandle, bulbRadius);
}
float SpotLightComponentController::GetInnerConeAngleInDegrees() const
{
return m_configuration.m_innerConeDegrees;
}
void SpotLightComponentController::SetInnerConeAngleInDegrees(float degrees)
{
m_configuration.m_innerConeDegrees = degrees;
ConeAnglesChanged();
}
float SpotLightComponentController::GetOuterConeAngleInDegrees() const
{
return m_configuration.m_outerConeDegrees;
}
void SpotLightComponentController::SetOuterConeAngleInDegrees(float degrees)
{
m_configuration.m_outerConeDegrees = degrees;
ConeAnglesChanged();
}
float SpotLightComponentController::GetPenumbraBias() const
{
return m_configuration.m_penumbraBias;
}
void SpotLightComponentController::SetPenumbraBias(float penumbraBias)
{
m_configuration.m_penumbraBias = penumbraBias;
PenumbraBiasChanged();
}
float SpotLightComponentController::GetAttenuationRadius() const
{
return m_configuration.m_attenuationRadius;
}
void SpotLightComponentController::SetAttenuationRadius(float radius)
{
m_configuration.m_attenuationRadius = radius;
AttenuationRadiusChanged();
}
LightAttenuationRadiusMode SpotLightComponentController::GetAttenuationRadiusMode() const
{
return m_configuration.m_attenuationRadiusMode;
}
void SpotLightComponentController::SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode)
{
m_configuration.m_attenuationRadiusMode = attenuationRadiusMode;
if (attenuationRadiusMode == LightAttenuationRadiusMode::Automatic)
{
AutoCalculateAttenuationRadius();
}
}
bool SpotLightComponentController::GetEnableShadow() const
{
return m_configuration.m_enabledShadow;
}
void SpotLightComponentController::SetEnableShadow(bool enabled)
{
m_configuration.m_enabledShadow = enabled;
m_featureProcessor->SetShadowmapSize(
m_lightHandle,
m_configuration.m_enabledShadow ?
m_configuration.m_shadowmapSize :
ShadowmapSize::None);
}
ShadowmapSize SpotLightComponentController::GetShadowmapSize() const
{
return m_configuration.m_shadowmapSize;
}
void SpotLightComponentController::SetShadowmapSize(ShadowmapSize size)
{
// The minimum valid ShadowmapSize is 256 and maximum one is 2048.
const uint32_t sizeInt = aznumeric_cast<uint32_t>(size);
if (sizeInt < aznumeric_cast<uint32_t>(ShadowmapSize::Size512))
{
size = ShadowmapSize::Size256;
}
else if (sizeInt < aznumeric_cast<uint32_t>(ShadowmapSize::Size1024))
{
size = ShadowmapSize::Size512;
}
else if (sizeInt < aznumeric_cast<uint32_t>(ShadowmapSize::Size2048))
{
size = ShadowmapSize::Size1024;
}
else
{
size = ShadowmapSize::Size2048;
}
m_configuration.m_shadowmapSize = size;
m_featureProcessor->SetShadowmapSize(
m_lightHandle,
m_configuration.m_enabledShadow ?
m_configuration.m_shadowmapSize :
ShadowmapSize::None);
}
ShadowFilterMethod SpotLightComponentController::GetShadowFilterMethod() const
{
return m_configuration.m_shadowFilterMethod;
}
void SpotLightComponentController::SetShadowFilterMethod(ShadowFilterMethod method)
{
m_configuration.m_shadowFilterMethod = method;
m_featureProcessor->SetShadowFilterMethod(m_lightHandle, method);
}
float SpotLightComponentController::GetSofteningBoundaryWidthAngle() const
{
return m_configuration.m_boundaryWidthInDegrees;
}
void SpotLightComponentController::SetSofteningBoundaryWidthAngle(float width)
{
m_configuration.m_boundaryWidthInDegrees = width;
m_featureProcessor->SetShadowBoundaryWidthAngle(m_lightHandle, width);
}
uint32_t SpotLightComponentController::GetPredictionSampleCount() const
{
return m_configuration.m_predictionSampleCount;
}
void SpotLightComponentController::SetPredictionSampleCount(uint32_t count)
{
m_configuration.m_predictionSampleCount = count;
m_featureProcessor->SetPredictionSampleCount(m_lightHandle, count);
}
uint32_t SpotLightComponentController::GetFilteringSampleCount() const
{
return m_configuration.m_filteringSampleCount;
}
void SpotLightComponentController::SetFilteringSampleCount(uint32_t count)
{
m_configuration.m_filteringSampleCount = count;
m_featureProcessor->SetFilteringSampleCount(m_lightHandle, count);
}
PcfMethod SpotLightComponentController::GetPcfMethod() const
{
return m_configuration.m_pcfMethod;
}
void SpotLightComponentController::SetPcfMethod(PcfMethod method)
{
m_configuration.m_pcfMethod = method;
m_featureProcessor->SetPcfMethod(m_lightHandle, method);
}
} // namespace Render
} // namespace AZ
@@ -1,102 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AtomLyIntegration/CommonFeatures/CoreLights/SpotLightBus.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/SpotLightComponentConfig.h>
#include <Atom/Feature/CoreLights/SpotLightFeatureProcessorInterface.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Math/Color.h>
namespace AZ
{
namespace Render
{
class SpotLightComponentController final
: public TransformNotificationBus::Handler
, public SpotLightRequestBus::Handler
{
public:
friend class EditorSpotLightComponent;
AZ_TYPE_INFO(AZ::Render::SpotLightComponentController, "{2B37DC8C-BE9E-481C-A53B-FCBFFAB425E0}");
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
SpotLightComponentController() = default;
SpotLightComponentController(const SpotLightComponentConfig& config);
void Activate(EntityId entityId);
void Deactivate();
void SetConfiguration(const SpotLightComponentConfig& config);
const SpotLightComponentConfig& GetConfiguration() const;
private:
AZ_DISABLE_COPY(SpotLightComponentController);
// TransformNotificationBus::Handler overrides ...
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
// SpotLightRequestBus::Handler overrides ...
const Color& GetColor() const override;
void SetColor(const Color& color) override;
float GetIntensity() const override;
void SetIntensity(float intensity) override;
float GetBulbRadius() const override;
void SetBulbRadius(float bulbRadius) override;
float GetInnerConeAngleInDegrees() const override;
void SetInnerConeAngleInDegrees(float degrees) override;
float GetOuterConeAngleInDegrees() const override;
void SetOuterConeAngleInDegrees(float degrees) override;
float GetPenumbraBias() const override;
void SetPenumbraBias(float penumbraBias) override;
float GetAttenuationRadius() const override;
void SetAttenuationRadius(float radius) override;
LightAttenuationRadiusMode GetAttenuationRadiusMode() const override;
void SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode) override;
bool GetEnableShadow() const override;
void SetEnableShadow(bool enabled) override;
ShadowmapSize GetShadowmapSize() const override;
void SetShadowmapSize(ShadowmapSize size) override;
ShadowFilterMethod GetShadowFilterMethod() const override;
void SetShadowFilterMethod(ShadowFilterMethod method) override;
float GetSofteningBoundaryWidthAngle() const override;
void SetSofteningBoundaryWidthAngle(float width) override;
uint32_t GetPredictionSampleCount() const override;
void SetPredictionSampleCount(uint32_t count) override;
uint32_t GetFilteringSampleCount() const override;
void SetFilteringSampleCount(uint32_t count) override;
PcfMethod GetPcfMethod() const override;
void SetPcfMethod(PcfMethod method) override;
void ConfigurationChanged();
void ColorIntensityChanged();
void ConeAnglesChanged();
void AttenuationRadiusChanged();
void PenumbraBiasChanged();
void AutoCalculateAttenuationRadius();
SpotLightComponentConfig m_configuration;
PhotometricValue m_photometricValue;
SpotLightFeatureProcessorInterface* m_featureProcessor = nullptr;
SpotLightFeatureProcessorInterface::LightHandle m_lightHandle;
EntityId m_entityId;
};
} // namespace Render
} // AZ namespace
@@ -175,19 +175,19 @@ namespace AZ
tableWidget->setCellWidget(row, OverwriteFileColumn, overwriteCheckBoxContainer);
// Whenever the selection is updated, automatically apply the change to the export item
QObject::connect(materialSlotCheckBox, &QCheckBox::stateChanged, materialSlotCheckBox, [&]([[maybe_unused]] int state) {
QObject::connect(materialSlotCheckBox, &QCheckBox::stateChanged, materialSlotCheckBox, [&exportItem, materialFileWidget, materialSlotCheckBox, overwriteCheckBox]([[maybe_unused]] int state) {
exportItem.m_enabled = materialSlotCheckBox->isChecked();
materialFileWidget->setEnabled(exportItem.m_enabled);
overwriteCheckBox->setEnabled(exportItem.m_enabled && exportItem.m_exists);
});
// Whenever the overwrite check box is updated, automatically apply the change to the export item
QObject::connect(overwriteCheckBox, &QCheckBox::stateChanged, overwriteCheckBox, [&]([[maybe_unused]] int state) {
QObject::connect(overwriteCheckBox, &QCheckBox::stateChanged, overwriteCheckBox, [&exportItem, overwriteCheckBox]([[maybe_unused]] int state) {
exportItem.m_overwrite = overwriteCheckBox->isChecked();
});
// Whenever the browse button is clicked, open a save file dialog in the same location as the current export file setting
QObject::connect(materialFileWidget, &AzQtComponents::BrowseEdit::attachedButtonTriggered, materialFileWidget, [&]() {
QObject::connect(materialFileWidget, &AzQtComponents::BrowseEdit::attachedButtonTriggered, materialFileWidget, [&dialog, &exportItem, materialFileWidget, overwriteCheckBox]() {
QFileInfo fileInfo = QFileDialog::getSaveFileName(&dialog,
QString("Select Material Filename"),
exportItem.m_exportPath.c_str(),
@@ -201,7 +201,7 @@ namespace AZ
exportItem.m_exportPath = fileInfo.absoluteFilePath().toUtf8().constData();
exportItem.m_exists = fileInfo.exists();
exportItem.m_overwrite = fileInfo.exists();
\
// Update the controls to display the new state
materialFileWidget->setText(fileInfo.fileName());
overwriteCheckBox->setChecked(exportItem.m_overwrite);
@@ -98,10 +98,7 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::DefaultAsset, &EditorMaterialComponentSlot::GetDefaultAssetId)
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &EditorMaterialComponentSlot::GetLabel)
->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, true)
->Attribute("ShowThumbnail", true)
->Attribute("EditButton", ":/Cards/img/UI20/Cards/menu_ico.svg")
->Attribute("EditDescription", "")
->Attribute("EditCallback", &EditorMaterialComponentSlot::OpenPopupMenu)
->Attribute("ThumbnailWithDropDown", &EditorMaterialComponentSlot::OpenPopupMenu)
;
}
}
@@ -109,7 +106,6 @@ namespace AZ
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<EditorMaterialComponentSlot>("EditorMaterialComponentSlot")
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview)
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
->Attribute(AZ::Script::Attributes::Category, "Editor")
->Attribute(AZ::Script::Attributes::Module, "editor")
@@ -75,7 +75,6 @@ namespace AZ
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<MaterialComponentConfig>("MaterialComponentConfig")
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview)
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "render")
->Attribute(AZ::Script::Attributes::Module, "render")
@@ -33,7 +33,6 @@ namespace AZ
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<MaterialComponentRequestBus>("MaterialComponentRequestBus")
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview)
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "render")
->Attribute(AZ::Script::Attributes::Module, "render")
@@ -140,7 +140,9 @@ namespace AZ
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
return m_controller.GetModel()->RayIntersection(transform, nonUniformScale, src, dir, distance);
AZ::Vector3 ignoreNormal;
return m_controller.GetModel()->RayIntersection(transform, nonUniformScale, src, dir, distance, ignoreNormal);
}
bool EditorMeshComponent::SupportsEditorRayIntersect()
@@ -200,7 +202,6 @@ namespace AZ
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay,
AzToolsFramework::Refresh_EntireTree);
}
AZ::u32 EditorMeshComponent::OnConfigurationChanged()
{
// temp variable is needed to hold reference to m_modelAsset while it's being loaded.
@@ -87,6 +87,12 @@ namespace AZ
return values;
}
MeshComponentController::~MeshComponentController()
{
// Release memory, disconnect from buses in the right order and broadcast events so that other components are aware.
Deactivate();
}
void MeshComponentController::Reflect(ReflectContext* context)
{
MeshComponentConfig::Reflect(context);
@@ -130,11 +136,13 @@ namespace AZ
void MeshComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("MaterialReceiverService", 0x0d1a6a74));
provided.push_back(AZ_CRC("MeshService", 0x71d8a455));
}
void MeshComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("MaterialReceiverService", 0x0d1a6a74));
incompatible.push_back(AZ_CRC("MeshService", 0x71d8a455));
}
// [GFX TODO] [ATOM-13339] Remove the ModelAsset id fix up function in MeshComponentController
@@ -157,7 +165,7 @@ namespace AZ
}
else
{
AZ_Assert(false, "Failed to find asset id for [%s] ", modelAsset.GetHint().c_str());
AZ_Error("MeshComponentController", false, "Failed to find asset id for [%s] ", modelAsset.GetHint().c_str());
}
}
}
@@ -197,14 +205,15 @@ namespace AZ
void MeshComponentController::Deactivate()
{
// Buses must be disconnected after unregistering the model, otherwise they can't deliver the events during the process.
UnregisterModel();
AzFramework::BoundsRequestBus::Handler::BusDisconnect();
MeshComponentRequestBus::Handler::BusDisconnect();
TransformNotificationBus::Handler::BusDisconnect();
MaterialReceiverRequestBus::Handler::BusDisconnect();
MaterialComponentNotificationBus::Handler::BusDisconnect();
UnregisterModel();
m_meshFeatureProcessor = nullptr;
m_transformInterface = nullptr;
m_entityId = AZ::EntityId(AZ::EntityId::InvalidEntityId);
@@ -299,8 +308,9 @@ namespace AZ
void MeshComponentController::UnregisterModel()
{
if (m_meshFeatureProcessor)
if (m_meshFeatureProcessor && m_meshHandle.IsValid())
{
MeshComponentNotificationBus::Event(m_entityId, &MeshComponentNotificationBus::Events::OnModelPreDestroy);
m_meshFeatureProcessor->ReleaseMesh(m_meshHandle);
}
}
@@ -338,7 +348,7 @@ namespace AZ
const Data::Asset<RPI::ModelAsset>& MeshComponentController::GetModelAsset() const
{
return m_configuration.m_modelAsset;
return GetModel() ? GetModel()->GetModelAsset() : m_configuration.m_modelAsset;
}
Data::AssetId MeshComponentController::GetModelAssetId() const
@@ -67,6 +67,8 @@ namespace AZ
AZ_CLASS_ALLOCATOR(MeshComponentController, AZ::SystemAllocator, 0);
AZ_RTTI(AZ::Render::MeshComponentController, "{D0F35FAC-4194-4C89-9487-D000DDB8B272}");
~MeshComponentController();
static void Reflect(AZ::ReflectContext* context);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
@@ -17,8 +17,6 @@
#include <CommonFeaturesSystemComponent.h>
#include <CoreLights/AreaLightComponent.h>
#include <CoreLights/DirectionalLightComponent.h>
#include <CoreLights/PointLightComponent.h>
#include <CoreLights/SpotLightComponent.h>
#include <Decals/DecalComponent.h>
#include <DiffuseProbeGrid/DiffuseProbeGridComponent.h>
#include <Grid/GridComponent.h>
@@ -40,14 +38,13 @@
#include <SkyBox/HDRiSkyboxComponent.h>
#include <SkyBox/PhysicalSkyComponent.h>
#include <Scripting/EntityReferenceComponent.h>
#include <SurfaceData/SurfaceDataMeshComponent.h>
#ifdef ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
#include <EditorCommonFeaturesSystemComponent.h>
#include <PostProcess/EditorPostFxSystemComponent.h>
#include <CoreLights/EditorAreaLightComponent.h>
#include <CoreLights/EditorDirectionalLightComponent.h>
#include <CoreLights/EditorPointLightComponent.h>
#include <CoreLights/EditorSpotLightComponent.h>
#include <Decals/EditorDecalComponent.h>
#include <DiffuseProbeGrid/EditorDiffuseProbeGridComponent.h>
#include <Grid/EditorGridComponent.h>
@@ -71,6 +68,7 @@
#include <SkyBox/EditorHDRiSkyboxComponent.h>
#include <SkyBox/EditorPhysicalSkyComponent.h>
#include <Scripting/EditorEntityReferenceComponent.h>
#include <SurfaceData/EditorSurfaceDataMeshComponent.h>
#endif
namespace AZ
@@ -104,16 +102,15 @@ namespace AZ
MaterialComponent::CreateDescriptor(),
MeshComponent::CreateDescriptor(),
PhysicalSkyComponent::CreateDescriptor(),
PointLightComponent::CreateDescriptor(),
PostFxLayerComponent::CreateDescriptor(),
ReflectionProbeComponent::CreateDescriptor(),
SpotLightComponent::CreateDescriptor(),
RadiusWeightModifierComponent::CreateDescriptor(),
ShapeWeightModifierComponent::CreateDescriptor(),
EntityReferenceComponent::CreateDescriptor(),
GradientWeightModifierComponent::CreateDescriptor(),
DiffuseProbeGridComponent::CreateDescriptor(),
DeferredFogComponent::CreateDescriptor(),
SurfaceData::SurfaceDataMeshComponent::CreateDescriptor(),
#ifdef ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
EditorAreaLightComponent::CreateDescriptor(),
@@ -135,16 +132,15 @@ namespace AZ
EditorMeshSystemComponent::CreateDescriptor(),
EditorMeshComponent::CreateDescriptor(),
EditorPhysicalSkyComponent::CreateDescriptor(),
EditorPointLightComponent::CreateDescriptor(),
EditorPostFxLayerComponent::CreateDescriptor(),
EditorReflectionProbeComponent::CreateDescriptor(),
EditorSpotLightComponent::CreateDescriptor(),
EditorRadiusWeightModifierComponent::CreateDescriptor(),
EditorShapeWeightModifierComponent::CreateDescriptor(),
EditorEntityReferenceComponent::CreateDescriptor(),
EditorGradientWeightModifierComponent::CreateDescriptor(),
EditorDiffuseProbeGridComponent::CreateDescriptor(),
EditorDeferredFogComponent::CreateDescriptor(),
SurfaceData::EditorSurfaceDataMeshComponent::CreateDescriptor(),
#endif
});
}
@@ -16,7 +16,7 @@
#include <AzFramework/Components/ComponentAdapter.h>
#include <AtomLyIntegration/CommonFeatures/PostProcess/GradientWeightModifier/GradientWeightModifierComponentConstants.h>
#include <AtomLyIntegration/CommonFeatures/PostProcess/GradientWeightModifier/GradientWeightModifierComponentConfig.h>
#include <PostProcess/GradientWeightModifier/GradientWeightModifierComponentController.h>
#include <PostProcess/GradientWeightModifier/GradientWeightModifierController.h>
namespace AZ
{
@@ -10,7 +10,7 @@
*
*/
#include <PostProcess/GradientWeightModifier/GradientWeightModifierComponentController.h>
#include <PostProcess/GradientWeightModifier/GradientWeightModifierController.h>
namespace AZ
{
@@ -0,0 +1,25 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "EditorSurfaceDataMeshComponent.h"
#include <AzCore/Serialization/Utils.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <LmbrCentral/Dependency/DependencyNotificationBus.h>
namespace SurfaceData
{
void EditorSurfaceDataMeshComponent::Reflect(AZ::ReflectContext* context)
{
BaseClassType::ReflectSubClass<EditorSurfaceDataMeshComponent, BaseClassType>(context, 2, &LmbrCentral::EditorWrappedComponentBaseVersionConverter<typename BaseClassType::WrappedComponentType, typename BaseClassType::WrappedConfigType,2>);
}
}
@@ -0,0 +1,38 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Module/Module.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
#include <SurfaceData/SurfaceDataMeshComponent.h>
#include <LmbrCentral/Component/EditorWrappedComponentBase.h>
namespace SurfaceData
{
class EditorSurfaceDataMeshComponent
: public LmbrCentral::EditorWrappedComponentBase<SurfaceDataMeshComponent, SurfaceDataMeshConfig>
{
public:
using BaseClassType = LmbrCentral::EditorWrappedComponentBase<SurfaceDataMeshComponent, SurfaceDataMeshConfig>;
AZ_EDITOR_COMPONENT(EditorSurfaceDataMeshComponent, "{4D73E979-5463-4B75-AE46-70B1E52CBF43}", BaseClassType);
static void Reflect(AZ::ReflectContext* context);
static constexpr const char* const s_categoryName = "Surface Data";
static constexpr const char* const s_componentName = "Mesh Surface Tag Emitter";
static constexpr const char* const s_componentDescription = "Enables a static mesh to emit surface tags";
static constexpr const char* const s_icon = "Editor/Icons/Components/SurfaceData.svg";
static constexpr const char* const s_viewportIcon = "Editor/Icons/Components/Viewport/SurfaceData.png";
static constexpr const char* const s_helpUrl = "https://docs.aws.amazon.com/console/lumberyard/surfacedata/mesh-surface-tag-emitter";
};
}
@@ -0,0 +1,288 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensor's.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "SurfaceDataMeshComponent.h"
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <LmbrCentral/Rendering/MeshAsset.h>
#include <Atom/RPI.Reflect/Model/ModelAssetCreator.h>
#include <SurfaceData/SurfaceDataSystemRequestBus.h>
#include <SurfaceData/Utility/SurfaceDataUtility.h>
#include <MathConversion.h>
namespace SurfaceData
{
void SurfaceDataMeshConfig::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<SurfaceDataMeshConfig, AZ::ComponentConfig>()
->Version(0)
->Field("SurfaceTags", &SurfaceDataMeshConfig::m_tags)
;
AZ::EditContext* edit = serialize->GetEditContext();
if (edit)
{
edit->Class<SurfaceDataMeshConfig>(
"Mesh Surface Tag Emitter", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(0, &SurfaceDataMeshConfig::m_tags, "Generated Tags", "")
;
}
}
}
void SurfaceDataMeshComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("SurfaceDataProviderService", 0xfe9fb95e));
}
void SurfaceDataMeshComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("SurfaceDataProviderService", 0xfe9fb95e));
}
void SurfaceDataMeshComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("MeshService", 0x71d8a455));
}
void SurfaceDataMeshComponent::Reflect(AZ::ReflectContext* context)
{
SurfaceDataMeshConfig::Reflect(context);
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<SurfaceDataMeshComponent, AZ::Component>()
->Version(0)
->Field("Configuration", &SurfaceDataMeshComponent::m_configuration)
;
}
}
SurfaceDataMeshComponent::SurfaceDataMeshComponent(const SurfaceDataMeshConfig& configuration)
: m_configuration(configuration)
{
}
void SurfaceDataMeshComponent::Activate()
{
AZ::TransformNotificationBus::Handler::BusConnect(GetEntityId());
AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
m_providerHandle = InvalidSurfaceDataRegistryHandle;
m_refresh = false;
// Update the cached mesh data and bounds, then register the surface data provider
UpdateMeshData();
}
void SurfaceDataMeshComponent::Deactivate()
{
if (m_providerHandle != InvalidSurfaceDataRegistryHandle)
{
SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle);
m_providerHandle = InvalidSurfaceDataRegistryHandle;
}
SurfaceDataProviderRequestBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
AZ::TransformNotificationBus::Handler::BusDisconnect();
AZ::Render::MeshComponentNotificationBus::Handler::BusDisconnect();
m_refresh = false;
// Clear the cached mesh data
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
m_meshAssetData = {};
m_meshBounds = AZ::Aabb::CreateNull();
m_meshWorldTM = AZ::Transform::CreateIdentity();
m_meshWorldTMInverse = AZ::Transform::CreateIdentity();
}
}
bool SurfaceDataMeshComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
{
if (auto config = azrtti_cast<const SurfaceDataMeshConfig*>(baseConfig))
{
m_configuration = *config;
return true;
}
return false;
}
bool SurfaceDataMeshComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
{
if (auto config = azrtti_cast<SurfaceDataMeshConfig*>(outBaseConfig))
{
*config = m_configuration;
return true;
}
return false;
}
bool SurfaceDataMeshComponent::DoRayTrace(const AZ::Vector3& inPosition, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Entity);
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
// test AABB as first pass to claim the point
const AZ::Vector3 testPosition = AZ::Vector3(
inPosition.GetX(),
inPosition.GetY(),
(m_meshBounds.GetMax().GetZ() + m_meshBounds.GetMin().GetZ()) * 0.5f);
if (!m_meshBounds.Contains(testPosition))
{
return false;
}
AZ::RPI::ModelAsset* mesh = m_meshAssetData.GetAs<AZ::RPI::ModelAsset>();
if (!mesh)
{
return false;
}
const AZ::Vector3 rayOrigin = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMax().GetZ() + s_rayAABBHeightPadding);
const AZ::Vector3 rayDirection = -AZ::Vector3::CreateAxisZ();
return GetMeshRayIntersection(*mesh, m_meshWorldTM, m_meshWorldTMInverse, rayOrigin, rayDirection, outPosition, outNormal);
}
void SurfaceDataMeshComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
{
AZ::Vector3 hitPosition;
AZ::Vector3 hitNormal;
if (DoRayTrace(inPosition, hitPosition, hitNormal))
{
SurfacePoint point;
point.m_entityId = GetEntityId();
point.m_position = hitPosition;
point.m_normal = hitNormal;
AddMaxValueForMasks(point.m_masks, m_configuration.m_tags, 1.0f);
surfacePointList.push_back(point);
}
}
AZ::Aabb SurfaceDataMeshComponent::GetSurfaceAabb() const
{
return m_meshBounds;
}
SurfaceTagVector SurfaceDataMeshComponent::GetSurfaceTags() const
{
return m_configuration.m_tags;
}
void SurfaceDataMeshComponent::OnCompositionChanged()
{
if (!m_refresh)
{
m_refresh = true;
AZ::TickBus::Handler::BusConnect();
}
}
void SurfaceDataMeshComponent::OnModelReady([[maybe_unused]] const AZ::Data::Asset<AZ::RPI::ModelAsset>& modelAsset, [[maybe_unused]] const AZ::Data::Instance<AZ::RPI::Model>& model)
{
OnCompositionChanged();
}
void SurfaceDataMeshComponent::OnTransformChanged(const AZ::Transform & local, const AZ::Transform & world)
{
(void)local;
(void)world;
OnCompositionChanged();
}
void SurfaceDataMeshComponent::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
{
if (m_refresh)
{
UpdateMeshData();
m_refresh = false;
}
AZ::TickBus::Handler::BusDisconnect();
}
void SurfaceDataMeshComponent::UpdateMeshData()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Entity);
bool meshValidBeforeUpdate = false;
bool meshValidAfterUpdate = false;
{
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
meshValidBeforeUpdate = (m_meshAssetData.GetAs<AZ::RPI::ModelAsset>() != nullptr) && (m_meshBounds.IsValid());
m_meshAssetData = {};
AZ::Render::MeshComponentRequestBus::EventResult(m_meshAssetData, GetEntityId(), &AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
m_meshBounds = AZ::Aabb::CreateNull();
AZ::Render::MeshComponentRequestBus::EventResult(m_meshBounds, GetEntityId(), &AZ::Render::MeshComponentRequestBus::Events::GetWorldBounds);
m_meshWorldTM = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(m_meshWorldTM, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
m_meshWorldTMInverse = m_meshWorldTM.GetInverse();
meshValidAfterUpdate = (m_meshAssetData.GetAs<AZ::RPI::ModelAsset>() != nullptr) && (m_meshBounds.IsValid());
}
SurfaceDataRegistryEntry registryEntry;
registryEntry.m_entityId = GetEntityId();
registryEntry.m_bounds = GetSurfaceAabb();
registryEntry.m_tags = GetSurfaceTags();
if (!meshValidBeforeUpdate && !meshValidAfterUpdate)
{
// We didn't have a valid mesh asset before or after running this, so do nothing.
}
else if (!meshValidBeforeUpdate && meshValidAfterUpdate)
{
// Our mesh has become valid, so register as a provider and save off the provider handle
AZ_Assert((m_providerHandle == InvalidSurfaceDataRegistryHandle), "Surface data handle is initialized before our mesh became active");
AZ_Assert(m_meshBounds.IsValid(), "Mesh Geometry isn't correctly initialized.");
SurfaceDataSystemRequestBus::BroadcastResult(m_providerHandle, &SurfaceDataSystemRequestBus::Events::RegisterSurfaceDataProvider, registryEntry);
// Start listening for surface data events
AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
SurfaceDataProviderRequestBus::Handler::BusConnect(m_providerHandle);
}
else if (meshValidBeforeUpdate && !meshValidAfterUpdate)
{
// Our mesh has stopped being valid, so unregister and stop listening for surface data events
AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle);
m_providerHandle = InvalidSurfaceDataRegistryHandle;
SurfaceDataProviderRequestBus::Handler::BusDisconnect();
}
else if (meshValidBeforeUpdate && meshValidAfterUpdate)
{
// Our mesh was valid before and after, it just changed in some way, so update our registry entry.
AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UpdateSurfaceDataProvider, m_providerHandle, registryEntry);
}
}
}
@@ -0,0 +1,106 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
#include <SurfaceData/SurfaceDataProviderRequestBus.h>
#include <SurfaceData/SurfaceDataTypes.h>
namespace LmbrCentral
{
template<typename, typename>
class EditorWrappedComponentBase;
}
namespace SurfaceData
{
constexpr float s_rayAABBHeightPadding = 0.1f;
class SurfaceDataMeshConfig
: public AZ::ComponentConfig
{
public:
AZ_CLASS_ALLOCATOR(SurfaceDataMeshConfig, AZ::SystemAllocator, 0);
AZ_RTTI(SurfaceDataMeshConfig, "{764C602E-7CA8-4BCC-AB2D-3E46623B3A20}", AZ::ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
SurfaceTagVector m_tags;
};
class SurfaceDataMeshComponent
: public AZ::Component
, public AZ::TickBus::Handler
, public AZ::TransformNotificationBus::Handler
, public AZ::Render::MeshComponentNotificationBus::Handler
, public SurfaceDataProviderRequestBus::Handler
{
public:
template<typename, typename> friend class LmbrCentral::EditorWrappedComponentBase;
AZ_COMPONENT(SurfaceDataMeshComponent, "{F8915F34-BE8B-40B4-B7E8-01EBF3DA1C95}");
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void Reflect(AZ::ReflectContext* context);
SurfaceDataMeshComponent(const SurfaceDataMeshConfig& configuration);
SurfaceDataMeshComponent() = default;
~SurfaceDataMeshComponent() = default;
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
//////////////////////////////////////////////////////////////////////////
// MeshComponentNotificationBus
void OnModelReady(const AZ::Data::Asset<AZ::RPI::ModelAsset>& modelAsset, const AZ::Data::Instance<AZ::RPI::Model>& model) override;
//////////////////////////////////////////////////////////////////////////
// TransformNotificationBus
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
////////////////////////////////////////////////////////////////////////
// AZ::TickBus
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
////////////////////////////////////////////////////////////////////////
// SurfaceDataProviderRequestBus
void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const override;
private:
bool DoRayTrace(const AZ::Vector3& inPosition, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const;
void UpdateMeshData();
void OnCompositionChanged();
AZ::Aabb GetSurfaceAabb() const;
SurfaceTagVector GetSurfaceTags() const;
SurfaceDataMeshConfig m_configuration;
SurfaceDataRegistryHandle m_providerHandle = InvalidSurfaceDataRegistryHandle;
// cached data
AZStd::atomic_bool m_refresh{ false };
mutable AZStd::recursive_mutex m_cacheMutex;
AZ::Data::Asset<AZ::Data::AssetData> m_meshAssetData;
AZ::Transform m_meshWorldTM = AZ::Transform::CreateIdentity();
AZ::Transform m_meshWorldTMInverse = AZ::Transform::CreateIdentity();
AZ::Aabb m_meshBounds = AZ::Aabb::CreateNull();
};
}
@@ -35,7 +35,7 @@ namespace AZ
//! ThumbnailRendererData encapsulates all data used by thumbnail renderer and caches assets
struct ThumbnailRendererData final
{
static constexpr const char* LightingPresetPath = "lightingpresets/default.lightingpreset.azasset";
static constexpr const char* LightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset";
static constexpr const char* DefaultModelPath = "materialeditor/viewportmodels/quadsphere.azmodel";
static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial";
@@ -147,7 +147,7 @@ namespace AZ
data->m_renderPipeline->SetDefaultView(data->m_view);
// Create lighting preset
data->m_lightingPresetAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::AnyAsset>(LightingPresetPath);
data->m_lightingPresetAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::AnyAsset>(ThumbnailRendererData::LightingPresetPath);
if (data->m_lightingPresetAsset.IsReady())
{
auto preset = data->m_lightingPresetAsset->GetDataAs<Render::LightingPreset>();
@@ -31,7 +31,6 @@ namespace AZ
void Start() override;
private:
static constexpr const char* LightingPresetPath = "lightingpresets/default.lightingpreset.azasset";
static constexpr float AspectRatio = 1.0f;
static constexpr float NearDist = 0.1f;
static constexpr float FarDist = 100.0f;
@@ -19,10 +19,6 @@ set(FILES
Source/CoreLights/EditorAreaLightComponent.cpp
Source/CoreLights/EditorDirectionalLightComponent.h
Source/CoreLights/EditorDirectionalLightComponent.cpp
Source/CoreLights/EditorPointLightComponent.h
Source/CoreLights/EditorPointLightComponent.cpp
Source/CoreLights/EditorSpotLightComponent.h
Source/CoreLights/EditorSpotLightComponent.cpp
Source/Decals/EditorDecalComponent.h
Source/Decals/EditorDecalComponent.cpp
Source/DiffuseProbeGrid/EditorDiffuseProbeGridComponent.h
@@ -111,5 +107,7 @@ set(FILES
Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h
Source/Scripting/EditorEntityReferenceComponent.cpp
Source/Scripting/EditorEntityReferenceComponent.h
Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp
Source/SurfaceData/EditorSurfaceDataMeshComponent.h
Resources/AtomLyIntegrationResources.qrc
)
@@ -27,21 +27,16 @@ set(FILES
Source/CoreLights/LightDelegateBase.h
Source/CoreLights/LightDelegateBase.inl
Source/CoreLights/LightDelegateInterface.h
Source/CoreLights/PointLightComponent.h
Source/CoreLights/PointLightComponent.cpp
Source/CoreLights/PointLightComponentController.h
Source/CoreLights/PointLightComponentController.cpp
Source/CoreLights/PolygonLightDelegate.h
Source/CoreLights/PolygonLightDelegate.cpp
Source/CoreLights/QuadLightDelegate.h
Source/CoreLights/QuadLightDelegate.cpp
Source/CoreLights/SimplePointLightDelegate.h
Source/CoreLights/SimplePointLightDelegate.cpp
Source/CoreLights/SimpleSpotLightDelegate.h
Source/CoreLights/SimpleSpotLightDelegate.cpp
Source/CoreLights/SphereLightDelegate.h
Source/CoreLights/SphereLightDelegate.cpp
Source/CoreLights/SpotLightComponent.h
Source/CoreLights/SpotLightComponent.cpp
Source/CoreLights/SpotLightComponentConfig.cpp
Source/CoreLights/SpotLightComponentController.h
Source/CoreLights/SpotLightComponentController.cpp
Source/Decals/DecalComponent.h
Source/Decals/DecalComponent.cpp
Source/Decals/DecalComponentController.h
@@ -117,8 +112,8 @@ set(FILES
Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponent.h
Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponent.cpp
Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponentConfig.cpp
Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponentController.h
Source/PostProcess/GradientWeightModifier/GradientWeightModifierComponentController.cpp
Source/PostProcess/GradientWeightModifier/GradientWeightModifierController.h
Source/PostProcess/GradientWeightModifier/GradientWeightModifierController.cpp
Source/ScreenSpace/DeferredFogComponentController.h
Source/ScreenSpace/DeferredFogComponentController.cpp
Source/ScreenSpace/DeferredFogComponent.h
@@ -145,4 +140,6 @@ set(FILES
Source/Scripting/EntityReferenceComponentConfig.cpp
Source/Scripting/EntityReferenceComponentController.cpp
Source/Scripting/EntityReferenceComponentController.h
Source/SurfaceData/SurfaceDataMeshComponent.cpp
Source/SurfaceData/SurfaceDataMeshComponent.h
)
@@ -15,10 +15,6 @@ set(FILES
Include/AtomLyIntegration/CommonFeatures/CoreLights/CoreLightsConstants.h
Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightBus.h
Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightComponentConfig.h
Include/AtomLyIntegration/CommonFeatures/CoreLights/PointLightBus.h
Include/AtomLyIntegration/CommonFeatures/CoreLights/PointLightComponentConfig.h
Include/AtomLyIntegration/CommonFeatures/CoreLights/SpotLightBus.h
Include/AtomLyIntegration/CommonFeatures/CoreLights/SpotLightComponentConfig.h
Include/AtomLyIntegration/CommonFeatures/Decals/DecalBus.h
Include/AtomLyIntegration/CommonFeatures/Decals/DecalComponentConfig.h
Include/AtomLyIntegration/CommonFeatures/Decals/DecalConstants.h