/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #if defined(AZ_COMPILER_MSVC) #pragma warning(push) #pragma warning(disable : 4714) #endif #include "EMotionFX_precompiled.h" #include #include #include #include #include #include #if defined(AZ_COMPILER_MSVC) #pragma warning(push, 0) #endif #include #include #if defined(AZ_COMPILER_MSVC) #pragma warning(pop) #endif namespace EMotionFX { namespace Integration { void SimpleLODComponent::Configuration::Reflect(AZ::ReflectContext *context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { serializeContext->Class() ->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("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(context); if (serializeContext) { serializeContext->Class() ->Version(1) ->Field("Configuration", &SimpleLODComponent::m_configuration) ; AZ::EditContext* editContext = serializeContext->GetEditContext(); if (editContext) { editContext->Class( "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& 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(i); } } return static_cast(max - 1); } void SimpleLODComponent::UpdateLodLevelByDistance(EMotionFX::ActorInstance * actorInstance, const Configuration& configuration, AZ::EntityId entityId) { if (actorInstance) { AZ::Transform worldTransform; AZ::TransformBus::EventResult(worldTransform, entityId, &AZ::TransformBus::Events::GetWorldTM); const AZ::Vector3& worldPos = worldTransform.GetPosition(); // Compute the distance between the camera and the entity if (gEnv->pSystem) { const CCamera& camera = gEnv->pSystem->GetViewCamera(); const AZ::Vector3& cameraPos = LYVec3ToAZVec3(camera.GetPosition()); const AZ::VectorFloat distance = cameraPos.GetDistance(worldPos); 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 #if defined(AZ_COMPILER_MSVC) #pragma warning(pop) #endif