도플러(Doppler) 효과는 음파를 기준으로 관찰자가 움직임에 따라 파동의 주파수가 변하는 것입니다. 이 물리적인 현상은 모든 종류의 파동 전달에서 일어나며 음파도 예외가 아닙니다. 게임 오디오 산업이 성장하면서 수많은 게임 엔진이 자체적으로 도플러 솔루션을 구현하기 시작했습니다. 예를 들어 Unity와 Unreal (UE) 모두 도플러 효과를 제작하는 오디오 기능을 제공합니다. 하지만 이 기능은 게임 엔진 안에서만 사용할 수 있으며 Wwise와 상호 작용할 수 없기 때문에 Wwise를 사용하여 게임 오디오를 개발할 때 활용할 수가 없게 되죠.
최근 저는 Wwise로 도플러 효과를 만드는 법을 연구했습니다. 그리고 UE4와 Wwise를 사용하여 두 애플리케이션 간의 도플러 효과를 비교하면서 제 작업을 검토했습니다. 작업 결과를 함께 보고 들어볼까요?
Wwise로 도플러 효과 제작하기
도플러 효과를 사용하지 않을 경우, UE 도플러 효과를 사용할 경우, Wwise 도플러 효과를 사용할 경우의 결과를 살펴봅시다.
소리 표현에 큰 차이가 있다는 것이 들리시나요? 도플러 효과가 없으면 움직임의 속도조차 느낄 수가 없습니다. UE와 Wwise 도플러 효과의 경우 음색에서는 차이가 거의 없습니다. 단지 UE에서 카메라 대신 플레이어 캐릭터에 리스너 위치를 지정해서 패닝이 좀 더 좁았습니다. 플레이어 캐릭터를 리스너로 사용한 이유는 UE와 Wwise 간에 플레이어의 위치 계산이 통일되고 도플러 효과가 카메라의 움직임에 영향을 받지 않기 위해서였습니다.
자, 이제 이 효과가 어떻게 작동하는지 알아볼까요? UE와 Wwise에서 오디오 설정을 살펴봅시다.
그림 1.1: UE에서의 도플러 효과 설정
UE에서 Doppler 노드를 추가하기만 하면 도플러 효과를 제작할 수 있습니다.
그림 1.2: Wwise에서의 도플러 효과 설정
Wwise에서는 RTPC를 만들고 효과를 사용할 모든 사운드가 Doppler 노드와 동일한 도플러 효과를 가지도록 해줍니다. 이제 제가 RTPC 곡선을 만든 방법과 작동 방식을 살펴봅시다.
2. RTPC로 도플러 효과 구동하기
도플러 곡선을 설정하기 전에 먼저 도플러 효과의 물리학을 알아야 합니다. 혼선과 변수를 줄이기 위해 먼저 말씀드리자면, 제가 다음 섹션에서 파동이라고 할 때 이 파동은 음파를 말합니다. 그리고 파동은 완전히 정적인 공기에서 초당 340 미터를 이동합니다. 모든 이미터와 리스너는 (공기와 상대적으로) 소리의 속도보다 느린 속도로 이동합니다 (광파와 로렌츠 변환의 영향은 여기에서 논의하지 않겠습니다). 이 조건에 한해서 이미터와 리스너가 이동함에 따른 도플러 효과는 다음 공식을 따릅니다.
f’는 리스너가 듣는 사운드의 주파수입니다. f는 음원에 의해 방사되는 사운드의 주파수입니다. v는 사운드의 속도입니다. v0은 공기와 상대적으로 리스너가 이동하는 속도이며, v8은 공기와 상대적으로 이미터가 이동하는 속도입니다.
(1) 이미터는 가만히 있고 리스너가 움직일 경우와 (2) 리스너는 가만히 있고 이미터가 움직이는 경우의 두 가지 상황이 있습니다. 이 두 상황에 따른 도플러 효과는 아주 다릅니다. 첫 번째의 경우 v8 = 0이 되고 두 번째의 경우 v0 = 0이 됩니다. 공식이 변화되는 방식과 어떤 곡선이 사용되는지를 살펴봅시다.
그림 2.1: v8 = 0일 때 f’-v0 곡선
그림 2.2: v0 = 0일 때 f’-v8 곡선
두 상황에서의 도플러 효과를 모두 들어봅시다.
이제 두 상황에서 얼마나 큰 차이가 있는지 들리시나요? 이 중 하나를 무시하거나 단순히 평균값을 낼 수가 없습니다. 그러면 효과가 제대로 작동하지 않게 되죠. 그럴듯한 도플러 효과를 제작하려면 두 상황을 모두 고려해야 합니다. 하지만 동시에 두 RTPC를 사용하는 것은 추후 관리 면에서 좋은 선택이 아닙니다. 이렇게 두 속도 값을 사용하는 대신에 f’/f 값을 RTPC 변수로 사용할 수 있습니다. 그러면 Wwise에서 한 RTPC 곡선만 필요하게 되죠. 관리하고 변경하기도 훨씬 더 쉽습니다. 피치와 주파수는 한 옥타브가 주파수의 두 배를 의미한다는 기본적인 규칙을 따릅니다. 이 규칙은 y = 2x라는 간단한 함수 곡선으로 나타낼 수 있습니다. 하지만 피치는 y 축으로만 사용할 수 있기 때문에 Wwise에서 이런 곡선을 만들 수가 없습니다. y와 x의 위치를 서로 바꾸면 x = log2y라는 새로운 함수 곡선이 생깁니다. 자, 우리는 소리의 속도가 340m/s이며 1200센트(피치값)가 Wwise에서 한 옥타브와 동일하다는 것을 알고 있습니다. 이 정보를 사용하면 Wwise에서 피치-속도 곡선을 만들 수 있습니다.
그림 2.3: Wwise에서의 피치-속도 곡선
이렇게 Wwise에서 도플러 효과를 어떻게 제작할 수 있는지 어느 정도 이해하게 되었습니다. 이제 프로그래머에게 “플레이어와 이미터 간의 상대적 속도를 계산하고, 이 속도를 공식에 넣어서 f’/f를 알아내고, 이 값을 Wwise로 RTPC 값으로써 전송하는 데에 도움이 필요해요”라고 저희가 필요한 것이 무엇인지 분명히 알려줘야 합니다.
다음 동영상을 통해 효과가 어떻게 작동하는지 확인해 보세요.
물론 저는 전문적인 프로그래머의 도움을 통해 효과를 작동시킬 수 있었습니다. 하지만 프로그래머가 없거나 여러분이 직접 작업하고 싶다면 어떻게 해야 할까요?
RTPC 값을 설정하는 방식을 살펴봅시다.
3. 게임 엔진으로부터 필요한 RTPC 변수 가져오기
다음 작업 과정을 살펴봅시다.
그림 3.1: 필요한 RTPC 변수를 가져오는 작업 과정
저는 C++를 잘 모르기 때문에 여기에 코드를 보여드리지는 않겠습니다. 대신 제가 만든 Unreal Blueprint를 살펴볼까요? Blueprint(블루프린트)는 효과를 구현한 법과 필요한 작동 매개 변수를 가져온 방법을 보여줍니다. 완벽하게 논리적이지는 않습니다. 그저 참고만 해주세요. 위의 작업 과정에 따라 저는 다음 Blueprint를 만들었습니다.
그림 3.2: 필요한 RTPC 변수를 가져오는 블루프린트
하지만 여기에는 작은 문제가 있습니다. Get Component Velocity 노드는 속도 설정이 있는 컴포넌트에만 작동한다는 것이죠. 예를 들어 UE4의 3인칭 데모 게임에는 기본 플레이어 캐릭터가 함께 제공됩니다.
그림 3.3: UE4 3인칭 데모 캐릭터의 속도 설정
컴포넌트에 속도 설정이 없을 경우 Get Component Velocity 노드를 읽을 수가 없게 됩니다. 이 경우 속도를 직접 계산해야 하죠. 제가 만든 Blueprint는 다음과 같습니다.
그림 3.4: 이동 속도를 계산하여 RTPC 변수를 가져오는 블루프린트 (1)
그리고 다음 Blueprint도 만들었습니다.
그림 3.5: 이동 속도를 계산하여 RTPC 변수를 가져오는 블루프린트 (2)
두 Blueprint 모두 각 프레임에서 플레이어와 이미터의 위치를 읽고, 이전 프레임의 속도 벡터를 얻은 다음, 플레이어와 이미터 사이의 선에 벡터를 반영하여 상대적 속도를 얻고, 마지막으로 공식에 따라 RTPC 값을 구동하게 됩니다. 하지만 첫 번째 Blueprint는 각 프레임에서 이미터나 리스너의 위치 좌표를 계산함으로써 상대적 속도를 얻고, 두 번째 Blueprint는 각 프레임에서 이미터나 리스너간의 상대적 거리를 계산함으로써 상대적 속도를 얻습니다. 이 두 방법으로 얻은 값의 차이는 무시해도 될 만큼 굉장히 작습니다.
4. 도플러 레벨 조정하기
앞서 말씀드린 모든 RTPC 계산은 시스템 플랫폼에서 극소량을 부하합니다. 이 부동 소수점 연산은 이미지 프로세싱에 비하면 정말 미미합니다. 하지만 이렇게 엄청나게 정확한 도플러 효과가 필요하지 않는 상황이 있을 수도 있습니다. 이 경우 값을 낮추고 연산 시간을 줄이면 시스템 부하량을 낮출 수 있습니다. Blueprint에서 저는 Tick Event를 사용하여 RTPC 계산을 구동했습니다. 이 Event는 각 프레임에서 값을 가져옵니다. 굉장히 정확한 도플러 효과가 필요하지 않다면 Loop Event를 추가적으로 만들어서 RTPC 계산을 구동하세요. 반복 간격은 원하는대로 설정할 수 있습니다. Tick Event에 의해 제공된 Delta Seconds 대신 이 값을 사용해 봅시다. 값의 범위는 상대적으로 작아야 합니다. 그렇지 않으면 이동 속도가 크게 변할 경우 급격하게 변화할 수 있습니다.
데모 프로젝트에서 저는 수많은 방법으로 도플러 레벨을 조정해봤습니다. 하지만 글이 너무 복잡해질 수 있기 때문에 모든 방법을 여기에서 보여드리지는 않을게요. 주파수 변경을 더 잘 이해하기 위해서 'UFO engine'이 Helicopter로 설정되었습니다.
도플러 레벨은 두 가지 방법으로 변경할 수 있습니다. 첫 번째 방법은 Wwise에서 곡선의 곡률을 변경하는 것이고, 두 번째는 RTPC 값을 변경하는 것입니다. 도플러 레벨은 결과 속도 값에 원하는 인수를 곱해서 제어할 수 있습니다. 도플러 레벨과 속도는 반비례 함수를 따릅니다. UE가 효과를 작동하는 방식과는 약간 다르죠 (UE는 값이 동일하지 않습니다.)
자, 이제 도플러 레벨을 조정해 볼까요? 이론적으로 도플러 레벨은 현실에서 고정적이기 때문에 게임에서도 그러해야 합니다. 전달 매체의 종류나 밀도를 변경하고 싶지 않다면 말이죠. 미래의 게임에서는 그렇게 해야 할 수도 있겠네요. 또 다른 큰 장점은 같은 레벨에서 서로 다른 거리 단위를 사용할 수 있다는 것입니다. 플레이어가 커지거나 작아지는 게임이 있다고 가정해 봅시다. 플레이어가 작아질 경우 플레이어는 물론 플레이어와 상호작용하는 오브젝트도 훨씬 느리게 이동합니다. 이 경우 사운드의 표현력이 떨어지죠. 이때 거리 값을 변경하는 대신 도플러 레벨을 조정하는 것이 훨씬 더 쉽습니다.
5. 상호작용적인 도플러 효과
게임 엔진에서 제공하는 상호작용적인 도플러 효과도 좋지만 게임 개발과 오디오 디자인에 따라 일부 씬에서만 적용할 수 있다는 단점이 있습니다.
상호작용적 도플러 효과는 차, 헬리콥터, 롤러 코스터, RPG 투사체 등과 같이 보통 오랫동안 계속해서 소리를 내는 아음속 이미터에 사용됩니다.
천음속이나 초음속 물체의 경우 이 효과가 자동으로 작동하지 않습니다. 이미터가 소리의 속도와 가까워질 경우 소리의 패턴이 바뀌며 대부분의 소리가 물체 자체가 아닌 공기 중 마찰이나 충격파로부터 생기게 됩니다. 이 현상은 도플러 효과의 능력을 넘어선 더 복잡한 음향 이론을 다루게 됩니다. 리스너가 소리의 속도를 능가할 경우 뒤에서 오는 소리는 더 이상 들리지 않으며 리스너 자체가 이미터가 됩니다. 그렇기 때문에 도플러 효과가 초음속 오브젝트의 작동 방식을 완전히 표현해낼 수가 없게 되죠.
게임에 있는 초음속 오브젝트의 경우 저희는 기존의 에셋 제작 방법을 더 선호합니다. 사운드 에셋 자체에 도플러 효과가 있어서 오브젝트의 작동 방식을 시뮬레이션하기 위해 타이밍만 조정하면 되죠. 가장 흔한 예시 중 하나는 게임에 있는 총알입니다. 총알이 날아갈 때마다 쉭- 하는 소리가 나죠. 총알의 속도는 아주 빠르기 때문에 타이밍과 강도가 약간씩 달라지더라도 플레이어는 보통 그 차이를 느끼지 못합니다.
또한 지속 시간과 타이밍이 고정된 사운드도 있습니다. 이 경우 실시간 계산 대신 특정 에셋을 트리거할 수 있습니다. 예를 들어 1p 플레이어가 화살을 쏠 경우 실시간으로 도플러 효과를 계산하는 대신 화살을 쏘는 소리에 쉭- 소리를 포함시킬 수 있죠. 실제 상황에 따라 다른 설정을 만들면 더 나은 효과를 얻을 수 있습니다.
6. Wwise에 도플러 효과 통합하기
Wwise를 사용하여 게임에서 도플러 효과를 제작하려면 이미터와 리스너 간의 상대적 속도를 얻고, 이 속도를 RTPC 값으로 번역한 다음, 이 값을 사용하여 피치를 제어하면 됩니다. RTPC 값을 번역하기 위해서는 이미터와 리스너의 좌표 위치를 계속해서 알아내야 합니다. 다행히 Wwise는 감쇠, 공간 음향 정보 등을 계산하기 위해 게임 플레이 도중 이 데이터를 계속해서 모니터링하고 수집합니다. 사실 Wwise 자체 내에서 이미 도플러 작업을 실행할 준비가 되어 있답니다. 각 이미터의 거리를 계산하는 것과 아주 비슷하지만 부동 소수점 연산이 조금 더 복잡하죠. 다른 프로젝트를 위해 변경하는 것도 도플러 레벨을 조정하여 쉽게 실행할 수 있습니다. 예를 들어 UE의 기본 측정 단위 센티미터이지만 다른 게임 엔진은 미터를 사용할 수가 있습니다. 이 경우 소리의 속도(34,000)를 340로 바꿔서 RTPC를 계산하면 됩니다. 혹은 게임의 거리 단위와 현실 거리 단위가 1:1이 아닐 경우엔 어떻게 할까요? 이 경우도 꽤나 쉽게 해결할 수 있습니다. 척도 인자를 사용하면 간단하게 문제를 해결할 수 있죠. 이 작업은 도플러 레벨을 조정하는 것과 아주 비슷합니다.
Wwise를 사용하여 도플러 효과를 제작하면서 저는 Wwise가 이미 이 모듈에 필요한 모든 전제 조건을 충족한다는 것에 놀랐습니다. 멀지 않은 미래에 Wwise로 만든 커스텀 도플러 도구를 사용하기를 기대해 보겠습니다!
댓글