Files
o3de/Gems/EMotionFX/Code/Source/Integration/Components/SimpleLODComponent.cpp
T
Esteban Papp 1f9b284de2 Merge branch 'development' into cmake/SPEC-7179
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

# Conflicts:
#	Code/Editor/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin_precompiled.h
#	Code/Editor/Plugins/EditorCommon/EditorCommon_precompiled.h
#	Code/Editor/Plugins/EditorCommon/stdafx.cpp
#	Code/Editor/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.h
#	Code/Editor/Plugins/PerforcePlugin/PerforcePlugin_precompiled.h
#	Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsTool_precompiled.h
#	Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFramework_precompiled.h
#	Code/Tools/AssetProcessor/native/precompiled.h
#	Code/Tools/Standalone/StandaloneTools_precompiled.h
#	Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer_precompiled.h
#	Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessing_precompiled.h
#	Gems/Atom/RHI/DX12/Code/Source/RHI/Atom_RHI_DX12_precompiled.h
#	Gems/Atom/RHI/Metal/Code/Include/Platform/Mac/Atom_RHI_Metal_precompiled_Platform.h
#	Gems/Atom/RHI/Metal/Code/Include/Platform/iOS/Atom_RHI_Metal_precompiled_Platform.h
#	Gems/Atom/RHI/Metal/Code/Source/Atom_RHI_Metal_precompiled.h
#	Gems/Atom/RHI/Metal/Code/atom_rhi_metal_common_files.cmake
#	Gems/Atom/RHI/Null/Code/Source/Atom_RHI_Null_precompiled.h
#	Gems/Atom/RHI/Null/Code/atom_rhi_null_common_files.cmake
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Android/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Linux/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Mac/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Include/Platform/Windows/Atom_RHI_Vulkan_precompiled_Platform.h
#	Gems/Atom/RHI/Vulkan/Code/Source/Atom_RHI_Vulkan_precompiled.h
#	Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp
#	Gems/Atom/RHI/Vulkan/Code/atom_rhi_vulkan_common_files.cmake
#	Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont_precompiled.h
#	Gems/Blast/Code/Source/StdAfx.cpp
#	Gems/Camera/Code/Source/Camera_precompiled.h
#	Gems/EMotionFX/Code/Source/EMotionFX_precompiled.h
#	Gems/FastNoise/Code/Source/FastNoise_precompiled.h
#	Gems/Gestures/Code/Source/Gestures_precompiled.h
#	Gems/GradientSignal/Code/Source/GradientSignal_precompiled.h
#	Gems/GraphCanvas/Code/precompiled.h
#	Gems/ImGui/Code/Source/ImGui_precompiled.h
#	Gems/InAppPurchases/Code/Source/InAppPurchases_precompiled.h
#	Gems/LmbrCentral/Code/Source/LmbrCentral_precompiled.h
#	Gems/LmbrCentral/Code/Tests/ShapeGeometryUtilTest.cpp
#	Gems/LyShine/Code/Editor/UiCanvasEditor_precompiled.h
#	Gems/LyShine/Code/Source/Animation/LyShine_precompiled.h
#	Gems/LyShine/Code/Source/LyShine_precompiled.h
#	Gems/LyShineExamples/Code/Source/LyShineExamples_precompiled.h
#	Gems/Maestro/Code/Source/Cinematics/Maestro_precompiled.h
#	Gems/Maestro/Code/Source/Maestro_precompiled.h
#	Gems/MessagePopup/Code/Source/MessagePopup_precompiled.h
#	Gems/Metastream/Code/Source/Metastream_precompiled.h
#	Gems/Microphone/Code/Source/Microphone_precompiled.h
#	Gems/Multiplayer/Code/Source/Multiplayer_precompiled.h
#	Gems/PhysX/Code/NumericalMethods/Source/NumericalMethods_precompiled.h
#	Gems/PhysX/Code/Source/PhysXUnsupported_precompiled.h
#	Gems/PhysX/Code/Source/PhysX_precompiled.h
#	Gems/PhysX/Code/physx_unsupported_files.cmake
#	Gems/PhysXDebug/Code/Source/PhysXDebugUnsupported_precompiled.h
#	Gems/PhysXDebug/Code/Source/PhysXDebug_precompiled.h
#	Gems/ScriptCanvas/Code/Editor/precompiled.h
#	Gems/ScriptCanvas/Code/Source/precompiled.h
#	Gems/ScriptCanvasDeveloper/Code/Source/precompiled.h
#	Gems/ScriptCanvasPhysics/Code/Source/ScriptCanvasPhysics_precompiled.h
#	Gems/ScriptEvents/Code/Source/precompiled.h
#	Gems/ScriptEvents/Code/Tests/Editor/EditorTests.cpp
#	Gems/ScriptedEntityTweener/Code/Source/ScriptedEntityTweener_precompiled.h
#	Gems/SliceFavorites/Code/Source/SliceFavorites_precompiled.h
#	Gems/StartingPointCamera/Code/Source/StartingPointCamera_precompiled.h
#	Gems/StartingPointInput/Code/Source/StartingPointInput_precompiled.h
#	Gems/StartingPointMovement/Code/Source/StartingPointMovement_precompiled.h
#	Gems/SurfaceData/Code/Source/SurfaceData_precompiled.h
#	Gems/TextureAtlas/Code/Source/TextureAtlas_precompiled.h
#	Gems/TickBusOrderViewer/Code/Source/TickBusOrderViewer_precompiled.h
#	Gems/Twitch/Code/Source/Twitch_precompiled.h
#	Gems/VirtualGamepad/Code/Source/VirtualGamepad_precompiled.h
#	Gems/WhiteBox/Code/Source/WhiteBoxUnsupported_precompiled.h
#	Gems/WhiteBox/Code/Source/WhiteBox_precompiled.h
2021-07-16 15:42:37 -07:00

220 lines
8.9 KiB
C++

/*
* 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/PlatformDef.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <Integration/Components/SimpleLODComponent.h>
#include <MCore/Source/AttributeString.h>
#include <EMotionFX/Source/ActorInstance.h>
#include <MathConversion.h>
#include <IRenderAuxGeom.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
namespace EMotionFX
{
namespace Integration
{
void SimpleLODComponent::Configuration::Reflect(AZ::ReflectContext *context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<Configuration>()
->Version(2)
->Field("LODDistances", &Configuration::m_lodDistances)
->Field("EnableLODSampling", &Configuration::m_enableLodSampling)
->Field("LODSampleRates", &Configuration::m_lodSampleRates)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<SimpleLODComponent::Configuration>("Configuration", "The LOD Configuration.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(0, &SimpleLODComponent::Configuration::m_lodDistances,
"LOD distance (Max)", "The maximum camera distance of this LOD.")
->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->ElementAttribute(AZ::Edit::Attributes::Step, 0.01f)
->ElementAttribute(AZ::Edit::Attributes::Suffix, " m")
->DataElement(0, &SimpleLODComponent::Configuration::m_enableLodSampling,
"Enable LOD anim graph sampling", "AnimGraph sample rate will adjust based on LOD level.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
->DataElement(0, &SimpleLODComponent::Configuration::m_lodSampleRates,
"Anim graph sample rates", "The sample rate of anim graph based on LOD. Setting it to O means the maximum sample rate.")
->Attribute(AZ::Edit::Attributes::Visibility, &SimpleLODComponent::Configuration::GetEnableLodSampling)
->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->ElementAttribute(AZ::Edit::Attributes::Step, 1.0f);
}
}
}
void SimpleLODComponent::Configuration::Reset()
{
m_lodDistances.clear();
}
void SimpleLODComponent::Configuration::GenerateDefaultValue(AZ::u32 numLODs)
{
if (numLODs != m_lodDistances.size())
{
// Generate the default LOD (max) distance to 10, 20, 30....
m_lodDistances.resize(numLODs);
for (AZ::u32 i = 0; i < numLODs; ++i)
{
m_lodDistances[i] = i * 10.0f + 10.0f;
}
}
if (numLODs != m_lodSampleRates.size())
{
// Generate the default LOD Sample Rate to 140, 60, 45, 25, 15, 10
const float defaultSampleRate[] = {140.0f, 60.0f, 45.0f, 25.0f, 15.0f, 10.0f};
m_lodSampleRates.resize(numLODs);
for (AZ::u32 i = 0; i < numLODs; ++i)
{
m_lodSampleRates[i] = defaultSampleRate[i];
}
}
}
bool SimpleLODComponent::Configuration::GetEnableLodSampling()
{
return m_enableLodSampling;
}
void SimpleLODComponent::Reflect(AZ::ReflectContext* context)
{
Configuration::Reflect(context);
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<SimpleLODComponent, AZ::Component>()
->Version(1)
->Field("Configuration", &SimpleLODComponent::m_configuration)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<SimpleLODComponent>(
"Simple LOD distance", "The Simple LOD distance component alters the actor LOD level based on distance to camera")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
;
}
}
}
SimpleLODComponent::SimpleLODComponent(const Configuration* config)
: m_actorInstance(nullptr)
{
if (config)
{
m_configuration = *config;
}
}
SimpleLODComponent::~SimpleLODComponent()
{
}
void SimpleLODComponent::Init()
{
}
void SimpleLODComponent::Activate()
{
ActorComponentNotificationBus::Handler::BusConnect(GetEntityId());
AZ::TickBus::Handler::BusConnect();
}
void SimpleLODComponent::Deactivate()
{
AZ::TickBus::Handler::BusDisconnect();
ActorComponentNotificationBus::Handler::BusDisconnect();
}
void SimpleLODComponent::OnActorInstanceCreated(EMotionFX::ActorInstance* actorInstance)
{
m_actorInstance = actorInstance;
}
void SimpleLODComponent::OnActorInstanceDestroyed(EMotionFX::ActorInstance* actorInstance)
{
AZ_UNUSED(actorInstance);
m_actorInstance = nullptr;
}
void SimpleLODComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time)
{
AZ_UNUSED(deltaTime);
AZ_UNUSED(time);
UpdateLodLevelByDistance(m_actorInstance, m_configuration, GetEntityId());
}
AZ::u32 SimpleLODComponent::GetLodByDistance(const AZStd::vector<float>& distances, float distance)
{
const size_t max = distances.size();
for (size_t i = 0; i < max; ++i)
{
const float rDistance = distances[i];
if (distance < rDistance)
{
return static_cast<AZ::u32>(i);
}
}
return static_cast<AZ::u32>(max - 1);
}
void SimpleLODComponent::UpdateLodLevelByDistance(EMotionFX::ActorInstance * actorInstance, const Configuration& configuration, AZ::EntityId entityId)
{
if (actorInstance)
{
// Compute the distance between the camera and the entity
AZ::Transform worldTransform;
AZ::TransformBus::EventResult(worldTransform, entityId, &AZ::TransformBus::Events::GetWorldTM);
const AZ::Vector3& worldPos = worldTransform.GetTranslation();
auto viewportContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
if (!viewportContextManager)
{
return;
}
AZ::RPI::ViewportContextPtr defaultViewportContext =
viewportContextManager->GetViewportContextByName(viewportContextManager->GetDefaultViewportContextName());
const float distance = worldPos.GetDistance(defaultViewportContext->GetCameraTransform().GetTranslation());
const AZ::u32 lodByDistance = GetLodByDistance(configuration.m_lodDistances, distance);
actorInstance->SetLODLevel(lodByDistance);
if (configuration.m_enableLodSampling)
{
const float animGraphSampleRate = configuration.m_lodSampleRates[lodByDistance];
const float updateRateInSeconds = animGraphSampleRate > 0.0f ? 1.0f / animGraphSampleRate : 0.0f;
actorInstance->SetMotionSamplingRate(updateRateInSeconds);
}
}
}
} // namespace integration
} // namespace EMotionFX