Dev./UE 언리얼 엔진

[TIL_250225] 언리얼 엔진으로 구현하는 표면 기반 발소리 & 3D 사운드 시스템

raindrovvv 2025. 2. 25. 23:12

💭회고

표면 기반 발소리와 3D 사운드 시스템은 게임 개발에서 몰입감을 크게 향상시키는 중요한 요소이다. 이 기법들을 적용하면 플레이어에게 더 현실감 있고 풍부한 오디오 경험을 제공할 수 있다.

🗺️마인드맵

📒학습 내용

1. 개요: 왜 표면 기반 발소리와 3D 사운드가 필요한가?

게임에서 오디오는 시각적 요소만큼 몰입감에 중요한 역할을 한다. 특히 캐릭터가 다양한 표면을 밟을 때 발생하는 소리는 게임 세계의 현실감을 크게 높인다.

🎮 게임 몰입감 향상

표면 기반 발소리 시스템은 플레이어에게 현실적인 오디오 피드백을 제공한다. 금속 바닥을 걷는 딸깍거리는 소리와 흙길을 밟는 푹신한 소리의 차이는 게임 내 환경과의 상호작용을 더욱 직관적으로 전달한다.

🔊 사운드 오버로드 방지
사운드 동시성(Sound Concurrency) 제어는 과도한 소리 중첩을 막는다. 캐릭터가 빠르게 움직일 때 발생하는 연속적인 발소리가 모두 동시에 재생되면 오디오가 불명확해지고 성능에도 부정적 영향을 미친다.

📍 공간적 오디오 인식
3D 사운드는 게임 내 소리의 위치와 거리감을 표현하여 플레이어가 소리의 출처를 파악하는 데 도움을 준다. 이는 FPS나 스텔스 게임에서 특히 중요한 게임플레이 요소로 작용한다.


2. 표면 기반 발소리 시스템 구현

핵심 요약:
표면 기반 발소리 시스템 구현은
1) 피지컬 머티리얼 설정,
2) 애니메이션 노티파이 배치,
3) 라인 트레이스를 통한 표면 감지의 세 단계로 이루어진다.

각 단계를 체계적으로 구현하면 다양한 표면에 따라 적절한 발소리를 재생할 수 있다.

피지컬 머티리얼 설정

표면 기반 발소리를 구현하기 위한 첫 단계는 다양한 표면 유형을 정의하는 피지컬 머티리얼(Physical Material)을 설정하는 것이다.

1. 다양한 표면 유형(금속, 흙, 콘크리트 등)에 대한 피지컬 머티리얼을 생성한다.
2. 각 피지컬 머티리얼에 적절한 물리적 특성(마찰, 밀도)을 설정한다.
3. 각 머티리얼에 고유 식별자를 설정하여 코드에서 참조할 수 있게 한다.

// 피지컬 머티리얼 네이밍 컨벤션 예시
PM_Metal
PM_Dirt
PM_Concrete
PM_Wood
PM_Water
🔧 실무 팁: 피지컬 머티리얼은 발소리뿐만 아니라 충돌 효과, 입자 효과 등 다양한 물리적 상호작용에 활용할 수 있다. 프로젝트 초기에 체계적으로 설계하면 추후 개발 과정이 훨씬 효율적으로 진행된다.

애니메이션 노티파이 설정

애니메이션 노티파이(Animation Notify)는 애니메이션의 특정 지점에서 이벤트를 발생시키는 기능이다. 발소리 시스템에서는 캐릭터의 발이 지면에 닿는 순간을 감지하는 데 사용한다.

1. 애니메이션 노티파이 블루프린트를 생성한다.
2. 캐릭터의 걷기/뛰기 애니메이션에서 발이 지면에 닿는 시점을 식별한다.
3. 각 애니메이션에 노티파이를 배치하고 발소리 함수를 연결한다.

🔧 실무 팁: 복잡한 애니메이션이 많은 게임에서는 모든 애니메이션마다 노티파이를 일일이 설정하는 것이 번거롭다. 이런 경우 애니메이션 블루프린트 내에서 IK(Inverse Kinematics) 시스템과 연동하거나 자동화 도구를 활용하여 효율성을 높이는 것이 좋다.

라인 트레이스를 통한 표면 감지

캐릭터가 밟고 있는 표면을 감지하기 위해 라인 트레이스(Line Trace) 또는 구체 트레이스(Sphere Trace)를 사용한다.

(구체 트레이스가 좀 더 좋다고 한다)


1. 캐릭터의 발 위치에서 아래쪽으로 트레이스를 발사한다.
2. 트레이스 결과에서 충돌한 표면의 피지컬 머티리얼 정보를 추출한다.
3. 감지된 피지컬 머티리얼에 따라 적절한 발소리를 재생한다.

// 라인 트레이스 코드 예시 (블루프린트로 표현)
FVector StartLocation = FootSocket.GetLocation();
FVector EndLocation = StartLocation + FVector(0, 0, -100);  // 아래쪽으로 100유닛
FHitResult HitResult;

if (GetWorld()->LineTraceSingleByChannel(HitResult, StartLocation, EndLocation, ECC_Visibility))
{
    UPhysicalMaterial* PhysMat = HitResult.PhysMaterial.Get();
    // PhysMat을 기반으로 적절한 사운드 재생
}

 


3. 사운드 큐와 오디오 최적화

핵심 요약:  
사운드 큐를 활용하여 다양한 발소리 샘플을 랜덤화하고,
캐릭터 속도에 따라 발소리 특성을 조절하며,
사운드 동시성 설정을 통해 오디오 시스템을 최적화할 수 있다.

이러한 기법들을 조합하면 더 자연스럽고 몰입감 있는 게임 오디오 환경을 구축할 수 있다.

사운드 큐 생성 및 설정

사운드 큐(Sound Cue)는 여러 오디오 샘플을 조합하고 랜덤화하여 더 자연스러운 소리를 만들 수 있는 UE의 기능이다.

1. 각 표면 유형별로 별도의 사운드 큐를 생성한다.
2. 각 사운드 큐에 여러 발소리 샘플을 추가하고 랜덤 재생 설정을 적용한다.
3. 어테뉴에이션(감쇠) 설정을 통해 거리에 따른 소리 크기 변화를 조절한다.

🔧 실무 팁: 동일한 소리가 반복 재생되면 게임 경험이 단조로워질 수 있다. 각 표면 유형별로 5-7개의 다양한 발소리 샘플을 준비하고 랜덤 재생과 피치 변조를 적용하면 훨씬 자연스러운 오디오 경험을 제공할 수 있다.

속도에 따른 발소리 조절

캐릭터의 이동 속도에 따라 발소리의 특성을 조절하면 더 현실감 있는 오디오 피드백을 제공할 수 있다.

1. 캐릭터의 현재 이동 속도를 감지한다.
2. 속도에 따라 사운드의 피치와 볼륨을 조절한다.
3. 걷기/뛰기 상태에 따라 다른 발소리 세트를 재생한다.

// 속도에 따른 발소리 조절 예시
float Speed = Character->GetVelocity().Size();
float PitchMultiplier = 1.0f;

if (Speed > RunningThreshold)
{
    PitchMultiplier = 1.75f;  // 달릴 때 빠른 피치로 재생
}

FootstepAudioComponent->SetPitchMultiplier(PitchMultiplier);

사운드 동시성 제어

사운드 동시성(Sound Concurrency)은 동시에 재생되는 소리의 수를 제한하여 오디오 품질과 성능을 최적화하는 기능이다.

1. 발소리용 사운드 동시성 그룹을 생성한다.
2. 최대 동시 재생 수와 소리 겹침 처리 방식을 설정한다.
3. 모든 발소리 사운드 큐에 동시성 설정을 적용한다.

()

 

🔧 실무 팁: 발소리는 빠르게 연속해서 발생할 수 있는 소리이므로, 동시성 설정에서 '가장 오래된 소리 중단(Stop Oldest)' 옵션을 활성화하는 것이 좋다. 이렇게 하면 새로운 발소리가 재생될 때 이미 들리고 있는 이전 발소리가 자연스럽게 중단된다.

 


4. 최종 구현 및 개선점

핵심 요약:
최종 구현에서는 다양한 표면 유형에 따른 발소리 재생, 속도 기반 소리 조절, 사운드 동시성 제어, 공중 상태 감지 등의 기능을 통합하여 완성도 높은 발소리 시스템을 구현할 수 있다.

구체 트레이스와 벡터 조정을 통해 더 안정적이고 현실감 있는 시스템으로 개선할 수 있다.

구현된 기능 및 결과

지금까지 설명한 내용을 종합하여 다음과 같은 최종 시스템을 구현할 수 있다:

1. 다양한 표면 유형(금속, 흙, 콘크리트, 나무 등)에 따라 차별화된 발소리 재생
2. 캐릭터 속도에 따른 발소리 변화 (달릴 때는 1.75배 빠른 재생)
3. 사운드 동시성을 통한 자연스러운 오디오 환경 구현
4. 공중에 있을 때는 발소리가 재생되지 않도록 개선

// 최종 시스템 구성 요약
- 피지컬 머티리얼: 5종류 (금속, 흙, 콘크리트, 나무, 물)
- 사운드 큐: 표면별 각 1개씩 (총 5개)
- 애니메이션 노티파이: 걷기/달리기 애니메이션에 적용
- 블루프린트 함수: 표면 감지 및 사운드 재생 로직

트레이스 설정 최적화

발소리 시스템에서 중요한 부분 중 하나는 트레이스 설정이다. 라인 트레이스보다 구체 트레이스(Sphere Trace)를 사용하면 더 안정적인 표면 감지가 가능하다.

1. 캐릭터의 발 소켓 위치에서 아래로 구체 트레이스를 발사한다.
2. 트레이스 길이는 너무 길지 않게 설정하여 의도하지 않은 표면 감지를 방지한다.
3. 트레이스 디버깅을 활성화하여 개발 중에 문제를 시각적으로 확인한다.

()

🔧 실무 팁: 프로덕션 빌드에서는 반드시 트레이스 디버깅을 비활성화하자. 디버깅 시각화는 성능에 영향을 미칠 수 있으며, 최종 사용자에게는 필요 없는 기능이다.

 

벡터 조정을 통한 공중 상태 감지

캐릭터가 공중에 있을 때 발소리가 재생되지 않도록 하는 것은 현실감을 높이는 중요한 요소이다.

// 공중 상태 감지 개선 예시
FVector StartLocation = FootSocket.GetLocation();
FVector DownVector = FVector(0, 0, -1);  // 아래 방향 벡터
FVector EndLocation = StartLocation + (DownVector * 100.0f);  // 적당한 거리

FHitResult HitResult;
if (GetWorld()->LineTraceSingleByChannel(HitResult, StartLocation, EndLocation, ECC_Visibility))
{
    // 표면에 닿아 있음, 발소리 재생
    PlayFootstepSound(HitResult.PhysMaterial.Get());
}
else
{
    // 공중에 있음, 발소리 재생하지 않음
}

 


5. 학습 방향 및 추가 리소스

다음 학습 단계 

표면 기반 발소리와 3D 사운드 시스템 구현 후, 다음과 같은 주제로 학습을 확장할 수 있다:

1. 메타사운드 활용: 언리얼 엔진 5의 메타사운드를 활용한 더 고급 오디오 시스템 개발
2. 애니메이션 시스템 심화: 애니메이션 블루프린트와 IK를 활용한 더 정교한 발소리 연동
3. AI 캐릭터 오디오: NPC와 AI 캐릭터에 발소리 시스템 적용
4. 환경 오디오 시스템: 날씨, 시간에 따른 동적 환경 사운드 구현

// 캐릭터 블루프린트 내 발소리 시스템 구현 코드 (의사 코드)

// 피지컬 머티리얼에 따른 사운드 큐 매핑
TMap<UPhysicalMaterial*, USoundCue*> SurfaceToSound;

// 발소리 재생 함수 (애니메이션 노티파이에서 호출)
void PlayFootstepSound(FName FootSocketName)
{
    // 1. 발 소켓 위치 가져오기
    FVector SocketLocation = GetMesh()->GetSocketLocation(FootSocketName);

    // 2. 구체 트레이스 수행
    FVector Start = SocketLocation;
    FVector DownVector = FVector(0, 0, -1);
    FVector End = Start + (DownVector * 100.0f);

    FHitResult HitResult;
    FCollisionQueryParams QueryParams;
    QueryParams.bReturnPhysicalMaterial = true;
    QueryParams.AddIgnoredActor(this);

    bool bHit = GetWorld()->SphereTraceSingleByChannel(
        HitResult,
        Start,
        End,
        10.0f,  // 구체 반경
        ECC_Visibility,
        QueryParams
    );

    // 3. 히트 결과에 따라 발소리 재생
    if (bHit)
    {
        UPhysicalMaterial* PhysMat = HitResult.PhysMaterial.Get();
        if (PhysMat && SurfaceToSound.Contains(PhysMat))
        {
            USoundCue* SoundToPlay = SurfaceToSound[PhysMat];

            // 4. 속도에 따른 피치 조절
            float Speed = GetVelocity().Size();
            float PitchMultiplier = 1.0f;

            if (Speed > 600.0f)  // 달리기 속도 임계값
            {
                PitchMultiplier = 1.75f;
            }

            // 5. 사운드 재생
            UAudioComponent* AudioComp = UGameplayStatics::SpawnSoundAtLocation(
                this,
                SoundToPlay,
                HitResult.Location,
                FRotator::ZeroRotator,
                1.0f,  // 볼륨
                PitchMultiplier
            );

            // 6. 사운드 컴포넌트 설정 (옵션)
            if (AudioComp)
            {
                AudioComp->SetLowPassFilterFrequency(22000.0f);
                AudioComp->SetAutoDestroy(true);
            }
        }
    }
}

📌 참고 자료

1. 표면에 따른 발소리 구현: [YouTube - How to Play Footsteps Depending on the Surface in UE5](https://www.youtube.com/watch?v=k28vy4lOpW8)
2. 3D 사운드 구현: [YouTube - How to Make a 3D Sound in Unreal Engine 5](https://www.youtube.com/embed/dttUv6--1nA)
3. 메타사운드 활용: [YouTube - How to Make Footsteps with Metasounds in UE5](https://www.youtube.com/embed/Zv8aRutdflQ)
4. 1인칭 발소리 구현: [YouTube - How To Create First Person Footsteps in UE5](https://www.youtube.com/embed/rTTmS3Mql9A)
5. 언리얼 엔진 공식 문서 - 오디오 시스템: [Unreal Engine Documentation - Audio](https://docs.unrealengine.com/5.0/en-US/audio-in-unreal-engine/)

 


🟣오늘의 옵시디언 현황