Sistema de Pasos en Unreal Engine y FMOD (Blueprints y C++)

If you prefer to read an English version, click on this button =>

Unreal Engine Version: 5.0.3

FMOD Version: 2.02.08

Este post the muestra cómo crear un sistema de pasos de audio en Unreal Engine 5 y FMOD. Este sistema usa un line trace generado desde la posición del Personaje hacia el piso. Este line trace va a obtener información sobre el Physical Material de las superficies y va a definir los parámetros en FMOD para cambiar el tipo de sonido de pasos.

Para este proyecto, he implementado este sistema dos veces, una usando el scripting visual Blueprints y otra usando C++ nativo. Aquí una lista con herramientas y palabras clave usadas en este proyecto:

Programé todo el sistema dentro de la clase padre C++ MyUE5ProjectCharacter, la clase blueprint hija BP_ThirdPersonCharacter, y el blueprint de animación ABP_Manny.

Importante:

Ten en consideración que esta guía no pretende enseñar diseño de sonido creativo. En cambio, se enfoca exclusivamente en aspectos de implementación y programación de game audio.


Descarga el Proyecto Aquí:

IMPORTANTE!

〰️

IMPORTANTE! 〰️

Prerequisitos:

  1. Crea un proyecto C++ third-person vacio y llámalo “MyUE5Project”.

  2. Descarga e integra el plugin FMOD en tu proyecto.

  3. Crea un nuevo proyecto FMOD Studio y define el directorio para construir tus bancos en MyUEProject/Content/FMOD

  4. Construye el Master Bank

Para que este tutorial tenga sentido, es importante que sepas cómo integrar el plugin FMOD y cómo llamar sus propiedades en Unreal Engine. Adicionalmente, considera leer y consultar mi post anterior sobre UPROPERTY & UFUNCTION:

IMPORTANTE!

〰️

IMPORTANTE! 〰️

 

Setup FMOD:

Dentro del proyecto FMOD, crea un evento de tipo 3D Timeline llamado Play_Footsteps. Añade cuatro tracks y un Multi Instrument en cada uno de ellos. Importa tus archivos de audio dentro de cada Multi Instrument.

 

Ve a Window > Preset Browser, o presiona Command - 8 en tu teclado y después da click en el botón New Parameter. Crea un Labeled Parameter llamado “Footsteps” con cuatro labels, una por instrumento. Define el primero como el valor inicial. Finalmente, selecciona la opción Hold Value During Playback para asegurar que los sonidos no van a ser interrumpidos si el parametro cambia en medio de la reproducción.

Desafortunadamente, Unreal Engine no soporta llamar parámetros FMOD por medio del nombre de los labels, pero podemos usar los valores numéricos asociados a estos para lograr el mismo resultado.

 

Selecciona un Multi Instrument, y ve al Deck de FMOD en la parte inferior del editor. Da click en la flecha de Trigger Behaviour y después da click en Add Condition. Selecciona "Footsteps" y finalmente selecciona el Label apropiado. Como un paso adicional, puedes definir una modulación aleatoria de la afinación dando click derecho en Pitch > Add Modulation. Esta opción añade variación adicional a los sonidos de pasos. Repite este proceso por cada Multi Instrument en el evento.

Guarda y construye el Master Audio Bank.

 

Materials y Physical Materials:

Los Environmental Artists usan recursos de tipo Material y Physical Material para definir como se ven y simulan la física las superficies en el juego. Como artistas y programadores de audio, podemos usar estos materiales añadidos a las superficies y un Line trace para definir parámetros FMOD de forma dinámica.

Crea una carpeta de materiales y añade un Material y un Physical Material por cada superficie requerida. Para este proyecto, cree cuatro materiales diferentes.

 

Da double click en cada material y define su color y su Physical Material en el editor.

Ve a Window > Place Actors > Plane. Arrastra y coloca estas nuevas superficies en el viewport, y después asígnale un Material. Adicionalmente, puedes añadir un nombre a estas con un Text Render Component.

 

Setup C++:

Implementé todas las propiedades de este proyecto y un FMOD Audio Component en C++. 

La clase blueprint va a heredar todas estas propiedades de la clase padre y las va a exponer en el graph blueprint. Finalmente, cree dos funciones en C++ y dos funciones en Blueprints que hacen lo mismo, para mostrarte cómo los dos sistemas se reflejan.

Importante:

Yo uso comentarios de tipo Doxygen para explicar el código. Estos comentarios no van a comprometer la funcionalidad del código o su compilación. Siéntete libre de copiar el código tal como está escrito aquí.

Build.cs:

Abre la solución en tu IDE y localiza MyUE5Project.Build.cs en MyUE5Project > Source, y añade "FMODStudio" y "PhysicsCore" como dependencias del build.

/** Añade "FMODStudio" y "PhysicsCore" para poder usar y compilar el API de FMOD y UPhysicalMaterial en C++ */
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "FMODStudio", "PhysicsCore"});

Declaración de Funciones y Propiedades:

Ve a MyUE5Project > Source, y abre MyUE5ProjectCharacter.h Incluye estas directivas:

.h file:

#include "FMODBlueprintStatics.h" // Incluye esta directiva para acceder al API de FMOD.
#include "PhysicalMaterials/PhysicalMaterial.h" // Incluye esta directiva para poder trabajar con Physical Materials.

Declara un FMOD Audio Component, un TMap, un booleano, y un float.

.h file:

/** Fmod Audio Component. Creado en el constructor de la clase. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Audio")
UFMODAudioComponent* FmodAudioComponent;

/** Un map es una structura de datos. Contiene Physical Materials como claves y floats como valores.
 *  Estos valores van a definir el parámetro correcto en FMOD */
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Audio")
TMap<UPhysicalMaterial*, float> PhysicalMaterialMap;
	
/** Propiedad Booleana que define la visibilidad de la función AddOnScreenDebugMessage y hace que el line trace sea visible en el juego. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Audio")
bool bPrintDebug;

/** Define que tan lejos el line trace se extiende desde la posición de nuestro Character en el vector Z.
 *  Números positivos vector hacia arriba, números negativos vector hacia abajo. -150cm definido por defecto */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Audio")
float Offset = -150;

Declara dos funciones, GetPhysicalMaterialByLineTrace() y SetFootstepsParameter().

.h file:

/**
 * @brief Obtiene una referencia del Physical Material del suelo con un line trace.
 * @param OffsetZ Qué tan lejos el line trace se extiende desde el centro de nuestro personaje.
 * @param bDebug Define la visibilidad del line trace. true: Visible, false: No Visible
 * @return A Physical Material reference
 */
UFUNCTION(BlueprintCallable, Category="Audio")
UPhysicalMaterial* GetPhysicalMaterialByLineTrace(const float &OffsetZ, const bool &bDebug);

/**
 * @brief Obtiene una referencia del Physical Material y define el valor del parámetro apropiado en FMOD. 
 * @param HitPhysicalMaterial Una referencia del Physical Material 
 * @param bDebug Define la visibilidad para imprimir el nombre del Physical Material actual en la pantalla. true: Visible, false: No Visible
 * @param ParameterName Nombre del parámetro FMOD.
 */
UFUNCTION(BlueprintCallable, Category="Audio")
void SetFootstepsParameter(const UPhysicalMaterial* HitPhysicalMaterial, const bool &bDebug, const FName ParameterName);

Implementación C++ y Blueprint:

En esta sección te muestro cómo acceder al Line trace en el Kismet System Library y cómo crear un FMOD Audio Component. Finalmente, te muestro la implementación del BP_ThirdPersonCharacter en el graph blueprint y luego la implementación C++ en el archivo MyUE5ProjectCharacter.cpp.

.cpp file:

#include "Kismet/KismetSystemLibrary.h" // Incluye esta directiva para acceder a las funciones de line trace.

FMOD Audio Component en el Constructor de la Clase:

Crea un FMOD Audio Component en el constructor. El constructor lleva el mismo nombre que su clase: MyUE5ProjectCharacter::MyUE5ProjectCharacter(). Este FMOD Audio Component va a contener el evento FMOD de pasos, y va a seguir la posición del personaje en el mundo. Adicionalmente, este componente nos permite definir el valor de los parámetros antes de crear una instancia de su evento.

.cpp file:

// Crea un FMOD Component. 
FmodAudioComponent = CreateDefaultSubobject<UFMODAudioComponent>(TEXT("Footsteps Audio Component")); //Crea un FMOD Audio Component.
FmodAudioComponent->SetupAttachment(GetMesh()); // Vincula a este componente al Skeletal Mesh para que el sonido viaje con nuestro personaje.
FmodAudioComponent->SetAutoActivate(false); // Inicializa a este componente desactivado para que no reproduzca el evento al inicio.

Get Physical Material By LineTrace

Esta función crea un line trace y devuelve el Physical Material con el que colisiona.

Blueprint:

.cpp file:

UPhysicalMaterial* AMyUE5ProjectCharacter::GetPhysicalMaterialByLineTrace(const float &OffsetZ, const bool &bDebug)
{
   const FVector LineStart = GetActorLocation(); //Define el origen de la línea en la ubicación de nuestro personaje.
   const FVector LineEnd = FVector(LineStart.X, LineStart.Y, LineStart.Z + OffsetZ); // Define el final de la línea en la posición de nuestro personaje más el offset.
   EDrawDebugTrace::Type DebugType; // Esta enumeración es usada para definir la visibilidad del line trace.
   FHitResult HitResult; // Esta estructura va a contener los resultados de la colisión de la línea.
	
   if (bDebug) // Activar la visibilidad de la línea?
	DebugType = EDrawDebugTrace::ForDuration;
   else                                          
	DebugType = EDrawDebugTrace::None;       

   // Función del line trace.
   UKismetSystemLibrary::LineTraceSingle(this, LineStart, LineEnd,UEngineTypes::ConvertToTraceType(ECC_Visibility), false,TArray<AActor*>(), DebugType, HitResult, true, FLinearColor::Red, FLinearColor::Red, 2.0f);
	
   return Cast<UPhysicalMaterial>(HitResult.PhysMaterial); // Hace un cast y devuelve el Physical Material desde HitResult.
}

Set Footsteps Parameter

Esta función obtiene una referencia del Physical Material e intenta encontrarla como una clave en nuestro TMap. Si tiene éxito, esta va a definir el valor relacionado con esta clave como el FMOD parameter actual. Adicionalmente, va a imprimir el nombre del Physical Material actual en la pantalla.

Blueprint:

.cpp file:

void AMyUE5ProjectCharacter::SetFootstepsParameter(const UPhysicalMaterial* HitPhysicalMaterial, const bool &bDebug, const FName ParameterName)
{
   /* Comprueba si el mapa contiene el Physical Material como clave antes de definir el FMOD parameter.
   *  El juego va generar un crash si intenta encontrar una referencia nula o la clave no existe en el mapa. */
   if (PhysicalMaterialMap.Contains(HitPhysicalMaterial)) 
   {
      FmodAudioComponent->SetParameter(ParameterName, PhysicalMaterialMap[HitPhysicalMaterial]); // Define el FMOD parameter usando el valor de la clave en el mapa.

      if (bDebug) // Sí esta definido como true, imprime el nombre del Physical Material en la pantalla y "C++ Implementation".
      {
	GEngine->AddOnScreenDebugMessage(0, 1, FColor::Orange, "Physical Material: " + HitPhysicalMaterial->GetName());

	GEngine->AddOnScreenDebugMessage(1, 1, FColor::Red, "C++ Implementation");
      }
   }
   else // Si no se encontró una clave valida, define el valor del parámetro por defecto value = 0, de lo contrario el último valor se va a mantener.
   {
      FmodAudioComponent->SetParameter(ParameterName, 0); 
   }
}

Full Blueprint Graph:

.cpp file:


Guarda tu código y compila en el editor.

 
 

Deberías poder ver el FMOD Audio Component y todas tus propiedades en las pestañas de componentes y variables en la clase BP_ThirdPersonCharacter. Asigna el evento de pasos en el componente.


El Animation Blueprint:

En el BP_ThirdPersonCharacter, ve a al Physical Material Map definido previamente en C++ y asigna los Physical Materials como claves. Llena los valores del mapa basado en los FMOD parameter values definidos en tu evento.

Da click derecho en el graph y crea una función de tipo custom event function. Yo nombré a esta función como BPF_PlayFootsteps. Finalmente, arrastra el Fmod Audio Component hacia el graph y llama a su función Play.

Toda la funcionalidad para cambiar los FMOD parameters de forma dinámica, está lista. Ahora, debemos disparar el evento de pasos. Para lograr esto, implementa esta funcionalidad en el Animation Blueprint. Abre el Content Drawer, ve a Content > Characters > Mannequins > Animations, y abre ABP_Manny. Ve a la esquina superior derecha del editor y da click en el botón Animation Sequence.

En el Asset Browser, abre la secuencia "MF_Run_Fwd" sequence y añade un notify track. Luego, da click derecho en el y selecciona Add Notify > New Notify. Llama a tu notify "Footstep." Duplica tu notify en cada frame en donde los pies del skeletal mesh tocan el suelo. Repite el mismo proceso para las secuencias "MF_Walk_Fwd" y "MM_Walk_InPlace."

Regresa al Animation Blueprint y llama a la función Event Blueprint Begin Play para hacer un cast y guardar la referencia de BP_ThirdPersonCharacter en una variable apenas el juego empiece. Llama al notify buscando la función AnimNotify_Footstep. Finalmente, llama a la función BPF_PlayFootsteps.

Implementación Blueprint Completa:

En este proyecto cree una bifurcación o branch para seleccionar entre la implementación blueprint y la implementación C++ nativa.


EL FIN

〰️〰️〰️

EL FIN 〰️〰️〰️

Previous
Previous

Sistema de pasos en Unreal Engine y Wwise (Blueprints and C++)

Next
Next

Eventos Wwise en Unreal Engine 5 (Post Event) - Game Audio Basics