Merge main

This commit is contained in:
mnaumov
2021-06-02 13:40:33 -07:00
1241 changed files with 24782 additions and 19704 deletions
@@ -21,18 +21,42 @@ namespace AZ
{
namespace Render
{
bool EditorAttachmentComponentVersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
{
if (classElement.GetVersion() < 2)
{
float uniformScaleOffset = 1.0f;
int scaleElementIndex = classElement.FindElement(AZ_CRC_CE("Scale Offset"));
if (scaleElementIndex != -1)
{
AZ::Vector3 oldScaleValue = AZ::Vector3::CreateOne();
AZ::SerializeContext::DataElementNode& dataElementNode = classElement.GetSubElement(scaleElementIndex);
if (dataElementNode.GetData<AZ::Vector3>(oldScaleValue))
{
uniformScaleOffset = oldScaleValue.GetMaxElement();
}
classElement.RemoveElement(scaleElementIndex);
}
classElement.AddElementWithData(context, "Uniform Scale Offset", uniformScaleOffset);
}
return true;
}
void EditorAttachmentComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<EditorAttachmentComponent, EditorComponentBase>()
->Version(1)
->Version(2, &EditorAttachmentComponentVersionConverter)
->Field("Target ID", &EditorAttachmentComponent::m_targetId)
->Field("Target Bone Name", &EditorAttachmentComponent::m_targetBoneName)
->Field("Position Offset", &EditorAttachmentComponent::m_positionOffset)
->Field("Rotation Offset", &EditorAttachmentComponent::m_rotationOffset)
->Field("Scale Offset", &EditorAttachmentComponent::m_scaleOffset)
->Field("Uniform Scale Offset", &EditorAttachmentComponent::m_uniformScaleOffset)
->Field("Attached Initially", &EditorAttachmentComponent::m_attachedInitially)
->Field("Scale Source", &EditorAttachmentComponent::m_scaleSource);
@@ -70,7 +94,7 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::Min, -AZ::RadToDeg(AZ::Constants::TwoPi))
->Attribute(AZ::Edit::Attributes::Max, AZ::RadToDeg(AZ::Constants::TwoPi))
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetOffsetChanged)
->DataElement(0, &EditorAttachmentComponent::m_scaleOffset, "Scale offset", "Local scale offset from target entity")
->DataElement(0, &EditorAttachmentComponent::m_uniformScaleOffset, "Scale offset", "Local scale offset from target entity")
->Attribute(AZ::Edit::Attributes::Step, 0.1f)
->Attribute(AZ::Edit::Attributes::Min, 0.001f)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetOffsetChanged)
@@ -128,7 +152,7 @@ namespace AZ
{
AZ::Transform offset = AZ::ConvertEulerDegreesToTransform(m_rotationOffset);
offset.SetTranslation(m_positionOffset);
offset.MultiplyByScale(m_scaleOffset);
offset.MultiplyByUniformScale(m_uniformScaleOffset);
return offset;
}
@@ -88,7 +88,7 @@ namespace AZ
AZ::Vector3 m_rotationOffset = AZ::Vector3::CreateZero();
//! Offset from target entity's scale.
AZ::Vector3 m_scaleOffset = AZ::Vector3::CreateOne();
float m_uniformScaleOffset = 1.0f;
//! Observe scale information from the specified source.
AttachmentConfiguration::ScaleSource m_scaleSource = AttachmentConfiguration::ScaleSource::WorldScale;
@@ -76,12 +76,12 @@ namespace AZ
float QuadLightDelegate::GetWidth() const
{
return m_shapeBus->GetQuadWidth() * GetTransform().GetScale().GetX();
return m_shapeBus->GetQuadWidth() * GetTransform().GetUniformScale();
}
float QuadLightDelegate::GetHeight() const
{
return m_shapeBus->GetQuadHeight() * GetTransform().GetScale().GetY();
return m_shapeBus->GetQuadHeight() * GetTransform().GetUniformScale();
}
} // namespace Render
@@ -44,7 +44,17 @@ namespace AZ
->Field("AmbientMultiplier", &DiffuseProbeGridComponentConfig::m_ambientMultiplier)
->Field("ViewBias", &DiffuseProbeGridComponentConfig::m_viewBias)
->Field("NormalBias", &DiffuseProbeGridComponentConfig::m_normalBias)
;
->Field("EditorMode", &DiffuseProbeGridComponentConfig::m_editorMode)
->Field("RuntimeMode", &DiffuseProbeGridComponentConfig::m_runtimeMode)
->Field("BakedIrradianceTextureRelativePath", &DiffuseProbeGridComponentConfig::m_bakedIrradianceTextureRelativePath)
->Field("BakedDistanceTextureRelativePath", &DiffuseProbeGridComponentConfig::m_bakedDistanceTextureRelativePath)
->Field("BakedRelocationTextureRelativePath", &DiffuseProbeGridComponentConfig::m_bakedRelocationTextureRelativePath)
->Field("BakedClassificationTextureRelativePath", &DiffuseProbeGridComponentConfig::m_bakedClassificationTextureRelativePath)
->Field("BakedIrradianceTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedIrradianceTextureAsset)
->Field("BakedDistanceTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedDistanceTextureAsset)
->Field("BakedRelocationTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedRelocationTextureAsset)
->Field("BakedClassificationTextureAsset", &DiffuseProbeGridComponentConfig::m_bakedClassificationTextureAsset)
;
}
}
@@ -110,6 +120,26 @@ namespace AZ
m_boxShapeInterface = LmbrCentral::BoxShapeComponentRequestsBus::FindFirstHandler(m_entityId);
AZ_Assert(m_boxShapeInterface, "DiffuseProbeGridComponentController was unable to find box shape component");
// special handling is required if this component is being cloned in the editor:
// check to see if the baked textures are already referenced by another DiffuseProbeGrid
if (m_featureProcessor->AreBakedTexturesReferenced(
m_configuration.m_bakedIrradianceTextureRelativePath,
m_configuration.m_bakedDistanceTextureRelativePath,
m_configuration.m_bakedRelocationTextureRelativePath,
m_configuration.m_bakedClassificationTextureRelativePath))
{
// clear the baked texture paths and assets, since they belong to the original entity (not the clone)
m_configuration.m_bakedIrradianceTextureRelativePath.clear();
m_configuration.m_bakedDistanceTextureRelativePath.clear();
m_configuration.m_bakedRelocationTextureRelativePath.clear();
m_configuration.m_bakedClassificationTextureRelativePath.clear();
m_configuration.m_bakedIrradianceTextureAsset.Reset();
m_configuration.m_bakedDistanceTextureAsset.Reset();
m_configuration.m_bakedRelocationTextureAsset.Reset();
m_configuration.m_bakedClassificationTextureAsset.Reset();
}
// add this diffuse probe grid to the feature processor
const AZ::Transform& transform = m_transformInterface->GetWorldTM();
m_handle = m_featureProcessor->AddProbeGrid(transform, m_configuration.m_extents, m_configuration.m_probeSpacing);
@@ -118,11 +148,61 @@ namespace AZ
m_featureProcessor->SetViewBias(m_handle, m_configuration.m_viewBias);
m_featureProcessor->SetNormalBias(m_handle, m_configuration.m_normalBias);
// load the baked texture assets, but only if they are all valid
if (m_configuration.m_bakedIrradianceTextureAsset.GetId().IsValid() &&
m_configuration.m_bakedDistanceTextureAsset.GetId().IsValid() &&
m_configuration.m_bakedRelocationTextureAsset.GetId().IsValid() &&
m_configuration.m_bakedClassificationTextureAsset.GetId().IsValid())
{
Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_bakedIrradianceTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_bakedDistanceTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_bakedRelocationTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_bakedClassificationTextureAsset.GetId());
m_configuration.m_bakedIrradianceTextureAsset.QueueLoad();
m_configuration.m_bakedDistanceTextureAsset.QueueLoad();
m_configuration.m_bakedRelocationTextureAsset.QueueLoad();
m_configuration.m_bakedClassificationTextureAsset.QueueLoad();
}
else if (m_configuration.m_runtimeMode == DiffuseProbeGridMode::Baked ||
m_configuration.m_runtimeMode == DiffuseProbeGridMode::AutoSelect ||
m_configuration.m_editorMode == DiffuseProbeGridMode::Baked ||
m_configuration.m_editorMode == DiffuseProbeGridMode::AutoSelect)
{
AZ_Error("DiffuseProbeGrid", false, "DiffuseProbeGrid mdoe is set to Baked or Auto-Select, but it does not have baked texture assets. Please re-bake this DiffuseProbeGrid.");
}
m_featureProcessor->SetMode(m_handle, m_configuration.m_runtimeMode);
// set box shape component dimensions from the configuration
// this will invoke the OnShapeChanged() handler and set the outer extents on the feature processor
m_boxShapeInterface->SetBoxDimensions(m_configuration.m_extents);
}
void DiffuseProbeGridComponentController::OnAssetReady(Data::Asset<Data::AssetData> asset)
{
// if all assets are ready we can set the baked texture images
if (m_configuration.m_bakedIrradianceTextureAsset.IsReady() &&
m_configuration.m_bakedDistanceTextureAsset.IsReady() &&
m_configuration.m_bakedRelocationTextureAsset.IsReady() &&
m_configuration.m_bakedClassificationTextureAsset.IsReady())
{
Data::AssetBus::MultiHandler::BusDisconnect(m_configuration.m_bakedIrradianceTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusDisconnect(m_configuration.m_bakedDistanceTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusDisconnect(m_configuration.m_bakedRelocationTextureAsset.GetId());
Data::AssetBus::MultiHandler::BusDisconnect(m_configuration.m_bakedClassificationTextureAsset.GetId());
UpdateBakedTextures();
}
}
void DiffuseProbeGridComponentController::OnAssetError(Data::Asset<Data::AssetData> asset)
{
Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId());
AZ_Error("DiffuseProbeGrid", false, "Failed to load baked texture [%s], please re-bake this DiffuseProbeGrid.", asset.GetId().ToString<AZStd::string>().c_str());
}
void DiffuseProbeGridComponentController::Deactivate()
{
if (m_featureProcessor)
@@ -212,20 +292,96 @@ namespace AZ
void DiffuseProbeGridComponentController::SetAmbientMultiplier(float ambientMultiplier)
{
if (!m_featureProcessor)
{
return;
}
m_configuration.m_ambientMultiplier = ambientMultiplier;
m_featureProcessor->SetAmbientMultiplier(m_handle, m_configuration.m_ambientMultiplier);
}
void DiffuseProbeGridComponentController::SetViewBias(float viewBias)
{
if (!m_featureProcessor)
{
return;
}
m_configuration.m_viewBias = viewBias;
m_featureProcessor->SetViewBias(m_handle, m_configuration.m_viewBias);
}
void DiffuseProbeGridComponentController::SetNormalBias(float normalBias)
{
if (!m_featureProcessor)
{
return;
}
m_configuration.m_normalBias = normalBias;
m_featureProcessor->SetNormalBias(m_handle, m_configuration.m_normalBias);
}
void DiffuseProbeGridComponentController::SetEditorMode(DiffuseProbeGridMode editorMode)
{
if (!m_featureProcessor)
{
return;
}
// update the configuration and change the DiffuseProbeGrid mode
m_configuration.m_editorMode = editorMode;
m_featureProcessor->SetMode(m_handle, m_configuration.m_editorMode);
}
void DiffuseProbeGridComponentController::SetRuntimeMode(DiffuseProbeGridMode runtimeMode)
{
if (!m_featureProcessor)
{
return;
}
// only update the configuration
m_configuration.m_runtimeMode = runtimeMode;
}
void DiffuseProbeGridComponentController::BakeTextures(DiffuseProbeGridBakeTexturesCallback callback)
{
if (!m_featureProcessor)
{
return;
}
m_featureProcessor->BakeTextures(
m_handle,
callback,
m_configuration.m_bakedIrradianceTextureRelativePath,
m_configuration.m_bakedDistanceTextureRelativePath,
m_configuration.m_bakedRelocationTextureRelativePath,
m_configuration.m_bakedClassificationTextureRelativePath);
}
void DiffuseProbeGridComponentController::UpdateBakedTextures()
{
if (!m_featureProcessor)
{
return;
}
DiffuseProbeGridBakedTextures bakedTextures;
bakedTextures.m_irradianceImage = RPI::StreamingImage::FindOrCreate(m_configuration.m_bakedIrradianceTextureAsset);
bakedTextures.m_irradianceImageRelativePath = m_configuration.m_bakedIrradianceTextureRelativePath;
bakedTextures.m_distanceImage = RPI::StreamingImage::FindOrCreate(m_configuration.m_bakedDistanceTextureAsset);
bakedTextures.m_distanceImageRelativePath = m_configuration.m_bakedDistanceTextureRelativePath;
bakedTextures.m_relocationImageDescriptor = m_configuration.m_bakedRelocationTextureAsset->GetImageDescriptor();
bakedTextures.m_relocationImageData = m_configuration.m_bakedRelocationTextureAsset->GetSubImageData(0, 0);
bakedTextures.m_relocationImageRelativePath = m_configuration.m_bakedRelocationTextureRelativePath;
bakedTextures.m_classificationImageDescriptor = m_configuration.m_bakedClassificationTextureAsset->GetImageDescriptor();
bakedTextures.m_classificationImageData = m_configuration.m_bakedClassificationTextureAsset->GetSubImageData(0, 0);
bakedTextures.m_classificationImageRelativePath = m_configuration.m_bakedClassificationTextureRelativePath;
m_featureProcessor->SetBakedTextures(m_handle, bakedTextures);
}
} // namespace Render
} // namespace AZ
@@ -39,6 +39,19 @@ namespace AZ
float m_ambientMultiplier = DefaultDiffuseProbeGridAmbientMultiplier;
float m_viewBias = DefaultDiffuseProbeGridViewBias;
float m_normalBias = DefaultDiffuseProbeGridNormalBias;
DiffuseProbeGridMode m_editorMode = DiffuseProbeGridMode::RealTime;
DiffuseProbeGridMode m_runtimeMode = DiffuseProbeGridMode::RealTime;
AZStd::string m_bakedIrradianceTextureRelativePath;
AZStd::string m_bakedDistanceTextureRelativePath;
AZStd::string m_bakedRelocationTextureRelativePath;
AZStd::string m_bakedClassificationTextureRelativePath;
Data::Asset<RPI::StreamingImageAsset> m_bakedIrradianceTextureAsset;
Data::Asset<RPI::StreamingImageAsset> m_bakedDistanceTextureAsset;
Data::Asset<RPI::StreamingImageAsset> m_bakedRelocationTextureAsset;
Data::Asset<RPI::StreamingImageAsset> m_bakedClassificationTextureAsset;
};
class DiffuseProbeGridComponentController final
@@ -79,12 +92,24 @@ namespace AZ
// ShapeComponentNotificationsBus overrides
void OnShapeChanged(ShapeChangeReasons changeReason) override;
// AssetBus overrides
void OnAssetReady(Data::Asset<Data::AssetData> asset) override;
void OnAssetError(Data::Asset<Data::AssetData> asset) override;
// Property handlers
bool ValidateProbeSpacing(const AZ::Vector3& newSpacing);
void SetProbeSpacing(const AZ::Vector3& probeSpacing);
void SetAmbientMultiplier(float ambientMultiplier);
void SetViewBias(float viewBias);
void SetNormalBias(float normalBias);
void SetEditorMode(DiffuseProbeGridMode editorMode);
void SetRuntimeMode(DiffuseProbeGridMode runtimeMode);
// Bake the diffuse probe grid textures to assets
void BakeTextures(DiffuseProbeGridBakeTexturesCallback callback);
// Update the baked texture assets from the configuration
void UpdateBakedTextures();
// box shape component, used for defining the outer extents of the probe area
LmbrCentral::BoxShapeComponentRequests* m_boxShapeInterface = nullptr;
@@ -16,6 +16,14 @@
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/IO/SystemFile.h>
#include <Atom/RPI.Reflect/Image/StreamingImagePoolAsset.h>
#include <Atom/Utils/DdsFile.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QApplication>
#include <QMessageBox>
AZ_POP_DISABLE_WARNING
namespace AZ
{
@@ -35,7 +43,9 @@ namespace AZ
->Field("ambientMultiplier", &EditorDiffuseProbeGridComponent::m_ambientMultiplier)
->Field("viewBias", &EditorDiffuseProbeGridComponent::m_viewBias)
->Field("normalBias", &EditorDiffuseProbeGridComponent::m_normalBias)
;
->Field("editorMode", &EditorDiffuseProbeGridComponent::m_editorMode)
->Field("runtimeMode", &EditorDiffuseProbeGridComponent::m_runtimeMode)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
@@ -48,25 +58,26 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo<RPI::ModelAsset>::Uuid())
->ClassElement(AZ::Edit::ClassElements::Group, "Probe Spacing")
->ClassElement(AZ::Edit::ClassElements::Group, "Probe Spacing (meters between probes)")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &EditorDiffuseProbeGridComponent::m_probeSpacingX, "X", "Probe spacing on the X-axis")
->DataElement(AZ::Edit::UIHandlers::Default, &EditorDiffuseProbeGridComponent::m_probeSpacingX, "X", "Probe spacing on the X-axis, in meters")
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
->Attribute(AZ::Edit::Attributes::ChangeValidate, &EditorDiffuseProbeGridComponent::OnProbeSpacingValidateX)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnProbeSpacingChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &EditorDiffuseProbeGridComponent::m_probeSpacingY, "Y", "Probe spacing on the Y-axis")
->DataElement(AZ::Edit::UIHandlers::Default, &EditorDiffuseProbeGridComponent::m_probeSpacingY, "Y", "Probe spacing on the Y-axis, in meters")
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
->Attribute(AZ::Edit::Attributes::ChangeValidate, &EditorDiffuseProbeGridComponent::OnProbeSpacingValidateY)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnProbeSpacingChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &EditorDiffuseProbeGridComponent::m_probeSpacingZ, "Z", "Probe spacing on the Z-axis")
->DataElement(AZ::Edit::UIHandlers::Default, &EditorDiffuseProbeGridComponent::m_probeSpacingZ, "Z", "Probe spacing on the Z-axis, in meters")
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
->Attribute(AZ::Edit::Attributes::ChangeValidate, &EditorDiffuseProbeGridComponent::OnProbeSpacingValidateZ)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnProbeSpacingChanged)
->ClassElement(AZ::Edit::ClassElements::Group, "Grid Settings")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Slider, &EditorDiffuseProbeGridComponent::m_ambientMultiplier, "Ambient Multiplier", "Multiplier for the irradiance intensity")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnAmbientMultiplierChanged)
->Attribute(Edit::Attributes::Decimals, 0)
->Attribute(Edit::Attributes::Step, 1.0f)
->Attribute(Edit::Attributes::Decimals, 1)
->Attribute(Edit::Attributes::Step, 0.1f)
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 10.0f)
->DataElement(AZ::Edit::UIHandlers::Slider, &EditorDiffuseProbeGridComponent::m_viewBias, "View Bias", "View bias adjustment")
@@ -81,6 +92,27 @@ namespace AZ
->Attribute(Edit::Attributes::Step, 0.1f)
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 1.0f)
->ClassElement(AZ::Edit::ClassElements::EditorData, "Grid mode")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(Edit::UIHandlers::ComboBox, &EditorDiffuseProbeGridComponent::m_editorMode, "Editor Mode", "Controls whether the editor uses RealTime or Baked diffuse GI. RealTime requires a ray-tracing capable GPU. Auto-Select will fallback to Baked if ray-tracing is not available")
->Attribute(AZ::Edit::Attributes::ChangeValidate, &EditorDiffuseProbeGridComponent::OnModeChangeValidate)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnEditorModeChanged)
->EnumAttribute(DiffuseProbeGridMode::RealTime, "Real Time (Ray-Traced)")
->EnumAttribute(DiffuseProbeGridMode::Baked, "Baked")
->EnumAttribute(DiffuseProbeGridMode::AutoSelect, "Auto Select")
->DataElement(Edit::UIHandlers::ComboBox, &EditorDiffuseProbeGridComponent::m_runtimeMode, "Runtime Mode", "Controls whether the runtime uses RealTime or Baked diffuse GI. RealTime requires a ray-tracing capable GPU. Auto-Select will fallback to Baked if ray-tracing is not available")
->Attribute(AZ::Edit::Attributes::ChangeValidate, &EditorDiffuseProbeGridComponent::OnModeChangeValidate)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnRuntimeModeChanged)
->EnumAttribute(DiffuseProbeGridMode::RealTime, "Real Time (Ray-Traced)")
->EnumAttribute(DiffuseProbeGridMode::Baked, "Baked")
->EnumAttribute(DiffuseProbeGridMode::AutoSelect, "Auto Select")
->ClassElement(AZ::Edit::ClassElements::Group, "Bake Textures")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->UIElement(AZ::Edit::UIHandlers::Button, "Bake Textures", "Bake the Diffuse Probe Grid textures to static assets that will be used when the mode is set to Baked")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
->Attribute(AZ::Edit::Attributes::ButtonText, "Bake Textures")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::BakeDiffuseProbeGrid)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorDiffuseProbeGridComponent::GetBakeDiffuseProbeGridVisibilitySetting)
;
editContext->Class<DiffuseProbeGridComponentController>(
@@ -90,12 +122,6 @@ namespace AZ
->DataElement(AZ::Edit::UIHandlers::Default, &DiffuseProbeGridComponentController::m_configuration, "Configuration", "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
;
editContext->Class<DiffuseProbeGridComponentConfig>(
"DiffuseProbeGridComponentConfig", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
}
}
@@ -121,15 +147,73 @@ namespace AZ
BaseClass::Activate();
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusConnect(GetEntityId());
AZ::TickBus::Handler::BusConnect();
AzToolsFramework::EditorEntityInfoNotificationBus::Handler::BusConnect();
}
void EditorDiffuseProbeGridComponent::Deactivate()
{
AzToolsFramework::EditorEntityInfoNotificationBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusDisconnect();
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
BaseClass::Deactivate();
}
void EditorDiffuseProbeGridComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
if (!m_controller.m_featureProcessor)
{
return;
}
DiffuseProbeGridComponentConfig& configuration = m_controller.m_configuration;
// set the editor mode, which will override the runtime mode set by the controller
if (!m_editorModeSet)
{
m_controller.m_featureProcessor->SetMode(m_controller.m_handle, configuration.m_editorMode);
m_editorModeSet = true;
}
CheckTextureAssetNotification(configuration.m_bakedIrradianceTextureRelativePath, configuration.m_bakedIrradianceTextureAsset);
CheckTextureAssetNotification(configuration.m_bakedDistanceTextureRelativePath, configuration.m_bakedDistanceTextureAsset);
CheckTextureAssetNotification(configuration.m_bakedRelocationTextureRelativePath, configuration.m_bakedRelocationTextureAsset);
CheckTextureAssetNotification(configuration.m_bakedClassificationTextureRelativePath, configuration.m_bakedClassificationTextureAsset);
}
void EditorDiffuseProbeGridComponent::CheckTextureAssetNotification(const AZStd::string& relativePath, Data::Asset<RPI::StreamingImageAsset>& configurationAsset)
{
Data::Asset<RPI::StreamingImageAsset> textureAsset;
DiffuseProbeGridTextureNotificationType notificationType = DiffuseProbeGridTextureNotificationType::None;
if (m_controller.m_featureProcessor->CheckTextureAssetNotification(relativePath + ".streamingimage", textureAsset, notificationType))
{
if (notificationType == DiffuseProbeGridTextureNotificationType::Ready)
{
// bake is complete, update configuration with the new baked texture asset
AzToolsFramework::ScopedUndoBatch undoBatch("DiffuseProbeGrid Texture Bake");
configurationAsset = { textureAsset.GetAs<RPI::StreamingImageAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
SetDirty();
if (m_controller.m_configuration.m_bakedIrradianceTextureAsset.IsReady() &&
m_controller.m_configuration.m_bakedDistanceTextureAsset.IsReady() &&
m_controller.m_configuration.m_bakedClassificationTextureAsset.IsReady() &&
m_controller.m_configuration.m_bakedRelocationTextureAsset.IsReady())
{
m_controller.UpdateBakedTextures();
}
}
else if (notificationType == DiffuseProbeGridTextureNotificationType::Error)
{
QMessageBox::information(
QApplication::activeWindow(),
"Diffuse Probe Grid",
"Diffuse Probe Grid texture failed to bake, please check the Asset Processor for more information.",
QMessageBox::Ok);
}
}
}
AZ::Aabb EditorDiffuseProbeGridComponent::GetEditorSelectionBoundsViewport([[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo)
{
return m_controller.GetAabb();
@@ -140,11 +224,19 @@ namespace AZ
return false;
}
void EditorDiffuseProbeGridComponent::OnEntityInfoUpdatedVisibility(AZ::EntityId entityId, bool visible)
{
if ((GetEntityId() == entityId) && !visible)
{
m_editorModeSet = false;
}
}
AZ::Outcome<void, AZStd::string> EditorDiffuseProbeGridComponent::OnProbeSpacingValidateX(void* newValue, [[maybe_unused]] const AZ::Uuid& valueType)
{
if (!m_controller.m_featureProcessor)
{
return AZ::Failure(AZStd::string("Unable to adjust probe spacing, please try again"));
return AZ::Failure(AZStd::string("This Diffuse Probe Grid entity is hidden, it must be visible in order to change the probe spacing."));
}
float newProbeSpacingX = *(reinterpret_cast<float*>(newValue));
@@ -152,7 +244,7 @@ namespace AZ
Vector3 newSpacing(newProbeSpacingX, m_probeSpacingY, m_probeSpacingZ);
if (!m_controller.ValidateProbeSpacing(newSpacing))
{
return AZ::Failure(AZStd::string("Probe spacing exceeds max allowable grid size with current extents"));
return AZ::Failure(AZStd::string("Probe spacing exceeds max allowable grid size with current extents."));
}
return AZ::Success();
@@ -162,7 +254,7 @@ namespace AZ
{
if (!m_controller.m_featureProcessor)
{
return AZ::Failure(AZStd::string("Unable to adjust probe spacing, please try again"));
return AZ::Failure(AZStd::string("This Diffuse Probe Grid entity is hidden, it must be visible in order to change the probe spacing."));
}
float newProbeSpacingY = *(reinterpret_cast<float*>(newValue));
@@ -170,7 +262,7 @@ namespace AZ
Vector3 newSpacing(m_probeSpacingX, newProbeSpacingY, m_probeSpacingZ);
if (!m_controller.ValidateProbeSpacing(newSpacing))
{
return AZ::Failure(AZStd::string("Probe spacing exceeds max allowable grid size with current extents"));
return AZ::Failure(AZStd::string("Probe spacing exceeds max allowable grid size with current extents."));
}
return AZ::Success();
@@ -180,7 +272,7 @@ namespace AZ
{
if (!m_controller.m_featureProcessor)
{
return AZ::Failure(AZStd::string("Unable to adjust probe spacing, please try again"));
return AZ::Failure(AZStd::string("This Diffuse Probe Grid entity is hidden, it must be visible in order to change the probe spacing."));
}
float newProbeSpacingZ = *(reinterpret_cast<float*>(newValue));
@@ -188,7 +280,7 @@ namespace AZ
Vector3 newSpacing(m_probeSpacingX, m_probeSpacingY, newProbeSpacingZ);
if (!m_controller.ValidateProbeSpacing(newSpacing))
{
return AZ::Failure(AZStd::string("Probe spacing exceeds max allowable grid size with current extents"));
return AZ::Failure(AZStd::string("Probe spacing exceeds max allowable grid size with current extents."));
}
return AZ::Success();
@@ -218,5 +310,226 @@ namespace AZ
m_controller.SetNormalBias(m_normalBias);
return AZ::Edit::PropertyRefreshLevels::None;
}
AZ::u32 EditorDiffuseProbeGridComponent::OnEditorModeChanged()
{
// this will update the configuration and also change the DiffuseProbeGrid mode
m_controller.SetEditorMode(m_editorMode);
return AZ::Edit::PropertyRefreshLevels::EntireTree;
}
AZ::u32 EditorDiffuseProbeGridComponent::OnRuntimeModeChanged()
{
// this will only update the configuration
m_controller.SetRuntimeMode(m_runtimeMode);
return AZ::Edit::PropertyRefreshLevels::None;
}
AZ::Outcome<void, AZStd::string> EditorDiffuseProbeGridComponent::OnModeChangeValidate([[maybe_unused]] void* newValue, [[maybe_unused]] const AZ::Uuid& valueType)
{
DiffuseProbeGridMode newMode = (*(reinterpret_cast<DiffuseProbeGridMode*>(newValue)));
if (newMode == DiffuseProbeGridMode::Baked || newMode == DiffuseProbeGridMode::AutoSelect)
{
if (!m_controller.m_configuration.m_bakedIrradianceTextureAsset.GetId().IsValid() ||
!m_controller.m_configuration.m_bakedDistanceTextureAsset.GetId().IsValid() ||
!m_controller.m_configuration.m_bakedRelocationTextureAsset.GetId().IsValid() ||
!m_controller.m_configuration.m_bakedClassificationTextureAsset.GetId().IsValid())
{
return AZ::Failure(AZStd::string("Please bake textures before changing the Diffuse Probe Grid to Baked or Auto-Select mode."));
}
}
return AZ::Success();
}
AZ::u32 EditorDiffuseProbeGridComponent::GetBakeDiffuseProbeGridVisibilitySetting()
{
// the Bake button is visible only when the editor mode is set to RealTime
return m_editorMode == DiffuseProbeGridMode::RealTime ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
}
AZ::u32 EditorDiffuseProbeGridComponent::BakeDiffuseProbeGrid()
{
if (m_bakeInProgress)
{
return AZ::Edit::PropertyRefreshLevels::None;
}
// retrieve entity visibility
bool isHidden = false;
AzToolsFramework::EditorEntityInfoRequestBus::EventResult(
isHidden,
GetEntityId(),
&AzToolsFramework::EditorEntityInfoRequestBus::Events::IsHidden);
// the entity must be visible in order to bake
if (isHidden)
{
QMessageBox::information(
QApplication::activeWindow(),
"Diffuse Probe Grid",
"This Diffuse Probe Grid entity is hidden, it must be visible in order to bake textures.",
QMessageBox::Ok);
return AZ::Edit::PropertyRefreshLevels::None;
}
DiffuseProbeGridComponentConfig& configuration = m_controller.m_configuration;
// retrieve the source image paths from the configuration
// Note: we need to make sure to use the same source image for each bake
AZStd::string irradianceTextureRelativePath = ValidateOrCreateNewTexturePath(configuration.m_bakedIrradianceTextureRelativePath, DiffuseProbeGridIrradianceFileName);
AZStd::string distanceTextureRelativePath = ValidateOrCreateNewTexturePath(configuration.m_bakedDistanceTextureRelativePath, DiffuseProbeGridDistanceFileName);
AZStd::string relocationTextureRelativePath = ValidateOrCreateNewTexturePath(configuration.m_bakedRelocationTextureRelativePath, DiffuseProbeGridRelocationFileName);
AZStd::string classificationTextureRelativePath = ValidateOrCreateNewTexturePath(configuration.m_bakedClassificationTextureRelativePath, DiffuseProbeGridClassificationFileName);
// create the full paths
char projectPath[AZ_MAX_PATH_LEN];
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN);
AZStd::string irradianceTextureFullPath;
AzFramework::StringFunc::Path::Join(projectPath, irradianceTextureRelativePath.c_str(), irradianceTextureFullPath, true, true);
AZStd::string distanceTextureFullPath;
AzFramework::StringFunc::Path::Join(projectPath, distanceTextureRelativePath.c_str(), distanceTextureFullPath, true, true);
AZStd::string relocationTextureFullPath;
AzFramework::StringFunc::Path::Join(projectPath, relocationTextureRelativePath.c_str(), relocationTextureFullPath, true, true);
AZStd::string classificationTextureFullPath;
AzFramework::StringFunc::Path::Join(projectPath, classificationTextureRelativePath.c_str(), classificationTextureFullPath, true, true);
// make sure the folder is created
AZStd::string diffuseProbeGridFolder;
AzFramework::StringFunc::Path::GetFolderPath(irradianceTextureFullPath.data(), diffuseProbeGridFolder);
AZ::IO::SystemFile::CreateDir(diffuseProbeGridFolder.c_str());
// check out the files in source control
CheckoutSourceTextureFile(irradianceTextureFullPath);
CheckoutSourceTextureFile(distanceTextureFullPath);
CheckoutSourceTextureFile(relocationTextureFullPath);
CheckoutSourceTextureFile(classificationTextureFullPath);
// update the configuration
AzToolsFramework::ScopedUndoBatch undoBatch("DiffuseProbeGrid bake");
configuration.m_bakedIrradianceTextureRelativePath = irradianceTextureRelativePath;
configuration.m_bakedDistanceTextureRelativePath = distanceTextureRelativePath;
configuration.m_bakedRelocationTextureRelativePath = relocationTextureRelativePath;
configuration.m_bakedClassificationTextureRelativePath = classificationTextureRelativePath;
SetDirty();
// callback for the texture readback
DiffuseProbeGridBakeTexturesCallback bakeTexturesCallback = [=](
DiffuseProbeGridTexture irradianceTexture,
DiffuseProbeGridTexture distanceTexture,
DiffuseProbeGridTexture relocationTexture,
DiffuseProbeGridTexture classificationTexture)
{
// irradiance
{
AZ::DdsFile::DdsFileData fileData = { irradianceTexture.m_size, irradianceTexture.m_format, irradianceTexture.m_data.get() };
[[maybe_unused]] const auto outcome = AZ::DdsFile::WriteFile(irradianceTextureFullPath, fileData);
AZ_Assert(outcome.IsSuccess(), "Failed to write Irradiance texture .dds file [%s]", irradianceTextureFullPath.c_str());
}
// distance
{
AZ::DdsFile::DdsFileData fileData = { distanceTexture.m_size, distanceTexture.m_format, distanceTexture.m_data.get() };
[[maybe_unused]] const auto outcome = AZ::DdsFile::WriteFile(distanceTextureFullPath, fileData);
AZ_Assert(outcome.IsSuccess(), "Failed to write Distance texture .dds file [%s]", distanceTextureFullPath.c_str());
}
// relocation
{
AZ::DdsFile::DdsFileData fileData = { relocationTexture.m_size, relocationTexture.m_format, relocationTexture.m_data.get() };
[[maybe_unused]] const auto outcome = AZ::DdsFile::WriteFile(relocationTextureFullPath, fileData);
AZ_Assert(outcome.IsSuccess(), "Failed to write Relocation texture .dds file [%s]", relocationTextureFullPath.c_str());
}
// classification
{
AZ::DdsFile::DdsFileData fileData = { classificationTexture.m_size, classificationTexture.m_format, classificationTexture.m_data.get() };
[[maybe_unused]] const auto outcome = AZ::DdsFile::WriteFile(classificationTextureFullPath, fileData);
AZ_Assert(outcome.IsSuccess(), "Failed to write Classification texture .dds file [%s]", classificationTextureFullPath.c_str());
}
m_bakeInProgress = false;
};
m_bakeInProgress = true;
m_controller.BakeTextures(bakeTexturesCallback);
while (m_bakeInProgress)
{
QApplication::processEvents();
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(100));
}
QMessageBox::information(
QApplication::activeWindow(),
"Diffuse Probe Grid",
"Successfully baked Diffuse Probe Grid textures.",
QMessageBox::Ok);
return AZ::Edit::PropertyRefreshLevels::None;
}
AZStd::string EditorDiffuseProbeGridComponent::ValidateOrCreateNewTexturePath(const AZStd::string& configurationRelativePath, const char* fileSuffix)
{
AZStd::string relativePath = configurationRelativePath;
AZStd::string fullPath;
char projectPath[AZ_MAX_PATH_LEN];
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN);
if (!relativePath.empty())
{
// test to see if the texture file is actually there, if it was removed we need to
// generate a new filename, otherwise it will cause an error in the asset system
AzFramework::StringFunc::Path::Join(projectPath, configurationRelativePath.c_str(), fullPath, true, true);
if (!AZ::IO::FileIOBase::GetInstance()->Exists(fullPath.c_str()))
{
// file does not exist, clear the relative path so we generate a new name
relativePath.clear();
}
}
// build a new image path if necessary
if (relativePath.empty())
{
// the file name is a combination of the entity name, a UUID, and the filemask
Entity* entity = GetEntity();
AZ_Assert(entity, "DiffuseProbeGrid entity is null");
AZ::Uuid uuid = AZ::Uuid::CreateRandom();
AZStd::string uuidString;
uuid.ToString(uuidString);
relativePath = "DiffuseProbeGrids/" + entity->GetName() + uuidString + fileSuffix;
// replace any invalid filename characters
auto invalidCharacters = [](char letter)
{
return
letter == ':' || letter == '"' || letter == '\'' ||
letter == '{' || letter == '}' ||
letter == '<' || letter == '>';
};
AZStd::replace_if(relativePath.begin(), relativePath.end(), invalidCharacters, '_');
}
return relativePath;
}
void EditorDiffuseProbeGridComponent::CheckoutSourceTextureFile(const AZStd::string& fullPath)
{
bool checkedOutSuccessfully = false;
using ApplicationBus = AzToolsFramework::ToolsApplicationRequestBus;
ApplicationBus::BroadcastResult(
checkedOutSuccessfully,
&ApplicationBus::Events::RequestEditForFileBlocking,
fullPath.c_str(),
"Checking out for edit...",
ApplicationBus::Events::RequestEditProgressCallback());
}
} // namespace Render
} // namespace AZ
@@ -12,8 +12,10 @@
#pragma once
#include <AzCore/Component/TickBus.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <DiffuseProbeGrid/DiffuseProbeGridComponent.h>
#include <DiffuseProbeGrid/DiffuseProbeGridComponentConstants.h>
#include <Atom/Feature/Utils/EditorRenderComponentAdapter.h>
@@ -26,6 +28,8 @@ namespace AZ
: public EditorRenderComponentAdapter<DiffuseProbeGridComponentController, DiffuseProbeGridComponent, DiffuseProbeGridComponentConfig>
, private AzToolsFramework::EditorComponentSelectionRequestsBus::Handler
, private AzFramework::EntityDebugDisplayEventBus::Handler
, private AZ::TickBus::Handler
, private AzToolsFramework::EditorEntityInfoNotificationBus::Handler
{
public:
using BaseClass = EditorRenderComponentAdapter<DiffuseProbeGridComponentController, DiffuseProbeGridComponent, DiffuseProbeGridComponentConfig>;
@@ -41,10 +45,22 @@ namespace AZ
void Deactivate() override;
private:
// AZ::TickBus overrides
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
// EditorComponentSelectionRequestsBus overrides
AZ::Aabb GetEditorSelectionBoundsViewport(const AzFramework::ViewportInfo& viewportInfo) override;
bool SupportsEditorRayIntersect() override;
// EditorEntityInfoNotifications overrides
void OnEntityInfoUpdatedVisibility(AZ::EntityId entityId, bool visible) override;
// helper functions
AZStd::string ValidateOrCreateNewTexturePath(const AZStd::string& relativePath, const char* fileSuffix);
void CheckoutSourceTextureFile(const AZStd::string& fullPath);
void CheckTextureAssetNotification(const AZStd::string& relativePath, Data::Asset<RPI::StreamingImageAsset>& configurationAsset);
// property change notifications
AZ::Outcome<void, AZStd::string> OnProbeSpacingValidateX(void* newValue, const AZ::Uuid& valueType);
AZ::Outcome<void, AZStd::string> OnProbeSpacingValidateY(void* newValue, const AZ::Uuid& valueType);
@@ -53,6 +69,13 @@ namespace AZ
AZ::u32 OnAmbientMultiplierChanged();
AZ::u32 OnViewBiasChanged();
AZ::u32 OnNormalBiasChanged();
AZ::u32 OnEditorModeChanged();
AZ::u32 OnRuntimeModeChanged();
AZ::Outcome<void, AZStd::string> OnModeChangeValidate(void* newValue, const AZ::Uuid& valueType);
// Button handler
AZ::u32 BakeDiffuseProbeGrid();
AZ::u32 GetBakeDiffuseProbeGridVisibilitySetting();
// properties
float m_probeSpacingX = DefaultDiffuseProbeGridSpacing;
@@ -61,6 +84,12 @@ namespace AZ
float m_ambientMultiplier = DefaultDiffuseProbeGridAmbientMultiplier;
float m_viewBias = DefaultDiffuseProbeGridViewBias;
float m_normalBias = DefaultDiffuseProbeGridNormalBias;
DiffuseProbeGridMode m_editorMode = DiffuseProbeGridMode::RealTime;
DiffuseProbeGridMode m_runtimeMode = DiffuseProbeGridMode::RealTime;
// flags
bool m_editorModeSet = false;
AZStd::atomic_bool m_bakeInProgress = false;
};
} // namespace Render
} // namespace AZ
@@ -184,7 +184,7 @@ namespace AZ
void MaterialPropertyInspector::AddUvNamesGroup()
{
const AZStd::string groupNameId = AZ::RPI::UvGroupName;
const AZStd::string groupDisplayName = "UV Names";
const AZStd::string groupDisplayName = "UV Sets";
const AZStd::string groupDescription = "UV set names in this material, which can be renamed to match those in the model.";
auto& group = m_groups[groupNameId];
@@ -78,11 +78,9 @@ namespace AZ
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorMaterialComponentSlot>()
->Version(4, &EditorMaterialComponentSlot::ConvertVersion)
->Version(5, &EditorMaterialComponentSlot::ConvertVersion)
->Field("id", &EditorMaterialComponentSlot::m_id)
->Field("materialAsset", &EditorMaterialComponentSlot::m_materialAsset)
->Field("propertyOverrides", &EditorMaterialComponentSlot::m_propertyOverrides)
->Field("matModUvOverrides", &EditorMaterialComponentSlot::m_matModUvOverrides)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
@@ -140,9 +140,16 @@ namespace AZ
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
float t;
AZ::Vector3 ignoreNormal;
constexpr float rayLength = 1000.0f;
if (m_controller.GetModel()->RayIntersection(transform, nonUniformScale, src, dir * rayLength, t, ignoreNormal))
{
distance = rayLength * t;
return true;
}
return m_controller.GetModel()->RayIntersection(transform, nonUniformScale, src, dir, distance, ignoreNormal);
return false;
}
bool EditorMeshComponent::SupportsEditorRayIntersect()
@@ -35,14 +35,13 @@ namespace AZ
, private MeshComponentNotificationBus::Handler
{
public:
using BaseClass = EditorRenderComponentAdapter<MeshComponentController, MeshComponent, MeshComponentConfig>;
AZ_EDITOR_COMPONENT(AZ::Render::EditorMeshComponent, EditorMeshComponentTypeId, BaseClass);
static void Reflect(AZ::ReflectContext* context);
EditorMeshComponent() = default;
EditorMeshComponent(const MeshComponentConfig& config);
explicit EditorMeshComponent(const MeshComponentConfig& config);
// AZ::Component overrides ...
void Activate() override;
@@ -25,12 +25,11 @@ namespace AZ
: public AzFramework::Components::ComponentAdapter<MeshComponentController, MeshComponentConfig>
{
public:
using BaseClass = AzFramework::Components::ComponentAdapter<MeshComponentController, MeshComponentConfig>;
AZ_COMPONENT(AZ::Render::MeshComponent, MeshComponentTypeId, BaseClass);
MeshComponent() = default;
MeshComponent(const MeshComponentConfig& config);
explicit MeshComponent(const MeshComponentConfig& config);
static void Reflect(AZ::ReflectContext* context);
};
@@ -177,28 +177,33 @@ namespace AZ
FixUpModelAsset(m_configuration.m_modelAsset);
}
void MeshComponentController::Activate(AZ::EntityId entityId)
void MeshComponentController::Activate(const AZ::EntityComponentIdPair& entityComponentIdPair)
{
FixUpModelAsset(m_configuration.m_modelAsset);
m_entityId = entityId;
const AZ::EntityId entityId = entityComponentIdPair.GetEntityId();
m_entityComponentIdPair = entityComponentIdPair;
m_transformInterface = TransformBus::FindFirstHandler(m_entityId);
m_transformInterface = TransformBus::FindFirstHandler(entityId);
AZ_Warning("MeshComponentController", m_transformInterface, "Unable to attach to a TransformBus handler. This mesh will always be rendered at the origin.");
m_meshFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity<MeshFeatureProcessorInterface>(m_entityId);
m_meshFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity<MeshFeatureProcessorInterface>(entityId);
AZ_Error("MeshComponentController", m_meshFeatureProcessor, "Unable to find a MeshFeatureProcessorInterface on the entityId.");
m_cachedNonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(m_cachedNonUniformScale, m_entityId, &AZ::NonUniformScaleRequests::GetScale);
AZ::NonUniformScaleRequestBus::Event(m_entityId, &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent,
AZ::NonUniformScaleRequestBus::EventResult(m_cachedNonUniformScale, entityId, &AZ::NonUniformScaleRequests::GetScale);
AZ::NonUniformScaleRequestBus::Event(entityId, &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent,
m_nonUniformScaleChangedHandler);
MeshComponentRequestBus::Handler::BusConnect(m_entityId);
TransformNotificationBus::Handler::BusConnect(m_entityId);
MaterialReceiverRequestBus::Handler::BusConnect(m_entityId);
MaterialComponentNotificationBus::Handler::BusConnect(m_entityId);
AzFramework::BoundsRequestBus::Handler::BusConnect(m_entityId);
MeshComponentRequestBus::Handler::BusConnect(entityId);
TransformNotificationBus::Handler::BusConnect(entityId);
MaterialReceiverRequestBus::Handler::BusConnect(entityId);
MaterialComponentNotificationBus::Handler::BusConnect(entityId);
AzFramework::BoundsRequestBus::Handler::BusConnect(entityId);
AzFramework::EntityContextId contextId;
AzFramework::EntityIdContextQueryBus::EventResult(
contextId, entityId, &AzFramework::EntityIdContextQueries::GetOwningContextId);
AzFramework::RenderGeometry::IntersectionRequestBus::Handler::BusConnect({entityId, contextId});
//Buses must be connected before RegisterModel in case requests are made as a result of HandleModelChange
RegisterModel();
@@ -209,6 +214,7 @@ namespace AZ
// Buses must be disconnected after unregistering the model, otherwise they can't deliver the events during the process.
UnregisterModel();
AzFramework::RenderGeometry::IntersectionRequestBus::Handler::BusDisconnect();
AzFramework::BoundsRequestBus::Handler::BusDisconnect();
MeshComponentRequestBus::Handler::BusDisconnect();
TransformNotificationBus::Handler::BusDisconnect();
@@ -219,7 +225,7 @@ namespace AZ
m_meshFeatureProcessor = nullptr;
m_transformInterface = nullptr;
m_entityId = AZ::EntityId(AZ::EntityId::InvalidEntityId);
m_entityComponentIdPair = AZ::EntityComponentIdPair(AZ::EntityId(), AZ::InvalidComponentId);
m_configuration.m_modelAsset.Release();
}
@@ -293,10 +299,11 @@ namespace AZ
Data::Asset<RPI::ModelAsset> modelAsset = m_meshFeatureProcessor->GetModelAsset(m_meshHandle);
if (model && modelAsset)
{
const AZ::EntityId entityId = m_entityComponentIdPair.GetEntityId();
m_configuration.m_modelAsset = modelAsset;
MeshComponentNotificationBus::Event(m_entityId, &MeshComponentNotificationBus::Events::OnModelReady, m_configuration.m_modelAsset, model);
MaterialReceiverNotificationBus::Event(m_entityId, &MaterialReceiverNotificationBus::Events::OnMaterialAssignmentsChanged);
AZ::Interface<AzFramework::IEntityBoundsUnion>::Get()->RefreshEntityLocalBoundsUnion(m_entityId);
MeshComponentNotificationBus::Event(entityId, &MeshComponentNotificationBus::Events::OnModelReady, m_configuration.m_modelAsset, model);
MaterialReceiverNotificationBus::Event(entityId, &MaterialReceiverNotificationBus::Events::OnMaterialAssignmentsChanged);
AZ::Interface<AzFramework::IEntityBoundsUnion>::Get()->RefreshEntityLocalBoundsUnion(entityId);
}
}
@@ -304,8 +311,10 @@ namespace AZ
{
if (m_meshFeatureProcessor && m_configuration.m_modelAsset.GetId().IsValid())
{
const AZ::EntityId entityId = m_entityComponentIdPair.GetEntityId();
MaterialAssignmentMap materials;
MaterialComponentRequestBus::EventResult(materials, m_entityId, &MaterialComponentRequests::GetMaterialOverrides);
MaterialComponentRequestBus::EventResult(materials, entityId, &MaterialComponentRequests::GetMaterialOverrides);
m_meshFeatureProcessor->ReleaseMesh(m_meshHandle);
m_meshHandle = m_meshFeatureProcessor->AcquireMesh(m_configuration.m_modelAsset, materials,
@@ -330,7 +339,8 @@ namespace AZ
{
if (m_meshFeatureProcessor && m_meshHandle.IsValid())
{
MeshComponentNotificationBus::Event(m_entityId, &MeshComponentNotificationBus::Events::OnModelPreDestroy);
MeshComponentNotificationBus::Event(
m_entityComponentIdPair.GetEntityId(), &MeshComponentNotificationBus::Events::OnModelPreDestroy);
m_meshFeatureProcessor->ReleaseMesh(m_meshHandle);
}
}
@@ -462,5 +472,30 @@ namespace AZ
return Aabb::CreateNull();
}
}
AzFramework::RenderGeometry::RayResult MeshComponentController::RenderGeometryIntersect(
const AzFramework::RenderGeometry::RayRequest& ray)
{
AzFramework::RenderGeometry::RayResult result;
if (const Data::Instance<RPI::Model> model = GetModel())
{
float t;
AZ::Vector3 normal;
if (model->RayIntersection(
m_transformInterface->GetWorldTM(), m_cachedNonUniformScale, ray.m_startWorldPosition,
ray.m_endWorldPosition - ray.m_startWorldPosition, t, normal))
{
// fill in ray result structure after successful intersection
const auto intersectionLine = (ray.m_endWorldPosition - ray.m_startWorldPosition);
result.m_uv = AZ::Vector2::CreateZero();
result.m_worldPosition = ray.m_startWorldPosition + intersectionLine * t;
result.m_worldNormal = normal;
result.m_distance = intersectionLine.GetLength() * t;
result.m_entityAndComponent = m_entityComponentIdPair;
}
}
return result;
}
} // namespace Render
} // namespace AZ
@@ -13,11 +13,13 @@
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Component/ComponentBus.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/NonUniformScaleBus.h>
#include <AtomCore/Instance/InstanceDatabase.h>
#include <AzFramework/Render/GeometryIntersectionBus.h>
#include <AzFramework/Visibility/BoundsBus.h>
#include <Atom/RPI.Public/Model/Model.h>
@@ -32,9 +34,7 @@ namespace AZ
{
namespace Render
{
/**
* A configuration structure for the MeshComponentController
*/
//! A configuration structure for the MeshComponentController
class MeshComponentConfig final
: public AZ::ComponentConfig
{
@@ -57,6 +57,7 @@ namespace AZ
class MeshComponentController final
: private MeshComponentRequestBus::Handler
, public AzFramework::BoundsRequestBus::Handler
, public AzFramework::RenderGeometry::IntersectionRequestBus::Handler
, private TransformNotificationBus::Handler
, private MaterialReceiverRequestBus::Handler
, private MaterialComponentNotificationBus::Handler
@@ -77,7 +78,7 @@ namespace AZ
MeshComponentController() = default;
MeshComponentController(const MeshComponentConfig& config);
void Activate(AZ::EntityId entityId);
void Activate(const AZ::EntityComponentIdPair& entityComponentIdPair);
void Deactivate();
void SetConfiguration(const MeshComponentConfig& config);
const MeshComponentConfig& GetConfiguration() const;
@@ -103,10 +104,13 @@ namespace AZ
void SetVisibility(bool visible) override;
bool GetVisibility() const override;
// BoundsRequestBus and MeshComponentRequestBus ...
// BoundsRequestBus and MeshComponentRequestBus overrides ...
AZ::Aabb GetWorldBounds() override;
AZ::Aabb GetLocalBounds() override;
// IntersectionRequestBus overrides ...
AzFramework::RenderGeometry::RayResult RenderGeometryIntersect(const AzFramework::RenderGeometry::RayRequest& ray) override;
// TransformNotificationBus::Handler overrides ...
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
@@ -134,7 +138,7 @@ namespace AZ
Render::MeshFeatureProcessorInterface* m_meshFeatureProcessor = nullptr;
Render::MeshFeatureProcessorInterface::MeshHandle m_meshHandle;
TransformInterface* m_transformInterface = nullptr;
AZ::EntityId m_entityId;
AZ::EntityComponentIdPair m_entityComponentIdPair;
bool m_isVisible = true;
MeshComponentConfig m_configuration;
AZ::Vector3 m_cachedNonUniformScale = AZ::Vector3::CreateOne();
@@ -209,8 +209,8 @@ namespace AZ
AZ::Vector3 position = AZ::Vector3::CreateZero();
AZ::TransformBus::EventResult(position, GetEntityId(), &AZ::TransformBus::Events::GetWorldTranslation);
AZ::Vector3 scale = AZ::Vector3::CreateOne();
AZ::TransformBus::EventResult(scale, GetEntityId(), &AZ::TransformBus::Events::GetLocalScale);
float scale = 1.0f;
AZ::TransformBus::EventResult(scale, GetEntityId(), &AZ::TransformBus::Events::GetLocalUniformScale);
// draw AABB at probe position using the inner dimensions
Color color(0.0f, 0.0f, 1.0f, 1.0f);
@@ -32,32 +32,29 @@ namespace AZ
void ReleaseResourcesStep::Start()
{
m_context->GetData()->m_defaultMaterialAsset.Release();
m_context->GetData()->m_defaultModelAsset.Release();
m_context->GetData()->m_materialAsset.Release();
m_context->GetData()->m_modelAsset.Release();
auto data = m_context->GetData();
data->m_defaultMaterialAsset.Release();
data->m_defaultModelAsset.Release();
data->m_materialAsset.Release();
data->m_modelAsset.Release();
data->m_lightingPresetAsset.Release();
if (m_context->GetData()->m_modelEntity)
if (data->m_modelEntity)
{
AzFramework::EntityContextRequestBus::Event(m_context->GetData()->m_entityContext->GetContextId(),
&AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_context->GetData()->m_modelEntity);
m_context->GetData()->m_modelEntity = nullptr;
AzFramework::EntityContextRequestBus::Event(data->m_entityContext->GetContextId(),
&AzFramework::EntityContextRequestBus::Events::DestroyEntity, data->m_modelEntity);
data->m_modelEntity = nullptr;
}
m_context->GetData()->m_frameworkScene->UnsetSubsystem<RPI::Scene>();
m_context->GetData()->m_scene->Deactivate();
m_context->GetData()->m_scene->RemoveRenderPipeline(m_context->GetData()->m_renderPipeline->GetId());
RPI::RPISystemInterface::Get()->UnregisterScene(m_context->GetData()->m_scene);
auto sceneSystem = AzFramework::SceneSystemInterface::Get();
AZ_Assert(sceneSystem, "Thumbnail system failed to get scene system implementation.");
[[maybe_unused]] bool sceneRemovedSuccessfully = sceneSystem->RemoveScene(m_context->GetData()->m_sceneName);
AZ_Assert(
sceneRemovedSuccessfully, "Thumbnail system was unable to remove scene '%s' from the scene system.",
m_context->GetData()->m_sceneName.c_str());
m_context->GetData()->m_scene = nullptr;
m_context->GetData()->m_renderPipeline = nullptr;
data->m_scene->Deactivate();
data->m_scene->RemoveRenderPipeline(data->m_renderPipeline->GetId());
RPI::RPISystemInterface::Get()->UnregisterScene(data->m_scene);
data->m_frameworkScene->UnsetSubsystem(data->m_scene);
data->m_frameworkScene->UnsetSubsystem(data->m_entityContext.get());
data->m_scene = nullptr;
data->m_frameworkScene = nullptr;
data->m_renderPipeline = nullptr;
}
} // namespace Thumbnails
} // namespace LyIntegration