'프로젝트DH'는 2016년 넥슨의 지스타 발표회를 통해 처음으로 공개된 '데브캣 스튜디오'의 신작이다. 프로젝트DH는 멀티플레이 액션 게임으로, 넓은 필드를 말을 타고 달리며 '용'과 같은 거대한 적들과 싸울 수 있는 마상 전투를 특징으로 한다. 현재 프로젝트 DH의 맵 규모는 약 6km x 6km 정도의 크기로 구현되고 있으며, 사실적 애니메이션을 선보이기 위해 많은 작업이 이뤄지고 있다.

이번 NDC에서는 이 '프로젝트DH'에 대한 개발 강연이 다수 준비되어 있었다. 넥슨 데브캣 스튜디오의 심예람 개발자는 프로젝트DH에서 '용'을 자연스럽게 비행시키기 위한 적절한 공중 AI 내비게이션 기법을 개발하면서 겪은 어려움과 문제 해결 방안에 대해서 공유했다.

넥슨 데브캣스튜디오의 심예람 개발자

일단 가장 먼저 '용'에 대한 연구가 필요했다. 용은 걸을 수도, 날 수도 있으며 넓은 지역을 돌아다니는 존재다. 게다가 프로젝트DH의 맵은 6km x 6km의 사이즈로 상당히 거대한 편이였다. 이미 많은 매체로 알려진 '용'은 비행 방식에 따라서 다양한 모션이 존재하고, 지형지물 혹은 상황에 따라서는 독특한 행동을 보이기도 한다.

하지만, 용의 움직임을 내비게이션적으로 분석해보면 비슷한 패턴이 있었다. 공중에서의 방향 전환은 일정한 선회 반경과 선회율을 유지하며, 공중 정지나 후진 비행 역시 자유롭지만 물리법칙을 무시한 채로 급선회하는 경우는 거의 없었다. 즉, 용 역시 '물리법칙'에 영향을 받는 생명체라는 것. 심예람 개발자는 여기서부터 용의 자유로운 비행을 위한 내비게이션 시스템을 설계했다.



그래서 일단은 먼저 공중 내비게이션에 도입할 수 있을만한 기존의 내비게이션 시스템들을 조사하기 시작했지만 결과는 만족스럽지 않았다. 기존의 지상 내비게이션 시스템을 공중 전용으로 확장하기는 어려웠으며, 복셀 기반의 네비게이션은 '생명체'의 움직임을 표현하기에는 다소 부족한 부분이 많았다. 또한 복셀 데이터 기반의 내비게이션은 데이터량을 감당하기가 어렵기도 했다.

프로젝트DH는 결국, 물리적 타당성에 몰두하지 않고 내비게이션을 제작하기로 결정했다. 하지만 스플라인 패스 팔로잉 기능 자체는 부드러운 경로 표현에는 적절했다. 대신 다루기가 까다로운 단점이 있었지만, 적용하기에는 적절하다는 판단으로 '스플라인'을 기반으로 한 시스템 제작이 이뤄졌다.


가장 먼저 먼저 용의 비행 영역을 정의하고 이를 '하늘길'이라 이름 붙였다. 그래서 이 '하늘길'을 기반으로 하여 안전이 보장된 길을 중심으로 하는 용의 실제 이동 경로가 생성됐다. '길'을 중심으로 자유롭게 비행이 가능한 영역이 정의된 셈. 여기에 유연한 패스 팔로잉을 위해 완충장치인 '프로브'가 마련됐다. 프로브는 생성된 이동 경로를 용보다 앞서 나가며, 용은 이 '프로브'를 따라 자연스럽게 비행하게 된다.

이렇게 길을 구성하는 데에는 몇 가지 요소들이 필요했다. 일단 하늘길 고속도로의 IC 역할이라고 할 수 있는 '웨이포인트'가 마련됐고, 이는 안전 반경을 기록하고 연결된 하늘길 목록을 관리하는 요소다. 두 번째는 스플라인 기반으로 제작된 하늘길 '도로'다. 웨이포인트끼리 연결된 도로는 일정 간격마다 안전 반경을 기록해 용의 실질적인 이동 경로가 된다.

앞서 설명했던 '프로브'는 최종 경로를 따라가는 객체로서, 전체 경로에 대한 분석 결과를 기록하여 용이 언제 어떻게 날아야 할지를 결정해주는 요소였다. 실질적으로 용의 비행을 직접적으로 제어할 수 있는 객체라고 할 수 있다.



하늘길 시스템의 핵심은, 스플라인이라고 할 수 있다. 프로젝트DH는 부드러운 스플라인 구성을 위해서 연속성을 고려하고, 보간 속도의 일관성을 보장할 장치를 마련하여 하늘길을 보강하기로 했다.

이렇게 만들어진 다양한 '하늘길'들 중, 이제 용이 다닐 적합한 루트를 찾아야 한다. 이게 패스 파인딩의 본격적인 절차라고 할 수 있는데, 먼저 용이 출발하는 지점과 도착하는 지점을 설정하고 하늘길로 임시 경로를 연결하게 된다. 그리고 그래프 최단 경로 탐색을 수행하고, 들어오고 나가는 경로를 생성하게 된다.

단, 이 과정에서 용의 경로가 용이 안전하지 못한 영역이 설정될 수도 있다. 때문에 하늘길마다 가중치를 달리하여 길의 '선호도'를 만들게 된다. 이런 방식으로 '들어오는 길'과 '나가는 길'이 생성됐지만, 여전히 출발과 도착 지점과 연결된 하늘길의 연결은 미흡한 부분이 있었다. 그대로 따라가면 용의 루트가 부자연스러울 수 있었기 때문이다. 그래서 짧은 거리의 두 지점을 간단히 잇는 방법으로 보완을 했지만, 이 과정에서도 문제가 발생했다. 만들어진 경로에 중간중간 '꺾인' 지점이 많았기 때문이다.

꺾이는 지점은 '웨이포인트'였던 것. 이 꺾이는 지점을 보다 부드럽게 바꾸면 용의 경로는 많이 자연스러워질 수 있었다. 그래서 인접한 세그먼트 위에서 용의 '안전성'을 검사하고, 용의 부피와 크기를 고려해서 새로운 경로를 간단하게 마련했다. 이런 스무딩의 과정을 통해서 용이 지나갈 '하늘길'이 마련됐다.




이제 길이 마련됐으니 길을 따라가야 할 시점이다. 그렇다면 용의 위치를 어떻게 해야 할까? 사실 답은 간단하다. 만들어진 스플라인의 시간을 정의하는 점( t )를 만들고, 이에 따라서 용의 위치를 갱신하면 된다. 그러나, 이렇게 할 경우 용의 움직임이 매우 단조로워진다. 또한 재매개화(Reparameterization) 정밀도가 낮으면, 용이 일정한 속력으로 이동할 수 없고, 외력(플레이어의 공격, 혹은 다른 용-오브젝트-에 의한 충돌 등)에 의한 경로 이탈을 제어하기가 힘들어진다.

그래서 심예람 개발자는 앞서 설명한 것처럼, 용보다 앞서나가는 '프로브'를 만들기로 결심했다. 프로브를 간단하게 설명하자면, 다른 배들의 길을 인도해주는 YTL, 예인선 같은 느낌이라고 보면 된다. 프로브는 스플라인 위를 정직하게 이동하며, 용은 프로브를 향해 날아간다. 프로브는 용이 뒤처지거나 앞서지 않도록 속도를 제어하는 역할을 맡는다. 일종의 패스 팔로잉 로직의 완충 장치다.



하지만 결국, '어떻게' 비행하는가에 대한 의문은 여전히 남아있다. 그래서 용의 전체 패스를 분석하여 일정한 기준으로 구간을 나누고, 각 구간의 최대/최소 속력과 선회 속력, 롤링 등을 분석하여 각 구간별 모션 유형을 미리 결정했다.

스플라인 경로의 ( Z )성분 극점을 기준으로 선형 속도에 유의미한 변화가 발생하는 구간은 1차 도함수의 극점이고, 2차 도함수의 극점은 기술기의 변화량, 즉 변곡점이 된다. 이를 Cubic hermite Cure: 3차 다항식으로 3차원 벡터의 수직 성분에 대해서만 계산하여 값을 도출하고, 적용하면 좀 더 자연스러운 속도 변화가 이뤄진다(사실 이건 물리적으로 맞지는 않은데 결과가 괜찮아서 그냥 쓰기로 결정됐다).

여기에 자연스러운 용의 선회를 위해서, '뱅크 턴'이라 부르는 공중 기동 기법을 분석, 수평 곡률로 뱅크 앵글에 해당하는 롤 요소를 계산하고 이를 적용했다.

이를 토대로 프로브는 현재 구간의 유형을 확인하고, 현재 위치의 기울기로 가속력과 속력 등 필요한 값을 계산하여, 요 객체에 전달한다. 이에 따라서 용 객체는 구간에 따라 지정된 액션을 취하게 되고, 한층 더 자연스러운 움직임을 보여줄 수 있게 된다.



그러나 외력에 의한 경로 재탐색이라는 문제가 남는다. 용을 사냥하는 게임인 만큼, 주된 외력은 플레이어에 의해 발생한다. 플레이어를 추격하거나 도망갈 때는 결국 기존의 루트가 쓸모 없어지는 경우가 생기므로, 용이 이동할 경로의 재탐색이 필수적이다.

AI 내비게이션의 대상은 움직이는 물체인 경우가 많다. 그래서 타깃이 이동한 경우 패스의 재탐색이 필요한 건 당연. 심예람 개발자는 적당한 지점에서 현재 용중인 루트를 자르고, 해당 지점의 위치 및 탄젠트를 유지한 채 타깃 위치로 새로 경로를 찾는 방법을 선택했다.

이렇게 탐색된 새로운 하늘길이 기존 경로에 접붙여지면서 용의 이동경로는 자연스럽게 변화하게 된다. 이렇게 용의 위치를 탐색하고, 자연스럽게 움직이는 걸 도와줄 'AI 내비게이션'이 완성됐다. 이제 남은 것은 게임 내에 사용하기 위해 '언리얼엔진4'와의 융합을 하는 과정이었다.

기존에 언리얼4에서 사용하던 AIController를 응용, 기존 MoveTo 기능과 유사하게 'FlyingMoveTo' 요청을 구현하여 공중에서 용이 움직일 시 새로운 패스 파인딩 시스템을 호출하는 방식이다. 이렇게 언리얼4의 네비 게이션 시스템 대신 새로 제작한 패스 파인딩 시스템을 호출하여 용을 움직이도록 만들었다.
기존에 언리얼4에서 사용하던 AIController를 응용, 기존 MoveTo 기능과 유사하게 'FlyingMoveTo' 요청을 구현하여 공중에서 용이 움직일 시 새로운 패스 파인딩 시스템을 호출하는 방식이다. 이렇게 언리얼4의 내비게이션 시스템 대신 새로 제작한 패스파인딩 시스템을 호출하여 용을 움직이도록 만들었다.





이런 과정을 통해 새롭게 제작한 프로젝트DH의 패스 파인딩 시스템과 AI 내비게이션은 아직 최적화를 거치지 않았음에도 게임 플레이에 영향을 주지 않는 수준의 퍼포먼스를 보여줬다. 하지만 스플라인의 생성과 파괴가 매우 잦고, 레이 트레이스나 캡슐 오버랩 테스트가 매우 잦아 이를 최적화하는 과정이 필요했다.

마지막으로 심예람 개발자는 향후의 계획을 간략하게 소개하며 깨달은 점을 공유했다. 아쉬운 점은 AI 내비게이션의 역사는 상당히 깊은데, 아직까지 실버 불릿이 없다는 점이었다. 그리고 당장은 복셀 기반 패스 파인딩 시스템은 배제했지만, 향후 연구를 통해 좀 이를 융합하면 좀 더 좋은 결과를 보일 수 있을 것 같아 연구하고 있다고 전하며 강연을 마쳤다.