서론
이전 글에서 음향 재질을 위한 데이터 파이프라인 구축 과정을 작성했다.
https://mstone8370.tistory.com/53
[Audio Tracing] 음향 재질을 위한 Custom Primitive Data 획득
서론소리의 전파는 충돌한 표면에 따라 달라진다.예를 들어 콘크리트와 카펫을 비교해 보면, 콘크리트는 소리를 더 많이 반사시키고 카펫은 흡수한다.이런 재질의 특징을 묘사하기 위해, '음향
mstone8370.tistory.com
이후, 음향 재질을 사용자가 쉽게 다룰 수 있게 하는 에디터 기능을 제공해야 됐다.
이를 위해 음향 재질을 다루는 컴포넌트를 만들기로 했고, 자세한 내용은 다음 글을 통해 다루겠다.
이 글에서는 간단하게 음향 재질을 위한 에셋인 Sound Material 제작 과정만 다룬다.
에셋을 만들기로 한 이유는, 동일한 음향 재질 값을 여러 곳에서 쉽게 사용할 수 있게 만들기 위함이다.
구현
간단하게 UObject를 상속받는 클래스를 만들었고, 음향 재질 속성인 3개의 float 타입 멤버 변수를 추가했다.
// Sound/SoundMaterial.h
UCLASS(BlueprintType)
class AUDIOTRACING_API USoundMaterial : public UObject
{
GENERATED_BODY()
public:
USoundMaterial();
static constexpr float DefaultScatteringFactor = 0.1f;
static constexpr float DefaultReflectionFactor = 0.97f;
static constexpr float DefaultAbsorptionCoefficient = 0.2f;
static constexpr uint32 NumProperties = 3;
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Audio Tracing Sound Material")
FORCEINLINE float GetScatteringFactor() const { return ScatteringFactor; }
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Audio Tracing Sound Material")
FORCEINLINE float GetReflectionFactor() const { return ReflectionFactor; }
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Audio Tracing Sound Material")
FORCEINLINE float GetAbsorptionCoefficient() const { return AbsorptionCoefficient; }
protected:
/**
* Defines how much of the reflected sound energy is scattered diffusely vs. reflected specularly.
* A value of 0.0 means perfect mirror-like reflections (specular).
* A value of 1.0 means all reflected sound scatters in random directions (fully diffuse).
* Range: [0.0, 1.0]
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Audio Tracing", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0"))
float ScatteringFactor;
/**
* The fraction of sound energy that is reflected when it hits a surface.
* This value determines how much sound "bounces off" the material.
* A value of 1.0 means all energy is reflected.
* A value of 0.0 means all energy is absorbed.
* Range: [0.0, 1.0]
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Audio Tracing", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0"))
float ReflectionFactor;
/**
* Defines how much sound energy is lost per centimeter as it travels through the material.
* This is used to calculate sound transmission (occlusion) and is unit-dependent.
* Higher values mean the material blocks more sound. A value of 0.0 means the material
* is acoustically transparent.
*
* Unit: per centimeter (1/cm)
* Range: [0.0, infinity)
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Audio Tracing", DisplayName = "Absorption Coefficient (per cm)", meta = (ClampMin = "0.0", UIMin = "0.0"))
float AbsorptionCoefficient;
};
// Sound/SoundMaterial.cpp
USoundMaterial::USoundMaterial()
: ScatteringFactor(DefaultScatteringFactor)
, ReflectionFactor(DefaultReflectionFactor)
, AbsorptionCoefficient(DefaultAbsorptionCoefficient)
{}
기본 음향 재질 값과 Get 함수들이 있고, 각 멤버 변수들을 UPROPERTY를 통해 에디터에서 값을 수정할 수 있게 했다.
또한, meta 지정자를 통해 UI에서 지정할 수 있는 값의 범위 또한 제한해서 안정성을 높였다.
여기에서 음향 재질 값을 Set 하는 함수는 추가하지 않았다.
그 이유는, 이미 에디터를 통해 에셋을 열어서 값을 수정할 수 있고, 게임 플레이 중 에셋을 수정하는 것은 방지해야 하기 때문이다.
다음으로, 에디터 상태에서 에셋의 값이 바뀌면 에셋을 사용하고 있는 프리미티브에도 바로 반영되어야 한다.
따라서 델리게이트를 통해 값이 바뀌었음을 알리는 방법을 사용했다.
// Sound/SoundMaterial.h
#if WITH_EDITOR
DECLARE_MULTICAST_DELEGATE(FOnSoundMaterialPropertyChanged);
#endif
UCLASS(BlueprintType)
class AUDIOTRACING_API USoundMaterial : public UObject
{
GENERATED_BODY()
public:
// ...
#if WITH_EDITOR
FOnSoundMaterialPropertyChanged OnSoundMaterialPropertyChanged;
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
// ...
};
// Sound/SoundMaterial.cpp
#if WITH_EDITOR
void USoundMaterial::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
UObject::PostEditChangeProperty(PropertyChangedEvent);
OnSoundMaterialPropertyChanged.Broadcast();
}
#endif
프로퍼티의 값이 바뀌었을 때는 PostEditChangeProperty와 같은 함수가 호출된다.
이를 이용해서 델리게이트를 Broadcast했다.
또한, 이 델리게이트는 에디터로 작업할 때에만 필요하므로, 전처리기를 통해 에디터인 경우에만 코드를 컴파일하게 했다.
이후, AssetTypeActions와 Factory를 플러그인의 에디터 모듈에 추가해서 에셋을 생성하기 쉽게 했다.
AssetTypeActions
// AssetTools/SoundMaterialAssetActions.h
class FSoundMaterialAssetActions : public FAssetTypeActions_Base
{
public:
virtual FText GetName() const override;
virtual FColor GetTypeColor() const override;
virtual UClass* GetSupportedClass() const override;
virtual uint32 GetCategories() override;
};
// AssetTools/SoundMaterialAssetActions.cpp
FText FSoundMaterialAssetActions::GetName() const
{
return FText::FromString("Sound Material");
}
FColor FSoundMaterialAssetActions::GetTypeColor() const
{
return FColor(89, 146, 179);
}
UClass* FSoundMaterialAssetActions::GetSupportedClass() const
{
return USoundMaterial::StaticClass();
}
uint32 FSoundMaterialAssetActions::GetCategories()
{
return EAssetTypeCategories::Sounds;
}
Factory
// Factories/SoundMaterialFactory.h
UCLASS()
class USoundMaterialFactory : public UFactory
{
GENERATED_BODY()
public:
USoundMaterialFactory();
virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
virtual bool ShouldShowInNewMenu() const override;
};
// Factories/SoundMaterialFactory.cpp
USoundMaterialFactory::USoundMaterialFactory()
{
SupportedClass = USoundMaterial::StaticClass();
bCreateNew = true;
bEditAfterNew = true;
}
UObject* USoundMaterialFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags,
UObject* Context, FFeedbackContext* Warn)
{
return NewObject<USoundMaterial>(InParent, Class, Name, Flags);
}
bool USoundMaterialFactory::ShouldShowInNewMenu() const
{
return true;
}
AudioTracingEditor 모듈
// AudioTrcingEditor.cpp
void FAudioTracingEditorModule::StartupModule()
{
IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
const TSharedPtr<FSoundMaterialAssetActions> Actions = MakeShareable(new FSoundMaterialAssetActions());
AssetTools.RegisterAssetTypeActions(Actions.ToSharedRef());
CreatedAssetTypeActions.Add(Actions);
}
결과
콘텐츠 브라우저를 통해 Sound Material 에셋 생성

생성된 에셋들

에셋의 디테일 패널

'게임테크랩 1기 > Audio Tracing' 카테고리의 다른 글
| [UE5 | Audio Tracing] 다양한 에디터 조작에 대응하는 Sound Material 컴포넌트 개발 (0) | 2025.12.01 |
|---|---|
| [UE5 | Audio Tracing] 실시간 음향 정보 갱신을 위한 Readback 버퍼 풀과 데이터 캡처 (0) | 2025.11.23 |
| [UE5 | Audio Tracing] 음향 재질을 위한 Custom Primitive Data 획득 (2) | 2025.10.27 |
| [UE5 | Audio Tracing] TraceRayInline을 통한 월드 노멀 획득 (1) | 2025.09.29 |
| [UE5 | Audio Tracing] UE5 Lumen HWRT 활용하기 (0) | 2025.09.29 |