Merge branch 'development' into issues/exception_handling
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> # Conflicts: # Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp
This commit is contained in:
-3
@@ -10,8 +10,5 @@ ly_add_external_target(
|
||||
NAME renderdoc
|
||||
3RDPARTY_ROOT_DIRECTORY "${LY_RENDERDOC_PATH}"
|
||||
VERSION
|
||||
INCLUDE_DIRECTORIES
|
||||
.
|
||||
include
|
||||
COMPILE_DEFINITIONS USE_RENDERDOC
|
||||
)
|
||||
|
||||
@@ -7,3 +7,4 @@
|
||||
#
|
||||
|
||||
set(RENDERDOC_RUNTIME_DEPENDENCIES "${BASE_PATH}/lib/librenderdoc.so")
|
||||
set(RENDERDOC_INCLUDE_DIRECTORIES "include")
|
||||
|
||||
@@ -7,3 +7,4 @@
|
||||
#
|
||||
|
||||
set(RENDERDOC_RUNTIME_DEPENDENCIES "${BASE_PATH}/renderdoc.dll")
|
||||
set(RENDERDOC_INCLUDE_DIRECTORIES ".")
|
||||
|
||||
@@ -36,6 +36,7 @@ ly_add_target(
|
||||
Gem::Atom_RPI.Edit
|
||||
Gem::Atom_RPI.Public
|
||||
Gem::Atom_RHI.Reflect
|
||||
Gem::Atom_Feature_Common.Static
|
||||
Gem::Atom_Bootstrap.Headers
|
||||
)
|
||||
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
//! Interface for describing scene content that will be rendered using the PreviewRenderer
|
||||
class PreviewContent
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PreviewContent, AZ::SystemAllocator, 0);
|
||||
|
||||
PreviewContent() = default;
|
||||
virtual ~PreviewContent() = default;
|
||||
|
||||
//! Initiate loading of scene content, models, materials, etc
|
||||
virtual void Load() = 0;
|
||||
|
||||
//! Return true if content is loaded and ready to render
|
||||
virtual bool IsReady() const = 0;
|
||||
|
||||
//! Return true if content failed to load
|
||||
virtual bool IsError() const = 0;
|
||||
|
||||
//! Report any issues encountered while loading
|
||||
virtual void ReportErrors() = 0;
|
||||
|
||||
//! Prepare or pose content before rendering
|
||||
virtual void Update() = 0;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/RPI.Public/Base.h>
|
||||
#include <Atom/RPI.Public/Pass/AttachmentReadback.h>
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewContent.h>
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRendererState.h>
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h>
|
||||
#include <AzFramework/Entity/GameEntityContextComponent.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class Scene;
|
||||
}
|
||||
|
||||
class QPixmap;
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
//! Processes requests for setting up content that gets rendered to a texture and captured to an image
|
||||
class PreviewRenderer final : public PreviewerFeatureProcessorProviderBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PreviewRenderer, AZ::SystemAllocator, 0);
|
||||
|
||||
PreviewRenderer(const AZStd::string& sceneName, const AZStd::string& pipelineName);
|
||||
~PreviewRenderer();
|
||||
|
||||
struct CaptureRequest final
|
||||
{
|
||||
int m_size = 512;
|
||||
AZStd::shared_ptr<PreviewContent> m_content;
|
||||
AZStd::function<void()> m_captureFailedCallback;
|
||||
AZStd::function<void(const QPixmap&)> m_captureCompleteCallback;
|
||||
};
|
||||
|
||||
void AddCaptureRequest(const CaptureRequest& captureRequest);
|
||||
|
||||
AZ::RPI::ScenePtr GetScene() const;
|
||||
AZ::RPI::ViewPtr GetView() const;
|
||||
AZ::Uuid GetEntityContextId() const;
|
||||
|
||||
void ProcessCaptureRequests();
|
||||
void CancelCaptureRequest();
|
||||
void CompleteCaptureRequest();
|
||||
|
||||
void LoadContent();
|
||||
void UpdateLoadContent();
|
||||
void CancelLoadContent();
|
||||
|
||||
void PoseContent();
|
||||
|
||||
bool StartCapture();
|
||||
void EndCapture();
|
||||
|
||||
private:
|
||||
//! AZ::Render::PreviewerFeatureProcessorProviderBus::Handler interface overrides...
|
||||
void GetRequiredFeatureProcessors(AZStd::unordered_set<AZStd::string>& featureProcessors) const override;
|
||||
|
||||
static constexpr float AspectRatio = 1.0f;
|
||||
static constexpr float NearDist = 0.001f;
|
||||
static constexpr float FarDist = 100.0f;
|
||||
static constexpr float FieldOfView = AZ::Constants::HalfPi;
|
||||
|
||||
AZ::RPI::ScenePtr m_scene;
|
||||
AZStd::shared_ptr<AzFramework::Scene> m_frameworkScene;
|
||||
AZ::RPI::RenderPipelinePtr m_renderPipeline;
|
||||
AZ::RPI::ViewPtr m_view;
|
||||
AZStd::vector<AZStd::string> m_passHierarchy;
|
||||
AZStd::unique_ptr<AzFramework::EntityContext> m_entityContext;
|
||||
|
||||
//! Incoming requests are appended to this queue and processed one at a time in OnTick function.
|
||||
AZStd::queue<CaptureRequest> m_captureRequestQueue;
|
||||
CaptureRequest m_currentCaptureRequest;
|
||||
|
||||
AZStd::unique_ptr<PreviewRendererState> m_state;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
class PreviewRenderer;
|
||||
|
||||
//! PreviewRendererState decouples PreviewRenderer logic into easy-to-understand and debug pieces
|
||||
class PreviewRendererState
|
||||
{
|
||||
public:
|
||||
explicit PreviewRendererState(PreviewRenderer* renderer)
|
||||
: m_renderer(renderer)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~PreviewRendererState() = default;
|
||||
|
||||
protected:
|
||||
PreviewRenderer* m_renderer = {};
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
//! PreviewerFeatureProcessorProviderRequests allows registering custom Feature Processors for preview image generation
|
||||
class PreviewerFeatureProcessorProviderRequests : public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//! Get a list of custom feature processors to register with preview image renderer
|
||||
virtual void GetRequiredFeatureProcessors(AZStd::unordered_set<AZStd::string>& featureProcessors) const = 0;
|
||||
};
|
||||
|
||||
using PreviewerFeatureProcessorProviderBus = AZ::EBus<PreviewerFeatureProcessorProviderRequests>;
|
||||
} // namespace AtomToolsFramework
|
||||
+2
-2
@@ -25,7 +25,7 @@
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
//! The RenderViewportWidget class is a Qt wrapper around an Atom viewport.
|
||||
//! RenderViewportWidget renders to an internal window using RPI::ViewportContext
|
||||
//! RenderViewportWidget renders to an internal window using AZ::RPI::ViewportContext
|
||||
//! and delegates input via its internal ViewportControllerList.
|
||||
//! @see AZ::RPI::ViewportContext for Atom's API for setting up
|
||||
class RenderViewportWidget
|
||||
@@ -39,7 +39,7 @@ namespace AtomToolsFramework
|
||||
public:
|
||||
//! Creates a RenderViewportWidget.
|
||||
//! Requires the Atom RPI to be initialized in order
|
||||
//! to internally construct an RPI::ViewportContext.
|
||||
//! to internally construct an AZ::RPI::ViewportContext.
|
||||
//! If initializeViewportContext is set to false, nothing will be displayed on-screen until InitiliazeViewportContext is called.
|
||||
explicit RenderViewportWidget(QWidget* parent = nullptr, bool shouldInitializeViewportContext = true);
|
||||
~RenderViewportWidget();
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/Feature/Utils/FrameCaptureBus.h>
|
||||
#include <Atom/RPI.Public/Pass/Specific/RenderToTexturePass.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
#include <Atom/RPI.Reflect/System/RenderPipelineDescriptor.h>
|
||||
#include <Atom/RPI.Reflect/System/SceneDescriptor.h>
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRenderer.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzFramework/Scene/Scene.h>
|
||||
#include <AzFramework/Scene/SceneSystemInterface.h>
|
||||
#include <PreviewRenderer/PreviewRendererCaptureState.h>
|
||||
#include <PreviewRenderer/PreviewRendererIdleState.h>
|
||||
#include <PreviewRenderer/PreviewRendererLoadState.h>
|
||||
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
PreviewRenderer::PreviewRenderer(const AZStd::string& sceneName, const AZStd::string& pipelineName)
|
||||
{
|
||||
PreviewerFeatureProcessorProviderBus::Handler::BusConnect();
|
||||
|
||||
m_entityContext = AZStd::make_unique<AzFramework::EntityContext>();
|
||||
m_entityContext->InitContext();
|
||||
|
||||
// Create and register a scene with all required feature processors
|
||||
AZStd::unordered_set<AZStd::string> featureProcessors;
|
||||
PreviewerFeatureProcessorProviderBus::Broadcast(
|
||||
&PreviewerFeatureProcessorProviderBus::Handler::GetRequiredFeatureProcessors, featureProcessors);
|
||||
|
||||
AZ::RPI::SceneDescriptor sceneDesc;
|
||||
sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end());
|
||||
m_scene = AZ::RPI::Scene::CreateScene(sceneDesc);
|
||||
|
||||
// Bind m_frameworkScene to the entity context's AzFramework::Scene
|
||||
auto sceneSystem = AzFramework::SceneSystemInterface::Get();
|
||||
AZ_Assert(sceneSystem, "Failed to get scene system implementation.");
|
||||
|
||||
AZ::Outcome<AZStd::shared_ptr<AzFramework::Scene>, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(sceneName);
|
||||
AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str());
|
||||
|
||||
m_frameworkScene = createSceneOutcome.TakeValue();
|
||||
m_frameworkScene->SetSubsystem(m_scene);
|
||||
m_frameworkScene->SetSubsystem(m_entityContext.get());
|
||||
|
||||
// Create a render pipeline from the specified asset for the window context and add the pipeline to the scene
|
||||
AZ::RPI::RenderPipelineDescriptor pipelineDesc;
|
||||
pipelineDesc.m_mainViewTagName = "MainCamera";
|
||||
pipelineDesc.m_name = pipelineName;
|
||||
pipelineDesc.m_rootPassTemplate = "MainPipelineRenderToTexture";
|
||||
|
||||
// We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue
|
||||
// [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost
|
||||
pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4;
|
||||
m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc);
|
||||
m_scene->AddRenderPipeline(m_renderPipeline);
|
||||
m_scene->Activate();
|
||||
AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene);
|
||||
m_passHierarchy.push_back(pipelineName);
|
||||
m_passHierarchy.push_back("CopyToSwapChain");
|
||||
|
||||
// Connect camera to pipeline's default view after camera entity activated
|
||||
AZ::Matrix4x4 viewToClipMatrix;
|
||||
AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true);
|
||||
m_view = AZ::RPI::View::CreateView(AZ::Name("MainCamera"), AZ::RPI::View::UsageCamera);
|
||||
m_view->SetViewToClipMatrix(viewToClipMatrix);
|
||||
m_renderPipeline->SetDefaultView(m_view);
|
||||
|
||||
m_state.reset(new PreviewRendererIdleState(this));
|
||||
}
|
||||
|
||||
PreviewRenderer::~PreviewRenderer()
|
||||
{
|
||||
PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect();
|
||||
|
||||
m_state.reset();
|
||||
|
||||
m_currentCaptureRequest = {};
|
||||
m_captureRequestQueue = {};
|
||||
|
||||
m_scene->Deactivate();
|
||||
m_scene->RemoveRenderPipeline(m_renderPipeline->GetId());
|
||||
AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene);
|
||||
m_frameworkScene->UnsetSubsystem(m_scene);
|
||||
m_frameworkScene->UnsetSubsystem(m_entityContext.get());
|
||||
}
|
||||
|
||||
void PreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest)
|
||||
{
|
||||
m_captureRequestQueue.push(captureRequest);
|
||||
}
|
||||
|
||||
AZ::RPI::ScenePtr PreviewRenderer::GetScene() const
|
||||
{
|
||||
return m_scene;
|
||||
}
|
||||
|
||||
AZ::RPI::ViewPtr PreviewRenderer::GetView() const
|
||||
{
|
||||
return m_view;
|
||||
}
|
||||
|
||||
AZ::Uuid PreviewRenderer::GetEntityContextId() const
|
||||
{
|
||||
return m_entityContext->GetContextId();
|
||||
}
|
||||
|
||||
void PreviewRenderer::ProcessCaptureRequests()
|
||||
{
|
||||
if (!m_captureRequestQueue.empty())
|
||||
{
|
||||
// pop the next request to be rendered from the queue
|
||||
m_currentCaptureRequest = m_captureRequestQueue.front();
|
||||
m_captureRequestQueue.pop();
|
||||
|
||||
m_state.reset();
|
||||
m_state.reset(new PreviewRendererLoadState(this));
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewRenderer::CancelCaptureRequest()
|
||||
{
|
||||
if (m_currentCaptureRequest.m_captureFailedCallback)
|
||||
{
|
||||
m_currentCaptureRequest.m_captureFailedCallback();
|
||||
}
|
||||
m_state.reset();
|
||||
m_state.reset(new PreviewRendererIdleState(this));
|
||||
}
|
||||
|
||||
void PreviewRenderer::CompleteCaptureRequest()
|
||||
{
|
||||
m_state.reset();
|
||||
m_state.reset(new PreviewRendererIdleState(this));
|
||||
}
|
||||
|
||||
void PreviewRenderer::LoadContent()
|
||||
{
|
||||
m_currentCaptureRequest.m_content->Load();
|
||||
}
|
||||
|
||||
void PreviewRenderer::UpdateLoadContent()
|
||||
{
|
||||
if (m_currentCaptureRequest.m_content->IsReady())
|
||||
{
|
||||
m_state.reset();
|
||||
m_state.reset(new PreviewRendererCaptureState(this));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_currentCaptureRequest.m_content->IsError())
|
||||
{
|
||||
CancelLoadContent();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewRenderer::CancelLoadContent()
|
||||
{
|
||||
m_currentCaptureRequest.m_content->ReportErrors();
|
||||
CancelCaptureRequest();
|
||||
}
|
||||
|
||||
void PreviewRenderer::PoseContent()
|
||||
{
|
||||
m_currentCaptureRequest.m_content->Update();
|
||||
}
|
||||
|
||||
bool PreviewRenderer::StartCapture()
|
||||
{
|
||||
auto captureCompleteCallback = m_currentCaptureRequest.m_captureCompleteCallback;
|
||||
auto captureFailedCallback = m_currentCaptureRequest.m_captureFailedCallback;
|
||||
auto captureCallback = [captureCompleteCallback, captureFailedCallback](const AZ::RPI::AttachmentReadback::ReadbackResult& result)
|
||||
{
|
||||
if (result.m_dataBuffer)
|
||||
{
|
||||
if (captureCompleteCallback)
|
||||
{
|
||||
captureCompleteCallback(QPixmap::fromImage(QImage(
|
||||
result.m_dataBuffer.get()->data(), result.m_imageDescriptor.m_size.m_width,
|
||||
result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (captureFailedCallback)
|
||||
{
|
||||
captureFailedCallback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (auto renderToTexturePass = azrtti_cast<AZ::RPI::RenderToTexturePass*>(m_renderPipeline->GetRootPass().get()))
|
||||
{
|
||||
renderToTexturePass->ResizeOutput(m_currentCaptureRequest.m_size, m_currentCaptureRequest.m_size);
|
||||
}
|
||||
|
||||
m_renderPipeline->AddToRenderTickOnce();
|
||||
|
||||
bool startedCapture = false;
|
||||
AZ::Render::FrameCaptureRequestBus::BroadcastResult(
|
||||
startedCapture, &AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, m_passHierarchy,
|
||||
AZStd::string("Output"), captureCallback, AZ::RPI::PassAttachmentReadbackOption::Output);
|
||||
return startedCapture;
|
||||
}
|
||||
|
||||
void PreviewRenderer::EndCapture()
|
||||
{
|
||||
m_currentCaptureRequest = {};
|
||||
m_renderPipeline->RemoveFromRenderTick();
|
||||
}
|
||||
|
||||
void PreviewRenderer::GetRequiredFeatureProcessors(AZStd::unordered_set<AZStd::string>& featureProcessors) const
|
||||
{
|
||||
featureProcessors.insert({
|
||||
"AZ::Render::TransformServiceFeatureProcessor",
|
||||
"AZ::Render::MeshFeatureProcessor",
|
||||
"AZ::Render::SimplePointLightFeatureProcessor",
|
||||
"AZ::Render::SimpleSpotLightFeatureProcessor",
|
||||
"AZ::Render::PointLightFeatureProcessor",
|
||||
// There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow
|
||||
// flickering [ATOM-13568]
|
||||
// as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now.
|
||||
// Possibly re-enable with [GFX TODO][ATOM-13639]
|
||||
// "AZ::Render::DirectionalLightFeatureProcessor",
|
||||
"AZ::Render::DiskLightFeatureProcessor",
|
||||
"AZ::Render::CapsuleLightFeatureProcessor",
|
||||
"AZ::Render::QuadLightFeatureProcessor",
|
||||
"AZ::Render::DecalTextureArrayFeatureProcessor",
|
||||
"AZ::Render::ImageBasedLightFeatureProcessor",
|
||||
"AZ::Render::PostProcessFeatureProcessor",
|
||||
"AZ::Render::SkyBoxFeatureProcessor" });
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRenderer.h>
|
||||
#include <PreviewRenderer/PreviewRendererCaptureState.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
PreviewRendererCaptureState::PreviewRendererCaptureState(PreviewRenderer* renderer)
|
||||
: PreviewRendererState(renderer)
|
||||
{
|
||||
m_renderer->PoseContent();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
PreviewRendererCaptureState::~PreviewRendererCaptureState()
|
||||
{
|
||||
AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
m_renderer->EndCapture();
|
||||
}
|
||||
|
||||
void PreviewRendererCaptureState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
if ((m_ticksToCapture-- <= 0) && m_renderer->StartCapture())
|
||||
{
|
||||
AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewRendererCaptureState::OnCaptureFinished(
|
||||
[[maybe_unused]] AZ::Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info)
|
||||
{
|
||||
m_renderer->CompleteCaptureRequest();
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Feature/Utils/FrameCaptureBus.h>
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRendererState.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
//! PreviewRendererCaptureState renders a thumbnail to a pixmap and notifies MaterialOrModelThumbnail once finished
|
||||
class PreviewRendererCaptureState final
|
||||
: public PreviewRendererState
|
||||
, public AZ::TickBus::Handler
|
||||
, public AZ::Render::FrameCaptureNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
PreviewRendererCaptureState(PreviewRenderer* renderer);
|
||||
~PreviewRendererCaptureState();
|
||||
|
||||
private:
|
||||
//! AZ::TickBus::Handler interface overrides...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
//! AZ::Render::FrameCaptureNotificationBus::Handler overrides...
|
||||
void OnCaptureFinished(AZ::Render::FrameCaptureResult result, const AZStd::string& info) override;
|
||||
|
||||
//! This is necessary to suspend capture to allow a frame for Material and Mesh components to assign materials
|
||||
int m_ticksToCapture = 1;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRenderer.h>
|
||||
#include <PreviewRenderer/PreviewRendererIdleState.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
PreviewRendererIdleState::PreviewRendererIdleState(PreviewRenderer* renderer)
|
||||
: PreviewRendererState(renderer)
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
PreviewRendererIdleState::~PreviewRendererIdleState()
|
||||
{
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void PreviewRendererIdleState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
m_renderer->ProcessCaptureRequests();
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRendererState.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
//! PreviewRendererIdleState checks whether there are any new thumbnails that need to be rendered every tick
|
||||
class PreviewRendererIdleState final
|
||||
: public PreviewRendererState
|
||||
, public AZ::TickBus::Handler
|
||||
{
|
||||
public:
|
||||
PreviewRendererIdleState(PreviewRenderer* renderer);
|
||||
~PreviewRendererIdleState();
|
||||
|
||||
private:
|
||||
//! AZ::TickBus::Handler interface overrides...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRenderer.h>
|
||||
#include <PreviewRenderer/PreviewRendererLoadState.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
PreviewRendererLoadState::PreviewRendererLoadState(PreviewRenderer* renderer)
|
||||
: PreviewRendererState(renderer)
|
||||
{
|
||||
m_renderer->LoadContent();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
PreviewRendererLoadState::~PreviewRendererLoadState()
|
||||
{
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void PreviewRendererLoadState::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
if ((m_timeRemainingS += deltaTime) > TimeOutS)
|
||||
{
|
||||
m_renderer->CancelLoadContent();
|
||||
return;
|
||||
}
|
||||
|
||||
m_renderer->UpdateLoadContent();
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRendererState.h>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
//! PreviewRendererLoadState pauses further rendering until all assets used for rendering a thumbnail have been loaded
|
||||
class PreviewRendererLoadState final
|
||||
: public PreviewRendererState
|
||||
, public AZ::TickBus::Handler
|
||||
{
|
||||
public:
|
||||
PreviewRendererLoadState(PreviewRenderer* renderer);
|
||||
~PreviewRendererLoadState();
|
||||
|
||||
private:
|
||||
//! AZ::TickBus::Handler interface overrides...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
static constexpr float TimeOutS = 5.0f;
|
||||
float m_timeRemainingS = 0.0f;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
@@ -58,4 +58,15 @@ set(FILES
|
||||
Source/Window/AtomToolsMainWindow.cpp
|
||||
Source/Window/AtomToolsMainWindowSystemComponent.cpp
|
||||
Source/Window/AtomToolsMainWindowSystemComponent.h
|
||||
Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h
|
||||
Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h
|
||||
Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h
|
||||
Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h
|
||||
Source/PreviewRenderer/PreviewRenderer.cpp
|
||||
Source/PreviewRenderer/PreviewRendererIdleState.cpp
|
||||
Source/PreviewRenderer/PreviewRendererIdleState.h
|
||||
Source/PreviewRenderer/PreviewRendererLoadState.cpp
|
||||
Source/PreviewRenderer/PreviewRendererLoadState.h
|
||||
Source/PreviewRenderer/PreviewRendererCaptureState.cpp
|
||||
Source/PreviewRenderer/PreviewRendererCaptureState.h
|
||||
)
|
||||
@@ -1353,8 +1353,9 @@ namespace AZ::AtomBridge
|
||||
// if 2d draw need to project pos to screen first
|
||||
AzFramework::TextDrawParameters params;
|
||||
AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext();
|
||||
const auto dpiScaleFactor = viewportContext->GetDpiScalingFactor();
|
||||
params.m_drawViewportId = viewportContext->GetId(); // get the viewport ID so default viewport works
|
||||
params.m_position = AZ::Vector3(x, y, 1.0f);
|
||||
params.m_position = AZ::Vector3(x * dpiScaleFactor, y * dpiScaleFactor, 1.0f);
|
||||
params.m_color = m_rendState.m_color;
|
||||
params.m_scale = AZ::Vector2(size);
|
||||
params.m_hAlign = center ? AzFramework::TextHorizontalAlignment::Center : AzFramework::TextHorizontalAlignment::Left; //! Horizontal text alignment
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Feature/Material/MaterialAssignmentId.h>
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
class QPixmap;
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
//! EditorMaterialSystemComponentNotifications is an interface for handling notifications from EditorMaterialSystemComponent, like
|
||||
//! being informed that material preview images are available
|
||||
class EditorMaterialSystemComponentNotifications : public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||
|
||||
//! Notify that a material preview image is ready
|
||||
virtual void OnRenderMaterialPreviewComplete(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) = 0;
|
||||
};
|
||||
using EditorMaterialSystemComponentNotificationBus = AZ::EBus<EditorMaterialSystemComponentNotifications>;
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
+13
-3
@@ -5,20 +5,22 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Feature/Material/MaterialAssignmentId.h>
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <QPixmap>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
//! EditorMaterialSystemComponentRequests provides an interface to communicate with MaterialEditor
|
||||
class EditorMaterialSystemComponentRequests
|
||||
: public AZ::EBusTraits
|
||||
//! EditorMaterialSystemComponentRequests provides an interface for interacting with EditorMaterialSystemComponent, performing
|
||||
//! different operations like opening the material editor, the material instance inspector, and managing material preview images
|
||||
class EditorMaterialSystemComponentRequests : public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
// Only a single handler is allowed
|
||||
@@ -31,6 +33,14 @@ namespace AZ
|
||||
//! Open material instance editor
|
||||
virtual void OpenMaterialInspector(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0;
|
||||
|
||||
//! Generate a material preview image
|
||||
virtual void RenderMaterialPreview(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0;
|
||||
|
||||
//! Get recently rendered material preview image
|
||||
virtual QPixmap GetRenderedMaterialPreview(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const = 0;
|
||||
};
|
||||
using EditorMaterialSystemComponentRequestBus = AZ::EBus<EditorMaterialSystemComponentRequests>;
|
||||
} // namespace Render
|
||||
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
//! ThumbnailFeatureProcessorProviderRequests allows registering custom Feature Processors for thumbnail generation
|
||||
//! Duplicates will be ignored
|
||||
//! You can check minimal feature processors that are already registered in CommonThumbnailRenderer.cpp
|
||||
class ThumbnailFeatureProcessorProviderRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//! Get a list of custom feature processors to register with thumbnail renderer
|
||||
virtual const AZStd::vector<AZStd::string>& GetCustomFeatureProcessors() const = 0;
|
||||
};
|
||||
|
||||
using ThumbnailFeatureProcessorProviderBus = AZ::EBus<ThumbnailFeatureProcessorProviderRequests>;
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+44
-10
@@ -6,15 +6,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <EditorCommonFeaturesSystemComponent.h>
|
||||
#include <SkinnedMesh/SkinnedMeshDebugDisplay.h>
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/EditContextConstants.inl>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzToolsFramework/API/EditorCameraBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <EditorCommonFeaturesSystemComponent.h>
|
||||
#include <SharedPreview/SharedThumbnail.h>
|
||||
#include <SkinnedMesh/SkinnedMeshDebugDisplay.h>
|
||||
|
||||
#include <IEditor.h>
|
||||
|
||||
@@ -68,7 +70,7 @@ namespace AZ
|
||||
|
||||
void EditorCommonFeaturesSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
AZ_UNUSED(required);
|
||||
required.push_back(AZ_CRC_CE("ThumbnailerService"));
|
||||
}
|
||||
|
||||
void EditorCommonFeaturesSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
@@ -82,24 +84,23 @@ namespace AZ
|
||||
|
||||
void EditorCommonFeaturesSystemComponent::Activate()
|
||||
{
|
||||
m_renderer = AZStd::make_unique<AZ::LyIntegration::Thumbnails::CommonThumbnailRenderer>();
|
||||
m_previewerFactory = AZStd::make_unique <LyIntegration::CommonPreviewerFactory>();
|
||||
m_skinnedMeshDebugDisplay = AZStd::make_unique<SkinnedMeshDebugDisplay>();
|
||||
|
||||
AzToolsFramework::EditorLevelNotificationBus::Handler::BusConnect();
|
||||
AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusConnect();
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
||||
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void EditorCommonFeaturesSystemComponent::Deactivate()
|
||||
{
|
||||
AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect();
|
||||
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect();
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusDisconnect();
|
||||
|
||||
m_skinnedMeshDebugDisplay.reset();
|
||||
m_previewerFactory.reset();
|
||||
m_renderer.reset();
|
||||
TeardownThumbnails();
|
||||
}
|
||||
|
||||
void EditorCommonFeaturesSystemComponent::OnNewLevelCreated()
|
||||
@@ -191,6 +192,13 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void EditorCommonFeaturesSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile)
|
||||
{
|
||||
AZ::TickBus::QueueFunction([this](){
|
||||
SetupThumbnails();
|
||||
});
|
||||
}
|
||||
|
||||
const AzToolsFramework::AssetBrowser::PreviewerFactory* EditorCommonFeaturesSystemComponent::GetPreviewerFactory(
|
||||
const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const
|
||||
{
|
||||
@@ -199,7 +207,33 @@ namespace AZ
|
||||
|
||||
void EditorCommonFeaturesSystemComponent::OnApplicationAboutToStop()
|
||||
{
|
||||
TeardownThumbnails();
|
||||
}
|
||||
|
||||
void EditorCommonFeaturesSystemComponent::SetupThumbnails()
|
||||
{
|
||||
using namespace AzToolsFramework::Thumbnailer;
|
||||
using namespace LyIntegration;
|
||||
|
||||
ThumbnailerRequestsBus::Broadcast(
|
||||
&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SharedThumbnailCache),
|
||||
ThumbnailContext::DefaultContext);
|
||||
|
||||
m_renderer = AZStd::make_unique<AZ::LyIntegration::SharedThumbnailRenderer>();
|
||||
m_previewerFactory = AZStd::make_unique<LyIntegration::SharedPreviewerFactory>();
|
||||
}
|
||||
|
||||
void EditorCommonFeaturesSystemComponent::TeardownThumbnails()
|
||||
{
|
||||
using namespace AzToolsFramework::Thumbnailer;
|
||||
using namespace LyIntegration;
|
||||
|
||||
ThumbnailerRequestsBus::Broadcast(
|
||||
&ThumbnailerRequests::UnregisterThumbnailProvider, SharedThumbnailCache::ProviderName,
|
||||
ThumbnailContext::DefaultContext);
|
||||
|
||||
m_renderer.reset();
|
||||
m_previewerFactory.reset();
|
||||
}
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+16
-7
@@ -11,10 +11,10 @@
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include <AzToolsFramework/API/EditorLevelNotificationBus.h>
|
||||
#include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Previewer/PreviewerBus.h>
|
||||
#include <Thumbnails/Rendering/CommonThumbnailRenderer.h>
|
||||
#include <Source/Thumbnails/Preview/CommonPreviewerFactory.h>
|
||||
#include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
|
||||
#include <SharedPreview/SharedPreviewerFactory.h>
|
||||
#include <SharedPreview/SharedThumbnailRenderer.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -28,6 +28,7 @@ namespace AZ
|
||||
, public AzToolsFramework::EditorLevelNotificationBus::Handler
|
||||
, public AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler
|
||||
, public AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler
|
||||
, public AzFramework::AssetCatalogEventBus::Handler
|
||||
, public AzFramework::ApplicationLifecycleEvents::Bus::Handler
|
||||
{
|
||||
public:
|
||||
@@ -53,15 +54,23 @@ namespace AZ
|
||||
void OnNewLevelCreated() override;
|
||||
|
||||
// SliceEditorEntityOwnershipServiceBus overrides ...
|
||||
void OnSliceInstantiated(const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override;
|
||||
void OnSliceInstantiated(
|
||||
const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override;
|
||||
void OnSliceInstantiationFailed(const AZ::Data::AssetId&, const AzFramework::SliceInstantiationTicket&) override;
|
||||
|
||||
// AzFramework::AssetCatalogEventBus::Handler overrides ...
|
||||
void OnCatalogLoaded(const char* catalogFile) override;
|
||||
|
||||
// AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler overrides...
|
||||
const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override;
|
||||
const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory(
|
||||
const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override;
|
||||
|
||||
// AzFramework::ApplicationLifecycleEvents overrides...
|
||||
void OnApplicationAboutToStop() override;
|
||||
|
||||
void SetupThumbnails();
|
||||
void TeardownThumbnails();
|
||||
|
||||
private:
|
||||
AZStd::unique_ptr<SkinnedMeshDebugDisplay> m_skinnedMeshDebugDisplay;
|
||||
|
||||
@@ -69,8 +78,8 @@ namespace AZ
|
||||
AZStd::string m_atomLevelDefaultAssetPath{ "LevelAssets/default.slice" };
|
||||
float m_envProbeHeight{ 200.0f };
|
||||
|
||||
AZStd::unique_ptr<AZ::LyIntegration::Thumbnails::CommonThumbnailRenderer> m_renderer;
|
||||
AZStd::unique_ptr<LyIntegration::CommonPreviewerFactory> m_previewerFactory;
|
||||
AZStd::unique_ptr<AZ::LyIntegration::SharedThumbnailRenderer> m_renderer;
|
||||
AZStd::unique_ptr<LyIntegration::SharedPreviewerFactory> m_previewerFactory;
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+14
@@ -148,11 +148,13 @@ namespace AZ
|
||||
BaseClass::Activate();
|
||||
MaterialReceiverNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
MaterialComponentNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusConnect();
|
||||
UpdateMaterialSlots();
|
||||
}
|
||||
|
||||
void EditorMaterialComponent::Deactivate()
|
||||
{
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
|
||||
MaterialReceiverNotificationBus::Handler::BusDisconnect();
|
||||
MaterialComponentNotificationBus::Handler::BusDisconnect();
|
||||
BaseClass::Deactivate();
|
||||
@@ -260,6 +262,18 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void EditorMaterialComponent::OnRenderMaterialPreviewComplete(
|
||||
[[maybe_unused]] const AZ::EntityId& entityId,
|
||||
[[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId,
|
||||
[[maybe_unused]] const QPixmap& pixmap)
|
||||
{
|
||||
if (entityId == GetEntityId())
|
||||
{
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::u32 EditorMaterialComponent::OnConfigurationChanged()
|
||||
{
|
||||
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
|
||||
|
||||
+8
-2
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Feature/Utils/EditorRenderComponentAdapter.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
|
||||
#include <Material/EditorMaterialComponentSlot.h>
|
||||
@@ -21,8 +22,9 @@ namespace AZ
|
||||
//! In-editor material component for displaying and editing material assignments.
|
||||
class EditorMaterialComponent final
|
||||
: public EditorRenderComponentAdapter<MaterialComponentController, MaterialComponent, MaterialComponentConfig>
|
||||
, private MaterialReceiverNotificationBus::Handler
|
||||
, private MaterialComponentNotificationBus::Handler
|
||||
, public MaterialReceiverNotificationBus::Handler
|
||||
, public MaterialComponentNotificationBus::Handler
|
||||
, public EditorMaterialSystemComponentNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
using BaseClass = EditorRenderComponentAdapter<MaterialComponentController, MaterialComponent, MaterialComponentConfig>;
|
||||
@@ -52,6 +54,10 @@ namespace AZ
|
||||
//! MaterialComponentNotificationBus::Handler overrides...
|
||||
void OnMaterialInstanceCreated(const MaterialAssignment& materialAssignment) override;
|
||||
|
||||
//! EditorMaterialSystemComponentNotificationBus::Handler overrides...
|
||||
void OnRenderMaterialPreviewComplete(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) override;
|
||||
|
||||
// Regenerates the editor component material slots based on the material and
|
||||
// LOD mapping from the model or other consumer of materials.
|
||||
// If any corresponding material assignments are found in the component
|
||||
|
||||
+99
-86
@@ -23,10 +23,6 @@
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/ProductThumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailWidget.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConfig.h>
|
||||
@@ -49,29 +45,18 @@ namespace AZ
|
||||
MaterialPropertyInspector::MaterialPropertyInspector(QWidget* parent)
|
||||
: AtomToolsFramework::InspectorWidget(parent)
|
||||
{
|
||||
// Create the menu button
|
||||
QToolButton* menuButton = new QToolButton(this);
|
||||
menuButton->setAutoRaise(true);
|
||||
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
|
||||
menuButton->setVisible(true);
|
||||
QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); });
|
||||
AddHeading(menuButton);
|
||||
|
||||
m_messageLabel = new QLabel(this);
|
||||
m_messageLabel->setWordWrap(true);
|
||||
m_messageLabel->setVisible(true);
|
||||
m_messageLabel->setAlignment(Qt::AlignCenter);
|
||||
m_messageLabel->setText(tr("Material not available"));
|
||||
AddHeading(m_messageLabel);
|
||||
|
||||
CreateHeading();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
AZ::EntitySystemBus::Handler::BusConnect();
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
MaterialPropertyInspector::~MaterialPropertyInspector()
|
||||
{
|
||||
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
|
||||
AZ::EntitySystemBus::Handler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AZ::EntitySystemBus::Handler::BusDisconnect();
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
|
||||
MaterialComponentNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
@@ -140,7 +125,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
Populate();
|
||||
m_messageLabel->setVisible(false);
|
||||
LoadOverridesFromEntity();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -152,8 +137,9 @@ namespace AZ
|
||||
m_dirtyPropertyFlags.set();
|
||||
m_editorFunctors = {};
|
||||
m_internalEditNotification = {};
|
||||
m_messageLabel->setVisible(true);
|
||||
m_messageLabel->setText(tr("Material not available"));
|
||||
m_updateUI = {};
|
||||
m_updatePreview = {};
|
||||
UpdateHeading();
|
||||
}
|
||||
|
||||
bool MaterialPropertyInspector::IsLoaded() const
|
||||
@@ -168,49 +154,63 @@ namespace AZ
|
||||
m_dirtyPropertyFlags.set();
|
||||
m_internalEditNotification = {};
|
||||
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::InspectorWidget::Reset();
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::AddDetailsGroup()
|
||||
void MaterialPropertyInspector::CreateHeading()
|
||||
{
|
||||
const AZStd::string& groupName = "Details";
|
||||
const AZStd::string& groupDisplayName = "Details";
|
||||
const AZStd::string& groupDescription = "";
|
||||
// Create the menu button
|
||||
QToolButton* menuButton = new QToolButton(this);
|
||||
menuButton->setAutoRaise(true);
|
||||
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
|
||||
menuButton->setVisible(true);
|
||||
QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); });
|
||||
AddHeading(menuButton);
|
||||
|
||||
auto propertyGroupContainer = new QWidget(this);
|
||||
propertyGroupContainer->setLayout(new QHBoxLayout());
|
||||
m_overviewImage = new QLabel(this);
|
||||
m_overviewImage->setFixedSize(QSize(120, 120));
|
||||
m_overviewImage->setScaledContents(true);
|
||||
m_overviewImage->setVisible(false);
|
||||
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey =
|
||||
MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, m_editData.m_materialAssetId);
|
||||
auto thumbnailWidget = new AzToolsFramework::Thumbnailer::ThumbnailWidget(this);
|
||||
thumbnailWidget->setFixedSize(QSize(120, 120));
|
||||
thumbnailWidget->setVisible(true);
|
||||
thumbnailWidget->SetThumbnailKey(thumbnailKey, AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext);
|
||||
propertyGroupContainer->layout()->addWidget(thumbnailWidget);
|
||||
|
||||
auto materialInfoWidget = new QLabel(this);
|
||||
m_overviewText = new QLabel(this);
|
||||
QSizePolicy sizePolicy1(QSizePolicy::Ignored, QSizePolicy::Preferred);
|
||||
sizePolicy1.setHorizontalStretch(0);
|
||||
sizePolicy1.setVerticalStretch(0);
|
||||
sizePolicy1.setHeightForWidth(materialInfoWidget->sizePolicy().hasHeightForWidth());
|
||||
materialInfoWidget->setSizePolicy(sizePolicy1);
|
||||
materialInfoWidget->setMinimumSize(QSize(0, 0));
|
||||
materialInfoWidget->setMaximumSize(QSize(16777215, 16777215));
|
||||
materialInfoWidget->setTextFormat(Qt::AutoText);
|
||||
materialInfoWidget->setScaledContents(false);
|
||||
materialInfoWidget->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop);
|
||||
materialInfoWidget->setWordWrap(true);
|
||||
sizePolicy1.setHeightForWidth(m_overviewText->sizePolicy().hasHeightForWidth());
|
||||
m_overviewText->setSizePolicy(sizePolicy1);
|
||||
m_overviewText->setMinimumSize(QSize(0, 0));
|
||||
m_overviewText->setMaximumSize(QSize(16777215, 16777215));
|
||||
m_overviewText->setTextFormat(Qt::AutoText);
|
||||
m_overviewText->setScaledContents(false);
|
||||
m_overviewText->setWordWrap(true);
|
||||
m_overviewText->setVisible(true);
|
||||
|
||||
auto overviewContainer = new QWidget(this);
|
||||
overviewContainer->setLayout(new QHBoxLayout());
|
||||
overviewContainer->layout()->addWidget(m_overviewImage);
|
||||
overviewContainer->layout()->addWidget(m_overviewText);
|
||||
AddHeading(overviewContainer);
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::UpdateHeading()
|
||||
{
|
||||
if (!IsLoaded())
|
||||
{
|
||||
m_overviewText->setText(tr("Material not available"));
|
||||
m_overviewText->setAlignment(Qt::AlignCenter);
|
||||
m_overviewImage->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QFileInfo materialFileInfo(AZ::RPI::AssetUtils::GetProductPathByAssetId(m_editData.m_materialAsset.GetId()).c_str());
|
||||
QFileInfo materialSourceFileInfo(m_editData.m_materialSourcePath.c_str());
|
||||
QFileInfo materialTypeSourceFileInfo(m_editData.m_materialTypeSourcePath.c_str());
|
||||
QFileInfo materialParentSourceFileInfo(AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str());
|
||||
QFileInfo materialParentSourceFileInfo(
|
||||
AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str());
|
||||
|
||||
AZStd::string entityName;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(
|
||||
entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId);
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId);
|
||||
|
||||
AZStd::string slotName;
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
@@ -226,7 +226,8 @@ namespace AZ
|
||||
}
|
||||
if (!materialTypeSourceFileInfo.fileName().isEmpty())
|
||||
{
|
||||
materialInfo += tr("<tr><td><b>Material Type </b></td><td>%1</td></tr>").arg(materialTypeSourceFileInfo.fileName());
|
||||
materialInfo +=
|
||||
tr("<tr><td><b>Material Type </b></td><td>%1</td></tr>").arg(materialTypeSourceFileInfo.fileName());
|
||||
}
|
||||
if (!materialSourceFileInfo.fileName().isEmpty())
|
||||
{
|
||||
@@ -234,14 +235,21 @@ namespace AZ
|
||||
}
|
||||
if (!materialParentSourceFileInfo.fileName().isEmpty())
|
||||
{
|
||||
materialInfo += tr("<tr><td><b>Material Parent </b></td><td>%1</td></tr>").arg(materialParentSourceFileInfo.fileName());
|
||||
materialInfo +=
|
||||
tr("<tr><td><b>Material Parent </b></td><td>%1</td></tr>").arg(materialParentSourceFileInfo.fileName());
|
||||
}
|
||||
materialInfo += tr("</table>");
|
||||
materialInfoWidget->setText(materialInfo);
|
||||
|
||||
propertyGroupContainer->layout()->addWidget(materialInfoWidget);
|
||||
m_overviewText->setText(materialInfo);
|
||||
m_overviewText->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop);
|
||||
|
||||
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupContainer);
|
||||
QPixmap pixmap;
|
||||
EditorMaterialSystemComponentRequestBus::BroadcastResult(
|
||||
pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId,
|
||||
m_materialAssignmentId);
|
||||
m_overviewImage->setPixmap(pixmap);
|
||||
m_overviewImage->setVisible(true);
|
||||
m_updatePreview |= pixmap.isNull();
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::AddUvNamesGroup()
|
||||
@@ -282,13 +290,8 @@ namespace AZ
|
||||
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget);
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::Populate()
|
||||
void MaterialPropertyInspector::AddPropertiesGroup()
|
||||
{
|
||||
AddGroupsBegin();
|
||||
|
||||
AddDetailsGroup();
|
||||
AddUvNamesGroup();
|
||||
|
||||
// Copy all of the properties from the material asset to the source data that will be exported
|
||||
for (const auto& groupDefinition : m_editData.m_materialTypeSourceData.GetGroupDefinitionsInDisplayOrder())
|
||||
{
|
||||
@@ -327,10 +330,14 @@ namespace AZ
|
||||
[this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0);
|
||||
AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::Populate()
|
||||
{
|
||||
AddGroupsBegin();
|
||||
AddUvNamesGroup();
|
||||
AddPropertiesGroup();
|
||||
AddGroupsEnd();
|
||||
|
||||
LoadOverridesFromEntity();
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::LoadOverridesFromEntity()
|
||||
@@ -375,6 +382,7 @@ namespace AZ
|
||||
m_dirtyPropertyFlags.set();
|
||||
RunEditorMaterialFunctors();
|
||||
RebuildAll();
|
||||
UpdateHeading();
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::SaveOverridesToEntity(bool commitChanges)
|
||||
@@ -398,6 +406,9 @@ namespace AZ
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited);
|
||||
m_internalEditNotification = false;
|
||||
}
|
||||
|
||||
// m_updatePreview should be set to true here for continuous preview updates as slider/color properties change but needs
|
||||
// throttling
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::RunEditorMaterialFunctors()
|
||||
@@ -607,7 +618,8 @@ namespace AZ
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetPropertyOverrides, m_materialAssignmentId,
|
||||
MaterialPropertyOverrideMap());
|
||||
QueueUpdateUI();
|
||||
m_updateUI = true;
|
||||
m_updatePreview = true;
|
||||
});
|
||||
action->setEnabled(IsLoaded());
|
||||
|
||||
@@ -702,10 +714,7 @@ namespace AZ
|
||||
|
||||
void MaterialPropertyInspector::OnEntityActivated(const AZ::EntityId& entityId)
|
||||
{
|
||||
if (m_entityId == entityId)
|
||||
{
|
||||
QueueUpdateUI();
|
||||
}
|
||||
m_updateUI |= (m_entityId == entityId);
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::OnEntityDeactivated(const AZ::EntityId& entityId)
|
||||
@@ -719,25 +728,39 @@ namespace AZ
|
||||
void MaterialPropertyInspector::OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name)
|
||||
{
|
||||
AZ_UNUSED(name);
|
||||
if (m_entityId == entityId)
|
||||
{
|
||||
QueueUpdateUI();
|
||||
}
|
||||
m_updateUI |= (m_entityId == entityId);
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::OnTick(float deltaTime, ScriptTimePoint time)
|
||||
{
|
||||
AZ_UNUSED(time);
|
||||
AZ_UNUSED(deltaTime);
|
||||
UpdateUI();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
if (m_updateUI)
|
||||
{
|
||||
m_updateUI = false;
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
if (m_updatePreview)
|
||||
{
|
||||
m_updatePreview = false;
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_materialAssignmentId);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::OnMaterialsEdited()
|
||||
{
|
||||
if (!m_internalEditNotification)
|
||||
m_updateUI |= !m_internalEditNotification;
|
||||
m_updatePreview = true;
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::OnRenderMaterialPreviewComplete(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap)
|
||||
{
|
||||
if (m_overviewImage && m_entityId == entityId && m_materialAssignmentId == materialAssignmentId)
|
||||
{
|
||||
QueueUpdateUI();
|
||||
m_overviewImage->setPixmap(pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -761,16 +784,6 @@ namespace AZ
|
||||
LoadMaterial(m_entityId, m_materialAssignmentId);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::QueueUpdateUI()
|
||||
{
|
||||
if (!AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
}
|
||||
} // namespace EditorMaterialComponentInspector
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
//#include <AtomLyIntegration/CommonFeatures/moc_EditorMaterialComponentInspector.cpp>
|
||||
|
||||
+17
-6
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
|
||||
#include <AtomToolsFramework/Inspector/InspectorWidget.h>
|
||||
@@ -31,14 +32,13 @@ namespace AZ
|
||||
{
|
||||
namespace EditorMaterialComponentInspector
|
||||
{
|
||||
using PropertyChangedCallback = AZStd::function<void(const MaterialPropertyOverrideMap&)>;
|
||||
|
||||
class MaterialPropertyInspector
|
||||
: public AtomToolsFramework::InspectorWidget
|
||||
, public AzToolsFramework::IPropertyEditorNotify
|
||||
, public AZ::EntitySystemBus::Handler
|
||||
, public AZ::TickBus::Handler
|
||||
, public MaterialComponentNotificationBus::Handler
|
||||
, public EditorMaterialSystemComponentNotificationBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -89,11 +89,19 @@ namespace AZ
|
||||
//! MaterialComponentNotificationBus::Handler overrides...
|
||||
void OnMaterialsEdited() override;
|
||||
|
||||
void UpdateUI();
|
||||
void QueueUpdateUI();
|
||||
//! EditorMaterialSystemComponentNotificationBus::Handler overrides...
|
||||
void OnRenderMaterialPreviewComplete(
|
||||
const AZ::EntityId& entityId,
|
||||
const AZ::Render::MaterialAssignmentId& materialAssignmentId,
|
||||
const QPixmap& pixmap) override;
|
||||
|
||||
void UpdateUI();
|
||||
|
||||
void CreateHeading();
|
||||
void UpdateHeading();
|
||||
|
||||
void AddDetailsGroup();
|
||||
void AddUvNamesGroup();
|
||||
void AddPropertiesGroup();
|
||||
|
||||
void LoadOverridesFromEntity();
|
||||
void SaveOverridesToEntity(bool commitChanges);
|
||||
@@ -115,7 +123,10 @@ namespace AZ
|
||||
AZ::RPI::MaterialPropertyFlags m_dirtyPropertyFlags = {};
|
||||
AZStd::unordered_map<AZStd::string, AtomToolsFramework::DynamicPropertyGroup> m_groups = {};
|
||||
bool m_internalEditNotification = {};
|
||||
QLabel* m_messageLabel = {};
|
||||
bool m_updateUI = {};
|
||||
bool m_updatePreview = {};
|
||||
QLabel* m_overviewText = {};
|
||||
QLabel* m_overviewImage = {};
|
||||
};
|
||||
} // namespace EditorMaterialComponentInspector
|
||||
} // namespace Render
|
||||
|
||||
+45
-19
@@ -6,23 +6,25 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Material/EditorMaterialComponentSlot.h>
|
||||
#include <Material/EditorMaterialComponentExporter.h>
|
||||
#include <Material/EditorMaterialComponentInspector.h>
|
||||
#include <Material/EditorMaterialModelUvNameMapInspector.h>
|
||||
#include <AzCore/Asset/AssetSerializer.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
|
||||
#include <AzCore/Asset/AssetSerializer.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <Material/EditorMaterialComponentExporter.h>
|
||||
#include <Material/EditorMaterialComponentInspector.h>
|
||||
#include <Material/EditorMaterialComponentSlot.h>
|
||||
#include <Material/EditorMaterialModelUvNameMapInspector.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QAction>
|
||||
#include <QByteArray>
|
||||
#include <QCursor>
|
||||
#include <QDataStream>
|
||||
#include <QMenu>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace AZ
|
||||
@@ -100,6 +102,7 @@ namespace AZ
|
||||
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &EditorMaterialComponentSlot::GetLabel)
|
||||
->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, true)
|
||||
->Attribute("ThumbnailCallback", &EditorMaterialComponentSlot::OpenPopupMenu)
|
||||
->Attribute("ThumbnailIcon", &EditorMaterialComponentSlot::GetPreviewPixmapData)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -118,6 +121,33 @@ namespace AZ
|
||||
}
|
||||
};
|
||||
|
||||
AZStd::vector<char> EditorMaterialComponentSlot::GetPreviewPixmapData() const
|
||||
{
|
||||
if (!GetActiveAssetId().IsValid())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
QPixmap pixmap;
|
||||
EditorMaterialSystemComponentRequestBus::BroadcastResult(
|
||||
pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId, m_id);
|
||||
if (pixmap.isNull())
|
||||
{
|
||||
if (m_updatePreview)
|
||||
{
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id);
|
||||
m_updatePreview = false;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QByteArray pixmapBytes;
|
||||
QDataStream stream(&pixmapBytes, QIODevice::WriteOnly);
|
||||
stream << pixmap;
|
||||
return AZStd::vector<char>(pixmapBytes.begin(), pixmapBytes.end());
|
||||
}
|
||||
|
||||
AZ::Data::AssetId EditorMaterialComponentSlot::GetActiveAssetId() const
|
||||
{
|
||||
return m_materialAsset.GetId().IsValid() ? m_materialAsset.GetId() : GetDefaultAssetId();
|
||||
@@ -169,14 +199,6 @@ namespace AZ
|
||||
ClearOverrides();
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::ClearToDefaultAsset()
|
||||
{
|
||||
m_materialAsset = AZ::Data::Asset<AZ::RPI::MaterialAsset>(GetDefaultAssetId(), AZ::AzTypeInfo<AZ::RPI::MaterialAsset>::Uuid());
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId());
|
||||
ClearOverrides();
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::ClearOverrides()
|
||||
{
|
||||
MaterialComponentRequestBus::Event(
|
||||
@@ -315,6 +337,10 @@ namespace AZ
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, m_entityId);
|
||||
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
&EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id);
|
||||
m_updatePreview = false;
|
||||
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited);
|
||||
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
|
||||
+27
-11
@@ -8,37 +8,52 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/Feature/Material/MaterialAssignment.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <QPixmap>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
static const size_t DefaultMaterialSlotIndex = std::numeric_limits<size_t>::max();
|
||||
|
||||
//! Details for a single editable material assignment
|
||||
struct EditorMaterialComponentSlot final
|
||||
{
|
||||
AZ_RTTI(EditorMaterialComponentSlot, "{344066EB-7C3D-4E92-B53D-3C9EBD546488}");
|
||||
AZ_CLASS_ALLOCATOR(EditorMaterialComponentSlot, SystemAllocator, 0);
|
||||
|
||||
static void Reflect(ReflectContext* context);
|
||||
static bool ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
//! Get cached preview image as a buffer to use as an RPE attribute
|
||||
//! If a cached image isn't avalible then a request will be made to render one
|
||||
AZStd::vector<char> GetPreviewPixmapData() const;
|
||||
|
||||
//! Returns the overridden asset id if it's valid, otherwise gets the default asseet id
|
||||
AZ::Data::AssetId GetActiveAssetId() const;
|
||||
|
||||
//! Returns the default asseet id of the material provded by the model
|
||||
AZ::Data::AssetId GetDefaultAssetId() const;
|
||||
|
||||
//! Returns the display name of the material slot
|
||||
AZStd::string GetLabel() const;
|
||||
|
||||
//! Returns true if the active material asset has a source material
|
||||
bool HasSourceData() const;
|
||||
|
||||
//! Assign a new material override asset
|
||||
void SetAsset(const Data::AssetId& assetId);
|
||||
|
||||
//! Assign a new material override asset
|
||||
void SetAsset(const Data::Asset<RPI::MaterialAsset>& asset);
|
||||
|
||||
//! Remove material and prperty overrides
|
||||
void Clear();
|
||||
void ClearToDefaultAsset();
|
||||
|
||||
//! Remove prperty overrides
|
||||
void ClearOverrides();
|
||||
|
||||
void OpenMaterialExporter();
|
||||
@@ -54,6 +69,7 @@ namespace AZ
|
||||
void OpenPopupMenu(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType);
|
||||
void OnMaterialChanged() const;
|
||||
void OnDataChanged() const;
|
||||
mutable bool m_updatePreview = true;
|
||||
};
|
||||
|
||||
// Vector of slots for assignable or overridable material data.
|
||||
@@ -62,8 +78,8 @@ namespace AZ
|
||||
// Table containing all editable material data that is displayed in the edit context and inspector
|
||||
// The vector represents all the LODs that can have material overrides.
|
||||
// The container will be populated with every potential material slot on an associated model, using its default values.
|
||||
// Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment map
|
||||
// as overrides that will be applied to material instances
|
||||
// Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment
|
||||
// map as overrides that will be applied to material instances
|
||||
using EditorMaterialComponentSlotsByLodContainer = AZStd::vector<EditorMaterialComponentSlotContainer>;
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+88
-30
@@ -6,7 +6,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/EditContextConstants.inl>
|
||||
@@ -16,11 +19,10 @@
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/ViewPaneOptions.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <Editor/LyViewPaneNames.h>
|
||||
#include <Material/EditorMaterialComponentInspector.h>
|
||||
#include <Material/EditorMaterialSystemComponent.h>
|
||||
#include <Material/MaterialThumbnail.h>
|
||||
#include <SharedPreview/SharedPreviewContent.h>
|
||||
|
||||
// Disables warning messages triggered by the Qt library
|
||||
// 4251: class needs to have dll-interface to be used by clients of class
|
||||
@@ -30,6 +32,8 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option")
|
||||
#include <QApplication>
|
||||
#include <QDockWidget>
|
||||
#include <QObject>
|
||||
#include <QPixmap>
|
||||
#include <QImage>
|
||||
#include <QProcessEnvironment>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
@@ -72,11 +76,6 @@ namespace AZ
|
||||
incompatible.push_back(AZ_CRC("EditorMaterialSystem", 0x5c93bc4e));
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC("ThumbnailerService", 0x65422b97));
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
AZ_UNUSED(dependent);
|
||||
@@ -89,25 +88,26 @@ namespace AZ
|
||||
|
||||
void EditorMaterialSystemComponent::Activate()
|
||||
{
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusConnect();
|
||||
EditorMaterialSystemComponentRequestBus::Handler::BusConnect();
|
||||
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
|
||||
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect();
|
||||
AzToolsFramework::EditorMenuNotificationBus::Handler::BusConnect();
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
|
||||
|
||||
SetupThumbnails();
|
||||
m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions);
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
||||
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::Deactivate()
|
||||
{
|
||||
EditorMaterialSystemComponentRequestBus::Handler::BusDisconnect();
|
||||
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect();
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
|
||||
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
|
||||
EditorMaterialSystemComponentRequestBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::EditorMenuNotificationBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
|
||||
|
||||
TeardownThumbnails();
|
||||
m_previewRenderer.reset();
|
||||
m_materialBrowserInteractions.reset();
|
||||
|
||||
if (m_openMaterialEditorAction)
|
||||
@@ -154,11 +154,74 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::OnApplicationAboutToStop()
|
||||
void EditorMaterialSystemComponent::RenderMaterialPreview(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId)
|
||||
{
|
||||
TeardownThumbnails();
|
||||
static constexpr const char* DefaultModelPath = "models/sphere.azmodel";
|
||||
static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset";
|
||||
|
||||
if (m_previewRenderer)
|
||||
{
|
||||
AZ::Data::AssetId materialAssetId = {};
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, materialAssignmentId);
|
||||
if (!materialAssetId.IsValid())
|
||||
{
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, materialAssignmentId);
|
||||
if (!materialAssetId.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Render::MaterialPropertyOverrideMap propertyOverrides;
|
||||
AZ::Render::MaterialComponentRequestBus::EventResult(
|
||||
propertyOverrides, entityId, &AZ::Render::MaterialComponentRequestBus::Events::GetPropertyOverrides,
|
||||
materialAssignmentId);
|
||||
|
||||
m_previewRenderer->AddCaptureRequest(
|
||||
{ 128,
|
||||
AZStd::make_shared<AZ::LyIntegration::SharedPreviewContent>(
|
||||
m_previewRenderer->GetScene(), m_previewRenderer->GetView(), m_previewRenderer->GetEntityContextId(),
|
||||
AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath), materialAssetId,
|
||||
AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath), propertyOverrides),
|
||||
[]()
|
||||
{
|
||||
// failed
|
||||
},
|
||||
[entityId, materialAssignmentId](const QPixmap& pixmap)
|
||||
{
|
||||
AZ::Render::EditorMaterialSystemComponentNotificationBus::Broadcast(
|
||||
&AZ::Render::EditorMaterialSystemComponentNotificationBus::Events::OnRenderMaterialPreviewComplete, entityId,
|
||||
materialAssignmentId, pixmap);
|
||||
} });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QPixmap EditorMaterialSystemComponent::GetRenderedMaterialPreview(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const
|
||||
{
|
||||
const auto& itr1 = m_materialPreviews.find(entityId);
|
||||
if (itr1 != m_materialPreviews.end())
|
||||
{
|
||||
const auto& itr2 = itr1->second.find(materialAssignmentId);
|
||||
if (itr2 != itr1->second.end())
|
||||
{
|
||||
return itr2->second;
|
||||
}
|
||||
}
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::OnRenderMaterialPreviewComplete(
|
||||
[[maybe_unused]] const AZ::EntityId& entityId,
|
||||
[[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId,
|
||||
[[maybe_unused]] const QPixmap& pixmap)
|
||||
{
|
||||
m_materialPreviews[entityId][materialAssignmentId] = pixmap;
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::OnPopulateToolMenuItems()
|
||||
{
|
||||
if (!m_openMaterialEditorAction)
|
||||
@@ -201,24 +264,19 @@ namespace AZ
|
||||
"Material Property Inspector", LyViewPane::CategoryTools, inspectorOptions);
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::SetupThumbnails()
|
||||
void EditorMaterialSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile)
|
||||
{
|
||||
using namespace AzToolsFramework::Thumbnailer;
|
||||
using namespace LyIntegration;
|
||||
|
||||
ThumbnailerRequestsBus::Broadcast(
|
||||
&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::MaterialThumbnailCache),
|
||||
ThumbnailContext::DefaultContext);
|
||||
AZ::TickBus::QueueFunction([this](){
|
||||
m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions);
|
||||
m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer(
|
||||
"EditorMaterialSystemComponent Preview Scene", "EditorMaterialSystemComponent Preview Pipeline"));
|
||||
});
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::TeardownThumbnails()
|
||||
void EditorMaterialSystemComponent::OnApplicationAboutToStop()
|
||||
{
|
||||
using namespace AzToolsFramework::Thumbnailer;
|
||||
using namespace LyIntegration;
|
||||
|
||||
ThumbnailerRequestsBus::Broadcast(
|
||||
&ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::MaterialThumbnailCache::ProviderName,
|
||||
ThumbnailContext::DefaultContext);
|
||||
m_previewRenderer.reset();
|
||||
m_materialBrowserInteractions.reset();
|
||||
}
|
||||
|
||||
AzToolsFramework::AssetBrowser::SourceFileDetails EditorMaterialSystemComponent::GetSourceFileDetails(
|
||||
|
||||
+26
-16
@@ -7,29 +7,31 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRenderer.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzFramework/Application/Application.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Viewport/ActionBus.h>
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
|
||||
|
||||
#include <Material/MaterialBrowserInteractions.h>
|
||||
#include <QPixmap>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
//! System component that manages launching and maintaining connections with the material editor.
|
||||
class EditorMaterialSystemComponent
|
||||
class EditorMaterialSystemComponent final
|
||||
: public AZ::Component
|
||||
, private EditorMaterialSystemComponentRequestBus::Handler
|
||||
, private AzFramework::ApplicationLifecycleEvents::Bus::Handler
|
||||
, private AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler
|
||||
, private AzToolsFramework::EditorMenuNotificationBus::Handler
|
||||
, private AzToolsFramework::EditorEvents::Bus::Handler
|
||||
, public EditorMaterialSystemComponentNotificationBus::Handler
|
||||
, public EditorMaterialSystemComponentRequestBus::Handler
|
||||
, public AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler
|
||||
, public AzToolsFramework::EditorMenuNotificationBus::Handler
|
||||
, public AzToolsFramework::EditorEvents::Bus::Handler
|
||||
, public AzFramework::AssetCatalogEventBus::Handler
|
||||
, public AzFramework::ApplicationLifecycleEvents::Bus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(EditorMaterialSystemComponent, "{96652157-DA0B-420F-B49C-0207C585144C}");
|
||||
@@ -38,7 +40,6 @@ namespace AZ
|
||||
|
||||
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);
|
||||
|
||||
protected:
|
||||
@@ -51,9 +52,13 @@ namespace AZ
|
||||
//! EditorMaterialSystemComponentRequestBus::Handler overrides...
|
||||
void OpenMaterialEditor(const AZStd::string& sourcePath) override;
|
||||
void OpenMaterialInspector(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override;
|
||||
void RenderMaterialPreview(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override;
|
||||
QPixmap GetRenderedMaterialPreview(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const override;
|
||||
|
||||
// AzFramework::ApplicationLifecycleEvents overrides...
|
||||
void OnApplicationAboutToStop() override;
|
||||
//! EditorMaterialSystemComponentNotificationBus::Handler overrides...
|
||||
void OnRenderMaterialPreviewComplete(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap)override;
|
||||
|
||||
//! AssetBrowserInteractionNotificationBus::Handler overrides...
|
||||
AzToolsFramework::AssetBrowser::SourceFileDetails GetSourceFileDetails(const char* fullSourceFileName) override;
|
||||
@@ -65,12 +70,17 @@ namespace AZ
|
||||
// AztoolsFramework::EditorEvents::Bus::Handler overrides...
|
||||
void NotifyRegisterViews() override;
|
||||
|
||||
void SetupThumbnails();
|
||||
void TeardownThumbnails();
|
||||
|
||||
// AzFramework::AssetCatalogEventBus::Handler overrides ...
|
||||
void OnCatalogLoaded(const char* catalogFile) override;
|
||||
|
||||
// AzFramework::ApplicationLifecycleEvents overrides...
|
||||
void OnApplicationAboutToStop() override;
|
||||
|
||||
QAction* m_openMaterialEditorAction = nullptr;
|
||||
|
||||
AZStd::unique_ptr<MaterialBrowserInteractions> m_materialBrowserInteractions;
|
||||
AZStd::unique_ptr<AtomToolsFramework::PreviewRenderer> m_previewRenderer;
|
||||
AZStd::unordered_map<AZ::EntityId, AZStd::unordered_map<AZ::Render::MaterialAssignmentId, QPixmap>> m_materialPreviews;
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include <Source/Material/MaterialThumbnail.h>
|
||||
#include <Source/Thumbnails/ThumbnailUtils.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
static constexpr const int MaterialThumbnailSize = 512; // 512 is the default size in render to texture pass
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MaterialThumbnail
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
MaterialThumbnail::MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key)
|
||||
: Thumbnail(key)
|
||||
{
|
||||
m_assetId = GetAssetId(key, RPI::MaterialAsset::RTTI_Type());
|
||||
if (!m_assetId.IsValid())
|
||||
{
|
||||
AZ_Error("MaterialThumbnail", false, "Failed to find matching assetId for the thumbnailKey.");
|
||||
m_state = State::Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key);
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void MaterialThumbnail::LoadThread()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent(
|
||||
RPI::MaterialAsset::RTTI_Type(),
|
||||
&AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail,
|
||||
m_key,
|
||||
MaterialThumbnailSize);
|
||||
// wait for response from thumbnail renderer
|
||||
m_renderWait.acquire();
|
||||
}
|
||||
|
||||
MaterialThumbnail::~MaterialThumbnail()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect();
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void MaterialThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage)
|
||||
{
|
||||
m_pixmap = thumbnailImage;
|
||||
m_renderWait.release();
|
||||
}
|
||||
|
||||
void MaterialThumbnail::ThumbnailFailedToRender()
|
||||
{
|
||||
m_state = State::Failed;
|
||||
m_renderWait.release();
|
||||
}
|
||||
|
||||
void MaterialThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId)
|
||||
{
|
||||
if (m_assetId == assetId &&
|
||||
m_state == State::Ready)
|
||||
{
|
||||
m_state = State::Unloaded;
|
||||
Load();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MaterialThumbnailCache
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
MaterialThumbnailCache::MaterialThumbnailCache()
|
||||
: ThumbnailCache<MaterialThumbnail>()
|
||||
{
|
||||
}
|
||||
|
||||
MaterialThumbnailCache::~MaterialThumbnailCache() = default;
|
||||
|
||||
int MaterialThumbnailCache::GetPriority() const
|
||||
{
|
||||
// Material thumbnails override default source thumbnails, so carry higher priority
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* MaterialThumbnailCache::GetProviderName() const
|
||||
{
|
||||
return ProviderName;
|
||||
}
|
||||
|
||||
bool MaterialThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const
|
||||
{
|
||||
return
|
||||
GetAssetId(key, RPI::MaterialAsset::RTTI_Type()).IsValid() &&
|
||||
// in case it's a source scene file, it will contain both material and model products
|
||||
// model thumbnails are handled by MeshThumbnail
|
||||
!GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid();
|
||||
}
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
|
||||
#include <Material/moc_MaterialThumbnail.cpp>
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/parallel/binary_semaphore.h>
|
||||
#include <AzFramework/Asset/AssetCatalogBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <Thumbnails/Rendering/CommonThumbnailRenderer.h>
|
||||
#endif
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
/**
|
||||
* Custom material or model thumbnail that detects when an asset changes and updates the thumbnail
|
||||
*/
|
||||
class MaterialThumbnail
|
||||
: public AzToolsFramework::Thumbnailer::Thumbnail
|
||||
, public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler
|
||||
, private AzFramework::AssetCatalogEventBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key);
|
||||
~MaterialThumbnail() override;
|
||||
|
||||
//! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides...
|
||||
void ThumbnailRendered(const QPixmap& thumbnailImage) override;
|
||||
void ThumbnailFailedToRender() override;
|
||||
|
||||
protected:
|
||||
void LoadThread() override;
|
||||
|
||||
private:
|
||||
// AzFramework::AssetCatalogEventBus::Handler interface overrides...
|
||||
void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override;
|
||||
|
||||
AZStd::binary_semaphore m_renderWait;
|
||||
Data::AssetId m_assetId;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cache configuration for large material thumbnails
|
||||
*/
|
||||
class MaterialThumbnailCache
|
||||
: public AzToolsFramework::Thumbnailer::ThumbnailCache<MaterialThumbnail>
|
||||
{
|
||||
public:
|
||||
MaterialThumbnailCache();
|
||||
~MaterialThumbnailCache() override;
|
||||
|
||||
int GetPriority() const override;
|
||||
const char* GetProviderName() const override;
|
||||
|
||||
static constexpr const char* ProviderName = "Material Thumbnails";
|
||||
|
||||
protected:
|
||||
bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+2
-39
@@ -6,13 +6,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/EditContextConstants.inl>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <Source/Mesh/EditorMeshSystemComponent.h>
|
||||
#include <Source/Mesh/MeshThumbnail.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <Mesh/EditorMeshSystemComponent.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -47,11 +44,6 @@ namespace AZ
|
||||
incompatible.push_back(AZ_CRC_CE("EditorMeshSystem"));
|
||||
}
|
||||
|
||||
void EditorMeshSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC_CE("ThumbnailerService"));
|
||||
}
|
||||
|
||||
void EditorMeshSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
AZ_UNUSED(dependent);
|
||||
@@ -59,39 +51,10 @@ namespace AZ
|
||||
|
||||
void EditorMeshSystemComponent::Activate()
|
||||
{
|
||||
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
|
||||
SetupThumbnails();
|
||||
}
|
||||
|
||||
void EditorMeshSystemComponent::Deactivate()
|
||||
{
|
||||
TeardownThumbnails();
|
||||
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void EditorMeshSystemComponent::OnApplicationAboutToStop()
|
||||
{
|
||||
TeardownThumbnails();
|
||||
}
|
||||
|
||||
void EditorMeshSystemComponent::SetupThumbnails()
|
||||
{
|
||||
using namespace AzToolsFramework::Thumbnailer;
|
||||
using namespace LyIntegration;
|
||||
|
||||
ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider,
|
||||
MAKE_TCACHE(Thumbnails::MeshThumbnailCache),
|
||||
ThumbnailContext::DefaultContext);
|
||||
}
|
||||
|
||||
void EditorMeshSystemComponent::TeardownThumbnails()
|
||||
{
|
||||
using namespace AzToolsFramework::Thumbnailer;
|
||||
using namespace LyIntegration;
|
||||
|
||||
ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::UnregisterThumbnailProvider,
|
||||
Thumbnails::MeshThumbnailCache::ProviderName,
|
||||
ThumbnailContext::DefaultContext);
|
||||
}
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzFramework/Application/Application.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -17,7 +16,6 @@ namespace AZ
|
||||
//! System component that sets up necessary logic related to EditorMeshComponent.
|
||||
class EditorMeshSystemComponent
|
||||
: public AZ::Component
|
||||
, private AzFramework::ApplicationLifecycleEvents::Bus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(EditorMeshSystemComponent, "{4D332E3D-C4FC-410B-A915-8E234CBDD4EC}");
|
||||
@@ -26,20 +24,12 @@ namespace AZ
|
||||
|
||||
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);
|
||||
|
||||
protected:
|
||||
// AZ::Component interface overrides...
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
private:
|
||||
// AzFramework::ApplicationLifecycleEvents overrides...
|
||||
void OnApplicationAboutToStop() override;
|
||||
|
||||
void SetupThumbnails();
|
||||
void TeardownThumbnails();
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include <Source/Mesh/MeshThumbnail.h>
|
||||
#include <Source/Thumbnails/ThumbnailUtils.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
static constexpr const int MeshThumbnailSize = 512; // 512 is the default size in render to texture pass
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MeshThumbnail
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
MeshThumbnail::MeshThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key)
|
||||
: Thumbnail(key)
|
||||
{
|
||||
m_assetId = GetAssetId(key, RPI::ModelAsset::RTTI_Type());
|
||||
if (!m_assetId.IsValid())
|
||||
{
|
||||
AZ_Error("MeshThumbnail", false, "Failed to find matching assetId for the thumbnailKey.");
|
||||
m_state = State::Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key);
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void MeshThumbnail::LoadThread()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent(
|
||||
RPI::ModelAsset::RTTI_Type(),
|
||||
&AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail,
|
||||
m_key,
|
||||
MeshThumbnailSize);
|
||||
// wait for response from thumbnail renderer
|
||||
m_renderWait.acquire();
|
||||
}
|
||||
|
||||
MeshThumbnail::~MeshThumbnail()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect();
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void MeshThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage)
|
||||
{
|
||||
m_pixmap = thumbnailImage;
|
||||
m_renderWait.release();
|
||||
}
|
||||
|
||||
void MeshThumbnail::ThumbnailFailedToRender()
|
||||
{
|
||||
m_state = State::Failed;
|
||||
m_renderWait.release();
|
||||
}
|
||||
|
||||
void MeshThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId)
|
||||
{
|
||||
if (m_assetId == assetId &&
|
||||
m_state == State::Ready)
|
||||
{
|
||||
m_state = State::Unloaded;
|
||||
Load();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MeshThumbnailCache
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
MeshThumbnailCache::MeshThumbnailCache()
|
||||
: ThumbnailCache<MeshThumbnail>()
|
||||
{
|
||||
}
|
||||
|
||||
MeshThumbnailCache::~MeshThumbnailCache() = default;
|
||||
|
||||
int MeshThumbnailCache::GetPriority() const
|
||||
{
|
||||
// Material thumbnails override default source thumbnails, so carry higher priority
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* MeshThumbnailCache::GetProviderName() const
|
||||
{
|
||||
return ProviderName;
|
||||
}
|
||||
|
||||
bool MeshThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const
|
||||
{
|
||||
return GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid();
|
||||
}
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
|
||||
#include <Mesh/moc_MeshThumbnail.cpp>
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/parallel/binary_semaphore.h>
|
||||
#include <AzFramework/Asset/AssetCatalogBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#endif
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
/**
|
||||
* Custom material or model thumbnail that detects when an asset changes and updates the thumbnail
|
||||
*/
|
||||
class MeshThumbnail
|
||||
: public AzToolsFramework::Thumbnailer::Thumbnail
|
||||
, public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler
|
||||
, private AzFramework::AssetCatalogEventBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MeshThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key);
|
||||
~MeshThumbnail() override;
|
||||
|
||||
//! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides...
|
||||
void ThumbnailRendered(const QPixmap& thumbnailImage) override;
|
||||
void ThumbnailFailedToRender() override;
|
||||
|
||||
protected:
|
||||
void LoadThread() override;
|
||||
|
||||
private:
|
||||
// AzFramework::AssetCatalogEventBus::Handler interface overrides...
|
||||
void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override;
|
||||
|
||||
AZStd::binary_semaphore m_renderWait;
|
||||
Data::AssetId m_assetId;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cache configuration for large material thumbnails
|
||||
*/
|
||||
class MeshThumbnailCache
|
||||
: public AzToolsFramework::Thumbnailer::ThumbnailCache<MeshThumbnail>
|
||||
{
|
||||
public:
|
||||
MeshThumbnailCache();
|
||||
~MeshThumbnailCache() override;
|
||||
|
||||
int GetPriority() const override;
|
||||
const char* GetProviderName() const override;
|
||||
|
||||
static constexpr const char* ProviderName = "Mesh Thumbnails";
|
||||
|
||||
protected:
|
||||
bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/Utils/LightingPreset.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentConstants.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/Entity/EntityContextBus.h>
|
||||
#include <SharedPreview/SharedPreviewContent.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
SharedPreviewContent::SharedPreviewContent(
|
||||
RPI::ScenePtr scene,
|
||||
RPI::ViewPtr view,
|
||||
AZ::Uuid entityContextId,
|
||||
const Data::AssetId& modelAssetId,
|
||||
const Data::AssetId& materialAssetId,
|
||||
const Data::AssetId& lightingPresetAssetId,
|
||||
const Render::MaterialPropertyOverrideMap& materialPropertyOverrides)
|
||||
: m_scene(scene)
|
||||
, m_view(view)
|
||||
, m_entityContextId(entityContextId)
|
||||
, m_materialPropertyOverrides(materialPropertyOverrides)
|
||||
{
|
||||
// Create preview model
|
||||
AzFramework::EntityContextRequestBus::EventResult(
|
||||
m_modelEntity, m_entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "SharedPreviewContentModel");
|
||||
m_modelEntity->CreateComponent(Render::MeshComponentTypeId);
|
||||
m_modelEntity->CreateComponent(Render::MaterialComponentTypeId);
|
||||
m_modelEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_modelEntity->Init();
|
||||
m_modelEntity->Activate();
|
||||
|
||||
m_modelAsset.Create(modelAssetId);
|
||||
m_materialAsset.Create(materialAssetId);
|
||||
m_lightingPresetAsset.Create(lightingPresetAssetId);
|
||||
}
|
||||
|
||||
SharedPreviewContent::~SharedPreviewContent()
|
||||
{
|
||||
if (m_modelEntity)
|
||||
{
|
||||
m_modelEntity->Deactivate();
|
||||
AzFramework::EntityContextRequestBus::Event(
|
||||
m_entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity);
|
||||
m_modelEntity = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SharedPreviewContent::Load()
|
||||
{
|
||||
m_modelAsset.QueueLoad();
|
||||
m_materialAsset.QueueLoad();
|
||||
m_lightingPresetAsset.QueueLoad();
|
||||
}
|
||||
|
||||
bool SharedPreviewContent::IsReady() const
|
||||
{
|
||||
return (!m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady()) &&
|
||||
(!m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady()) &&
|
||||
(!m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady());
|
||||
}
|
||||
|
||||
bool SharedPreviewContent::IsError() const
|
||||
{
|
||||
return m_modelAsset.IsError() || m_materialAsset.IsError() || m_lightingPresetAsset.IsError();
|
||||
}
|
||||
|
||||
void SharedPreviewContent::ReportErrors()
|
||||
{
|
||||
AZ_Warning(
|
||||
"SharedPreviewContent", !m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady(), "Asset failed to load in time: %s",
|
||||
m_modelAsset.ToString<AZStd::string>().c_str());
|
||||
AZ_Warning(
|
||||
"SharedPreviewContent", !m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady(), "Asset failed to load in time: %s",
|
||||
m_materialAsset.ToString<AZStd::string>().c_str());
|
||||
AZ_Warning(
|
||||
"SharedPreviewContent", !m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady(),
|
||||
"Asset failed to load in time: %s", m_lightingPresetAsset.ToString<AZStd::string>().c_str());
|
||||
}
|
||||
|
||||
void SharedPreviewContent::Update()
|
||||
{
|
||||
UpdateModel();
|
||||
UpdateLighting();
|
||||
UpdateCamera();
|
||||
}
|
||||
|
||||
void SharedPreviewContent::UpdateModel()
|
||||
{
|
||||
Render::MeshComponentRequestBus::Event(
|
||||
m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset);
|
||||
|
||||
Render::MaterialComponentRequestBus::Event(
|
||||
m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetMaterialOverride,
|
||||
Render::DefaultMaterialAssignmentId, m_materialAsset.GetId());
|
||||
|
||||
Render::MaterialComponentRequestBus::Event(
|
||||
m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetPropertyOverrides,
|
||||
Render::DefaultMaterialAssignmentId, m_materialPropertyOverrides);
|
||||
}
|
||||
|
||||
void SharedPreviewContent::UpdateLighting()
|
||||
{
|
||||
if (m_lightingPresetAsset.IsReady())
|
||||
{
|
||||
auto preset = m_lightingPresetAsset->GetDataAs<Render::LightingPreset>();
|
||||
if (preset)
|
||||
{
|
||||
auto iblFeatureProcessor = m_scene->GetFeatureProcessor<Render::ImageBasedLightFeatureProcessorInterface>();
|
||||
auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor<Render::PostProcessFeatureProcessorInterface>();
|
||||
auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId());
|
||||
auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface();
|
||||
auto directionalLightFeatureProcessor =
|
||||
m_scene->GetFeatureProcessor<Render::DirectionalLightFeatureProcessorInterface>();
|
||||
auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor<Render::SkyBoxFeatureProcessorInterface>();
|
||||
skyboxFeatureProcessor->Enable(true);
|
||||
skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap);
|
||||
|
||||
Camera::Configuration cameraConfig;
|
||||
cameraConfig.m_fovRadians = FieldOfView;
|
||||
cameraConfig.m_nearClipDistance = NearDist;
|
||||
cameraConfig.m_farClipDistance = FarDist;
|
||||
cameraConfig.m_frustumWidth = 100.0f;
|
||||
cameraConfig.m_frustumHeight = 100.0f;
|
||||
|
||||
AZStd::vector<Render::DirectionalLightFeatureProcessorInterface::LightHandle> lightHandles;
|
||||
|
||||
preset->ApplyLightingPreset(
|
||||
iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor,
|
||||
cameraConfig, lightHandles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SharedPreviewContent::UpdateCamera()
|
||||
{
|
||||
// Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it
|
||||
Vector3 center = {};
|
||||
float radius = {};
|
||||
if (m_modelAsset.IsReady())
|
||||
{
|
||||
m_modelAsset->GetAabb().GetAsSphere(center, radius);
|
||||
}
|
||||
|
||||
const auto distance = radius + NearDist;
|
||||
const auto cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), CameraRotationAngle);
|
||||
const auto cameraPosition = center + cameraRotation.TransformVector(Vector3(0.0f, distance, 0.0f));
|
||||
const auto cameraTransform = Transform::CreateLookAt(cameraPosition, center);
|
||||
m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform));
|
||||
}
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Feature/Material/MaterialAssignment.h>
|
||||
#include <Atom/RPI.Public/Base.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
|
||||
#include <Atom/RPI.Reflect/System/AnyAsset.h>
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewContent.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
//! Creates a simple scene used for most previews and thumbnails
|
||||
class SharedPreviewContent final : public AtomToolsFramework::PreviewContent
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(SharedPreviewContent, AZ::SystemAllocator, 0);
|
||||
|
||||
SharedPreviewContent(
|
||||
RPI::ScenePtr scene,
|
||||
RPI::ViewPtr view,
|
||||
AZ::Uuid entityContextId,
|
||||
const Data::AssetId& modelAssetId,
|
||||
const Data::AssetId& materialAssetId,
|
||||
const Data::AssetId& lightingPresetAssetId,
|
||||
const Render::MaterialPropertyOverrideMap& materialPropertyOverrides);
|
||||
|
||||
~SharedPreviewContent() override;
|
||||
|
||||
void Load() override;
|
||||
bool IsReady() const override;
|
||||
bool IsError() const override;
|
||||
void ReportErrors() override;
|
||||
void Update() override;
|
||||
|
||||
private:
|
||||
void UpdateModel();
|
||||
void UpdateLighting();
|
||||
void UpdateCamera();
|
||||
|
||||
static constexpr float AspectRatio = 1.0f;
|
||||
static constexpr float NearDist = 0.001f;
|
||||
static constexpr float FarDist = 100.0f;
|
||||
static constexpr float FieldOfView = Constants::HalfPi;
|
||||
static constexpr float CameraRotationAngle = Constants::QuarterPi / 2.0f;
|
||||
|
||||
RPI::ScenePtr m_scene;
|
||||
RPI::ViewPtr m_view;
|
||||
AZ::Uuid m_entityContextId;
|
||||
Entity* m_modelEntity = nullptr;
|
||||
|
||||
Data::Asset<RPI::ModelAsset> m_modelAsset;
|
||||
Data::Asset<RPI::MaterialAsset> m_materialAsset;
|
||||
Data::Asset<RPI::AnyAsset> m_lightingPresetAsset;
|
||||
Render::MaterialPropertyOverrideMap m_materialPropertyOverrides;
|
||||
};
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+42
-12
@@ -11,37 +11,42 @@
|
||||
#include <AssetBrowser/Thumbnails/SourceThumbnail.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
|
||||
#include <Thumbnails/ThumbnailUtils.h>
|
||||
#include <Atom/RPI.Reflect/System/AnyAsset.h>
|
||||
#include <SharedPreview/SharedPreviewUtils.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
namespace SharedPreviewUtils
|
||||
{
|
||||
Data::AssetId GetAssetId(AzToolsFramework::Thumbnailer::SharedThumbnailKey key, const Data::AssetType& assetType)
|
||||
Data::AssetId GetAssetId(
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnailKey key,
|
||||
const Data::AssetType& assetType,
|
||||
const Data::AssetId& defaultAssetId)
|
||||
{
|
||||
static const Data::AssetId invalidAssetId;
|
||||
|
||||
// if it's a source thumbnail key, find first product with a matching asset type
|
||||
auto sourceKey = azrtti_cast<const AzToolsFramework::AssetBrowser::SourceThumbnailKey*>(key.data());
|
||||
if (sourceKey)
|
||||
{
|
||||
bool foundIt = false;
|
||||
AZStd::vector<Data::AssetInfo> productsAssetInfo;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID, sourceKey->GetSourceUuid(), productsAssetInfo);
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID,
|
||||
sourceKey->GetSourceUuid(), productsAssetInfo);
|
||||
if (!foundIt)
|
||||
{
|
||||
return invalidAssetId;
|
||||
return defaultAssetId;
|
||||
}
|
||||
auto assetInfoIt = AZStd::find_if(productsAssetInfo.begin(), productsAssetInfo.end(),
|
||||
auto assetInfoIt = AZStd::find_if(
|
||||
productsAssetInfo.begin(), productsAssetInfo.end(),
|
||||
[&assetType](const Data::AssetInfo& assetInfo)
|
||||
{
|
||||
return assetInfo.m_assetType == assetType;
|
||||
});
|
||||
if (assetInfoIt == productsAssetInfo.end())
|
||||
{
|
||||
return invalidAssetId;
|
||||
return defaultAssetId;
|
||||
}
|
||||
|
||||
return assetInfoIt->m_assetId;
|
||||
@@ -53,10 +58,9 @@ namespace AZ
|
||||
{
|
||||
return productKey->GetAssetId();
|
||||
}
|
||||
return invalidAssetId;
|
||||
return defaultAssetId;
|
||||
}
|
||||
|
||||
|
||||
QString WordWrap(const QString& string, int maxLength)
|
||||
{
|
||||
QString result;
|
||||
@@ -81,6 +85,32 @@ namespace AZ
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace Thumbnails
|
||||
|
||||
AZStd::unordered_set<AZ::Uuid> GetSupportedAssetTypes()
|
||||
{
|
||||
return { RPI::AnyAsset::RTTI_Type(), RPI::MaterialAsset::RTTI_Type(), RPI::ModelAsset::RTTI_Type() };
|
||||
}
|
||||
|
||||
bool IsSupportedAssetType(AzToolsFramework::Thumbnailer::SharedThumbnailKey key)
|
||||
{
|
||||
for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes())
|
||||
{
|
||||
const AZ::Data::AssetId& assetId = SharedPreviewUtils::GetAssetId(key, typeId);
|
||||
if (assetId.IsValid())
|
||||
{
|
||||
if (typeId == RPI::AnyAsset::RTTI_Type())
|
||||
{
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
||||
assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, assetId);
|
||||
return AzFramework::StringFunc::EndsWith(assetInfo.m_relativePath.c_str(), "lightingpreset.azasset");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace SharedPreviewUtils
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+14
-4
@@ -18,13 +18,23 @@ namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
namespace SharedPreviewUtils
|
||||
{
|
||||
//! Get assetId by assetType that belongs to either source or product thumbnail key
|
||||
Data::AssetId GetAssetId(AzToolsFramework::Thumbnailer::SharedThumbnailKey key, const Data::AssetType& assetType);
|
||||
Data::AssetId GetAssetId(
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnailKey key,
|
||||
const Data::AssetType& assetType,
|
||||
const Data::AssetId& defaultAssetId = {});
|
||||
|
||||
//! Word wrap function for previewer QLabel, since by default it does not break long words such as filenames, so manual word wrap needed
|
||||
//! Word wrap function for previewer QLabel, since by default it does not break long words such as filenames, so manual word
|
||||
//! wrap needed
|
||||
QString WordWrap(const QString& string, int maxLength);
|
||||
} // namespace Thumbnails
|
||||
|
||||
//! Get the set of all asset types supported by the shared preview
|
||||
AZStd::unordered_set<AZ::Uuid> GetSupportedAssetTypes();
|
||||
|
||||
//! Determine if a thumbnail key has an asset supported by the shared preview
|
||||
bool IsSupportedAssetType(AzToolsFramework::Thumbnailer::SharedThumbnailKey key);
|
||||
} // namespace SharedPreviewUtils
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+20
-18
@@ -7,23 +7,21 @@
|
||||
*/
|
||||
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
|
||||
#include <Source/Thumbnails/Preview/CommonPreviewer.h>
|
||||
#include <Source/Thumbnails/ThumbnailUtils.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <SharedPreview/SharedPreviewUtils.h>
|
||||
#include <SharedPreview/SharedPreviewer.h>
|
||||
|
||||
// Disables warning messages triggered by the Qt library
|
||||
// 4251: class needs to have dll-interface to be used by clients of class
|
||||
// 4251: class needs to have dll-interface to be used by clients of class
|
||||
// 4800: forcing value to bool 'true' or 'false' (performance warning)
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option")
|
||||
#include <Source/Thumbnails/Preview/ui_CommonPreviewer.h>
|
||||
#include <QString>
|
||||
#include <QResizeEvent>
|
||||
#include <QString>
|
||||
#include <SharedPreview/ui_SharedPreviewer.h>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace AZ
|
||||
@@ -32,18 +30,22 @@ namespace AZ
|
||||
{
|
||||
static constexpr int CharWidth = 6;
|
||||
|
||||
CommonPreviewer::CommonPreviewer(QWidget* parent)
|
||||
SharedPreviewer::SharedPreviewer(QWidget* parent)
|
||||
: Previewer(parent)
|
||||
, m_ui(new Ui::CommonPreviewerClass())
|
||||
, m_ui(new Ui::SharedPreviewerClass())
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
}
|
||||
|
||||
CommonPreviewer::~CommonPreviewer()
|
||||
SharedPreviewer::~SharedPreviewer()
|
||||
{
|
||||
}
|
||||
|
||||
void CommonPreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry)
|
||||
void SharedPreviewer::Clear() const
|
||||
{
|
||||
}
|
||||
|
||||
void SharedPreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry)
|
||||
{
|
||||
using namespace AzToolsFramework::AssetBrowser;
|
||||
using namespace AzToolsFramework::Thumbnailer;
|
||||
@@ -54,23 +56,23 @@ namespace AZ
|
||||
UpdateFileInfo();
|
||||
}
|
||||
|
||||
const QString& CommonPreviewer::GetName() const
|
||||
const QString& SharedPreviewer::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void CommonPreviewer::resizeEvent([[maybe_unused]] QResizeEvent* event)
|
||||
void SharedPreviewer::resizeEvent([[maybe_unused]] QResizeEvent* event)
|
||||
{
|
||||
m_ui->m_previewWidget->setMaximumHeight(m_ui->m_previewWidget->width());
|
||||
|
||||
UpdateFileInfo();
|
||||
}
|
||||
|
||||
void CommonPreviewer::UpdateFileInfo() const
|
||||
void SharedPreviewer::UpdateFileInfo() const
|
||||
{
|
||||
m_ui->m_fileInfoLabel->setText(Thumbnails::WordWrap(m_fileInfo, m_ui->m_fileInfoLabel->width() / CharWidth));
|
||||
m_ui->m_fileInfoLabel->setText(SharedPreviewUtils::WordWrap(m_fileInfo, m_ui->m_fileInfoLabel->width() / CharWidth));
|
||||
}
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
|
||||
#include <Source/Thumbnails/Preview/moc_CommonPreviewer.cpp>
|
||||
#include <SharedPreview/moc_SharedPreviewer.cpp>
|
||||
+13
-13
@@ -5,22 +5,23 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Previewer/Previewer.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QWidget>
|
||||
#include <QScopedPointer>
|
||||
#include <QWidget>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class CommonPreviewerClass;
|
||||
class SharedPreviewerClass;
|
||||
}
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -30,8 +31,8 @@ namespace AzToolsFramework
|
||||
class ProductAssetBrowserEntry;
|
||||
class SourceAssetBrowserEntry;
|
||||
class AssetBrowserEntry;
|
||||
}
|
||||
}
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
class QResizeEvent;
|
||||
|
||||
@@ -39,18 +40,17 @@ namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
class CommonPreviewer final
|
||||
: public AzToolsFramework::AssetBrowser::Previewer
|
||||
class SharedPreviewer final : public AzToolsFramework::AssetBrowser::Previewer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(CommonPreviewer, AZ::SystemAllocator, 0);
|
||||
AZ_CLASS_ALLOCATOR(SharedPreviewer, AZ::SystemAllocator, 0);
|
||||
|
||||
explicit CommonPreviewer(QWidget* parent = nullptr);
|
||||
~CommonPreviewer();
|
||||
explicit SharedPreviewer(QWidget* parent = nullptr);
|
||||
~SharedPreviewer();
|
||||
|
||||
// AzToolsFramework::AssetBrowser::Previewer overrides...
|
||||
void Clear() const override {}
|
||||
void Clear() const override;
|
||||
void Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) override;
|
||||
const QString& GetName() const override;
|
||||
|
||||
@@ -60,9 +60,9 @@ namespace AZ
|
||||
private:
|
||||
void UpdateFileInfo() const;
|
||||
|
||||
QScopedPointer<Ui::CommonPreviewerClass> m_ui;
|
||||
QScopedPointer<Ui::SharedPreviewerClass> m_ui;
|
||||
QString m_fileInfo;
|
||||
QString m_name = "CommonPreviewer";
|
||||
QString m_name = "SharedPreviewer";
|
||||
};
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CommonPreviewerClass</class>
|
||||
<widget class="QWidget" name="CommonPreviewerClass">
|
||||
<class>SharedPreviewerClass</class>
|
||||
<widget class="QWidget" name="SharedPreviewerClass">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
|
||||
#include <SharedPreview/SharedPreviewUtils.h>
|
||||
#include <SharedPreview/SharedPreviewer.h>
|
||||
#include <SharedPreview/SharedPreviewerFactory.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
AzToolsFramework::AssetBrowser::Previewer* SharedPreviewerFactory::CreatePreviewer(QWidget* parent) const
|
||||
{
|
||||
return new SharedPreviewer(parent);
|
||||
}
|
||||
|
||||
bool SharedPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const
|
||||
{
|
||||
return SharedPreviewUtils::IsSupportedAssetType(entry->GetThumbnailKey());
|
||||
}
|
||||
|
||||
const QString& SharedPreviewerFactory::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+6
-6
@@ -5,6 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
@@ -18,14 +19,13 @@ namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
class CommonPreviewerFactory final
|
||||
: public AzToolsFramework::AssetBrowser::PreviewerFactory
|
||||
class SharedPreviewerFactory final : public AzToolsFramework::AssetBrowser::PreviewerFactory
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(CommonPreviewerFactory, AZ::SystemAllocator, 0);
|
||||
AZ_CLASS_ALLOCATOR(SharedPreviewerFactory, AZ::SystemAllocator, 0);
|
||||
|
||||
CommonPreviewerFactory() = default;
|
||||
~CommonPreviewerFactory() = default;
|
||||
SharedPreviewerFactory() = default;
|
||||
~SharedPreviewerFactory() = default;
|
||||
|
||||
// AzToolsFramework::AssetBrowser::PreviewerFactory overrides...
|
||||
AzToolsFramework::AssetBrowser::Previewer* CreatePreviewer(QWidget* parent = nullptr) const override;
|
||||
@@ -33,7 +33,7 @@ namespace AZ
|
||||
const QString& GetName() const override;
|
||||
|
||||
private:
|
||||
QString m_name = "CommonPreviewer";
|
||||
QString m_name = "SharedPreviewer";
|
||||
};
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include <SharedPreview/SharedPreviewUtils.h>
|
||||
#include <SharedPreview/SharedThumbnail.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
static constexpr const int SharedThumbnailSize = 256;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SharedThumbnail
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
SharedThumbnail::SharedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key)
|
||||
: Thumbnail(key)
|
||||
{
|
||||
for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes())
|
||||
{
|
||||
const AZ::Data::AssetId& assetId = SharedPreviewUtils::GetAssetId(key, typeId);
|
||||
if (assetId.IsValid())
|
||||
{
|
||||
m_assetId = assetId;
|
||||
m_typeId = typeId;
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key);
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Error("SharedThumbnail", false, "Failed to find matching assetId for the thumbnailKey.");
|
||||
m_state = State::Failed;
|
||||
}
|
||||
|
||||
void SharedThumbnail::LoadThread()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent(
|
||||
m_typeId, &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, SharedThumbnailSize);
|
||||
// wait for response from thumbnail renderer
|
||||
m_renderWait.acquire();
|
||||
}
|
||||
|
||||
SharedThumbnail::~SharedThumbnail()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect();
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void SharedThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage)
|
||||
{
|
||||
m_pixmap = thumbnailImage;
|
||||
m_renderWait.release();
|
||||
}
|
||||
|
||||
void SharedThumbnail::ThumbnailFailedToRender()
|
||||
{
|
||||
m_state = State::Failed;
|
||||
m_renderWait.release();
|
||||
}
|
||||
|
||||
void SharedThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId)
|
||||
{
|
||||
if (m_assetId == assetId && m_state == State::Ready)
|
||||
{
|
||||
m_state = State::Unloaded;
|
||||
Load();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SharedThumbnailCache
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
SharedThumbnailCache::SharedThumbnailCache()
|
||||
: ThumbnailCache<SharedThumbnail>()
|
||||
{
|
||||
}
|
||||
|
||||
SharedThumbnailCache::~SharedThumbnailCache() = default;
|
||||
|
||||
int SharedThumbnailCache::GetPriority() const
|
||||
{
|
||||
// Thumbnails override default source thumbnails, so carry higher priority
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* SharedThumbnailCache::GetProviderName() const
|
||||
{
|
||||
return ProviderName;
|
||||
}
|
||||
|
||||
bool SharedThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const
|
||||
{
|
||||
return SharedPreviewUtils::IsSupportedAssetType(key);
|
||||
}
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
|
||||
#include <SharedPreview/moc_SharedThumbnail.cpp>
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/parallel/binary_semaphore.h>
|
||||
#include <AzFramework/Asset/AssetCatalogBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#endif
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
//! Custom thumbnail that detects when an asset changes and updates the thumbnail
|
||||
class SharedThumbnail final
|
||||
: public AzToolsFramework::Thumbnailer::Thumbnail
|
||||
, public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler
|
||||
, private AzFramework::AssetCatalogEventBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SharedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key);
|
||||
~SharedThumbnail() override;
|
||||
|
||||
//! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides...
|
||||
void ThumbnailRendered(const QPixmap& thumbnailImage) override;
|
||||
void ThumbnailFailedToRender() override;
|
||||
|
||||
protected:
|
||||
void LoadThread() override;
|
||||
|
||||
private:
|
||||
// AzFramework::AssetCatalogEventBus::Handler interface overrides...
|
||||
void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override;
|
||||
|
||||
AZStd::binary_semaphore m_renderWait;
|
||||
Data::AssetId m_assetId;
|
||||
AZ::Uuid m_typeId;
|
||||
};
|
||||
|
||||
//! Cache configuration for large thumbnails
|
||||
class SharedThumbnailCache final : public AzToolsFramework::Thumbnailer::ThumbnailCache<SharedThumbnail>
|
||||
{
|
||||
public:
|
||||
SharedThumbnailCache();
|
||||
~SharedThumbnailCache() override;
|
||||
|
||||
int GetPriority() const override;
|
||||
const char* GetProviderName() const override;
|
||||
|
||||
static constexpr const char* ProviderName = "Common Feature Shared Thumbnail= Provider";
|
||||
|
||||
protected:
|
||||
bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override;
|
||||
};
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <SharedPreview/SharedPreviewContent.h>
|
||||
#include <SharedPreview/SharedPreviewUtils.h>
|
||||
#include <SharedPreview/SharedThumbnailRenderer.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
SharedThumbnailRenderer::SharedThumbnailRenderer()
|
||||
{
|
||||
m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer(
|
||||
"SharedThumbnailRenderer Preview Scene", "SharedThumbnailRenderer Preview Pipeline"));
|
||||
|
||||
m_defaultModelAsset.Create(DefaultModelAssetId, true);
|
||||
m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true);
|
||||
m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true);
|
||||
|
||||
for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes())
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(typeId);
|
||||
}
|
||||
SystemTickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
SharedThumbnailRenderer::~SharedThumbnailRenderer()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect();
|
||||
SystemTickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void SharedThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize)
|
||||
{
|
||||
m_previewRenderer->AddCaptureRequest(
|
||||
{ thumbnailSize,
|
||||
AZStd::make_shared<SharedPreviewContent>(
|
||||
m_previewRenderer->GetScene(), m_previewRenderer->GetView(), m_previewRenderer->GetEntityContextId(),
|
||||
SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type(), DefaultModelAssetId),
|
||||
SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type(), DefaultMaterialAssetId),
|
||||
SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type(), DefaultLightingPresetAssetId),
|
||||
Render::MaterialPropertyOverrideMap()),
|
||||
[thumbnailKey]()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
|
||||
},
|
||||
[thumbnailKey](const QPixmap& pixmap)
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, pixmap);
|
||||
} });
|
||||
}
|
||||
|
||||
bool SharedThumbnailRenderer::Installed() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void SharedThumbnailRenderer::OnSystemTick()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents();
|
||||
}
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
|
||||
#include <Atom/RPI.Reflect/System/AnyAsset.h>
|
||||
#include <AtomToolsFramework/PreviewRenderer/PreviewRenderer.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <Thumbnails/Thumbnail.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
//! Provides custom rendering thumbnails of supported asset types
|
||||
class SharedThumbnailRenderer final
|
||||
: public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler
|
||||
, public SystemTickBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(SharedThumbnailRenderer, AZ::SystemAllocator, 0);
|
||||
|
||||
SharedThumbnailRenderer();
|
||||
~SharedThumbnailRenderer();
|
||||
|
||||
private:
|
||||
//! ThumbnailerRendererRequestsBus::Handler interface overrides...
|
||||
void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override;
|
||||
bool Installed() const override;
|
||||
|
||||
//! SystemTickBus::Handler interface overrides...
|
||||
void OnSystemTick() override;
|
||||
|
||||
// Default assets to be kept loaded and used for rendering if not overridden
|
||||
static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset";
|
||||
const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath);
|
||||
Data::Asset<RPI::AnyAsset> m_defaultLightingPresetAsset;
|
||||
|
||||
static constexpr const char* DefaultModelPath = "models/sphere.azmodel";
|
||||
const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath);
|
||||
Data::Asset<RPI::ModelAsset> m_defaultModelAsset;
|
||||
|
||||
static constexpr const char* DefaultMaterialPath = "";
|
||||
const Data::AssetId DefaultMaterialAssetId;
|
||||
Data::Asset<RPI::MaterialAsset> m_defaultMaterialAsset;
|
||||
|
||||
AZStd::unique_ptr<AtomToolsFramework::PreviewRenderer> m_previewRenderer;
|
||||
};
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
|
||||
#include <Source/Thumbnails/Preview/CommonPreviewer.h>
|
||||
#include <Source/Thumbnails/Preview/CommonPreviewerFactory.h>
|
||||
#include <Source/Thumbnails/ThumbnailUtils.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
AzToolsFramework::AssetBrowser::Previewer* CommonPreviewerFactory::CreatePreviewer(QWidget* parent) const
|
||||
{
|
||||
return new CommonPreviewer(parent);
|
||||
}
|
||||
|
||||
bool CommonPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const
|
||||
{
|
||||
return
|
||||
Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::MaterialAsset::RTTI_Type()).IsValid() ||
|
||||
Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::ModelAsset::RTTI_Type()).IsValid();
|
||||
}
|
||||
|
||||
const QString& CommonPreviewerFactory::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
-120
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <Thumbnails/Rendering/CommonThumbnailRenderer.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
CommonThumbnailRenderer::CommonThumbnailRenderer()
|
||||
: m_data(new ThumbnailRendererData)
|
||||
{
|
||||
// CommonThumbnailRenderer supports both models and materials, but we connect on materialAssetType
|
||||
// since MaterialOrModelThumbnail dispatches event on materialAssetType address too
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type());
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type());
|
||||
SystemTickBus::Handler::BusConnect();
|
||||
ThumbnailFeatureProcessorProviderBus::Handler::BusConnect();
|
||||
|
||||
m_steps[Step::Initialize] = AZStd::make_shared<InitializeStep>(this);
|
||||
m_steps[Step::FindThumbnailToRender] = AZStd::make_shared<FindThumbnailToRenderStep>(this);
|
||||
m_steps[Step::WaitForAssetsToLoad] = AZStd::make_shared<WaitForAssetsToLoadStep>(this);
|
||||
m_steps[Step::Capture] = AZStd::make_shared<CaptureStep>(this);
|
||||
m_steps[Step::ReleaseResources] = AZStd::make_shared<ReleaseResourcesStep>(this);
|
||||
|
||||
m_minimalFeatureProcessors =
|
||||
{
|
||||
"AZ::Render::TransformServiceFeatureProcessor",
|
||||
"AZ::Render::MeshFeatureProcessor",
|
||||
"AZ::Render::SimplePointLightFeatureProcessor",
|
||||
"AZ::Render::SimpleSpotLightFeatureProcessor",
|
||||
"AZ::Render::PointLightFeatureProcessor",
|
||||
// There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow
|
||||
// flickering [ATOM-13568]
|
||||
// as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now.
|
||||
// Possibly re-enable with [GFX TODO][ATOM-13639]
|
||||
// "AZ::Render::DirectionalLightFeatureProcessor",
|
||||
"AZ::Render::DiskLightFeatureProcessor",
|
||||
"AZ::Render::CapsuleLightFeatureProcessor",
|
||||
"AZ::Render::QuadLightFeatureProcessor",
|
||||
"AZ::Render::DecalTextureArrayFeatureProcessor",
|
||||
"AZ::Render::ImageBasedLightFeatureProcessor",
|
||||
"AZ::Render::PostProcessFeatureProcessor",
|
||||
"AZ::Render::SkyBoxFeatureProcessor"
|
||||
};
|
||||
}
|
||||
|
||||
CommonThumbnailRenderer::~CommonThumbnailRenderer()
|
||||
{
|
||||
if (m_currentStep != Step::None)
|
||||
{
|
||||
CommonThumbnailRenderer::SetStep(Step::ReleaseResources);
|
||||
}
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect();
|
||||
SystemTickBus::Handler::BusDisconnect();
|
||||
ThumbnailFeatureProcessorProviderBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void CommonThumbnailRenderer::SetStep(Step step)
|
||||
{
|
||||
if (m_currentStep != Step::None)
|
||||
{
|
||||
m_steps[m_currentStep]->Stop();
|
||||
}
|
||||
m_currentStep = step;
|
||||
m_steps[m_currentStep]->Start();
|
||||
}
|
||||
|
||||
Step CommonThumbnailRenderer::GetStep() const
|
||||
{
|
||||
return m_currentStep;
|
||||
}
|
||||
|
||||
bool CommonThumbnailRenderer::Installed() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CommonThumbnailRenderer::OnSystemTick()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents();
|
||||
}
|
||||
|
||||
const AZStd::vector<AZStd::string>& CommonThumbnailRenderer::GetCustomFeatureProcessors() const
|
||||
{
|
||||
return m_minimalFeatureProcessors;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<ThumbnailRendererData> CommonThumbnailRenderer::GetData() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
void CommonThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize)
|
||||
{
|
||||
m_data->m_thumbnailSize = thumbnailSize;
|
||||
m_data->m_thumbnailQueue.push(thumbnailKey);
|
||||
if (m_currentStep == Step::None)
|
||||
{
|
||||
SetStep(Step::Initialize);
|
||||
}
|
||||
}
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h>
|
||||
|
||||
// Disables warning messages triggered by the Qt library
|
||||
// 4251: class needs to have dll-interface to be used by clients of class
|
||||
// 4800: forcing value to bool 'true' or 'false' (performance warning)
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option")
|
||||
#include <QPixmap>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
class ThumbnailRendererStep;
|
||||
|
||||
//! Provides custom rendering of material and model thumbnails
|
||||
class CommonThumbnailRenderer
|
||||
: public ThumbnailRendererContext
|
||||
, private AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler
|
||||
, private SystemTickBus::Handler
|
||||
, private ThumbnailFeatureProcessorProviderBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(CommonThumbnailRenderer, AZ::SystemAllocator, 0)
|
||||
|
||||
CommonThumbnailRenderer();
|
||||
~CommonThumbnailRenderer();
|
||||
|
||||
//! ThumbnailRendererContext overrides...
|
||||
void SetStep(Step step) override;
|
||||
Step GetStep() const override;
|
||||
AZStd::shared_ptr<ThumbnailRendererData> GetData() const override;
|
||||
|
||||
private:
|
||||
//! ThumbnailerRendererRequestsBus::Handler interface overrides...
|
||||
void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override;
|
||||
bool Installed() const override;
|
||||
|
||||
//! SystemTickBus::Handler interface overrides...
|
||||
void OnSystemTick() override;
|
||||
|
||||
//! Render::ThumbnailFeatureProcessorProviderBus::Handler interface overrides...
|
||||
const AZStd::vector<AZStd::string>& GetCustomFeatureProcessors() const override;
|
||||
|
||||
AZStd::unordered_map<Step, AZStd::shared_ptr<ThumbnailRendererStep>> m_steps;
|
||||
Step m_currentStep = Step::None;
|
||||
AZStd::shared_ptr<ThumbnailRendererData> m_data;
|
||||
AZStd::vector<AZStd::string> m_minimalFeatureProcessors;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
struct ThumbnailRendererData;
|
||||
|
||||
enum class Step
|
||||
{
|
||||
None,
|
||||
Initialize,
|
||||
FindThumbnailToRender,
|
||||
WaitForAssetsToLoad,
|
||||
Capture,
|
||||
ReleaseResources
|
||||
};
|
||||
|
||||
//! An interface for ThumbnailRendererSteps to communicate with thumbnail renderer
|
||||
class ThumbnailRendererContext
|
||||
{
|
||||
public:
|
||||
virtual void SetStep(Step step) = 0;
|
||||
virtual Step GetStep() const = 0;
|
||||
virtual AZStd::shared_ptr<ThumbnailRendererData> GetData() const = 0;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Atom/RPI.Reflect/Model/ModelAsset.h"
|
||||
|
||||
#include <Atom/RPI.Public/Base.h>
|
||||
#include <Atom/RPI.Reflect/System/AnyAsset.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzFramework/Entity/GameEntityContextComponent.h>
|
||||
#include <Thumbnails/Thumbnail.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class Scene;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
//! ThumbnailRendererData encapsulates all data used by thumbnail renderer and caches assets
|
||||
struct ThumbnailRendererData final
|
||||
{
|
||||
static constexpr const char* LightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset";
|
||||
static constexpr const char* DefaultModelPath = "models/sphere.azmodel";
|
||||
static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial";
|
||||
|
||||
RPI::ScenePtr m_scene;
|
||||
AZStd::string m_sceneName = "Material Thumbnail Scene";
|
||||
AZStd::string m_pipelineName = "Material Thumbnail Pipeline";
|
||||
AZStd::shared_ptr<AzFramework::Scene> m_frameworkScene;
|
||||
RPI::RenderPipelinePtr m_renderPipeline;
|
||||
AZStd::unique_ptr<AzFramework::EntityContext> m_entityContext;
|
||||
AZStd::vector<AZStd::string> m_passHierarchy;
|
||||
|
||||
RPI::ViewPtr m_view = nullptr;
|
||||
Entity* m_modelEntity = nullptr;
|
||||
|
||||
int m_thumbnailSize = 512;
|
||||
|
||||
//! Incoming thumbnail requests are appended to this queue and processed one at a time in OnTick function.
|
||||
AZStd::queue<AzToolsFramework::Thumbnailer::SharedThumbnailKey> m_thumbnailQueue;
|
||||
//! Current thumbnail key being rendered.
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnailKey m_thumbnailKeyRendered;
|
||||
|
||||
Data::Asset<RPI::AnyAsset> m_lightingPresetAsset;
|
||||
|
||||
Data::Asset<RPI::ModelAsset> m_defaultModelAsset;
|
||||
//! Model asset about to be rendered
|
||||
Data::Asset<RPI::ModelAsset> m_modelAsset;
|
||||
|
||||
Data::Asset<RPI::MaterialAsset> m_defaultMaterialAsset;
|
||||
//! Material asset about to be rendered
|
||||
Data::Asset<RPI::MaterialAsset> m_materialAsset;
|
||||
|
||||
AZStd::unordered_set<Data::AssetId> m_assetsToLoad;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
-130
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/Feature/Utils/FrameCaptureBus.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
CaptureStep::CaptureStep(ThumbnailRendererContext* context)
|
||||
: ThumbnailRendererStep(context)
|
||||
{
|
||||
}
|
||||
|
||||
void CaptureStep::Start()
|
||||
{
|
||||
if (!m_context->GetData()->m_materialAsset ||
|
||||
!m_context->GetData()->m_modelAsset)
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
m_context->GetData()->m_thumbnailKeyRendered,
|
||||
&AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
|
||||
m_context->SetStep(Step::FindThumbnailToRender);
|
||||
return;
|
||||
}
|
||||
Render::MaterialComponentRequestBus::Event(
|
||||
m_context->GetData()->m_modelEntity->GetId(),
|
||||
&Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride,
|
||||
m_context->GetData()->m_materialAsset.GetId());
|
||||
Render::MeshComponentRequestBus::Event(
|
||||
m_context->GetData()->m_modelEntity->GetId(),
|
||||
&Render::MeshComponentRequestBus::Events::SetModelAsset,
|
||||
m_context->GetData()->m_modelAsset);
|
||||
RepositionCamera();
|
||||
m_readyToCapture = true;
|
||||
m_ticksToCapture = 1;
|
||||
TickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void CaptureStep::Stop()
|
||||
{
|
||||
m_context->GetData()->m_renderPipeline->RemoveFromRenderTick();
|
||||
TickBus::Handler::BusDisconnect();
|
||||
Render::FrameCaptureNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void CaptureStep::RepositionCamera() const
|
||||
{
|
||||
// Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it
|
||||
const Aabb& aabb = m_context->GetData()->m_modelAsset->GetAabb();
|
||||
Vector3 modelCenter;
|
||||
float radius;
|
||||
aabb.GetAsSphere(modelCenter, radius);
|
||||
|
||||
float distance = StartingDistanceMultiplier *
|
||||
GetMax(GetMax(aabb.GetExtents().GetX(), aabb.GetExtents().GetY()), aabb.GetExtents().GetZ()) +
|
||||
DepthNear;
|
||||
const Quaternion cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), StartingRotationAngle);
|
||||
Vector3 cameraPosition(modelCenter.GetX(), modelCenter.GetY() - distance, modelCenter.GetZ());
|
||||
cameraPosition = cameraRotation.TransformVector(cameraPosition);
|
||||
auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition);
|
||||
m_context->GetData()->m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform));
|
||||
}
|
||||
|
||||
void CaptureStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time)
|
||||
{
|
||||
if (m_readyToCapture && m_ticksToCapture-- <= 0)
|
||||
{
|
||||
m_context->GetData()->m_renderPipeline->AddToRenderTickOnce();
|
||||
|
||||
RPI::AttachmentReadback::CallbackFunction readbackCallback = [&](const RPI::AttachmentReadback::ReadbackResult& result)
|
||||
{
|
||||
if (!result.m_dataBuffer)
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
m_context->GetData()->m_thumbnailKeyRendered,
|
||||
&AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
|
||||
return;
|
||||
}
|
||||
uchar* data = result.m_dataBuffer.get()->data();
|
||||
QImage image(
|
||||
data, result.m_imageDescriptor.m_size.m_width, result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888);
|
||||
QPixmap pixmap;
|
||||
pixmap.convertFromImage(image);
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
m_context->GetData()->m_thumbnailKeyRendered,
|
||||
&AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered,
|
||||
pixmap);
|
||||
};
|
||||
|
||||
Render::FrameCaptureNotificationBus::Handler::BusConnect();
|
||||
bool startedCapture = false;
|
||||
Render::FrameCaptureRequestBus::BroadcastResult(
|
||||
startedCapture,
|
||||
&Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback,
|
||||
m_context->GetData()->m_passHierarchy, AZStd::string("Output"), readbackCallback, RPI::PassAttachmentReadbackOption::Output);
|
||||
// Reset the capture flag if the capture request was successful. Otherwise try capture it again next tick.
|
||||
if (startedCapture)
|
||||
{
|
||||
m_readyToCapture = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureStep::OnCaptureFinished([[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info)
|
||||
{
|
||||
m_context->SetStep(Step::FindThumbnailToRender);
|
||||
}
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Feature/Utils/FrameCaptureBus.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
//! CaptureStep renders a thumbnail to a pixmap and notifies MaterialOrModelThumbnail once finished
|
||||
class CaptureStep
|
||||
: public ThumbnailRendererStep
|
||||
, private TickBus::Handler
|
||||
, private Render::FrameCaptureNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
CaptureStep(ThumbnailRendererContext* context);
|
||||
|
||||
void Start() override;
|
||||
void Stop() override;
|
||||
|
||||
private:
|
||||
//! Places the camera so that the entire model is visible
|
||||
void RepositionCamera() const;
|
||||
|
||||
//! AZ::TickBus::Handler interface overrides...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
//! Render::FrameCaptureNotificationBus::Handler overrides...
|
||||
void OnCaptureFinished(Render::FrameCaptureResult result, const AZStd::string& info) override;
|
||||
|
||||
static constexpr float DepthNear = 0.01f;
|
||||
static constexpr float StartingDistanceMultiplier = 1.75f;
|
||||
static constexpr float StartingRotationAngle = Constants::QuarterPi / 2.0f;
|
||||
|
||||
//! This flag is needed to wait one frame after each frame capture to reset FrameCaptureSystemComponent
|
||||
bool m_readyToCapture = true;
|
||||
//! This is necessary to suspend capture to allow a frame for Material and Mesh components to assign materials
|
||||
int m_ticksToCapture = 0;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
|
||||
#include <Thumbnails/ThumbnailUtils.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
FindThumbnailToRenderStep::FindThumbnailToRenderStep(ThumbnailRendererContext* context)
|
||||
: ThumbnailRendererStep(context)
|
||||
{
|
||||
}
|
||||
|
||||
void FindThumbnailToRenderStep::Start()
|
||||
{
|
||||
TickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void FindThumbnailToRenderStep::Stop()
|
||||
{
|
||||
TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void FindThumbnailToRenderStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time)
|
||||
{
|
||||
PickNextThumbnail();
|
||||
}
|
||||
|
||||
void FindThumbnailToRenderStep::PickNextThumbnail()
|
||||
{
|
||||
if (!m_context->GetData()->m_thumbnailQueue.empty())
|
||||
{
|
||||
// pop the next thumbnailkey to be rendered from the queue
|
||||
m_context->GetData()->m_thumbnailKeyRendered = m_context->GetData()->m_thumbnailQueue.front();
|
||||
m_context->GetData()->m_thumbnailQueue.pop();
|
||||
|
||||
// Find whether thumbnailkey contains a material asset or set a default material
|
||||
m_context->GetData()->m_materialAsset = m_context->GetData()->m_defaultMaterialAsset;
|
||||
Data::AssetId materialAssetId = GetAssetId(m_context->GetData()->m_thumbnailKeyRendered, RPI::MaterialAsset::RTTI_Type());
|
||||
if (materialAssetId.IsValid())
|
||||
{
|
||||
if (m_context->GetData()->m_assetsToLoad.emplace(materialAssetId).second)
|
||||
{
|
||||
m_context->GetData()->m_materialAsset.Create(materialAssetId);
|
||||
m_context->GetData()->m_materialAsset.QueueLoad();
|
||||
}
|
||||
}
|
||||
|
||||
// Find whether thumbnailkey contains a model asset or set a default model
|
||||
m_context->GetData()->m_modelAsset = m_context->GetData()->m_defaultModelAsset;
|
||||
Data::AssetId modelAssetId = GetAssetId(m_context->GetData()->m_thumbnailKeyRendered, RPI::ModelAsset::RTTI_Type());
|
||||
if (modelAssetId.IsValid())
|
||||
{
|
||||
if (m_context->GetData()->m_assetsToLoad.emplace(modelAssetId).second)
|
||||
{
|
||||
m_context->GetData()->m_modelAsset.Create(modelAssetId);
|
||||
m_context->GetData()->m_modelAsset.QueueLoad();
|
||||
}
|
||||
}
|
||||
|
||||
m_context->SetStep(Step::WaitForAssetsToLoad);
|
||||
}
|
||||
}
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
//! FindThumbnailToRenderStep checks whether there are any new thumbnails that need to be rendered every tick
|
||||
class FindThumbnailToRenderStep
|
||||
: public ThumbnailRendererStep
|
||||
, private TickBus::Handler
|
||||
{
|
||||
public:
|
||||
FindThumbnailToRenderStep(ThumbnailRendererContext* context);
|
||||
|
||||
void Start() override;
|
||||
void Stop() override;
|
||||
|
||||
private:
|
||||
|
||||
//! AZ::TickBus::Handler interface overrides...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
void PickNextThumbnail();
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
|
||||
-191
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
#include <AzCore/EBus/Results.h>
|
||||
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
|
||||
#include <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/Utils/LightingPreset.h>
|
||||
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
|
||||
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
|
||||
#include <Atom/RPI.Reflect/System/RenderPipelineDescriptor.h>
|
||||
#include <Atom/RPI.Reflect/System/SceneDescriptor.h>
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h>
|
||||
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
InitializeStep::InitializeStep(ThumbnailRendererContext* context)
|
||||
: ThumbnailRendererStep(context)
|
||||
{
|
||||
}
|
||||
|
||||
void InitializeStep::Start()
|
||||
{
|
||||
auto data = m_context->GetData();
|
||||
|
||||
data->m_entityContext = AZStd::make_unique<AzFramework::EntityContext>();
|
||||
data->m_entityContext->InitContext();
|
||||
|
||||
// Create and register a scene with all required feature processors
|
||||
RPI::SceneDescriptor sceneDesc;
|
||||
|
||||
AZ::EBusAggregateResults<AZStd::vector<AZStd::string>> results;
|
||||
ThumbnailFeatureProcessorProviderBus::BroadcastResult(results, &ThumbnailFeatureProcessorProviderBus::Handler::GetCustomFeatureProcessors);
|
||||
|
||||
AZStd::set<AZStd::string> featureProcessorNames;
|
||||
for (auto& resultCollection : results.values)
|
||||
{
|
||||
for (auto& featureProcessorName : resultCollection)
|
||||
{
|
||||
if (featureProcessorNames.emplace(featureProcessorName).second)
|
||||
{
|
||||
sceneDesc.m_featureProcessorNames.push_back(featureProcessorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data->m_scene = RPI::Scene::CreateScene(sceneDesc);
|
||||
|
||||
// Bind m_defaultScene to the GameEntityContext's AzFramework::Scene
|
||||
auto* sceneSystem = AzFramework::SceneSystemInterface::Get();
|
||||
AZ_Assert(sceneSystem, "Thumbnail system failed to get scene system implementation.");
|
||||
Outcome<AZStd::shared_ptr<AzFramework::Scene>, AZStd::string> createSceneOutcome =
|
||||
sceneSystem->CreateScene(data->m_sceneName);
|
||||
AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); // This should never happen unless scene creation has changed.
|
||||
data->m_frameworkScene = createSceneOutcome.TakeValue();
|
||||
data->m_frameworkScene->SetSubsystem(data->m_scene);
|
||||
|
||||
data->m_frameworkScene->SetSubsystem(data->m_entityContext.get());
|
||||
// Create a render pipeline from the specified asset for the window context and add the pipeline to the scene
|
||||
RPI::RenderPipelineDescriptor pipelineDesc;
|
||||
pipelineDesc.m_mainViewTagName = "MainCamera";
|
||||
pipelineDesc.m_name = data->m_pipelineName;
|
||||
pipelineDesc.m_rootPassTemplate = "ThumbnailPipelineRenderToTexture";
|
||||
// We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue
|
||||
// [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost
|
||||
pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4;
|
||||
data->m_renderPipeline = RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc);
|
||||
data->m_scene->AddRenderPipeline(data->m_renderPipeline);
|
||||
data->m_scene->Activate();
|
||||
RPI::RPISystemInterface::Get()->RegisterScene(data->m_scene);
|
||||
data->m_passHierarchy.push_back(data->m_pipelineName);
|
||||
data->m_passHierarchy.push_back("CopyToSwapChain");
|
||||
|
||||
// Connect camera to pipeline's default view after camera entity activated
|
||||
Name viewName = Name("MainCamera");
|
||||
data->m_view = RPI::View::CreateView(viewName, RPI::View::UsageCamera);
|
||||
|
||||
Matrix4x4 viewToClipMatrix;
|
||||
MakePerspectiveFovMatrixRH(viewToClipMatrix,
|
||||
Constants::QuarterPi,
|
||||
AspectRatio,
|
||||
NearDist,
|
||||
FarDist, true);
|
||||
data->m_view->SetViewToClipMatrix(viewToClipMatrix);
|
||||
|
||||
data->m_renderPipeline->SetDefaultView(data->m_view);
|
||||
|
||||
// Create lighting preset
|
||||
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>();
|
||||
if (preset)
|
||||
{
|
||||
auto iblFeatureProcessor = data->m_scene->GetFeatureProcessor<Render::ImageBasedLightFeatureProcessorInterface>();
|
||||
auto postProcessFeatureProcessor = data->m_scene->GetFeatureProcessor<Render::PostProcessFeatureProcessorInterface>();
|
||||
auto exposureControlSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId())->GetOrCreateExposureControlSettingsInterface();
|
||||
auto directionalLightFeatureProcessor = data->m_scene->GetFeatureProcessor<Render::DirectionalLightFeatureProcessorInterface>();
|
||||
auto skyboxFeatureProcessor = data->m_scene->GetFeatureProcessor<Render::SkyBoxFeatureProcessorInterface>();
|
||||
skyboxFeatureProcessor->Enable(true);
|
||||
skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap);
|
||||
|
||||
Camera::Configuration cameraConfig;
|
||||
cameraConfig.m_fovRadians = Constants::HalfPi;
|
||||
cameraConfig.m_nearClipDistance = NearDist;
|
||||
cameraConfig.m_farClipDistance = FarDist;
|
||||
cameraConfig.m_frustumWidth = 100.0f;
|
||||
cameraConfig.m_frustumHeight = 100.0f;
|
||||
|
||||
AZStd::vector<Render::DirectionalLightFeatureProcessorInterface::LightHandle> lightHandles;
|
||||
|
||||
preset->ApplyLightingPreset(
|
||||
iblFeatureProcessor,
|
||||
skyboxFeatureProcessor,
|
||||
exposureControlSettingInterface,
|
||||
directionalLightFeatureProcessor,
|
||||
cameraConfig,
|
||||
lightHandles);
|
||||
}
|
||||
}
|
||||
|
||||
// Create preview model
|
||||
AzFramework::EntityContextRequestBus::EventResult(data->m_modelEntity, data->m_entityContext->GetContextId(),
|
||||
&AzFramework::EntityContextRequestBus::Events::CreateEntity, "ThumbnailPreviewModel");
|
||||
data->m_modelEntity->CreateComponent(Render::MeshComponentTypeId);
|
||||
data->m_modelEntity->CreateComponent(Render::MaterialComponentTypeId);
|
||||
data->m_modelEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
data->m_modelEntity->Init();
|
||||
data->m_modelEntity->Activate();
|
||||
|
||||
// preload default model
|
||||
Data::AssetId defaultModelAssetId;
|
||||
Data::AssetCatalogRequestBus::BroadcastResult(
|
||||
defaultModelAssetId,
|
||||
&Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
|
||||
m_context->GetData()->DefaultModelPath,
|
||||
RPI::ModelAsset::RTTI_Type(),
|
||||
false);
|
||||
AZ_Error("ThumbnailRenderer", defaultModelAssetId.IsValid(), "Default model asset is invalid. Verify the asset %s exists.", m_context->GetData()->DefaultModelPath);
|
||||
if (m_context->GetData()->m_assetsToLoad.emplace(defaultModelAssetId).second)
|
||||
{
|
||||
data->m_defaultModelAsset.Create(defaultModelAssetId);
|
||||
data->m_defaultModelAsset.QueueLoad();
|
||||
}
|
||||
|
||||
// preload default material
|
||||
Data::AssetId defaultMaterialAssetId;
|
||||
Data::AssetCatalogRequestBus::BroadcastResult(
|
||||
defaultMaterialAssetId,
|
||||
&Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
|
||||
m_context->GetData()->DefaultMaterialPath,
|
||||
RPI::MaterialAsset::RTTI_Type(),
|
||||
false);
|
||||
AZ_Error("ThumbnailRenderer", defaultMaterialAssetId.IsValid(), "Default material asset is invalid. Verify the asset %s exists.", m_context->GetData()->DefaultMaterialPath);
|
||||
if (m_context->GetData()->m_assetsToLoad.emplace(defaultMaterialAssetId).second)
|
||||
{
|
||||
data->m_defaultMaterialAsset.Create(defaultMaterialAssetId);
|
||||
data->m_defaultMaterialAsset.QueueLoad();
|
||||
}
|
||||
|
||||
m_context->SetStep(Step::FindThumbnailToRender);
|
||||
}
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
//! InitializeStep sets up RPI system and scene and prepares it for rendering thumbnail entities
|
||||
//! This step is only called once when CommonThumbnailRenderer begins rendering its first thumbnail
|
||||
class InitializeStep
|
||||
: public ThumbnailRendererStep
|
||||
{
|
||||
public:
|
||||
InitializeStep(ThumbnailRendererContext* context);
|
||||
|
||||
void Start() override;
|
||||
|
||||
private:
|
||||
static constexpr float AspectRatio = 1.0f;
|
||||
static constexpr float NearDist = 0.1f;
|
||||
static constexpr float FarDist = 100.0f;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <AzFramework/Scene/Scene.h>
|
||||
#include <AzFramework/Scene/SceneSystemInterface.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
ReleaseResourcesStep::ReleaseResourcesStep(ThumbnailRendererContext* context)
|
||||
: ThumbnailRendererStep(context)
|
||||
{
|
||||
}
|
||||
|
||||
void ReleaseResourcesStep::Start()
|
||||
{
|
||||
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 (data->m_modelEntity)
|
||||
{
|
||||
AzFramework::EntityContextRequestBus::Event(data->m_entityContext->GetContextId(),
|
||||
&AzFramework::EntityContextRequestBus::Events::DestroyEntity, data->m_modelEntity);
|
||||
data->m_modelEntity = 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
|
||||
} // namespace AZ
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
class ReleaseResourcesStep
|
||||
: public ThumbnailRendererStep
|
||||
{
|
||||
public:
|
||||
ReleaseResourcesStep(ThumbnailRendererContext* context);
|
||||
|
||||
void Start() override;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
class ThumbnailRendererContext;
|
||||
|
||||
//! ThumbnailRendererStep decouples CommonThumbnailRenderer logic into easy-to-understand and debug pieces
|
||||
class ThumbnailRendererStep
|
||||
{
|
||||
public:
|
||||
explicit ThumbnailRendererStep(ThumbnailRendererContext* context) : m_context(context) {}
|
||||
virtual ~ThumbnailRendererStep() = default;
|
||||
|
||||
//! Start is called when step begins execution
|
||||
virtual void Start() {}
|
||||
//! Stop is called when step ends execution
|
||||
virtual void Stop() {}
|
||||
|
||||
protected:
|
||||
ThumbnailRendererContext* m_context;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Thumbnails/ThumbnailerBus.h"
|
||||
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
WaitForAssetsToLoadStep::WaitForAssetsToLoadStep(ThumbnailRendererContext* context)
|
||||
: ThumbnailRendererStep(context)
|
||||
{
|
||||
}
|
||||
|
||||
void WaitForAssetsToLoadStep::Start()
|
||||
{
|
||||
LoadNextAsset();
|
||||
}
|
||||
|
||||
void WaitForAssetsToLoadStep::Stop()
|
||||
{
|
||||
Data::AssetBus::Handler::BusDisconnect();
|
||||
TickBus::Handler::BusDisconnect();
|
||||
m_context->GetData()->m_assetsToLoad.clear();
|
||||
}
|
||||
|
||||
void WaitForAssetsToLoadStep::LoadNextAsset()
|
||||
{
|
||||
if (m_context->GetData()->m_assetsToLoad.empty())
|
||||
{
|
||||
// When all assets are loaded, render the thumbnail itself
|
||||
m_context->SetStep(Step::Capture);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pick the the next asset and wait until its ready
|
||||
const auto assetIdIt = m_context->GetData()->m_assetsToLoad.begin();
|
||||
m_context->GetData()->m_assetsToLoad.erase(assetIdIt);
|
||||
m_assetId = *assetIdIt;
|
||||
Data::AssetBus::Handler::BusConnect(m_assetId);
|
||||
// If asset is already loaded, then AssetEvents will call OnAssetReady instantly and we don't need to wait this time
|
||||
if (Data::AssetBus::Handler::BusIsConnected())
|
||||
{
|
||||
TickBus::Handler::BusConnect();
|
||||
m_timeRemainingS = TimeOutS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaitForAssetsToLoadStep::OnAssetReady([[maybe_unused]] Data::Asset<Data::AssetData> asset)
|
||||
{
|
||||
Data::AssetBus::Handler::BusDisconnect();
|
||||
LoadNextAsset();
|
||||
}
|
||||
|
||||
void WaitForAssetsToLoadStep::OnAssetError([[maybe_unused]] Data::Asset<Data::AssetData> asset)
|
||||
{
|
||||
Data::AssetBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
m_context->GetData()->m_thumbnailKeyRendered,
|
||||
&AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
|
||||
m_context->SetStep(Step::FindThumbnailToRender);
|
||||
}
|
||||
|
||||
void WaitForAssetsToLoadStep::OnAssetCanceled([[maybe_unused]] Data::AssetId assetId)
|
||||
{
|
||||
Data::AssetBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
m_context->GetData()->m_thumbnailKeyRendered,
|
||||
&AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
|
||||
m_context->SetStep(Step::FindThumbnailToRender);
|
||||
}
|
||||
|
||||
void WaitForAssetsToLoadStep::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
m_timeRemainingS -= deltaTime;
|
||||
if (m_timeRemainingS < 0)
|
||||
{
|
||||
auto assetIdStr = m_assetId.ToString<AZStd::string>();
|
||||
AZ_Warning("CommonThumbnailRenderer", false, "Timed out waiting for asset %s to load.", assetIdStr.c_str());
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
m_context->GetData()->m_thumbnailKeyRendered,
|
||||
&AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
|
||||
m_context->SetStep(Step::FindThumbnailToRender);
|
||||
}
|
||||
}
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
//! WaitForAssetsToLoadStep pauses further rendering until all assets used for rendering a thumbnail have been loaded
|
||||
class WaitForAssetsToLoadStep
|
||||
: public ThumbnailRendererStep
|
||||
, private Data::AssetBus::Handler
|
||||
, private TickBus::Handler
|
||||
{
|
||||
public:
|
||||
WaitForAssetsToLoadStep(ThumbnailRendererContext* context);
|
||||
|
||||
void Start() override;
|
||||
void Stop() override;
|
||||
|
||||
private:
|
||||
void LoadNextAsset();
|
||||
|
||||
// AZ::Data::AssetBus::Handler
|
||||
void OnAssetReady(Data::Asset<Data::AssetData> asset) override;
|
||||
void OnAssetError(Data::Asset<Data::AssetData> asset) override;
|
||||
void OnAssetCanceled(Data::AssetId assetId) override;
|
||||
|
||||
//! AZ::TickBus::Handler interface overrides...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
static constexpr float TimeOutS = 3.0f;
|
||||
Data::AssetId m_assetId;
|
||||
float m_timeRemainingS = 0;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
|
||||
+14
-27
@@ -7,9 +7,9 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h
|
||||
Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h
|
||||
Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h
|
||||
Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h
|
||||
Source/Module.cpp
|
||||
Source/Animation/EditorAttachmentComponent.h
|
||||
Source/Animation/EditorAttachmentComponent.cpp
|
||||
@@ -45,8 +45,6 @@ set(FILES
|
||||
Source/Material/EditorMaterialSystemComponent.h
|
||||
Source/Material/MaterialBrowserInteractions.h
|
||||
Source/Material/MaterialBrowserInteractions.cpp
|
||||
Source/Material/MaterialThumbnail.cpp
|
||||
Source/Material/MaterialThumbnail.h
|
||||
Source/Mesh/EditorMeshComponent.h
|
||||
Source/Mesh/EditorMeshComponent.cpp
|
||||
Source/Mesh/EditorMeshStats.h
|
||||
@@ -55,8 +53,6 @@ set(FILES
|
||||
Source/Mesh/EditorMeshSystemComponent.h
|
||||
Source/Mesh/EditorMeshStatsSerializer.cpp
|
||||
Source/Mesh/EditorMeshStatsSerializer.h
|
||||
Source/Mesh/MeshThumbnail.h
|
||||
Source/Mesh/MeshThumbnail.cpp
|
||||
Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h
|
||||
Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp
|
||||
Source/PostProcess/EditorPostFxLayerComponent.cpp
|
||||
@@ -95,28 +91,19 @@ set(FILES
|
||||
Source/SkyBox/EditorHDRiSkyboxComponent.h
|
||||
Source/SkyBox/EditorPhysicalSkyComponent.cpp
|
||||
Source/SkyBox/EditorPhysicalSkyComponent.h
|
||||
Source/Thumbnails/ThumbnailUtils.h
|
||||
Source/Thumbnails/ThumbnailUtils.cpp
|
||||
Source/Thumbnails/Preview/CommonPreviewer.cpp
|
||||
Source/Thumbnails/Preview/CommonPreviewer.h
|
||||
Source/Thumbnails/Preview/CommonPreviewer.ui
|
||||
Source/Thumbnails/Preview/CommonPreviewerFactory.cpp
|
||||
Source/Thumbnails/Preview/CommonPreviewerFactory.h
|
||||
Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp
|
||||
Source/Thumbnails/Rendering/CommonThumbnailRenderer.h
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererData.h
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererContext.h
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp
|
||||
Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h
|
||||
Source/SharedPreview/SharedPreviewer.cpp
|
||||
Source/SharedPreview/SharedPreviewer.h
|
||||
Source/SharedPreview/SharedPreviewer.ui
|
||||
Source/SharedPreview/SharedPreviewerFactory.cpp
|
||||
Source/SharedPreview/SharedPreviewerFactory.h
|
||||
Source/SharedPreview/SharedPreviewContent.cpp
|
||||
Source/SharedPreview/SharedPreviewContent.h
|
||||
Source/SharedPreview/SharedPreviewUtils.cpp
|
||||
Source/SharedPreview/SharedPreviewUtils.h
|
||||
Source/SharedPreview/SharedThumbnail.cpp
|
||||
Source/SharedPreview/SharedThumbnail.h
|
||||
Source/SharedPreview/SharedThumbnailRenderer.cpp
|
||||
Source/SharedPreview/SharedThumbnailRenderer.h
|
||||
Source/Scripting/EditorEntityReferenceComponent.cpp
|
||||
Source/Scripting/EditorEntityReferenceComponent.h
|
||||
Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp
|
||||
|
||||
@@ -344,9 +344,9 @@ namespace Blast
|
||||
|
||||
void UpdateMassProperties(
|
||||
[[maybe_unused]] AzPhysics::MassComputeFlags flags,
|
||||
[[maybe_unused]] const AZ::Vector3* centerOfMassOffsetOverride,
|
||||
[[maybe_unused]] const AZ::Matrix3x3* inertiaTensorOverride,
|
||||
[[maybe_unused]] const float* massOverride) override
|
||||
[[maybe_unused]] const AZ::Vector3& centerOfMassOffsetOverride,
|
||||
[[maybe_unused]] const AZ::Matrix3x3& inertiaTensorOverride,
|
||||
[[maybe_unused]] const float massOverride) override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,9 @@ def generate_assetinfo_product(request):
|
||||
outputFilename = os.path.join(request.tempDirPath, assetinfoFilename)
|
||||
|
||||
# the only rule in it is to run this file again as a scene processor
|
||||
currentScript = pathlib.Path(__file__).resolve()
|
||||
currentScript = str(pathlib.Path(__file__).resolve())
|
||||
currentScript = currentScript.replace('\\', '/').lower()
|
||||
currentScript = currentScript.replace('blast_asset_builder.py', 'blast_chunk_processor.py')
|
||||
aDict = {"values": [{"$type": "ScriptProcessorRule", "scriptFilename": f"{currentScript}"}]}
|
||||
jsonString = json.dumps(aDict)
|
||||
jsonFile = open(outputFilename, "w")
|
||||
@@ -167,124 +169,3 @@ try:
|
||||
pythonAssetBuilderHandler = register_asset_builder()
|
||||
except:
|
||||
pythonAssetBuilderHandler = None
|
||||
|
||||
#
|
||||
# SceneAPI Processor
|
||||
#
|
||||
blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0)
|
||||
|
||||
def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList):
|
||||
import azlmbr.scene
|
||||
import azlmbr.object
|
||||
import azlmbr.paths
|
||||
import json, os
|
||||
|
||||
jsonFilename = os.path.basename(scene.sourceFilename)
|
||||
jsonFilename = os.path.join(outputDirectory, jsonFilename + '.blast_chunks')
|
||||
|
||||
# prepare output folder
|
||||
basePath, _ = os.path.split(jsonFilename)
|
||||
outputPath = os.path.join(outputDirectory, basePath)
|
||||
if not os.path.exists(outputPath):
|
||||
os.makedirs(outputPath, False)
|
||||
|
||||
# write out a JSON file with the chunk file info
|
||||
with open(jsonFilename, "w") as jsonFile:
|
||||
jsonFile.write(scene.manifest.ExportToJson())
|
||||
|
||||
exportProduct = azlmbr.scene.ExportProduct()
|
||||
exportProduct.filename = jsonFilename
|
||||
exportProduct.sourceId = scene.sourceGuid
|
||||
exportProduct.assetType = blastChunksAssetType
|
||||
exportProduct.subId = 101
|
||||
|
||||
exportProductList = azlmbr.scene.ExportProductList()
|
||||
exportProductList.AddProduct(exportProduct)
|
||||
return exportProductList
|
||||
|
||||
def on_prepare_for_export(args):
|
||||
try:
|
||||
scene = args[0] # azlmbr.scene.Scene
|
||||
outputDirectory = args[1] # string
|
||||
platformIdentifier = args[2] # string
|
||||
productList = args[3] # azlmbr.scene.ExportProductList
|
||||
return export_chunk_asset(scene, outputDirectory, platformIdentifier, productList)
|
||||
except:
|
||||
log_exception_traceback()
|
||||
|
||||
def get_mesh_node_names(sceneGraph):
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
meshDataList = []
|
||||
node = sceneGraph.get_root()
|
||||
children = []
|
||||
|
||||
while node.IsValid():
|
||||
# store children to process after siblings
|
||||
if sceneGraph.has_node_child(node):
|
||||
children.append(sceneGraph.get_node_child(node))
|
||||
|
||||
# store any node that has mesh data content
|
||||
nodeContent = sceneGraph.get_node_content(node)
|
||||
if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'):
|
||||
if sceneGraph.is_node_end_point(node) is False:
|
||||
nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node))
|
||||
nodePath = nodeName.get_path()
|
||||
if (len(nodeName.get_path())):
|
||||
meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node)))
|
||||
|
||||
# advance to next node
|
||||
if sceneGraph.has_node_sibling(node):
|
||||
node = sceneGraph.get_node_sibling(node)
|
||||
elif children:
|
||||
node = children.pop()
|
||||
else:
|
||||
node = azlmbr.scene.graph.NodeIndex()
|
||||
|
||||
return meshDataList
|
||||
|
||||
def update_manifest(scene):
|
||||
import uuid, os
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
graph = sceneData.SceneGraph(scene.graph)
|
||||
meshNameList = get_mesh_node_names(graph)
|
||||
sceneManifest = sceneData.SceneManifest()
|
||||
sourceFilenameOnly = os.path.basename(scene.sourceFilename)
|
||||
sourceFilenameOnly = sourceFilenameOnly.replace('.','_')
|
||||
|
||||
for activeMeshIndex in range(len(meshNameList)):
|
||||
chunkName = meshNameList[activeMeshIndex]
|
||||
chunkPath = chunkName.get_path()
|
||||
meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name())
|
||||
meshGroup = sceneManifest.add_mesh_group(meshGroupName)
|
||||
meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}'
|
||||
sceneManifest.mesh_group_select_node(meshGroup, chunkPath)
|
||||
|
||||
return sceneManifest.export()
|
||||
|
||||
sceneJobHandler = None
|
||||
|
||||
def on_update_manifest(args):
|
||||
try:
|
||||
scene = args[0]
|
||||
return update_manifest(scene)
|
||||
except:
|
||||
global sceneJobHandler
|
||||
sceneJobHandler = None
|
||||
log_exception_traceback()
|
||||
|
||||
# try to create SceneAPI handler for processing
|
||||
try:
|
||||
import azlmbr.scene as sceneApi
|
||||
if (sceneJobHandler == None):
|
||||
sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler()
|
||||
sceneJobHandler.connect()
|
||||
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
|
||||
sceneJobHandler.add_callback('OnPrepareForExport', on_prepare_for_export)
|
||||
except:
|
||||
sceneJobHandler = None
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
"""
|
||||
Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
"""
|
||||
This a Python Asset Builder script examines each .blast file to see if an
|
||||
associated .fbx file needs to be processed by exporting all of its chunks
|
||||
into a scene manifest
|
||||
|
||||
This is also a SceneAPI script that executes from a foo.fbx.assetinfo scene
|
||||
manifest that writes out asset chunk data for .blast files
|
||||
"""
|
||||
import os, traceback, binascii, sys, json, pathlib
|
||||
import azlmbr.math
|
||||
import azlmbr.asset
|
||||
import azlmbr.asset.entity
|
||||
import azlmbr.asset.builder
|
||||
import azlmbr.bus
|
||||
|
||||
#
|
||||
# SceneAPI Processor
|
||||
#
|
||||
blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0)
|
||||
|
||||
def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList):
|
||||
import azlmbr.scene
|
||||
import azlmbr.object
|
||||
import azlmbr.paths
|
||||
import json, os
|
||||
|
||||
jsonFilename = os.path.basename(scene.sourceFilename)
|
||||
jsonFilename = os.path.join(outputDirectory, jsonFilename + '.blast_chunks')
|
||||
|
||||
# prepare output folder
|
||||
basePath, _ = os.path.split(jsonFilename)
|
||||
outputPath = os.path.join(outputDirectory, basePath)
|
||||
if not os.path.exists(outputPath):
|
||||
os.makedirs(outputPath, False)
|
||||
|
||||
# write out a JSON file with the chunk file info
|
||||
with open(jsonFilename, "w") as jsonFile:
|
||||
jsonFile.write(scene.manifest.ExportToJson())
|
||||
|
||||
exportProduct = azlmbr.scene.ExportProduct()
|
||||
exportProduct.filename = jsonFilename
|
||||
exportProduct.sourceId = scene.sourceGuid
|
||||
exportProduct.assetType = blastChunksAssetType
|
||||
exportProduct.subId = 101
|
||||
|
||||
exportProductList = azlmbr.scene.ExportProductList()
|
||||
exportProductList.AddProduct(exportProduct)
|
||||
return exportProductList
|
||||
|
||||
def on_prepare_for_export(args):
|
||||
try:
|
||||
scene = args[0] # azlmbr.scene.Scene
|
||||
outputDirectory = args[1] # string
|
||||
platformIdentifier = args[2] # string
|
||||
productList = args[3] # azlmbr.scene.ExportProductList
|
||||
return export_chunk_asset(scene, outputDirectory, platformIdentifier, productList)
|
||||
except:
|
||||
log_exception_traceback()
|
||||
|
||||
def get_mesh_node_names(sceneGraph):
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
meshDataList = []
|
||||
node = sceneGraph.get_root()
|
||||
children = []
|
||||
|
||||
while node.IsValid():
|
||||
# store children to process after siblings
|
||||
if sceneGraph.has_node_child(node):
|
||||
children.append(sceneGraph.get_node_child(node))
|
||||
|
||||
# store any node that has mesh data content
|
||||
nodeContent = sceneGraph.get_node_content(node)
|
||||
if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'):
|
||||
if sceneGraph.is_node_end_point(node) is False:
|
||||
nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node))
|
||||
nodePath = nodeName.get_path()
|
||||
if (len(nodeName.get_path())):
|
||||
meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node)))
|
||||
|
||||
# advance to next node
|
||||
if sceneGraph.has_node_sibling(node):
|
||||
node = sceneGraph.get_node_sibling(node)
|
||||
elif children:
|
||||
node = children.pop()
|
||||
else:
|
||||
node = azlmbr.scene.graph.NodeIndex()
|
||||
|
||||
return meshDataList
|
||||
|
||||
def update_manifest(scene):
|
||||
import uuid, os
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
graph = sceneData.SceneGraph(scene.graph)
|
||||
meshNameList = get_mesh_node_names(graph)
|
||||
sceneManifest = sceneData.SceneManifest()
|
||||
sourceFilenameOnly = os.path.basename(scene.sourceFilename)
|
||||
sourceFilenameOnly = sourceFilenameOnly.replace('.','_')
|
||||
|
||||
for activeMeshIndex in range(len(meshNameList)):
|
||||
chunkName = meshNameList[activeMeshIndex]
|
||||
chunkPath = chunkName.get_path()
|
||||
meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name())
|
||||
meshGroup = sceneManifest.add_mesh_group(meshGroupName)
|
||||
meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}'
|
||||
sceneManifest.mesh_group_select_node(meshGroup, chunkPath)
|
||||
|
||||
return sceneManifest.export()
|
||||
|
||||
sceneJobHandler = None
|
||||
|
||||
def on_update_manifest(args):
|
||||
try:
|
||||
scene = args[0]
|
||||
return update_manifest(scene)
|
||||
except:
|
||||
global sceneJobHandler
|
||||
sceneJobHandler = None
|
||||
log_exception_traceback()
|
||||
|
||||
# try to create SceneAPI handler for processing
|
||||
try:
|
||||
import azlmbr.scene as sceneApi
|
||||
if (sceneJobHandler == None):
|
||||
sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler()
|
||||
sceneJobHandler.connect()
|
||||
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
|
||||
sceneJobHandler.add_callback('OnPrepareForExport', on_prepare_for_export)
|
||||
except:
|
||||
sceneJobHandler = None
|
||||
@@ -27,7 +27,7 @@ namespace EMotionFX
|
||||
{}
|
||||
};
|
||||
|
||||
class INTEG_PoseComparisonFixture
|
||||
class PoseComparisonFixture
|
||||
: public SystemComponentFixture
|
||||
, public ::testing::WithParamInterface<PoseComparisonFixtureParams>
|
||||
{
|
||||
@@ -47,8 +47,8 @@ namespace EMotionFX
|
||||
// This fixture exists to separate the tests that test the pose comparsion
|
||||
// functionality from the tests that use the pose comparison functionality
|
||||
// (even though it doesn't use the recording)
|
||||
class INTEG_TestPoseComparisonFixture
|
||||
: public INTEG_PoseComparisonFixture
|
||||
class TestPoseComparisonFixture
|
||||
: public PoseComparisonFixture
|
||||
{
|
||||
};
|
||||
}; // namespace EMotionFX
|
||||
|
||||
@@ -154,14 +154,14 @@ namespace EMotionFX
|
||||
return MakeMatcher(new KeyTrackMatcher<T>(expected, nodeName));
|
||||
}
|
||||
|
||||
void INTEG_PoseComparisonFixture::SetUp()
|
||||
void PoseComparisonFixture::SetUp()
|
||||
{
|
||||
SystemComponentFixture::SetUp();
|
||||
|
||||
LoadAssets();
|
||||
}
|
||||
|
||||
void INTEG_PoseComparisonFixture::TearDown()
|
||||
void PoseComparisonFixture::TearDown()
|
||||
{
|
||||
m_actorInstance->Destroy();
|
||||
|
||||
@@ -176,7 +176,7 @@ namespace EMotionFX
|
||||
SystemComponentFixture::TearDown();
|
||||
}
|
||||
|
||||
void INTEG_PoseComparisonFixture::LoadAssets()
|
||||
void PoseComparisonFixture::LoadAssets()
|
||||
{
|
||||
const AZStd::string actorPath = ResolvePath(GetParam().m_actorFile);
|
||||
m_actor = EMotionFX::GetImporter().LoadActor(actorPath);
|
||||
@@ -195,7 +195,7 @@ namespace EMotionFX
|
||||
m_actorInstance->SetAnimGraphInstance(AnimGraphInstance::Create(m_animGraph, m_actorInstance, m_motionSet));
|
||||
}
|
||||
|
||||
TEST_P(INTEG_PoseComparisonFixture, Integ_TestPoses)
|
||||
TEST_P(PoseComparisonFixture, TestPoses)
|
||||
{
|
||||
const AZStd::string recordingPath = ResolvePath(GetParam().m_recordingFile);
|
||||
Recorder* recording = EMotionFX::Recorder::LoadFromFile(recordingPath.c_str());
|
||||
@@ -231,7 +231,7 @@ namespace EMotionFX
|
||||
recording->Destroy();
|
||||
}
|
||||
|
||||
TEST_P(INTEG_TestPoseComparisonFixture, Integ_TestRecording)
|
||||
TEST_P(TestPoseComparisonFixture, TestRecording)
|
||||
{
|
||||
// Make one recording, 10 seconds at 60 fps
|
||||
Recorder::RecordSettings settings;
|
||||
@@ -294,30 +294,30 @@ namespace EMotionFX
|
||||
recording->Destroy();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Integ_TestPoses, INTEG_PoseComparisonFixture,
|
||||
INSTANTIATE_TEST_CASE_P(DISABLED_TestPoses, PoseComparisonFixture,
|
||||
::testing::Values(
|
||||
PoseComparisonFixtureParams (
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording"
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor",
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph",
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset",
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording"
|
||||
),
|
||||
PoseComparisonFixtureParams (
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording"
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor",
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph",
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset",
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Integ_TestPoseComparison, INTEG_TestPoseComparisonFixture,
|
||||
INSTANTIATE_TEST_CASE_P(DISABLED_TestPoseComparison, TestPoseComparisonFixture,
|
||||
::testing::Values(
|
||||
PoseComparisonFixtureParams (
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording"
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor",
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph",
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset",
|
||||
"@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -17,10 +17,16 @@
|
||||
#include <Source/PythonSymbolsBus.h>
|
||||
|
||||
#include <pybind11/embed.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/eval.h>
|
||||
|
||||
#include <AzCore/PlatformDef.h>
|
||||
#include <AzCore/JSON/rapidjson.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/RTTI/AttributeReader.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerializationSettings.h>
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
|
||||
namespace EditorPythonBindings
|
||||
{
|
||||
@@ -571,6 +577,37 @@ namespace EditorPythonBindings
|
||||
return false;
|
||||
}
|
||||
|
||||
pybind11::object PythonProxyObject::ToJson()
|
||||
{
|
||||
rapidjson::Document document;
|
||||
AZ::JsonSerializerSettings settings;
|
||||
settings.m_keepDefaults = true;
|
||||
|
||||
auto resultCode =
|
||||
AZ::JsonSerialization::Store(document, document.GetAllocator(), m_wrappedObject.m_address, nullptr, m_wrappedObject.m_typeId, settings);
|
||||
|
||||
if (resultCode.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted)
|
||||
{
|
||||
AZ_Error("PythonProxyObject", false, "Failed to serialize to json");
|
||||
return pybind11::cast<pybind11::none>(Py_None);
|
||||
}
|
||||
|
||||
AZStd::string jsonString;
|
||||
AZ::Outcome<void, AZStd::string> outcome = AZ::JsonSerializationUtils::WriteJsonString(document, jsonString);
|
||||
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("PythonProxyObject", false, "Failed to write json string: %s", outcome.GetError().c_str());
|
||||
return pybind11::cast<pybind11::none>(Py_None);
|
||||
}
|
||||
|
||||
jsonString.erase(AZStd::remove(jsonString.begin(), jsonString.end(), '\n'), jsonString.end());
|
||||
auto pythonCode = AZStd::string::format(
|
||||
R"PYTHON(exec("import json") or json.loads("""%s"""))PYTHON", jsonString.c_str());
|
||||
|
||||
return pybind11::eval(pythonCode.c_str());
|
||||
}
|
||||
|
||||
bool PythonProxyObject::DoComparisonEvaluation(pybind11::object pythonOther, Comparison comparison)
|
||||
{
|
||||
bool invertLogic = false;
|
||||
@@ -912,6 +949,7 @@ namespace EditorPythonBindings
|
||||
.def("set_property", &PythonProxyObject::SetPropertyValue)
|
||||
.def("get_property", &PythonProxyObject::GetPropertyValue)
|
||||
.def("invoke", &PythonProxyObject::Invoke)
|
||||
.def("to_json", &PythonProxyObject::ToJson)
|
||||
.def(Operator::s_isEqual, [](PythonProxyObject& self, pybind11::object rhs)
|
||||
{
|
||||
return self.DoEqualityEvaluation(rhs);
|
||||
|
||||
@@ -58,6 +58,8 @@ namespace EditorPythonBindings
|
||||
//! Performs an equality operation to compare this object with another object
|
||||
bool DoEqualityEvaluation(pybind11::object pythonOther);
|
||||
|
||||
pybind11::object ToJson();
|
||||
|
||||
//! Perform a comparison of a Python operator
|
||||
enum class Comparison
|
||||
{
|
||||
|
||||
@@ -7,52 +7,50 @@
|
||||
*/
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/std/parallel/atomic.h>
|
||||
#include <AzCore/std/parallel/condition_variable.h>
|
||||
|
||||
#include "HttpRequestManager.h"
|
||||
|
||||
class Integ_HttpTest
|
||||
: public ::testing::Test
|
||||
class HttpTest
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
HttpRequestor::ManagerPtr m_httpRequestManager;
|
||||
|
||||
// to wait for test to complete
|
||||
AZStd::mutex m_requestMutex;
|
||||
AZStd::condition_variable m_requestConditionVar;
|
||||
|
||||
AZStd::string resultData;
|
||||
AZStd::atomic<Aws::Http::HttpResponseCode> resultCode;
|
||||
|
||||
Integ_HttpTest()
|
||||
{
|
||||
m_httpRequestManager = AZStd::make_shared<HttpRequestor::Manager>();
|
||||
resultCode = Aws::Http::HttpResponseCode::REQUEST_NOT_MADE;
|
||||
resultData = "{}";
|
||||
|
||||
AZStd::unique_lock<AZStd::mutex> lock(m_requestMutex);
|
||||
m_requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
virtual ~Integ_HttpTest()
|
||||
{
|
||||
m_httpRequestManager.reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Integ_HttpTest, HttpRequesterTest)
|
||||
TEST_F(HttpTest, DISABLED_HttpRequesterTest)
|
||||
{
|
||||
m_httpRequestManager->AddTextRequest(HttpRequestor::TextParameters("https://httpbin.org/ip", Aws::Http::HttpMethod::HTTP_GET, [this](const AZStd::string & data, Aws::Http::HttpResponseCode code)
|
||||
{
|
||||
resultData = data;
|
||||
resultCode = code;
|
||||
m_requestConditionVar.notify_all();
|
||||
}));
|
||||
HttpRequestor::Manager httpRequestManager;
|
||||
|
||||
AZStd::unique_lock<AZStd::mutex> lock(m_requestMutex);
|
||||
m_requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(5000));
|
||||
// to wait for test to complete
|
||||
AZStd::mutex requestMutex;
|
||||
AZStd::condition_variable requestConditionVar;
|
||||
|
||||
AZStd::string resultData = {};
|
||||
AZStd::atomic<Aws::Http::HttpResponseCode> resultCode = Aws::Http::HttpResponseCode::REQUEST_NOT_MADE;
|
||||
|
||||
{
|
||||
AZStd::unique_lock<AZStd::mutex> lock(requestMutex);
|
||||
requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
httpRequestManager.AddTextRequest(
|
||||
HttpRequestor::TextParameters("https://httpbin.org/ip",
|
||||
Aws::Http::HttpMethod::HTTP_GET,
|
||||
[&resultData, &resultCode, &requestConditionVar](const AZStd::string& data, Aws::Http::HttpResponseCode code)
|
||||
{
|
||||
resultData = data;
|
||||
resultCode = code;
|
||||
requestConditionVar.notify_all();
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
{
|
||||
AZStd::unique_lock<AZStd::mutex> lock(requestMutex);
|
||||
requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(5000));
|
||||
}
|
||||
|
||||
EXPECT_NE(Aws::Http::HttpResponseCode::REQUEST_NOT_MADE, resultCode);
|
||||
}
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
namespace UnitTest
|
||||
{
|
||||
|
||||
class Integ_BundlingSystemComponentFixture :
|
||||
class BundlingSystemComponentFixture :
|
||||
public ::testing::Test
|
||||
|
||||
{
|
||||
public:
|
||||
Integ_BundlingSystemComponentFixture() = default;
|
||||
BundlingSystemComponentFixture() = default;
|
||||
|
||||
bool TestAsset(const char* assetPath)
|
||||
{
|
||||
@@ -59,7 +59,7 @@ namespace UnitTest
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Integ_BundlingSystemComponentFixture, HasBundle_LoadBundles_Success)
|
||||
TEST_F(BundlingSystemComponentFixture, DISABLED_HasBundle_LoadBundles_Success)
|
||||
{
|
||||
// This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our
|
||||
// cache as test/bundle/staticdata.pak and should be loaded below
|
||||
@@ -72,7 +72,7 @@ namespace UnitTest
|
||||
EXPECT_FALSE(TestAsset(testAssetPath));
|
||||
}
|
||||
|
||||
TEST_F(Integ_BundlingSystemComponentFixture, HasBundle_LoadBundlesCatalogChecks_Success)
|
||||
TEST_F(BundlingSystemComponentFixture, DISABLED_HasBundle_LoadBundlesCatalogChecks_Success)
|
||||
{
|
||||
// This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our
|
||||
// cache as test/bundle/staticdata.pak and should be loaded below
|
||||
@@ -92,7 +92,7 @@ namespace UnitTest
|
||||
EXPECT_FALSE(TestAsset(noCatalogAsset));
|
||||
}
|
||||
|
||||
TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SingleUnloadCheckCatalog_Success)
|
||||
TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SingleUnloadCheckCatalog_Success)
|
||||
{
|
||||
// This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our
|
||||
// cache as test/bundle/staticdata.pak and should be loaded below
|
||||
@@ -132,7 +132,7 @@ namespace UnitTest
|
||||
EXPECT_FALSE(TestAssetId(testDDSAsset));
|
||||
}
|
||||
|
||||
TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SingleLoadAndBundleMode_Success)
|
||||
TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SingleLoadAndBundleMode_Success)
|
||||
{
|
||||
// This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our
|
||||
// cache as test/bundle/staticdata.pak and should be loaded below
|
||||
@@ -157,7 +157,7 @@ namespace UnitTest
|
||||
EXPECT_FALSE(TestAssetId(testMTLAsset));
|
||||
}
|
||||
|
||||
TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_OpenClosePackCount_Match)
|
||||
TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_OpenClosePackCount_Match)
|
||||
{
|
||||
// This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our
|
||||
// cache as test/bundle/staticdata.pak and should be loaded below
|
||||
@@ -198,7 +198,7 @@ namespace UnitTest
|
||||
EXPECT_EQ(bundleCount, 0);
|
||||
}
|
||||
|
||||
TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SplitPakTestWithAsset_Success)
|
||||
TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SplitPakTestWithAsset_Success)
|
||||
{
|
||||
// This asset lives only within LmbrCentral/Assets/Test/SplitBundleTest/splitbundle__1.pak which is a dependent bundle of splitbundle.pak
|
||||
const char testDDSAsset_split[] = "textures/milestone2/am_floor_tile_ddna_test.dds.7";
|
||||
@@ -228,7 +228,7 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
// Verify that our bundles using catalogs of the same name work properly
|
||||
TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SharedCatalogName_Success)
|
||||
TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SharedCatalogName_Success)
|
||||
{
|
||||
// This bundle was built for PC but is generic and the test should work fine on other platforms
|
||||
// gamepropertioessmall_pc.pak has a smaller version of the gameproperties csv
|
||||
|
||||
@@ -148,16 +148,16 @@ namespace PhysX
|
||||
using VisibilityFunc = bool(*)();
|
||||
|
||||
editContext->Class<Collider>(
|
||||
"PhysX Collider Debug Draw", "Manages global and per-collider debug draw settings and logic")
|
||||
"PhysX Collider Debug Draw", "Global and per-collider debug draw preferences.")
|
||||
->DataElement(AZ::Edit::UIHandlers::CheckBox, &Collider::m_locallyEnabled, "Draw collider",
|
||||
"Shows the geometry for the collider in the viewport")
|
||||
"Display collider geometry in the viewport.")
|
||||
->Attribute(AZ::Edit::Attributes::CheckboxTooltip,
|
||||
"If set, the geometry of this collider is visible in the viewport. 'Draw Helpers' needs to be enabled to use.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility,
|
||||
VisibilityFunc{ []() { return IsGlobalColliderDebugCheck(GlobalCollisionDebugState::Manual); } })
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &IsDrawColliderReadOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Button, &Collider::m_globalButtonState, "Draw collider",
|
||||
"Shows the geometry for the collider in the viewport")
|
||||
"Display collider geometry in the viewport.")
|
||||
->Attribute(AZ::Edit::Attributes::ButtonText, "Global override")
|
||||
->Attribute(AZ::Edit::Attributes::ButtonTooltip,
|
||||
"A global setting is overriding this property (to disable the override, "
|
||||
|
||||
@@ -51,23 +51,27 @@ namespace PhysX
|
||||
if (auto* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<PhysX::EditorJointLimitConfig>(
|
||||
"Editor Joint Limit Config Base", "Base joint limit parameters")
|
||||
"Editor Joint Limit Config Base", "Base joint limit parameters.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(0, &PhysX::EditorJointLimitConfig::m_isLimited, "Limit", "True if the motion about the unconstrained axes of this joint are limited")
|
||||
->DataElement(0, &PhysX::EditorJointLimitConfig::m_isLimited, "Limit",
|
||||
"When active, the joint's degrees of freedom are limited.")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointLimitConfig::IsInComponentMode)
|
||||
->DataElement(0, &PhysX::EditorJointLimitConfig::m_isSoftLimit, "Soft limit", "True if the joint is allowed to rotate beyond limits and spring back")
|
||||
->DataElement(0, &PhysX::EditorJointLimitConfig::m_isSoftLimit, "Soft limit",
|
||||
"When active, motion beyond the joint limit with a spring-like return is allowed.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConfig::m_isLimited)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointLimitConfig::IsInComponentMode)
|
||||
->DataElement(0, &PhysX::EditorJointLimitConfig::m_damping, "Damping", "The damping strength of the drive, the force proportional to the velocity error")
|
||||
->DataElement(0, &PhysX::EditorJointLimitConfig::m_damping, "Damping",
|
||||
"Dissipation of energy and reduction in spring oscillations when outside the joint limit.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConfig::IsSoftLimited)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_springMax)
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_springMin)
|
||||
->DataElement(0, &PhysX::EditorJointLimitConfig::m_stiffness, "Stiffness", "The spring strength of the drive, the force proportional to the position error")
|
||||
->DataElement(0, &PhysX::EditorJointLimitConfig::m_stiffness, "Stiffness",
|
||||
"The spring's drive relative to the position of the follower when outside the joint limit.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConfig::IsSoftLimited)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_springMax)
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_springMin)
|
||||
@@ -115,18 +119,20 @@ namespace PhysX
|
||||
if (auto* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<PhysX::EditorJointLimitPairConfig>(
|
||||
"Angular Limit", "Rotation limitation")
|
||||
"Angular Limit", "Rotation limitation.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_standardLimitConfig
|
||||
, "Standard limit configuration"
|
||||
, "Common limit parameters to all joint types")
|
||||
->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitPositive, "Positive angular limit", "Positive rotation angle")
|
||||
, "Common limit parameters to all joint types.")
|
||||
->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitPositive, "Positive angular limit",
|
||||
"Positive rotation angle.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitPairConfig::IsLimited)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_angleMax)
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_angleMin)
|
||||
->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitNegative, "Negative angular limit", "Negative rotation angle")
|
||||
->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitNegative, "Negative angular limit",
|
||||
"Negative rotation angle.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitPairConfig::IsLimited)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_angleMin)
|
||||
->Attribute(AZ::Edit::Attributes::Min, -s_angleMax)
|
||||
@@ -164,18 +170,20 @@ namespace PhysX
|
||||
if (auto* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<PhysX::EditorJointLimitConeConfig>(
|
||||
"Angular Limit", "Rotation limitation")
|
||||
"Angular Limit", "Rotation limitation.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_standardLimitConfig
|
||||
, "Standard limit configuration"
|
||||
, "Common limit parameters to all joint types")
|
||||
->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitY, "Y axis angular limit", "Limit for swing angle about Y axis")
|
||||
, "Common limit parameters to all joint types.")
|
||||
->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitY, "Y axis angular limit",
|
||||
"Limit for swing angle about Y axis.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConeConfig::IsLimited)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_angleMax)
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_angleMin)
|
||||
->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitZ, "Z axis angular limit", "Limit for swing angle about Z axis")
|
||||
->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitZ, "Z axis angular limit",
|
||||
"Limit for swing angle about Z axis.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConeConfig::IsLimited)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_angleMax)
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_angleMin)
|
||||
@@ -226,33 +234,33 @@ namespace PhysX
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(0, &PhysX::EditorJointConfig::m_localPosition, "Local Position"
|
||||
, "Local Position of joint, relative to its entity")
|
||||
, "Local Position of joint, relative to its entity.")
|
||||
->DataElement(0, &PhysX::EditorJointConfig::m_localRotation, "Local Rotation"
|
||||
, "Local Rotation of joint, relative to its entity")
|
||||
, "Local Rotation of joint, relative to its entity.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, LocalRotationMin)
|
||||
->Attribute(AZ::Edit::Attributes::Max, LocalRotationMax)
|
||||
->DataElement(0, &PhysX::EditorJointConfig::m_leadEntity, "Lead Entity"
|
||||
, "Parent entity associated with joint")
|
||||
, "Parent entity associated with joint.")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorJointConfig::ValidateLeadEntityId)
|
||||
->DataElement(0, &PhysX::EditorJointConfig::m_selfCollide, "Lead-Follower Collide"
|
||||
, "Lead and follower pair will collide with each other")
|
||||
, "When active, the lead and follower pair will collide with each other.")
|
||||
->DataElement(0, &PhysX::EditorJointConfig::m_displayJointSetup, "Display Setup in Viewport"
|
||||
, "Display joint setup in the viewport")
|
||||
, "Display joint setup in the viewport.")
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointConfig::IsInComponentMode)
|
||||
->DataElement(0, &PhysX::EditorJointConfig::m_selectLeadOnSnap, "Select Lead on Snap"
|
||||
, "Select lead entity on snap to position in component mode")
|
||||
, "Select lead entity on snap to position in component mode.")
|
||||
->DataElement(0, &PhysX::EditorJointConfig::m_breakable
|
||||
, "Breakable"
|
||||
, "Joint is breakable when force or torque exceeds limit")
|
||||
, "Joint is breakable when force or torque exceeds limit.")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointConfig::IsInComponentMode)
|
||||
->DataElement(0, &PhysX::EditorJointConfig::m_forceMax,
|
||||
"Maximum Force", "Amount of force joint can withstand before breakage")
|
||||
"Maximum Force", "Amount of force joint can withstand before breakage.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointConfig::m_breakable)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_breakageMax)
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_breakageMin)
|
||||
->DataElement(0, &PhysX::EditorJointConfig::m_torqueMax,
|
||||
"Maximum Torque", "Amount of torque joint can withstand before breakage")
|
||||
"Maximum Torque", "Amount of torque joint can withstand before breakage.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointConfig::m_breakable)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_breakageMax)
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_breakageMin)
|
||||
|
||||
@@ -54,17 +54,17 @@ namespace PhysX
|
||||
|
||||
if (AZ::EditContext* editContext = serialize->GetEditContext())
|
||||
{
|
||||
editContext->Class<PhysX::WindConfiguration>("Wind Configuration", "Wind settings for PhysX")
|
||||
editContext->Class<PhysX::WindConfiguration>("Wind Configuration", "Wind force entity tags.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &WindConfiguration::m_globalWindTag,
|
||||
"Global wind tag",
|
||||
"Tag value that will be used to mark entities that provide global wind value.\n"
|
||||
"Global wind has no bounds and affects objects across entire level.")
|
||||
"Global wind provider tags.\n"
|
||||
"Global winds apply to entire world.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &WindConfiguration::m_localWindTag,
|
||||
"Local wind tag",
|
||||
"Tag value that will be used to mark entities that provide local wind value.\n"
|
||||
"Local wind is only applied within bounds defined by PhysX collider.")
|
||||
"Local wind provider tags.\n"
|
||||
"Local winds are constrained to a PhysX collider's boundaries.")
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,38 +31,39 @@ namespace PhysX
|
||||
|
||||
if (AZ::EditContext* editContext = serialize->GetEditContext())
|
||||
{
|
||||
editContext->Class<PvdConfiguration>("PhysX PVD Settings", "PhysX PVD Settings")
|
||||
editContext->Class<PvdConfiguration>("PhysX PVD Settings",
|
||||
"Connection configuration settings for the PhysX Visual Debugger (PVD). Requires PhysX Debug Gem.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &PvdConfiguration::m_transportType,
|
||||
"PVD Transport Type", "PVD supports writing to a TCP/IP network socket or to a file.")
|
||||
"PVD Transport Type", "Output PhysX Visual Debugger data to a TCP/IP network socket or to a file.")
|
||||
->EnumAttribute(Debug::PvdTransportType::Network, "Network")
|
||||
->EnumAttribute(Debug::PvdTransportType::File, "File")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_host,
|
||||
"PVD Host", "Host IP address of the PhysX Visual Debugger application")
|
||||
"PVD Host", "Host IP address of the PhysX Visual Debugger server.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsNetworkDebug)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_port,
|
||||
"PVD Port", "Port of the PhysX Visual Debugger application")
|
||||
"PVD Port", "Port of the PhysX Visual Debugger server.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsNetworkDebug)
|
||||
->Attribute(AZ::Edit::Attributes::Min, AZStd::numeric_limits<uint16_t>::min())
|
||||
->Attribute(AZ::Edit::Attributes::Max, AZStd::numeric_limits<uint16_t>::max())
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_timeoutInMilliseconds,
|
||||
"PVD Timeout", "Timeout (in milliseconds) used when connecting to the PhysX Visual Debugger application")
|
||||
"PVD Timeout", "Timeout (in milliseconds) when connecting to the PhysX Visual Debugger server.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsNetworkDebug)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_fileName,
|
||||
"PVD FileName", "Filename to output PhysX Visual Debugger data.")
|
||||
"PVD FileName", "Output filename for PhysX Visual Debugger data.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsFileDebug)
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &PvdConfiguration::m_autoConnectMode,
|
||||
"PVD Auto Connect", "Automatically connect to the PhysX Visual Debugger "
|
||||
"(Requires PhysX Debug gem for Editor and Game modes).")
|
||||
"PVD Auto Connect", "Automatically connect to the PhysX Visual Debugger.")
|
||||
->EnumAttribute(Debug::PvdAutoConnectMode::Disabled, "Disabled")
|
||||
->EnumAttribute(Debug::PvdAutoConnectMode::Editor, "Editor")
|
||||
->EnumAttribute(Debug::PvdAutoConnectMode::Game, "Game")
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::CheckBox, &PvdConfiguration::m_reconnect,
|
||||
"PVD Reconnect", "Reconnect (Disconnect and Connect) when switching between game and edit mode "
|
||||
"(Requires PhysX Debug gem).")
|
||||
->DataElement(AZ::Edit::UIHandlers::CheckBox, &PvdConfiguration::m_reconnect, "PVD Reconnect",
|
||||
"Reconnect (disconnect and connect) to the PhysX Visual Debugger server when switching between game and edit mode.")
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -131,7 +132,7 @@ namespace PhysX
|
||||
|
||||
if (AZ::EditContext* editContext = serialize->GetEditContext())
|
||||
{
|
||||
editContext->Class<DebugDisplayData>("Editor Configuration", "Editor settings for PhysX")
|
||||
editContext->Class<DebugDisplayData>("Editor Configuration", "Editor settings for PhysX.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Slider, &DebugDisplayData::m_centerOfMassDebugSize,
|
||||
|
||||
@@ -33,14 +33,14 @@ namespace PhysX
|
||||
if (auto* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorBallJointComponent>(
|
||||
"PhysX Ball Joint", "The ball joint supports a cone limiting the maximum rotation around the y and z axes.")
|
||||
"PhysX Ball Joint", "A dynamic joint constraint with swing rotation limits around the Y and Z axes of the joint.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/ball-joint/")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(0, &EditorBallJointComponent::m_swingLimit, "Swing Limit", "Limitations for the swing (Y and Z axis) about joint")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorBallJointComponent::m_componentModeDelegate, "Component Mode", "Ball Joint Component Mode")
|
||||
->DataElement(0, &EditorBallJointComponent::m_swingLimit, "Swing Limit", "The rotation angle limit around the joint's Y and Z axes.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorBallJointComponent::m_componentModeDelegate, "Component Mode", "Ball Joint Component Mode.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -53,13 +53,15 @@ namespace PhysX
|
||||
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorProxyAssetShapeConfig>("EditorProxyShapeConfig", "PhysX Base shape collider")
|
||||
editContext->Class<EditorProxyAssetShapeConfig>("EditorProxyShapeConfig", "PhysX Base collider.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_pxAsset, "PhysX Mesh", "PhysX mesh collider asset")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_pxAsset, "PhysX Mesh",
|
||||
"Specifies the PhysX mesh collider asset for this PhysX collider component.")
|
||||
->Attribute(AZ_CRC_CE("EditButton"), "")
|
||||
->Attribute(AZ_CRC_CE("EditDescription"), "Open in Scene Settings")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_configuration, "Configuration", "Configuration of asset shape")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_configuration, "Configuration",
|
||||
"PhysX mesh asset collider configuration.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly);
|
||||
}
|
||||
}
|
||||
@@ -86,7 +88,7 @@ namespace PhysX
|
||||
{
|
||||
editContext->Class<EditorProxyShapeConfig>(
|
||||
"EditorProxyShapeConfig", "PhysX Base shape collider")
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorProxyShapeConfig::m_shapeType, "Shape", "The shape of the collider")
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorProxyShapeConfig::m_shapeType, "Shape", "The shape of the collider.")
|
||||
->EnumAttribute(Physics::ShapeType::Sphere, "Sphere")
|
||||
->EnumAttribute(Physics::ShapeType::Box, "Box")
|
||||
->EnumAttribute(Physics::ShapeType::Capsule, "Capsule")
|
||||
@@ -96,20 +98,20 @@ namespace PhysX
|
||||
// potentially be different ComponentModes for different shape types)
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &AzToolsFramework::ComponentModeFramework::InComponentMode)
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_sphere, "Sphere", "Configuration of sphere shape")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_sphere, "Sphere", "Configuration of sphere shape.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsSphereConfig)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_box, "Box", "Configuration of box shape")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_box, "Box", "Configuration of box shape.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsBoxConfig)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_capsule, "Capsule", "Configuration of capsule shape")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_capsule, "Capsule", "Configuration of capsule shape.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsCapsuleConfig)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_physicsAsset, "Asset", "Configuration of asset shape")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_physicsAsset, "Asset", "Configuration of asset shape.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsAssetConfig)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_subdivisionLevel, "Subdivision level",
|
||||
"The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling")
|
||||
"The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, Utils::MinCapsuleSubdivisionLevel)
|
||||
->Attribute(AZ::Edit::Attributes::Max, Utils::MaxCapsuleSubdivisionLevel)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::ShowingSubdivisionLevel)
|
||||
@@ -200,7 +202,7 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorColliderComponent>(
|
||||
"PhysX Collider", "PhysX shape collider")
|
||||
"PhysX Collider", "Creates geometry in the PhysX simulation, using either a primitive shape or geometry from an asset.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCollider.svg")
|
||||
@@ -208,17 +210,17 @@ namespace PhysX
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/collider/")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_configuration, "Collider Configuration", "Configuration of the collider")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_configuration, "Collider Configuration", "Configuration of the collider.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorColliderComponent::OnConfigurationChanged)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_shapeConfiguration, "Shape Configuration", "Configuration of the shape")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_shapeConfiguration, "Shape Configuration", "Configuration of the shape.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorColliderComponent::OnConfigurationChanged)
|
||||
->Attribute(AZ::Edit::Attributes::RemoveNotify, &EditorColliderComponent::ValidateRigidBodyMeshGeometryType)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_componentModeDelegate, "Component Mode", "Collider Component Mode")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_componentModeDelegate, "Component Mode", "Collider Component Mode.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_colliderDebugDraw,
|
||||
"Debug draw settings", "Debug draw settings")
|
||||
"Debug draw settings", "Debug draw settings.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -30,13 +30,14 @@ namespace PhysX
|
||||
if (auto* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorFixedJointComponent>(
|
||||
"PhysX Fixed Joint", "The fixed joint constraints the position and orientation of a body to another.")
|
||||
"PhysX Fixed Joint",
|
||||
"A dynamic joint constraint that constrains a rigid body to the joint with no free translation or rotation on any axis.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/fixed-joint/")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorFixedJointComponent::m_componentModeDelegate, "Component Mode", "Fixed Joint Component Mode")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorFixedJointComponent::m_componentModeDelegate, "Component Mode", "Fixed Joint Component Mode.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace PhysX
|
||||
{
|
||||
// EditorForceRegionComponent
|
||||
editContext->Class<EditorForceRegionComponent>(
|
||||
"PhysX Force Region", "The force region component is used to apply a physical force on objects within the region")
|
||||
"PhysX Force Region", "The force region component is used to apply a physical force on objects within the region.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/ForceVolume.svg")
|
||||
@@ -173,9 +173,10 @@ namespace PhysX
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/force-region/")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::RequiredService, AZ_CRC("PhysXTriggerService", 0x3a117d7b))
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_visibleInEditor, "Visible", "Always show the component in viewport")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_debugForces, "Debug Forces", "Draws debug arrows when an entity enters a force region. This occurs in gameplay mode to show the force direction on an entity.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_forces, "Forces", "Forces in force region")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_visibleInEditor, "Visible", "Always show the component in viewport.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_debugForces, "Debug Forces",
|
||||
"Draws debug arrows when an entity enters a force region. This occurs in gameplay mode to show the force direction on an entity.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_forces, "Forces", "Forces in force region.")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorForceRegionComponent::OnForcesChanged)
|
||||
;
|
||||
|
||||
@@ -33,14 +33,14 @@ namespace PhysX
|
||||
if (auto* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorHingeJointComponent>(
|
||||
"PhysX Hinge Joint", "The entity constrains two actors in PhysX, keeping the origins and x-axes together, and allows free rotation around this common axis")
|
||||
"PhysX Hinge Joint", "A dynamic joint that constrains a rigid body with rotation limits around a single axis.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/hinge-joint/")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(0, &EditorHingeJointComponent::m_angularLimit, "Angular Limit", "Limitations for the rotation about hinge axis")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorHingeJointComponent::m_componentModeDelegate, "Component Mode", "Hinge Joint Component Mode")
|
||||
->DataElement(0, &EditorHingeJointComponent::m_angularLimit, "Angular Limit", "The rotation angle limit around the joint's axis.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorHingeJointComponent::m_componentModeDelegate, "Component Mode", "Hinge Joint Component Mode.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -37,11 +37,11 @@ namespace PhysX
|
||||
if (auto* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorJointComponent>(
|
||||
"PhysX Joint", "The joint constrains the position and orientation of a body to another.")
|
||||
"PhysX Joint", "A dynamic joint that constrains the position and orientation of one rigid body to another.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(0, &EditorJointComponent::m_config, "Standard Joint Parameters", "Joint parameters shared by all joint types")
|
||||
->DataElement(0, &EditorJointComponent::m_config, "Standard Joint Parameters", "Joint parameters shared by all joint types.")
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,38 +122,38 @@ namespace PhysX
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_initialLinearVelocity,
|
||||
"Initial linear velocity", "Initial linear velocity")
|
||||
"Initial linear velocity", "Linear velocity applied when the rigid body is activated.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInitialVelocitiesVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetSpeedUnit())
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_initialAngularVelocity,
|
||||
"Initial angular velocity", "Initial angular velocity (limited by maximum angular velocity)")
|
||||
"Initial angular velocity", "Angular velocity applied when the rigid body is activated (limited by maximum angular velocity).")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInitialVelocitiesVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetAngularVelocityUnit())
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_linearDamping,
|
||||
"Linear damping", "Linear damping (must be non-negative)")
|
||||
"Linear damping", "The rate of decay over time for linear velocity even if no forces are acting on the rigid body.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetDampingVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_angularDamping,
|
||||
"Angular damping", "Angular damping (must be non-negative)")
|
||||
"Angular damping", "The rate of decay over time for angular velocity even if no forces are acting on the rigid body.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetDampingVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_sleepMinEnergy,
|
||||
"Sleep threshold", "Kinetic energy per unit mass below which body can go to sleep (must be non-negative)")
|
||||
"Sleep threshold", "The rigid body can go to sleep (settle) when kinetic energy per unit mass is persistently below this value.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetSleepOptionsVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetSleepThresholdUnit())
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_startAsleep,
|
||||
"Start asleep", "The rigid body will be asleep when spawned")
|
||||
"Start asleep", "When active, the rigid body will be asleep when spawned, and wake when the body is disturbed.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetSleepOptionsVisibility)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_interpolateMotion,
|
||||
"Interpolate motion", "Makes object motion look smoother")
|
||||
"Interpolate motion", "When active, simulation results are interpolated resulting in smoother motion.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInterpolationVisibility)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_gravityEnabled,
|
||||
"Gravity enabled", "Rigid body will be affected by gravity")
|
||||
"Gravity enabled", "When active, global gravity affects this rigid body.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetGravityVisibility)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_kinematic,
|
||||
"Kinematic", "Rigid body is kinematic")
|
||||
"Kinematic", "When active, the rigid body is not affected by gravity or other forces and is moved by script.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetKinematicVisibility)
|
||||
|
||||
// Linear axis locking properties
|
||||
@@ -161,85 +161,90 @@ namespace PhysX
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, false)
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearX, "Lock X",
|
||||
"Lock motion along X direction")
|
||||
"When active, forces won't create translation on the X axis of the rigid body.")
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearY, "Lock Y",
|
||||
"Lock motion along Y direction")
|
||||
"When active, forces won't create translation on the Y axis of the rigid body.")
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearZ, "Lock Z",
|
||||
"Lock motion along Z direction")
|
||||
"When active, forces won't create translation on the Z axis of the rigid body.")
|
||||
|
||||
// Angular axis locking properties
|
||||
->ClassElement(AZ::Edit::ClassElements::Group, "Angular Axis Locking")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, false)
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularX, "Lock X",
|
||||
"Lock rotation around X direction")
|
||||
"When active, forces won't create rotation on the X axis of the rigid body.")
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularY, "Lock Y",
|
||||
"Lock rotation around Y direction")
|
||||
"When active, forces won't create rotation on the Y axis of the rigid body.")
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularZ, "Lock Z",
|
||||
"Lock rotation around Z direction")
|
||||
"When active, forces won't create rotation on the Z axis of the rigid body.")
|
||||
|
||||
->ClassElement(AZ::Edit::ClassElements::Group, "Continuous Collision Detection")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetCCDVisibility)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_ccdEnabled,
|
||||
"CCD enabled", "Whether continuous collision detection is enabled for this body")
|
||||
"CCD enabled", "When active, the rigid body has continuous collision detection (CCD). Use this to ensure accurate "
|
||||
"collision detection, particularly for fast moving rigid bodies. CCD must be activated in the global PhysX preferences.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetCCDVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_ccdMinAdvanceCoefficient,
|
||||
"Min advance coefficient", "Lower values reduce clipping but can affect simulation smoothness")
|
||||
"Min advance coefficient", "Lower values reduce clipping but can affect simulation smoothness.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
|
||||
->Attribute(AZ::Edit::Attributes::Step, 0.01f)
|
||||
->Attribute(AZ::Edit::Attributes::Max, 0.99f)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::IsCCDEnabled)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_ccdFrictionEnabled,
|
||||
"CCD friction", "Whether friction is applied when CCD collisions are resolved")
|
||||
"CCD friction", "When active, friction is applied when continuous collision detection (CCD) collisions are resolved.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::IsCCDEnabled)
|
||||
->ClassElement(AZ::Edit::ClassElements::Group, "") // end previous group by starting new unnamed expanded group
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_maxAngularVelocity,
|
||||
"Maximum angular velocity", "The PhysX solver will clamp angular velocities with magnitude exceeding this value")
|
||||
"Maximum angular velocity", "Clamp angular velocities to this maximum value. "
|
||||
"This prevents rigid bodies from rotating at unrealistic velocities after collisions.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetMaxVelocitiesVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetAngularVelocityUnit())
|
||||
|
||||
// Mass properties
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_computeCenterOfMass,
|
||||
"Compute COM", "Whether to automatically compute the center of mass")
|
||||
"Compute COM", "Compute the center of mass (COM) for this rigid body.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_centerOfMassOffset,
|
||||
"COM offset", "Center of mass offset in local frame")
|
||||
"COM offset", "Local space offset for the center of mass (COM).")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetCoMVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetLengthUnit())
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_computeMass,
|
||||
"Compute Mass", "Whether to automatically compute the mass")
|
||||
"Compute Mass", "When active, the mass of the rigid body is computed based on the volume and density values of its colliders.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_mass,
|
||||
"Mass", "The mass of the object (must be non-negative, with a value of zero treated as infinite)")
|
||||
"Mass", "The mass of the rigid body in kilograms. A value of 0 is treated as infinite. "
|
||||
"The trajectory of infinite mass bodies cannot be affected by any collisions or forces other than gravity.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetMassUnit())
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetMassVisibility)
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_computeInertiaTensor,
|
||||
"Compute inertia", "Whether to automatically compute the inertia values based on the mass and shape of the rigid body")
|
||||
"Compute inertia", "When active, inertia is computed based on the mass and shape of the rigid body.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
|
||||
->DataElement(Editor::InertiaHandler, &AzPhysics::RigidBodyConfiguration::m_inertiaTensor,
|
||||
"Inertia diagonal", "Diagonal elements of the inertia tensor")
|
||||
"Inertia diagonal", "Inertia diagonal elements that specify an inertia tensor; determines the "
|
||||
"torque required to rotate the rigid body on each axis.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetInertiaUnit())
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_includeAllShapesInMassCalculation,
|
||||
"Include non-simulated shapes in Mass", "If set, non-simulated shapes will also be included in the center of mass, inertia and mass calculations.")
|
||||
"Include non-simulated shapes in Mass",
|
||||
"When active, non-simulated shapes are included in the center of mass, inertia, and mass calculations.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
;
|
||||
@@ -250,7 +255,7 @@ namespace PhysX
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorRigidBodyConfiguration::m_centerOfMassDebugDraw,
|
||||
"Debug draw COM", "Whether to debug draw the center of mass for this body")
|
||||
"Debug draw COM", "Display the rigid body's center of mass (COM) in the viewport.")
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorShapeColliderComponent>(
|
||||
"PhysX Shape Collider", "Creates geometry in the PhysX simulation based on an attached shape component")
|
||||
"PhysX Shape Collider", "Create a PhysX collider using a shape provided by a Shape component.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCollider.svg")
|
||||
@@ -88,13 +88,14 @@ namespace PhysX
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/shape-collider/")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_colliderConfig,
|
||||
"Collider configuration", "Configuration of the collider")
|
||||
"Collider configuration", "Configuration of the collider.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnConfigurationChanged)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_colliderDebugDraw,
|
||||
"Debug draw settings", "Debug draw settings")
|
||||
"Debug draw settings", "Debug draw settings.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_subdivisionCount, "Subdivision count", "Number of angular subdivisions in the PhysX cylinder")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_subdivisionCount, "Subdivision count",
|
||||
"Number of angular subdivisions in the PhysX cylinder.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, Utils::MinFrustumSubdivisions)
|
||||
->Attribute(AZ::Edit::Attributes::Max, Utils::MaxFrustumSubdivisions)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnSubdivisionCountChange)
|
||||
|
||||
@@ -62,10 +62,10 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<ForceRegion>(
|
||||
"Force Region", "Applies forces on entities within a region")
|
||||
"Force Region", "Applies forces on entities within a region.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceRegion::m_forces, "Forces", "Forces acting in the region")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceRegion::m_forces, "Forces", "Forces acting in the region.")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -37,13 +37,13 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<ForceWorldSpace>(
|
||||
"World Space Force", "Applies a force in world space")
|
||||
"World Space Force", "Applies a force in world space.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceWorldSpace::m_direction, "Direction", "Direction of the force in world space")
|
||||
->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceWorldSpace::m_direction, "Direction", "Direction of the force in world space.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceWorldSpace::m_magnitude, "Magnitude", "Magnitude of the force in world space")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceWorldSpace::m_magnitude, "Magnitude", "Magnitude of the force in world space.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue)
|
||||
;
|
||||
@@ -109,13 +109,13 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<ForceLocalSpace>(
|
||||
"Local Space Force", "Applies a force in the volume's local space")
|
||||
"Local Space Force", "Applies a force in the volume's local space.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceLocalSpace::m_direction, "Direction", "Direction of the force in local space")
|
||||
->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceLocalSpace::m_direction, "Direction", "Direction of the force in local space.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceLocalSpace::m_magnitude, "Magnitude", "Magnitude of the force in local space")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceLocalSpace::m_magnitude, "Magnitude", "Magnitude of the force in local space.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue)
|
||||
;
|
||||
@@ -179,10 +179,10 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<ForcePoint>(
|
||||
"Point Force", "Applies a force relative to the center of the volume")
|
||||
"Point Force", "Applies a force directed towards or away from the center of the volume.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForcePoint::m_magnitude, "Magnitude", "Magnitude of the point force")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForcePoint::m_magnitude, "Magnitude", "Magnitude of the point force.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue)
|
||||
;
|
||||
@@ -242,19 +242,24 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<ForceSplineFollow>(
|
||||
"Spline Follow Force", "Applies a force to make objects follow a spline at a given speed")
|
||||
"Spline Follow Force", "Applies a force to make objects follow a spline at a given speed.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_dampingRatio, "Damping Ratio", "Amount of damping applied to an entity that is moving towards a spline")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_dampingRatio, "Damping Ratio",
|
||||
"Values below 1 cause the entity to approach the spline faster but lead to overshooting and oscillation, "
|
||||
"while higher values will cause it to approach more slowly but more smoothly.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxDampingRatio)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_frequency, "Frequency", "Frequency at which an entity moves towards a spline")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_frequency, "Frequency",
|
||||
"Affects how quickly the entity approaches the spline.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinFrequency)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxFrequency)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_targetSpeed, "Target Speed", "Speed at which entities in the force region move along a spline")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_targetSpeed, "Target Speed",
|
||||
"Speed at which entities in the force region move along a spline.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_lookAhead, "Lookahead", "Distance at which entities look ahead in their path to reach a point on a spline")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_lookAhead, "Lookahead",
|
||||
"Distance at which entities look ahead in their path to reach a point on a spline.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue)
|
||||
;
|
||||
@@ -393,10 +398,10 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<ForceSimpleDrag>(
|
||||
"Simple Drag Force", "Simulates a drag force on entities")
|
||||
"Simple Drag Force", "Simulates a drag force on entities.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceSimpleDrag::m_volumeDensity, "Region Density", "Density of the region")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceSimpleDrag::m_volumeDensity, "Region Density", "Density of the region.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxDensity)
|
||||
;
|
||||
@@ -463,10 +468,10 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<ForceLinearDamping>(
|
||||
"Linear Damping Force", "Applies an opposite force to the entity's velocity")
|
||||
"Linear Damping Force", "Applies an opposite force to the entity's velocity.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceLinearDamping::m_damping, "Damping", "Amount of damping applied to an opposite force")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &ForceLinearDamping::m_damping, "Damping", "Amount of damping applied to an opposite force.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue)
|
||||
->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxDamping)
|
||||
;
|
||||
|
||||
@@ -59,22 +59,22 @@ namespace PhysX
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_swingLimitY, "Swing limit Y",
|
||||
"Maximum angle from the Y axis of the joint frame")
|
||||
"The rotation angle limit around the joint's Y axis.")
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
|
||||
->Attribute(AZ::Edit::Attributes::Min, JointConstants::MinSwingLimitDegrees)
|
||||
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_swingLimitZ, "Swing limit Z",
|
||||
"Maximum angle from the Z axis of the joint frame")
|
||||
"The rotation angle limit around the joint's Z axis.")
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
|
||||
->Attribute(AZ::Edit::Attributes::Min, JointConstants::MinSwingLimitDegrees)
|
||||
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_twistLimitLower, "Twist lower limit",
|
||||
"Lower limit for rotation about the X axis of the joint frame")
|
||||
"The lower rotation angle limit around the joint's X axis.")
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
|
||||
->Attribute(AZ::Edit::Attributes::Min, -180.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_twistLimitUpper, "Twist upper limit",
|
||||
"Upper limit for rotation about the X axis of the joint frame")
|
||||
"The upper rotation angle limit around the joint's X axis.")
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
|
||||
->Attribute(AZ::Edit::Attributes::Min, -180.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
|
||||
|
||||
@@ -42,16 +42,16 @@ namespace PhysX
|
||||
"PhysX Character Controller Configuration", "PhysX Character Controller Configuration")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &CharacterControllerConfiguration::m_slopeBehaviour,
|
||||
"Slope Behaviour", "Behaviour of the controller on surfaces above the maximum slope")
|
||||
"Slope Behavior", "Behavior of the controller on surfaces that exceed the Maximum Slope Angle.")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
->EnumAttribute(SlopeBehaviour::PreventClimbing, "Prevent Climbing")
|
||||
->EnumAttribute(SlopeBehaviour::ForceSliding, "Force Sliding")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &CharacterControllerConfiguration::m_contactOffset,
|
||||
"Contact Offset", "Extra distance outside the controller used for smoother contact resolution")
|
||||
"Contact Offset", "Distance from the controller boundary where contact with surfaces can be resolved.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
|
||||
->Attribute(AZ::Edit::Attributes::Step, 0.01f)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &CharacterControllerConfiguration::m_scaleCoefficient,
|
||||
"Scale", "Scalar coefficient used to scale the controller, usually slightly smaller than 1")
|
||||
"Scale", "Scales the controller. Usually less than 1.0 to ensure visual contact between the character and surface.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
|
||||
->Attribute(AZ::Edit::Attributes::Step, 0.01f)
|
||||
;
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace PhysX
|
||||
"PhysX Character Gameplay Configuration", "PhysX Character Gameplay Configuration")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &CharacterGameplayConfiguration::m_gravityMultiplier,
|
||||
"Gravity Multiplier", "Multiplier to be combined with the world gravity value for applying character gravity")
|
||||
"Gravity Multiplier", "Multiplier for global gravity value that applies only to this character entity.")
|
||||
->Attribute(AZ::Edit::Attributes::Step, 0.1f)
|
||||
;
|
||||
}
|
||||
|
||||
+8
-7
@@ -36,18 +36,18 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorCharacterControllerProxyShapeConfig>(
|
||||
"EditorCharacterControllerProxyShapeConfig", "PhysX character controller shape")
|
||||
"EditorCharacterControllerProxyShapeConfig", "PhysX character controller shape.")
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorCharacterControllerProxyShapeConfig::m_shapeType, "Shape",
|
||||
"The shape associated with the character controller")
|
||||
"The shape of the character controller.")
|
||||
->EnumAttribute(Physics::ShapeType::Capsule, "Capsule")
|
||||
->EnumAttribute(Physics::ShapeType::Box, "Box")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerProxyShapeConfig::m_box, "Box",
|
||||
"Configuration of box shape")
|
||||
"Configuration of box shape.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorCharacterControllerProxyShapeConfig::IsBoxConfig)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerProxyShapeConfig::m_capsule, "Capsule",
|
||||
"Configuration of capsule shape")
|
||||
"Configuration of capsule shape.")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorCharacterControllerProxyShapeConfig::IsCapsuleConfig)
|
||||
;
|
||||
}
|
||||
@@ -93,7 +93,8 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorCharacterControllerComponent>(
|
||||
"PhysX Character Controller", "PhysX Character Controller")
|
||||
"PhysX Character Controller",
|
||||
"Provides basic character interactions with the physical world, such as preventing movement through other PhysX bodies.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCharacter.svg")
|
||||
@@ -101,12 +102,12 @@ namespace PhysX
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/character-controller/")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerComponent::m_configuration,
|
||||
"Configuration", "Configuration for the character controller")
|
||||
"Configuration", "Configuration for the character controller.")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorCharacterControllerComponent::OnControllerConfigChanged)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerComponent::m_proxyShapeConfiguration,
|
||||
"Shape Configuration", "The configuration for the shape associated with the character controller")
|
||||
"Shape Configuration", "The configuration for the shape associated with the character controller.")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorCharacterControllerComponent::OnShapeConfigChanged)
|
||||
|
||||
+2
-2
@@ -43,7 +43,7 @@ namespace PhysX
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorCharacterGameplayComponent>(
|
||||
"PhysX Character Gameplay", "PhysX Character Gameplay")
|
||||
"PhysX Character Gameplay", "An example implementation of character physics behavior such as gravity.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCharacter.svg")
|
||||
@@ -51,7 +51,7 @@ namespace PhysX
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/character-gameplay/")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterGameplayComponent::m_gameplayConfig,
|
||||
"Gameplay Configuration", "Gameplay Configuration")
|
||||
"Gameplay Configuration", "Gameplay Configuration.")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace PhysX
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<RagdollComponent>(
|
||||
"PhysX Ragdoll", "Provides simulation of characters in PhysX.")
|
||||
"PhysX Ragdoll", "Creates a PhysX ragdoll simulation for an animation actor.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXRagdoll.svg")
|
||||
@@ -91,26 +91,28 @@ namespace PhysX
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/ragdoll/")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_positionIterations, "Position Iteration Count",
|
||||
"A higher iteration count generally improves fidelity at the cost of performance, but note that very high "
|
||||
"values may lead to severe instability if ragdoll colliders interfere with satisfying joint constraints")
|
||||
"The frequency at which ragdoll collider positions are resolved. Higher values can increase fidelity but decrease "
|
||||
"performance. Very high values might introduce instability.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 1)
|
||||
->Attribute(AZ::Edit::Attributes::Max, 255)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_velocityIterations, "Velocity Iteration Count",
|
||||
"A higher iteration count generally improves fidelity at the cost of performance, but note that very high "
|
||||
"values may lead to severe instability if ragdoll colliders interfere with satisfying joint constraints")
|
||||
"The frequency at which ragdoll collider velocities are resolved. Higher values can increase fidelity but decrease "
|
||||
"performance. Very high values might introduce instability.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 1)
|
||||
->Attribute(AZ::Edit::Attributes::Max, 255)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_enableJointProjection,
|
||||
"Enable Joint Projection", "Whether to use joint projection to preserve joint constraints "
|
||||
"in demanding situations at the expense of potentially reducing physical correctness")
|
||||
"Enable Joint Projection", "When active, preserves joint constraints in volatile simulations. "
|
||||
"Might not be physically correct in all simulations.")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_jointProjectionLinearTolerance,
|
||||
"Joint Projection Linear Tolerance", "Linear joint error above which projection will be applied")
|
||||
"Joint Projection Linear Tolerance",
|
||||
"Maximum linear joint error. Projection is applied to linear joint errors above this value.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Step, 1e-3f)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &RagdollComponent::IsJointProjectionVisible)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_jointProjectionAngularToleranceDegrees,
|
||||
"Joint Projection Angular Tolerance", "Angular joint error (in degrees) above which projection will be applied")
|
||||
"Joint Projection Angular Tolerance",
|
||||
"Maximum angular joint error. Projection is applied to angular joint errors above this value.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Step, 0.1f)
|
||||
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/Math/ToString.h>
|
||||
#include <AzFramework/Physics/Utils.h>
|
||||
#include <AzFramework/Physics/Configuration/RigidBodyConfiguration.h>
|
||||
#include <PhysX/NativeTypeIdentifiers.h>
|
||||
@@ -23,6 +24,28 @@
|
||||
|
||||
namespace PhysX
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const AZ::Vector3 DefaultCenterOfMass = AZ::Vector3::CreateZero();
|
||||
const float DefaultMass = 1.0f;
|
||||
const AZ::Matrix3x3 DefaultInertiaTensor = AZ::Matrix3x3::CreateIdentity();
|
||||
|
||||
bool IsSimulationShape(const physx::PxShape& pxShape)
|
||||
{
|
||||
return (pxShape.getFlags() & physx::PxShapeFlag::eSIMULATION_SHAPE);
|
||||
}
|
||||
|
||||
bool CanShapeComputeMassProperties(const physx::PxShape& pxShape)
|
||||
{
|
||||
// Note: List based on computeMassAndInertia function in ExtRigidBodyExt.cpp file in PhysX.
|
||||
const physx::PxGeometryType::Enum geometryType = pxShape.getGeometryType();
|
||||
return geometryType == physx::PxGeometryType::eSPHERE
|
||||
|| geometryType == physx::PxGeometryType::eBOX
|
||||
|| geometryType == physx::PxGeometryType::eCAPSULE
|
||||
|| geometryType == physx::PxGeometryType::eCONVEXMESH;
|
||||
}
|
||||
}
|
||||
|
||||
void RigidBody::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
@@ -152,104 +175,120 @@ namespace PhysX
|
||||
m_shapes.erase(found);
|
||||
}
|
||||
|
||||
void RigidBody::UpdateMassProperties(AzPhysics::MassComputeFlags flags, const AZ::Vector3* centerOfMassOffsetOverride, const AZ::Matrix3x3* inertiaTensorOverride, const float* massOverride)
|
||||
void RigidBody::UpdateMassProperties(AzPhysics::MassComputeFlags flags, const AZ::Vector3& centerOfMassOffsetOverride, const AZ::Matrix3x3& inertiaTensorOverride, const float massOverride)
|
||||
{
|
||||
// Input validation
|
||||
bool computeCenterOfMass = AzPhysics::MassComputeFlags::COMPUTE_COM == (flags & AzPhysics::MassComputeFlags::COMPUTE_COM);
|
||||
AZ_Assert(computeCenterOfMass || centerOfMassOffsetOverride,
|
||||
"UpdateMassProperties: MassComputeFlags::COMPUTE_COM is not set but COM offset is not specified");
|
||||
computeCenterOfMass = computeCenterOfMass || !centerOfMassOffsetOverride;
|
||||
const bool computeCenterOfMass = AzPhysics::MassComputeFlags::COMPUTE_COM == (flags & AzPhysics::MassComputeFlags::COMPUTE_COM);
|
||||
const bool computeInertiaTensor = AzPhysics::MassComputeFlags::COMPUTE_INERTIA == (flags & AzPhysics::MassComputeFlags::COMPUTE_INERTIA);
|
||||
const bool computeMass = AzPhysics::MassComputeFlags::COMPUTE_MASS == (flags & AzPhysics::MassComputeFlags::COMPUTE_MASS);
|
||||
const bool needsCompute = computeCenterOfMass || computeInertiaTensor || computeMass;
|
||||
const bool includeAllShapesInMassCalculation = AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES == (flags & AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES);
|
||||
|
||||
bool computeInertiaTensor = AzPhysics::MassComputeFlags::COMPUTE_INERTIA == (flags & AzPhysics::MassComputeFlags::COMPUTE_INERTIA);
|
||||
AZ_Assert(computeInertiaTensor || inertiaTensorOverride,
|
||||
"UpdateMassProperties: MassComputeFlags::COMPUTE_INERTIA is not set but inertia tensor is not specified");
|
||||
computeInertiaTensor = computeInertiaTensor || !inertiaTensorOverride;
|
||||
|
||||
bool computeMass = AzPhysics::MassComputeFlags::COMPUTE_MASS == (flags & AzPhysics::MassComputeFlags::COMPUTE_MASS);
|
||||
AZ_Assert(computeMass || massOverride,
|
||||
"UpdateMassProperties: MassComputeFlags::COMPUTE_MASS is not set but mass is not specified");
|
||||
computeMass = computeMass || !massOverride;
|
||||
|
||||
AZ::u32 shapesCount = GetShapeCount();
|
||||
|
||||
// Basic cases when we don't need to compute anything
|
||||
if (shapesCount == 0 || flags == AzPhysics::MassComputeFlags::NONE)
|
||||
// Basic case where all properties are set directly.
|
||||
if (!needsCompute)
|
||||
{
|
||||
if (massOverride)
|
||||
{
|
||||
SetMass(*massOverride);
|
||||
}
|
||||
|
||||
if (inertiaTensorOverride)
|
||||
{
|
||||
SetInertia(*inertiaTensorOverride);
|
||||
}
|
||||
|
||||
if (centerOfMassOffsetOverride)
|
||||
{
|
||||
SetCenterOfMassOffset(*centerOfMassOffsetOverride);
|
||||
}
|
||||
SetCenterOfMassOffset(centerOfMassOffsetOverride);
|
||||
SetMass(massOverride);
|
||||
SetInertia(inertiaTensorOverride);
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup center of mass offset pointer for PxRigidBodyExt::updateMassAndInertia function
|
||||
AZStd::optional<physx::PxVec3> optionalComOverride;
|
||||
if (!computeCenterOfMass && centerOfMassOffsetOverride)
|
||||
// If there are no shapes then set the properties directly without computing anything.
|
||||
if (m_shapes.empty())
|
||||
{
|
||||
optionalComOverride = PxMathConvert(*centerOfMassOffsetOverride);
|
||||
}
|
||||
|
||||
const physx::PxVec3* massLocalPose = optionalComOverride.has_value() ? &optionalComOverride.value() : nullptr;
|
||||
|
||||
bool includeAllShapesInMassCalculation =
|
||||
AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES == (flags & AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES);
|
||||
|
||||
// Handle the case when we don't compute mass
|
||||
if (!computeMass)
|
||||
{
|
||||
{
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, *massOverride, massLocalPose,
|
||||
includeAllShapesInMassCalculation);
|
||||
}
|
||||
|
||||
if (!computeInertiaTensor)
|
||||
{
|
||||
SetInertia(*inertiaTensorOverride);
|
||||
}
|
||||
|
||||
SetCenterOfMassOffset(computeCenterOfMass ? DefaultCenterOfMass : centerOfMassOffsetOverride);
|
||||
SetMass(computeMass ? DefaultMass : massOverride);
|
||||
SetInertia(computeInertiaTensor ? DefaultInertiaTensor : inertiaTensorOverride);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the cases when mass should be computed from density
|
||||
if (shapesCount == 1)
|
||||
auto cannotComputeMassProperties = [this, includeAllShapesInMassCalculation]
|
||||
{
|
||||
AZStd::shared_ptr<Physics::Shape> shape = GetShape(0);
|
||||
float density = shape->GetMaterial()->GetDensity();
|
||||
PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene());
|
||||
return AZStd::any_of(m_shapes.cbegin(), m_shapes.cend(),
|
||||
[includeAllShapesInMassCalculation](const AZStd::shared_ptr<PhysX::Shape>& shape)
|
||||
{
|
||||
const physx::PxShape& pxShape = *shape->GetPxShape();
|
||||
const bool includeShape = includeAllShapesInMassCalculation || IsSimulationShape(pxShape);
|
||||
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor, density, massLocalPose,
|
||||
includeAllShapesInMassCalculation);
|
||||
return includeShape && !CanShapeComputeMassProperties(pxShape);
|
||||
});
|
||||
};
|
||||
|
||||
// If contains shapes that cannot compute mass properties (triangle mesh,
|
||||
// plane or heightfield) then default values will be used.
|
||||
if (cannotComputeMassProperties())
|
||||
{
|
||||
AZ_Warning("RigidBody", !computeCenterOfMass,
|
||||
"Rigid body '%s' cannot compute COM because it contains triangle mesh, plane or heightfield shapes, it will default to %s.",
|
||||
GetName().c_str(), AZ::ToString(DefaultCenterOfMass).c_str());
|
||||
AZ_Warning("RigidBody", !computeMass,
|
||||
"Rigid body '%s' cannot compute Mass because it contains triangle mesh, plane or heightfield shapes, it will default to %0.1f.",
|
||||
GetName().c_str(), DefaultMass);
|
||||
AZ_Warning("RigidBody", !computeInertiaTensor,
|
||||
"Rigid body '%s' cannot compute Inertia because it contains triangle mesh, plane or heightfield shapes, it will default to %s.",
|
||||
GetName().c_str(), AZ::ToString(DefaultInertiaTensor.RetrieveScale()).c_str());
|
||||
|
||||
SetCenterOfMassOffset(computeCenterOfMass ? DefaultCenterOfMass : centerOfMassOffsetOverride);
|
||||
SetMass(computeMass ? DefaultMass : massOverride);
|
||||
SetInertia(computeInertiaTensor ? DefaultInertiaTensor : inertiaTensorOverride);
|
||||
return;
|
||||
}
|
||||
|
||||
// Center of mass needs to be considered first since
|
||||
// it's needed when computing mass and inertia.
|
||||
if (computeCenterOfMass)
|
||||
{
|
||||
// Compute Center of Mass
|
||||
UpdateCenterOfMass(includeAllShapesInMassCalculation);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZStd::vector<float> densities(shapesCount);
|
||||
for (AZ::u32 i = 0; i < shapesCount; ++i)
|
||||
SetCenterOfMassOffset(centerOfMassOffsetOverride);
|
||||
}
|
||||
const physx::PxVec3 pxCenterOfMass = PxMathConvert(GetCenterOfMassLocal());
|
||||
|
||||
if (computeMass)
|
||||
{
|
||||
// Gather material densities from all shapes,
|
||||
// mass computation is based on them.
|
||||
AZStd::vector<float> densities;
|
||||
densities.reserve(m_shapes.size());
|
||||
for (const auto& shape : m_shapes)
|
||||
{
|
||||
densities[i] = GetShape(i)->GetMaterial()->GetDensity();
|
||||
densities.emplace_back(shape->GetMaterial()->GetDensity());
|
||||
}
|
||||
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor, densities.data(),
|
||||
shapesCount, massLocalPose, includeAllShapesInMassCalculation);
|
||||
}
|
||||
// Compute Mass + Inertia
|
||||
{
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor,
|
||||
densities.data(), static_cast<AZ::u32>(densities.size()),
|
||||
&pxCenterOfMass, includeAllShapesInMassCalculation);
|
||||
}
|
||||
|
||||
// Set the overrides if provided.
|
||||
// Note: We don't set the center of mass here because it was already provided
|
||||
// to PxRigidBodyExt::updateMassAndInertia above
|
||||
if (!computeInertiaTensor)
|
||||
// There is no physx function to only compute the mass without
|
||||
// computing the inertia. So now that both have been computed
|
||||
// we can override the inertia if it's suppose to use a
|
||||
// specific value set by the user.
|
||||
if (!computeInertiaTensor)
|
||||
{
|
||||
SetInertia(inertiaTensorOverride);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetInertia(*inertiaTensorOverride);
|
||||
if (computeInertiaTensor)
|
||||
{
|
||||
// Set Mass + Compute Inertia
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, massOverride,
|
||||
&pxCenterOfMass, includeAllShapesInMassCalculation);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetMass(massOverride);
|
||||
SetInertia(inertiaTensorOverride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,52 +383,49 @@ namespace PhysX
|
||||
}
|
||||
}
|
||||
|
||||
void RigidBody::UpdateComputedCenterOfMass()
|
||||
void RigidBody::UpdateCenterOfMass(bool includeAllShapesInMassCalculation)
|
||||
{
|
||||
if (m_pxRigidActor)
|
||||
if (m_shapes.empty())
|
||||
{
|
||||
physx::PxU32 shapeCount = 0;
|
||||
SetCenterOfMassOffset(DefaultCenterOfMass);
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::vector<const physx::PxShape*> pxShapes;
|
||||
pxShapes.reserve(m_shapes.size());
|
||||
{
|
||||
// Filter shapes in the same way that updateMassAndInertia function does.
|
||||
PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene());
|
||||
for (const auto& shape : m_shapes)
|
||||
{
|
||||
PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene());
|
||||
shapeCount = m_pxRigidActor->getNbShapes();
|
||||
}
|
||||
if (shapeCount > 0)
|
||||
{
|
||||
AZStd::vector<physx::PxShape*> shapes;
|
||||
shapes.resize(shapeCount);
|
||||
const physx::PxShape& pxShape = *shape->GetPxShape();
|
||||
const bool includeShape = includeAllShapesInMassCalculation || IsSimulationShape(pxShape);
|
||||
|
||||
if (includeShape && CanShapeComputeMassProperties(pxShape))
|
||||
{
|
||||
PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene());
|
||||
m_pxRigidActor->getShapes(&shapes[0], shapeCount);
|
||||
pxShapes.emplace_back(&pxShape);
|
||||
}
|
||||
|
||||
shapes.erase(AZStd::remove_if(shapes.begin()
|
||||
, shapes.end()
|
||||
, [](const physx::PxShape* shape)
|
||||
{
|
||||
return shape->getFlags() & physx::PxShapeFlag::eTRIGGER_SHAPE;
|
||||
})
|
||||
, shapes.end());
|
||||
shapeCount = static_cast<physx::PxU32>(shapes.size());
|
||||
|
||||
if (shapeCount == 0)
|
||||
{
|
||||
SetZeroCenterOfMass();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto properties = physx::PxRigidBodyExt::computeMassPropertiesFromShapes(&shapes[0], shapeCount);
|
||||
const physx::PxTransform computedCenterOfMass(properties.centerOfMass);
|
||||
{
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
m_pxRigidActor->setCMassLocalPose(computedCenterOfMass);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetZeroCenterOfMass();
|
||||
}
|
||||
}
|
||||
|
||||
if (pxShapes.empty())
|
||||
{
|
||||
SetCenterOfMassOffset(DefaultCenterOfMass);
|
||||
return;
|
||||
}
|
||||
|
||||
const physx::PxMassProperties pxMassProperties = [this, &pxShapes]
|
||||
{
|
||||
// Note: PhysX computeMassPropertiesFromShapes function does not use densities
|
||||
// to compute the shape's masses, which are needed to calculate the center of mass.
|
||||
// This differs from updateMassAndInertia function, which uses material density values.
|
||||
// So the masses used during center of mass calculation do not match the masses
|
||||
// used during mass/inertia calculation. This is an inconsistency in PhysX.
|
||||
PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene());
|
||||
return physx::PxRigidBodyExt::computeMassPropertiesFromShapes(pxShapes.data(), static_cast<physx::PxU32>(pxShapes.size()));
|
||||
}();
|
||||
|
||||
SetCenterOfMassOffset(PxMathConvert(pxMassProperties.centerOfMass));
|
||||
}
|
||||
|
||||
void RigidBody::SetInertia(const AZ::Matrix3x3& inertia)
|
||||
@@ -401,16 +437,6 @@ namespace PhysX
|
||||
}
|
||||
}
|
||||
|
||||
void RigidBody::ComputeInertia()
|
||||
{
|
||||
if (m_pxRigidActor)
|
||||
{
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
auto localPose = m_pxRigidActor->getCMassLocalPose().p;
|
||||
physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, m_pxRigidActor->getMass(), &localPose);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Vector3 RigidBody::GetLinearVelocity() const
|
||||
{
|
||||
if (m_pxRigidActor)
|
||||
@@ -783,13 +809,4 @@ namespace PhysX
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void RigidBody::SetZeroCenterOfMass()
|
||||
{
|
||||
if (m_pxRigidActor)
|
||||
{
|
||||
PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene());
|
||||
m_pxRigidActor->setCMassLocalPose(physx::PxTransform(PxMathConvert(AZ::Vector3::CreateZero())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,17 +109,15 @@ namespace PhysX
|
||||
void RemoveShape(AZStd::shared_ptr<Physics::Shape> shape) override;
|
||||
|
||||
void UpdateMassProperties(AzPhysics::MassComputeFlags flags = AzPhysics::MassComputeFlags::DEFAULT,
|
||||
const AZ::Vector3* centerOfMassOffsetOverride = nullptr,
|
||||
const AZ::Matrix3x3* inertiaTensorOverride = nullptr,
|
||||
const float* massOverride = nullptr) override;
|
||||
const AZ::Vector3& centerOfMassOffsetOverride = AZ::Vector3::CreateZero(),
|
||||
const AZ::Matrix3x3& inertiaTensorOverride = AZ::Matrix3x3::CreateIdentity(),
|
||||
const float massOverride = 1.0f) override;
|
||||
|
||||
private:
|
||||
void CreatePhysXActor(const AzPhysics::RigidBodyConfiguration& configuration);
|
||||
|
||||
void UpdateComputedCenterOfMass();
|
||||
void ComputeInertia();
|
||||
void UpdateCenterOfMass(bool includeAllShapesInMassCalculation);
|
||||
void SetInertia(const AZ::Matrix3x3& inertia);
|
||||
void SetZeroCenterOfMass();
|
||||
|
||||
AZStd::shared_ptr<physx::PxRigidDynamic> m_pxRigidActor;
|
||||
AZStd::vector<AZStd::shared_ptr<PhysX::Shape>> m_shapes;
|
||||
|
||||
@@ -198,8 +198,8 @@ namespace PhysX
|
||||
AZ_Warning("PhysXScene", shapeAdded, "No Collider or Shape information found when creating Rigid body [%s]", configuration->m_debugName.c_str());
|
||||
}
|
||||
const AzPhysics::MassComputeFlags& flags = configuration->GetMassComputeFlags();
|
||||
newBody->UpdateMassProperties(flags, &configuration->m_centerOfMassOffset,
|
||||
&configuration->m_inertiaTensor, &configuration->m_mass);
|
||||
newBody->UpdateMassProperties(flags, configuration->m_centerOfMassOffset,
|
||||
configuration->m_inertiaTensor, configuration->m_mass);
|
||||
|
||||
crc = AZ::Crc32(newBody, sizeof(*newBody));
|
||||
return newBody;
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace PhysX
|
||||
|
||||
if (AZ::EditContext* editContext = serialize->GetEditContext())
|
||||
{
|
||||
editContext->Class<SystemComponent>("PhysX", "Global PhysX physics configuration")
|
||||
editContext->Class<SystemComponent>("PhysX", "Global PhysX physics configuration.")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "PhysX")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user