LINE Corporation이 2023년 10월 1일부로 LY Corporation이 되었습니다. LY Corporation의 새로운 기술 블로그를 소개합니다. LY Corporation Tech Blog

Blog


LINE AR 렌더링 엔진 개발기

LINE DEVELOPER DAY 2020에서 임용선 님이 발표하신 AR Rendering Engine, SDK, Content, and Future. 세션 내용을 옮긴 글입니다.

안녕하세요. LINE PLUS 플랫폼 엔지니어링 2 센터에서 AR 렌더링 엔진을 개발하고 있는 임용선입니다. 현재 팀 리더를 맡아 프로젝트를 전반적으로 매니징하며 개발을 리딩하고 있습니다. 이번 글의 주제는 AR(Augmented Reality)입니다. 그중에서도 AR을 디스플레이에 '그려주는' 역할을 하는 렌더링 엔진에 관한 이야기입니다. 먼저 AR이 무엇인지 소개하고 LINE에 어떤 AR 서비스들이 있는지 간단하게 말씀드리겠습니다. 그다음 LINE에서 개발한 AR 렌더링 엔진을 소개하려는데요. AR 렌더링 엔진을 개발하면서 어떤 문제를 겪었고 어떻게 해결했는지, 또한 개발한 엔진을 대폭 개편하게 된 이야기까지 공유하겠습니다. 

AR

AR은 사진이나 영상 위에 비현실적인 2D나 3D 그래픽 결과물을 덧씌워서 마치 현실과 비현실이 공존하는 듯한 효과를 만드는 것을 말합니다. 증강된(augmented) 현실(reality)이죠. 예를 들면 아래와 같은 것들이 있습니다.

몇 년 전 유행했던 게임인 '포켓몬 GO'나 영상 통화의 배경 설정 기능 혹은 많은 분들이 사용하는 셀피(selfie) 앱들이 AR의 일종이라고 볼 수 있습니다. 최근 코로나19 사태로 인해 직접 만나기보다는 디스플레이를 통해서 만나는 경우가 많이 늘어났는데요. 아래 그래프에서 확인할 수 있듯이 LINE 비디오 콜 역시 코로나19 사태 이후 사용량이 급격히 늘어났습니다.

이에 따라 상대방에게 전송될 자신의 모습을 보정하는 AR 기능이 트렌드가 되면서 여러 업체에서 앞다퉈 도입하고 있습니다.

LINE의 AR

LINE에는 어떤 AR 기능이 있을까요? LINE 역시 일찌감치 AR의 중요성을 인식하고 많은 서비스와 콘텐츠를 제공하고 있는데요. 먼저 LINE 대화방에서 진입할 수 있는 인앱 카메라가 있습니다. 사용자들이 셀피 용도로 활발하게 이용하고 있는 기능입니다. LINE에서는 각종 시즌 혹은 기념일에 따라 참신한 콘텐츠들을 선보이고 있으며 사용자들의 호평이 이어지고 있습니다. 셀피뿐 아니라 풍경도 고화질로 촬영할 수 있어서 다용도로 활용할 수 있는 기능입니다.

두 번째는 LINE의 영상 통화입니다. 영상 통화할 때 사용자는 자신의 얼굴에 재미있는 효과를 적용한 상태로 통화할 수 있으며 그런 효과들을 이용해서 재미있는 AR 게임들도 즐길 수 있습니다.

마지막으로 얼마 전에 릴리스한 LINE 아바타 기능입니다. AI 기술과 접목해서 나와 닮은 3D 아바타를 자동으로 추천해 주는 재미있는 기능입니다. 최근 들어 많은 사용자들에게 호평받고 있습니다.

LINE의 AR 렌더링 엔진, YUKI

LINE의 여러 서비스에서 AR 기능을 제공하기 위해서는 이를 책임지고 맡아줄 엔진이 필요합니다. 이 엔진을 개발하기 위해 어떤 고민을 했는지 이야기해 보겠습니다. AR을 렌더링하기 위해서는 아래와 같은 기술 스택이 필요합니다. 하지만 그래픽스와 카메라에 익숙한 개발자가 없다면 빌드업이 용이하지 않을 테고 이런 작업들은 서비스 개발에 부담이 됩니다. 성능 또한 신경 쓰지 않을 수 없습니다.

이런 부담을 덜어내기 위해서 아래와 같이 그래픽스와 카메라 부분을 모두 관리하는 구조로 'YUKI'라는 AR 렌더링 엔진을 설계하고 개발을 시작했습니다.

LINE AR 렌더링 엔진의 조건

LINE에 적용해야 하는 만큼 엔진은 여러 가지 조건을 만족해야 했습니다. 먼저 경량이어야 합니다. LINE은 여러 가지 기술과 콘텐츠의 집합체입니다. 크기가 작지 않다면 LINE의 전체 용량이 늘어나면서 사용자 편의성에 마이너스 요소가 될 것입니다. 다음으로 크로스 플랫폼이 가능해야 합니다. LINE은 iOS와 Android는 물론 macOS와 Windows 등 여러 플랫폼을 지원하는 멀티 플랫폼 메신저이기 때문입니다. 엔진 역시 위에서 언급한 플랫폼을 모두 지원해야 합니다. 또한 성능이 좋아야 합니다. LINE은 여러 저 사양 단말을 지원하고 있기 때문에 사양이 좋지 않은 단말에서도 원활하게 동작할 수 있도록 성능이 좋아야 했습니다. 성능은 배터리 사용량에도 영향을 미치므로 매우 중요한 조건이라고 볼 수 있습니다.

개발 타임라인

YUKI 엔진을 개발하기 위해 거쳐 온 여정을 타임라인 형식으로 말씀드리겠습니다. 

2016년 말, 개발 시작

C++ 언어에 OpenGL ES를 사용해서 엔진 개발에 착수했습니다.

핵심 로직은 C++로 크로스 플랫폼화를 진행했고 정말 필요한 부분에 한해서 Swift나 Kotlin 같은 언어를 사용해서 플랫폼 친화적으로 개발했습니다.

2017년 초, LINE LIVE에 적용

LINE LIVE에 YUKI 엔진을 처음 적용했습니다. 엔진을 적용하면서 LINE LIVE에서 다양한 효과를 적용할 수 있게 되었고 사용자들에게 많은 호평을 받는 계기가 되었습니다.

LINE LIVE YUKI에는 AR 렌더링 엔진뿐 아니라 영상을 가공하고 송출하며 비트레이트를 자동으로 조절해 주는 브로드캐스트 기능까지 포함되어 있습니다.

2018년 초, LINE 인앱카메라와 LINE 영상 통화에 적용

앞서 말씀드렸던 LINE 인앱 카메라와 LINE 영상 통화에 적용해서 각 서비스 사용자를 활성화하는 데 많은 기여를 했습니다.

2018년 말, LINE의 여러 패밀리 앱에 적용

LINE뿐만 아니라 LINE의 여러 패밀리 앱에도 계속해서 적용을 진행하면서 여러 곳에 적용하기 쉬운, 좀 더 포터블한 아키텍처로 진화할 수 있었습니다.

2019년 초, 이슈 발생

순조롭게 엔진을 개발하며 서비스에 적용하고 있었는데요. YUKI 엔진이 적용된 서비스가 늘어나면서 몇 가지 문제에 직면했습니다.

첫 번째 문제는 차세대 그래픽스 API에 대한 지원이 필요해졌다는 점입니다. OpenGL 기반으로 프로젝트를 발전시켜 나가고 있었기 때문에 다른 그래픽스 API는 고려하지 못하고 있었는데요. 그런 상황에서 Apple이 OpenGL을 'deprecate'하고 말았습니다. Apple이 새로 권장한 'Metal'이라는 API를 지원하려면 많은 것을 바꿔야 했습니다. 또한 Vulkan과 DirectX 12와 같은 차세대 API를 지원하려면 중대한 결정이 필요했습니다. 다음으로는 엔진의 크기 문제인데요. 여러 서비스에 제공하기 시작하면서 엔진의 용량이 비대해지기 시작했습니다. 엔진에 대한 로직이 분산되지 않아도 전체 크기가 늘어나기 때문에 다이어트가 필요했습니다. 세 번째로는 성능 이슈입니다. 점점 복잡한 콘텐츠를 제공하게 되면서 기존보다 성능을 더 높일 필요가 생겼습니다. 마지막으로 진보된 기술을 사용해 지금까지 만들어내지 못했던 콘텐츠를 만들고자 하는 니즈가 있었습니다.

그래픽스 엔진, ELSA

앞서 언급한 이슈를 해결하기 위해 YUKI 엔진의 주요 구조를 리뉴얼하게 되었습니다. 기존 레이아웃에서는 YUKI 내부에 그래픽스 스택과 카메라 스택이 존재했는데요. 아래 포커싱한 그래픽스 스택을 리뉴얼했습니다.

리뉴얼하기 위해서 'ELSA'라는 새로운 이름의 그래픽스 엔진을 만들었습니다.

목표

ELSA의 목표는 다음과 같았습니다. Metal과 Vulkan, OpenGL, DirectX, 이렇게 네 가지 그래픽스 API를 지원하고 iOS와 Android, macOS, Windows, 이렇게 네 가지 플랫폼을 지원하는 것입니다. 또한 크기는 3MB 이하를 목표로 설정했습니다. 성능 또한 현재보다 월등히 좋아야 했고 코드 품질도 엄격하게 제어하기로 했습니다. 가장 중요한 것은 기존 엔진에서 표현할 수 없었던 신규 기술을 접목해 강력한 콘텐츠를 생산해 내는 것에 있었습니다. 

이렇게 목표를 정한 뒤 어떻게 이 목표를 이룰 것인지 고민했는데요. 다음과 같은 방법으로 목표에 도달할 수 있었습니다.

GAL

먼저 내부적으로 GAL이라고 부르는 'Graphics Abstraction Layer'입니다. 여러 그래픽스 API의 공통 특징을 추상화해서 인터페이스를 정의했습니다. 이 인터페이스는 엔진이 OpenGL을 사용하는지 DirectX를 사용하는지 모르는 상태에서도 사용할 수 있습니다. 백엔드가 바뀌어도 엔진의 사용법은 바뀌지 않습니다. 사용법을 하나로 추상화하는, 가장 기초적인 부분이면서도 가장 중요한 부분이라고 할 수 있습니다.

C++

C++는 크로스 플랫폼을 구현할 때 선택할 수 있는, 훌륭한 이식성을 갖고 있는 언어 중 하나입니다. 성능 측면에서도 다른 언어 대비 월등히 좋은 모습을 보여주며 C++ 17 버전 이상부터는 생산성 또한 뒤처지지 않습니다.

SPIR-V

다음은 SPIR-V입니다. 게임과 같은 콘텐츠를 만들기 위해서는 셰이더(shader) 사용이 불가피한데요. 셰이더도 하나의 프로그래밍 언어로 취급되기 때문에 각각의 문법이 존재합니다. 앞서 말씀드린 GAL과 같이 셰이더 역시 추상화해서 하나의 문법으로 사용할 수 있어야 합니다. 하지만 각 그래픽스 API마다 셰이더의 문법과 제약 사항이 다르기 때문에 실질적으로 추상화하기가 매우 어렵습니다. 이때 큰 도움이 되는 솔루션이 SPIR-V입니다. SPIR-V는 아래와 같이 하나의 셰이더 문법을 중간 컴파일해서 각 API에 맞는 셰이더 언어로 바꿔줍니다.

예를 들어 Vulkan에 사용하는 VKSL을 중간 컴파일해서 OpenGL에서 사용하는 GLSL이나 Metal에서 사용하는 MSL 등으로 바꿀 수 있다는 이야기입니다. 이와 같이 한 가지 문법으로 셰이더를 추상화하는 것은 SPIR-V를 사용해 달성할 수 있었습니다.

Frame Graph

다음은 렌더링 플로(flow)에 'Frame Graph'라는 개념을 도입한 것입니다. Frame Graph란 각 렌더 패스를 그래프로 엮어 렌더링하는 방식을 말하는데요. 그래프는 버텍스(vertex)들의 연결을 의미하기 때문에 각 버텍스는 '엔티티(entity)'라는 데이터를 갖고 렌더링을 수행합니다.

이런 연결 구조는 GPU의 프레임 연결 구조를 차용했습니다. 완전히 같은 방식입니다. 따라서 보다 GPU 친화적이고 디버깅도 용이합니다.

ELSA에서는 이 Frame Graph를 활용해 렌더링 성능을 이끌어내고 있습니다. Frame Graph의 모티브가 된 것은 Unity 엔진의 'ECS(Entity Component System)'라고 부르는 설계 방식입니다. 그래픽을 표현하는 데 있어서 전통적인 'Scene Graph' 방식과는 대조되는 방식으로, 신과 노드를 계층 구조로 이어 붙이는 방식이 아니라 엔티티에 컴포넌트를 이어 붙이고 컴포넌트는 엔티티에서 활용될 데이터만을 갖는 형식입니다. 사실상 데이터 드리븐 설계 방식을 따랐습니다. 아래 그림과 같이 하나의 엔티티에 포지션과 벨로시티, 스프라이트 등의 컴포넌트가 붙어 있습니다.

굳이 Scene Graph와 비교하자면 노드에 해당하는 부분이 엔티티라고 생각할 수 있습니다. 렌더링할 때 인접한 컴포넌트 데이터를 연속으로 읽어서 캐시 히트율을 획기적으로 올려 성능을 높이는 것이 이 방식의 핵심입니다.

하지만 데이터 드리븐 방식은 캡슐화를 위반할 수 있고 결합도와 응집도를 높인다는 단점이 있습니다. 이런 단점을 보완하기 위해 순수한 ECS가 아니라 하이브리드 ECS 개념을 차용해서 전통적인 Scene Graph 방식과 닮은 방식으로 인터페이스를 설계했습니다.

Scene Graph의 기능이 일부 남아 있기도 합니다. 랜더 패스의 진행에 따라서 랜더 스테이트의 변경을 최소화하고 패스 진행에 따른 텍스쳐 사용량을 효율적으로 제어해서 성능을 이끌어낼 수 있었습니다.

시각화된 툴

다음으로 시각화된 툴입니다. 게임을 만들 때도 툴 없이는 매우 힘들 듯이 AR 콘텐츠를 만들 때도 시각화된 툴이 필요하다고 생각했습니다. 특히 앞으로 더 복잡하고 신선하며 강력한 AR 콘텐츠를 생산하려면 시각화된 툴이 매우 중요하다고 생각합니다.

적용 결과

앞서 말씀드린 방식들을 활용해 마침내 만들어 냈습니다. 크기가 작으면서 기존보다 뛰어난 성능을 내며 생각했던 모든 API와 플랫폼을 지원할 수 있었습니다. 얼마나 개선되었는지 그래프로 살펴보겠습니다.

ELSA 도입 후 렌더링 처리에 들어가는 시간이 절반 이하로 줄어들었습니다. 두 배 이상의 성능 향상을 도출한 것이라고 볼 수 있습니다. 엔진의 용량도 비약적으로 줄어들었습니다. 목표로 삼았던 3MB보다 작은 2MB 안팎에 안착할 수 있었습니다. 이에 따라 앱 크기가 사용성에 영향을 미치는 서비스라도 부담 없이 적용할 수 있습니다.

향후 계획

앞으로도 계속 YUKI와 ELSA를 발전시켜 나가기 위해 다음과 같은 계획을 세우고 있습니다.

AI와 접목해서 여러 가지 효과를 내는 필터 기능을 추가할 예정이고 향후 오픈 소스화도 진행할 예정입니다.

마치며

앞으로 AR의 니즈는 계속 커질 것이고 콘텐츠 산업 또한 지속적으로 성장할 것입니다. AR을 렌더링하려면 개발 측면에서 많은 어려움이 있지만 YUKI와 ELSA를 사용하면 쉽고 효율적으로 AR 렌더링에 접근할 수 있을 것이라고 생각합니다. 이상으로 글을 마치겠습니다. 아래에서 발표 영상도 확인하실 수 있습니다. 긴 글 읽어주셔서 감사합니다.