Cómo proporcionar el suyo propio Lógica de interpolación para el componente Transform - Guía del usuario de Lumberyard

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Cómo proporcionar el suyo propio Lógica de interpolación para el componente Transform

Puede añadir su propia lógica de interpolación para el componente Transform utilizando un común El marco de trabajo de disponible en C++. En este tema se muestra cómo utilizar C++, la serialización y la Lumberyard Editor La interfaz de usuario para escribir su propio modo de interpolación.

Adición del modo de interpolación a la Lumberyard Editor Interfaz de usuario

Puede comenzar desde la interfaz de usuario en el editor de para el componente Transform — específicamente, con las opciones de interpolación. La siguiente imagen muestra la Transformar el componente Ninguno o bien Lineal opciones de interpolación en la Entity Inspector.


                Interpolación de posición para la transformación
                    componente

Ver cómo se implementan estas opciones en el código puede ayudarle a comprender el cambios que son necesarios para añadir sus propias opciones.

El Ninguno y Lineal opciones de interpolación en el Entity Inspector proceden de la serialización de AzToolsFramework:: TransformComponent:: Reflect, que es la variación del editor de TransformComponent.

El siguiente código fuente relacionado se puede encontrar en el archivo dev\Code\Framework\AzToolsFramework\AzToolsFramework\ToolsComponents\TransformComponent.cpp.

namespace AzToolsFramework { void TransformComponent::Reflect(AZ::ReflectContext* context) { // Reflect data for script, serialization, editing. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context)) { ... if (AZ::EditContext* ptrEdit = serializeContext->GetEditContext()) { ptrEdit->Class<TransformComponent>("Transform", "Controls the placement of the entity in the world in 3d")-> ... ClassElement(AZ::Edit::ClassElements::Group, "Network Sync")-> Attribute(AZ::Edit::Attributes::AutoExpand, true)-> DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_netSyncEnabled, "Sync to replicas", "Sync to network replicas.")-> DataElement(AZ::Edit::UIHandlers::ComboBox, &TransformComponent::m_interpolatePosition, "Position Interpolation", "Enable local interpolation of position.")-> EnumAttribute(AzFramework::InterpolationMode::NoInterpolation, "None")-> EnumAttribute(AzFramework::InterpolationMode::LinearInterpolation, "Linear")-> DataElement(AZ::Edit::UIHandlers::ComboBox, &TransformComponent::m_interpolateRotation, "Rotation Interpolation", "Enable local interpolation of rotation.")-> EnumAttribute(AzFramework::InterpolationMode::NoInterpolation, "None")-> EnumAttribute(AzFramework::InterpolationMode::LinearInterpolation, "Linear"); ... } } ... } }

Una línea de código como la siguiente añade estas opciones a Lumberyard Editor. Contiene un y un nombre de cadena para el valor que aparece en el editor. La reflexión para las opciones de posición y rotación es similar.

EnumAttribute(AzFramework::InterpolationMode::NoInterpolation,"None")->

AzFramework:: InterpolationMode:: NoInterpolation es un valor de enumeración de el AzFramework espacio de nombres. Puede encontrar el código fuente relacionado en el archivo dev\Code\Framework\AzFramework\AzFramework\Math\InterpolationSample.h.

namespace AzFramework { /** * Behavior types for smoothing of transform between network updates. */ enum class InterpolationMode : AZ::u32 { NoInterpolation, LinearInterpolation, }; }

A continuación de este ejemplo, puede añadir su propio valor de enumeración. El siguiente ejemplo llama a it MyInterpolation.

namespace AzFramework { /** * Behavior types for smoothing of transform between network updates. */ enum class InterpolationMode : AZ::u32 { NoInterpolation, LinearInterpolation, MyInterpolation, // <--- NEW CONTENT }; }

A continuación, actualice AzToolsFramework:: TransformComponent ::Reflect como en la siguiente ejemplo.

namespace AzToolsFramework { void TransformComponent::Reflect(AZ::ReflectContext* context) { // Reflect data for script, serialization, editing. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context)) { ... DataElement(AZ::Edit::UIHandlers::ComboBox, &TransformComponent::m_interpolatePosition, "Position Interpolation", "Enable local interpolation of position.")-> EnumAttribute(AzFramework::InterpolationMode::NoInterpolation, "None")-> EnumAttribute(AzFramework::InterpolationMode::LinearInterpolation, "Linear")-> EnumAttribute(AzFramework::InterpolationMode::MyInterpolation, "My Mode")-> // <--- NEW CONTENT ... } } } }

Implementación de la lógica de interpolación en C++

Ahora que Lumberyard Editor tiene su nueva opción, puede implementarla en su código.

El AzToolsFramework:: TransformComponent es simplemente un componente que el El editor de utiliza para crear la contraparte del componente de juego AzFramework:: TransformComponent. Examine el siguiente código fuente para el TransformComponent clase. El código muestra dónde se encuentra la interpolación Las muestras se conservan y se calcula el valor interpolado. El código está en el archivo dev\Code\Framework\AzFramework\AzFramework\Components\TransformComponent.h.

namespace AzFramework { class TransformComponent : public AZ::Component , public AZ::TransformBus::Handler , public AZ::TransformNotificationBus::Handler , public AZ::EntityBus::Handler , public AZ::TickBus::Handler , private AZ::TransformHierarchyInformationBus::Handler , public NetBindable { ... private: ... void CreateTranslationSample(); void CreateRotationSample(); AZStd::unique_ptr<Sample<AZ::Vector3>> m_netTargetTranslation; // <--- Sample<> is the base templated class for all interpolation logic. AZStd::unique_ptr<Sample<AZ::Quaternion>> m_netTargetRotation; AZ::Vector3 m_netTargetScale; ... }; } // namespace AZ

Sample<> es la clase abstracta base para toda la lógica de interpolación. Observe que se abstrae para admitir vectores de posición o cuaterniones para la rotación. El siguiente código muestra el origen de la Sample clase en el archivo dev\Code\Framework\AzFramework\AzFramework\Math\InterpolationSample.h.

namespace AzFramework { template<typename Value> class Sample { public: virtual ~Sample() = default; using TimeType = unsigned int; Sample() : m_targetValue() , m_targetTimestamp(0) , m_previousValue() , m_previousTimestamp(0) { } void SetNewTarget(Value newValue, TimeType timestamp) // <---- Network stack provides you these values every time it gets them. { m_targetValue = newValue; m_targetTimestamp = timestamp; } virtual Value GetInterpolatedValue(TimeType time) = 0; // <---- Provide your own interpolation logic here. Value GetTargetValue() const { return m_targetValue; } TimeType GetTargetTimestamp() const { return m_targetTimestamp; } protected: void SetPreviousValue(Value previousValue, TimeType previousTimestamp) { m_previousValue = previousValue; m_previousTimestamp = previousTimestamp; } Value m_targetValue; TimeType m_targetTimestamp; Value m_previousValue; TimeType m_previousTimestamp; }; }

La implementación más sencilla no es ninguna interpolación, para la que el código ya está ha escrito. Puede encontrarlo en el mismo archivo: dev\Code\Framework\AzFramework\AzFramework\Math\InterpolationSample.h.

template<typename T> class UninterpolatedSample; template<> class UninterpolatedSample<AZ::Vector3> final : public Sample<AZ::Vector3> { public: AZ::Vector3 GetInterpolatedValue(TimeType /*time*/) override final { return GetTargetValue(); } };

El siguiente código muestra una implementación de interpolación lineal que se incluye con Lumberyard (dev\Code\Framework\AzFramework\AzFramework\Math\InterpolationSample.h).

namespace AzFramework { template<typename T> class LinearlyInterpolatedSample; template<> class LinearlyInterpolatedSample<AZ::Vector3> final : public Sample<AZ::Vector3> { public: AZ::Vector3 GetInterpolatedValue(TimeType time) override final { AZ::Vector3 interpolatedValue = m_previousValue; if (m_targetTimestamp != 0) { if (m_targetTimestamp <= m_previousTimestamp || m_targetTimestamp <= time) { interpolatedValue = m_targetValue; } else if (time > m_previousTimestamp) { float t = float(time - m_previousTimestamp) / float(m_targetTimestamp - m_previousTimestamp); // lerp translation AZ::Vector3 deltaPos = t * (m_targetValue - m_previousValue); interpolatedValue = m_previousValue + deltaPos; AZ_Assert(interpolatedValue.IsFinite(), "interpolatedValue is not finite!"); } } SetPreviousValue(interpolatedValue, time); return interpolatedValue; } }; }

El siguiente ejemplo muestra una implementación completada denominada MyInterpolatedSample que solo proporciona interpolación de vectores para posición.

namespace AzFramework { template<typename T> class MyInterpolatedSample; template<> class MyInterpolatedSample<AZ::Vector3> final : public Sample<AZ::Vector3> { ... } }

Por último, debe activar TransformComponent para elegir su clase implementación de. Puede hacerlo en la instrucción switch case de AzFramework:: TransformComponent:: CreateTranslationSample(). El código fuente se encuentra en el campo archivo dev\Code\Framework\AzFramework\AzFramework\Components\TransformComponent.cpp.

void AzFramework::TransformComponent::CreateTranslationSample() { switch(m_interpolatePosition) { case InterpolationMode::LinearInterpolation: m_netTargetTranslation = AZStd::make_unique<LinearlyInterpolatedSample<AZ::Vector3>>(); break; case InterpolationMode::NoInterpolation: default: m_netTargetTranslation = AZStd::make_unique<UninterpolatedSample<AZ::Vector3>>(); break; } }

Proporcione una nueva declaración de caso para su opción de enumeración. La opción crea una instancia de su MyInterpolationSample clase.

void AzFramework::TransformComponent::CreateTranslationSample() { switch(m_interpolatePosition) { case InterpolationMode::MyInterpolation: // <--- NEW CONTENT m_netTargetTranslation = AZStd::make_unique<MyInterpolatedSample<AZ::Vector3>>(); // <--- NEW CONTENT break; // <--- NEW CONTENT case InterpolationMode::LinearInterpolation: m_netTargetTranslation = AZStd::make_unique<LinearlyInterpolatedSample<AZ::Vector3>>(); break; case InterpolationMode::NoInterpolation: default: m_netTargetTranslation = AZStd::make_unique<UninterpolatedSample<AZ::Vector3>>(); break; } }

¡Eso es todo! Ahora puedes seleccionar tu nueva opción en el paso Entity Inspectory su la lógica de interpolación personalizada realiza el trabajo.

Rotación Interpolación

El ejemplo anterior muestra cómo proporcionar su propia interpolación de posición. Rotación la interpolación es similar, pero con las siguientes diferencias menores:

  • Tiene que proporcionar la implementación de plantillas de MyInterpolationSample<Quaternion>.

  • Tienes que escribir código similar en AzFramework:: TransformComponent:: CreateRotationSample() en lugar de en ::CreateTranslationSample().

  • En la ubicación de las opciones de interpolación, el botón AzToolsFramework:: TransformComponent tiene una definición separada para la rotación interpolación.