▲ 펄어비스 최창애 팀장

[인벤게임컨퍼런스(IGC) 발표자 소개] 최창애 팀장은 웹젠 C9 엔진팀을 거쳐 현재 펄어비스 프로그램1팀을 맡고있다. 펄어비스에서는 검은사막의 3D 렌더링과 레벨 에디터, 리마스터 작업을 담당한다. 최창애 팀장은 스스로를 평범한 주부이자 아이 엄마, 그리고 프로그래머라 소개한다.

금일(1일) 개최된 IGC 2017에서는 펄어비스 최창애 팀장이 나와 검은사막의 수준 높은 3D 그래픽의 비결에 대해서 아낌없이 들려주었다. 또한, 레벨 에디터 과정과 생산성 향상을 위한 펄어비스만의 노하우를 많은 개발자, 그래픽 디자이너들에게 알려줬다.

3D 렌더링 기술에 대해 이해하고 HLSL 프로그래밍 지식, C++ 프로그래밍 기초를 쌓았다면, 펄어비스만의 그래픽 노하우를 익혀 한 단계 더 발전시킬 수 있는 기회를 최창애 팀장을 통해 만날 수 있었다.

※본 강연 기사는 주제 특성 상 강연자의 시점에서 서술했습니다.


■ 강연주제: 검은사막 속 3D Rendering

안녕하세요. 펄어비스의 최창애입니다. 오늘 발표에 대해 먼저 차례를 소개하도록 하겠습니다. 검은사막의 렌더링 작업 소개 이후 레벨 에디터, 생산성 향상을 위한 노력들에 대해 말씀드리겠습니다. 그리고 렌더링 엔진을 활용한 인게임 시스템과 마지막으로 검은사막 리마스터링 작업에 대해 발표하겠습니다.

그에 앞서, 그래픽스 엔진 관련 프로그래머 구성과 사용하는 프로그램을 소개하겠습니다. 3개 팀으로 구성되어 있고 김대일 의장을 포함, 팀장 3명 총 15명 이상이 렌더링, 최적화 작업 중입니다. 사용하는 그래픽 API는 PC에서는 D3D9, D3D11으로 개발을 했고, 모바일은 OpenGL ES3.1로, XBox one은 D3D11을 이용해 엔진을 개발 또는 지원 중입니다. 제가 이분들을 대표하여 발표하게 되어 진심으로 영광입니다.


검은사막의 렌더링

먼저 Voxel 기반의 폴리곤 지형에 관해 이야기하겠습니다. Voxel은 volumetric element의 약자입니다. Density function이라는 개념은, 3D 공간의 모든 점에 Density function을 가지고 공간이 비어있는지 채워있는 지 있는지 설명합니다. 값이 양수면 지형 표면 안에 속하게 되고, 음수면 대기 또는 물처럼 빈 공간에 속한다고 정의합니다. 밀도 값이 0인 경계에 지형의 표면이 있게 됩니다. 검은사막에서는 이러한 밀도 값을 Voxel 꼭짓점마다 RLE(Run-length encoding)로 저장했습니다.


Marching cube는 앞에 이야기한 밀도 값을 가지고 폴리곤을 만드는 알고리즘입니다. 밀도 값이 모두 같은 부호면 지형 내부, 또는 외부에 있어 폴리곤이 출력되지 않게 됩니다. 그 밖에 경우, 지형과 빈 공간 경계에 놓이게 되어 폴리곤이 생성됩니다. 복셀 12개 변위에 꼭지점의 밀도 값 2개를 보관하여 한 점을 정의하고 그 점들 3개를 연결하여 폴리곤을 만들게 됩니다. 아래 그림은 Marching cube를 이용한 폴리곤을 만드는 기본 케이스에 대한 것입니다. 검은사막에서는 pre-computation 방식으로 복셀을 기반으로 하여 지형 메쉬를 미리 만들고, 리얼타임에서는 해당 메쉬를 로딩하여 렌더링하는 폴리곤 지형 방식을 사용했습니다.


검은사막 지형의 장점은 기본적으로 Voxel 기반이기 때문에 효율적으로 연속 데이터를 저장할 수 있고, 쉽게 수정할 수 있습니다. 또한 GPU 복셀 터레인 방식에 비해 Geometry Shader가 필요하지 않아 빠르게 그릴 수 있습니다. vertex가 XZ 평면에 놓이지 않아도 되기 때문에 그로 인한 아티팩트가 없습니다. 하이트맵 방식보다, 구멍을 뚫거나 돌출부를 만들고 Seamless 터널을 만드는 등 다양한 지형 생성을 할 수 있습니다.

단, 하이트맵 방식에 비해 다이나믹 LOD를 구현할 수 없어 메쉬 LOD 방식을 사용했고, 메모리상에 지형의 높이를 들고 있지 않기 때문에 높이를 얻기 위해 collision detection을 활용했습니다.


검은사막은 전통적인 Deferred Shading을 사용합니다. BRDF의 평가에 필요한 정보, 즉 재질 속성, 표면 속성을 G-Buffer에 렌더링합니다. 포지션 정보는 하드웨어 뎁스 버퍼로부터 얻어서 사용하므로 G-Buffer에 렌더링하지 않았습니다. 그런 다음, 일반적인 방법으로 그림자를 그리고 각각 개별 섀이더를 이용해 조명, AO 등을 screen space 상에서 계산을 합니다. 최종 결과를 결합하고, 간단한 조명 계산의 투명 재질과 헤어를 렌더링합니다. 마지막으로 Post-process를 수행합니다.

검은사막의 G-Buffer에 더 자세히 설명하겠습니다. 렌더 타켓 0번의 RG 채널에는 DIFFUSE정보를, B채널에는 Vertex Normal을 알파 채널에는 Material ID를 저장했습니다.

렌더 타겟1번의 RG 채널에 노말 정보를, B 채널에는 GLOSS과 FRENEL계수를 알파 채널에는 Emissive 또는 Anisotropy와 Skin Mask를 저장했습니다. 월드 포지션은 Depth Buffer로부터 계산했습니다.

▲ half는 interlaced방식처럼, 세로줄을 홀수, 짝수로 번갈아 가며 half size로 저장한 것

메모리와 대역폭을 줄이기 위해 diffuse color는 YUV 인코딩을 사용해, 인간의 눈에 더 민감한 밝기정보는 full size로, 덜 민감한 색조정보는 half size로 저장했습니다. 또한, 노말 정보는 x, y 평면에 z 벡터를 투명 하는 방식의 인코딩을 사용하여 float2로 줄였습니다. 자세한 내용은 레퍼런스를 참조하시면 됩니다. 재질마다 다른 BRDF를 사용하기 위해 material id, Skin Mask, Anisotropy 정보를 저장했습니다. 그리고 뒤에서 이야기할 PBR을 위해 glossiness, Fresnel 계수를 저장했습니다.


왜 PBR인가?


위 이미지는 PBR 작업의 결과물입니다. 좀 더 사실적인 이미지를 쉽게 얻기 위해 검은사막은 물리 기반 렌더링을 택했습니다. 아티스트를 위한 간단한 인터페이스가 장점입니다. 몇 가지 정해진 매개 변수 입력으로 물리적인 표현이 가능하게 되었고 더 이상 감으로 작업을 하지 않아도 됩니다. 누가 작업을 하더라도 일관되게 에셋을 만들 수 있습니다.

효과적인 PBR을 위한 기반 작업으로 Gamma-Correct Rendering을 했습니다. 모니터의 색 공간은 비선형입니다. 그 이유로 인간의 눈이 선형적으로 밝기를 기록하면 어두운 부분에서 민감하게 반응하여 밝기가 변할 때 부드럽게 느껴지지 않고 단절되어 보이는 현상이 발생합니다. 따라서 비선형으로 인코딩해 어두운 부분을 더 자세히 기록할 필요가 있습니다.

이러한 비선형 모니터의 색 공간에서 조명 연산을 수행하면 아래 그림에서 보듯이 1 더하기 1이 2가 아닌, 2 이상의 값이 되는 것처럼 잘못된 결과를 발생 시킵니다. 그래서 검은사막에서는 모든 비선형 텍스처 입력을 linear 공간으로 변환 후 조명 연산을 수행하고 최종 출력은 다시 비선형 인코딩을 해, 계산된 값들이 올바르게 인지되도록 했습니다.

▲ 빛의 경우 1+1이 2의 밝기를 나타내지 않는다

또한, 효과적인 PBR을 위한 기반작업으로 HDR 그리고 HDR ENV을 필요로 합니다.

HDR의 Dynamic Range란 표현할 수 있는 가장 큰 값과 작은 값의 비율을 말합니다. 리얼 월드에서 Dynamic Range는 100,000 : 1이 될 수 있습니다.

게임에서 다이나믹 레인지를 표현하는 방법으로 3가지가 있습니다. 첫 번째 실제 luminance space로 렌더링하는 방법으로 2의 32승이면 모든 범위의 luminance를 직접 표현 가능합니다. 두 번째 Displayable image로 예전 LDR 게임에서는 2의 8승 범위로 밝기를 표현했습니다. 세 번째 relative luminance가 있습니다. 렌더링 시 노출값에 대한 스케일을 적용하는 방법으로 이상적으로 2의 15,16승 이상이 좋고, 게임에서는 2의 13~14승이면 적당합니다.

검은사막에서는 A2R10G10B10 포멧의 Render target을 사용했고, ENV map은 LDR 포멧을 사용했습니다. LDR과 HDR을 절충하는 방법을 채택해 메모리 소비를 줄였습니다. 이 부분은 나중에 리마스터링으로 수정하게 되었습니다.

검은사막에서 사용한 Diffuse BRDF는 Oren-Nayar 확산 반사입니다. 실세계 물체가 완벽한 램버트 반사를 보여주지 않는 경향이 있다는 것에 착안, 일반적으로 거친 표면에서 조명 방향이 시야 방향에 다가갈수록 더 밝게 보이는 것을 모델화했습니다.


위 그림에서 보이듯이 가장 오른쪽 Oren-Nayer 모델이 왼쪽 실제이미지처럼 가운데 램버트 반사에 비해 외곽 경계 반사, 명암 경계의 전환이 부드러운 것을 볼 수 있습니다.

Specular BRDF는 Microfacet 이론을 기반으로 하는 Cook-Torrance 모델을 사용했습니다. 해당 수식은 D, F, G 항으로 나누어집니다. 첫 번째로 설명할 F 항인 Frenel function은 입사각에 따른 반사와 투과에 대한 함수로, 사물을 직각으로 볼 때보다 비스듬히 봤을 때 더 밝아 보이는 현상을 표현합니다.


위 이미지에서 보듯 표면에서 반사되는 빛의 양은 시야각에 달려 있습니다. 90도 입사각인 수평각에서 물처럼 매끄러운 표면은 거의 100% 반사합니다. 0도 입사각인 수직 입사각에서 반사량은 재질의 굴절률에 따라 다릅니다. 물의 경우 2% 반사를 합니다.

▲ 그림(1)

▲ 그림(2)

먼저, 검은사막에서는 ‘The Shlick Approximation(쉴릭의 근사)’를 사용했습니다. 그 이유는 상당히 정확한 값을 구할 수 있기 때문입니다. 표면의 고유한 반사 색상이라 말할 수 있는 f0 프레넬 계수를 입력받아 위 그림(1)의 공식을 사용하여 프레넬 효과를 표현했습니다.

여기서 F0는 수직 입사각에서의 반사율로 재질의 IOR(Index Of Refraction, 굴절률)을 가지고 구할 수 있습니다. 일반적인 유전체의 F0는 0.02~0.05 범위로 gray scale입니다. 도체의 경우 위 그림(2) 오른쪽에 있는 것처럼 0.5~1.0 사이의 RGB 값을 가집니다. 검은사막에서는 프레넬 계수를 float type 하나의 매개 변수로 입력을 받고 있어서 metal 재질에서 프레넬 효과에 오차가 있습니다. 이 부분은 최근 리마스터링 작업에서 수정하게 되었습니다.


두 번째 D 항 Normal Distribution Function은 반사 빛의 크기와 모양을 결정합니다. 검은사막에서는 이 부분에 언리얼 엔진에서 사용한 Trowbridge-Reitz, 흔히 말하는 GGX 모델을 사용했습니다.


위 그림과 같이 Blinn-Phong모델에 비해 왼쪽의 GGX의 반사 빛이 부드러운 것을 볼 수 있습니다. 수식은 위와 같고 여기서 알파는 roughness를 뜻합니다. 이 값은 gloss로 입력 받은 값을 반전(inverse)시켜 사용했습니다.


세 번째 G항은 Geometric Shadowing입니다. Microfacet에서 나가는 beam의 일부가 블록이 되는 마스킹 현상과, 들어오는 빔의 일부가 블록 되는 섀도잉 현상을 표현합니다. 검은사막에서 Cook-Torrance 모델을 사용해 위 수식과 같이 계산했습니다. 이를 위한 매개변수는 필요하지 않습니다.

deferred shading을 사용해도 무한의 조명 연산을 사용하기에는 부담이 있습니다. 그래서 SH Lighting이라는 개념을 도입해 사용하고 있습니다. SH Lighting의 목적은 Point Lights, Spot Lights, GI Virtual Point Lights를 무한 렌더링하기 위함입니다. 해상도 1/4 사이즈로 연산한 조명 값을 2차 Spherical Harmonics를 이용해 각 RGB 채널마다 SH 계수(coefficient) 4개에 해당하는 값, 12개를 3개의 텍스처에 나눠 저장하고, 이를 반복해 조명 연산 값을 더합니다. 보통 게임에서 Diffuse Lighting에 3차 SH... 즉, SH 계수 9개를 저장하면 충분하다고 하는데, 저희는 메모리 성능을 고려해 2차를 사용했습니다.

SH 계수를 이용해 복원된 근사 mass light direction으로 specular 연산까지 할 수 있었습니다.

이 연산의 단점은 풀 사이즈 조명 연산보다는 밝기, 색감 차이가 존재해서 GI Virtual Point Lights와 거리가 먼 조명에만 사용하고 있습니다.

아래 그림은 SH 차수가 증가함에 따른 근사의 변화를 보여줍니다.


다음으로, 검은사막에 사용되는 Global Illumination Approximation에 대해 이야기하겠습니다. Directional Light Source로부터 CPU ray-casting을 해서 교차하는 표면에 virtual point light를 생성해 GL 효과를 근사했습니다. 이와 관련해서는 아래 이미지를 참고해주시기 바랍니다.


이때, 교차 표면의 위치와 normal 값을 저장하고, shadowmap 렌더 시, shadow map space에서 빛 위치의 diffuse color를 준비해둡니다. 그런 다음, screen space에서 준비된 diffuse color에 shadow를 적용하고 a-b-c 수치를 이용해서 앞서 얘기한 SH Lighting으로 조명 연산을 했습니다.

▲ 근사 이미지 효과 전

▲ 근사 이미지 효과 후

위 두 사진은 GI 근사 효과 적용을 비교한 것입니다. 보다시피 괜찮은 GI 효과로, 물리 엔진의 ray-casting 연산이 무겁지 않다면 시도할만한 품질입니다.

다음으로 Rendering Huge World를 주제로 말씀드리겠습니다.


위 이미지는 현재 검은사막 전체 맵입니다. 크기는 약 가로 34km, 세로 31km입니다. x 좌표의 가장 큰 수가 약 1,004,000 이상입니다. 숫자가 커지다 보니, 원점에서 멀어질수록 부동 소수점 정밀도 문제가 생겼습니다. 그래서 검은사막 맵 렌더링은 View Relative Position을 사용했습니다.

검은사막의 거의 모든 기하학적 구조는 instancing으로 렌더링합니다. instancing 데이터 구성 시 텍스처로 먼저 구분하고, 다시 메쉬 데이터로 분류합니다. 텍스처 바인딩을 vertex buffer 바인딩보다 적게 해서 최적화에 효과를 보았습니다.

또한, CPU 최적화를 위해 Command Buffer를 사용합니다. Dx11의 deferred contest 개념으로 graphics commands를 2, 3개 thread를 사용하여 command buffer에 레코딩한 다음 render thread에서 play back 하는 방식입니다.

그리고 VTF(Vertex Texture Fetch)를 사용해 캐릭터 GPU Skinning에서 성능 효과를 보았습니다.

▲ Crop Mode

Crop Mode는 위 그림에서 보듯, 화면 가장자리 부분에 UI만 렌더링하고 게임 화면은 해상도보다 작은 사이즈로 렌더링해 GPU 성능이 좋지 않은 PC를 지원합니다.

▲ Upscaling

마찬가지로 Upscaling은 게임 화면을 해상도보다 작은 사이즈로 렌더링 후 Bicubic Upsizing 필터를 사용해 화면 크기로 늘리는 방법의 저사양용 옵션입니다.


레벨 에디터, 생산성 향상을 위한 노력들

검은사막 레벨 에디터에 기능들은 아티스트와 함께 필요한 순서로 하나씩 기능을 추가하는 방식으로 작업했습니다. 개발 방향 첫 번째는 작업자가 바로바로 확인할 수 있게 하자는 것입니다. 이를 위해 pre-computation 작업을 최소화했습니다.

두 번째로 여러 명이 동시에 작업할 수 있게 하자는 요구가 있었습니다. 그래서 레벨 데이터를 지역별, 분류별 작은 단위로 나누어 리비전 관리를 했고 배포 시 병합을 하는 방식을 택했습니다. 또한, 라이브와 업데이트 데이터를 나누어 동시에 수정 작업이 가능하게 지원했습니다.

세 번째로 프로토타입을 빠르게 만들어 확인 후 세부 작업이 가능하게 하여 개발 속도를 줄었습니다. 줄인 시간만큼 아티스트는 더 많은 내용을 채워 넣을 수 있었습니다. 이를 위해 hightmap 데이터를 복셀 데이터로 불러와 기반이 되는 지형을 대규모로 만들 수 있게 하는 기능이라든지, 레벨 오브젝트를 그룹으로 배치하고 그 그룹을 템플릿화 하여 관리하는 기능을 추가했습니다. 또 데칼볼륨 등을 넣어 빠르게 디테일을 높이는 작업을 지원했습니다.

네 번째로 최대한 자동화를 하는 방향으로 개발했습니다. 내비게이션, 충돌, LOD 데이터들을 한 번의 레벨 디자인이 끝나면 자동으로 생성할 수 있도록 노력했습니다. 길을 꾸며주거나 건물에 넝쿨 식물을 자동으로 만드는 기능도 같은 목적으로 구현했습니다.

최적화는 리소스가 아닌 코드로! 이것은 펄어비스 엔진 개발의 모토라고 할 수 있습니다. 게임 오픈 시점이 되어서 최적화를 위해 리소스를 갈아엎는 일은 펄어비스에서 일어나지 않도록 하고 있습니다.

▲ 아무 것도 배치하지 않은 허허벌판의 지형에

▲ 레벨 디자이너가 스무 번 미만으로 클릭해 꾸민 지형

▲ 그룹 템플릿 기능으로 객체 여섯 개 배치한 모습
세 과정은 5분이 채 소요되지 않았다

▲ 검은사막의 디테일을 높이는 '데칼 볼륨'

▲ 데칼 볼룸 배치 후의 모습

▲ 자동화 기능으로 도로를 지정하면 저절로 꾸며진다


렌더링 엔진을 활용한 인게임 시스템

하루를 표현하기 위해 24시 설정을 포함하는 20개의 테이블을 관리합니다. 매개 변수로는 아래 이미지와 같습니다.


검은사막은 살아있는 세상을 표현하기 위해 렌더링 엔진의 기능을 최대한 활용했습니다. 태풍이 오면 앞이 보이지 않을 정도로 어두워지고, 비로 바닥이 젖거나, 눈이 바닥에 얼기도 합니다. 이 모든 것은 Weather System을 이용해 구현됐습니다.

다음으로 검은사막의 캐릭터 커스터마이징입니다. 얼굴 형태와 몸 커스터마이징은 bone transform, 문신은 texture uv transform, 헤어 컬링은 vertex transform, 대기 상태 표정은 vertex morphing으로 구현됐습니다.


다양한 환경 변화로 기분 전환과 재미를 주는 것을 목적으로, 레벨 오브젝트를 최대한 활용한 Event System을 개발했습니다. 이벤트 시간에 맞춰 오브젝트, 트리, 이펙트, 조명 등이 추가되거나 변경됩니다. 또한, 시간과 날씨도 변경됩니다.






그리고 검은사막에는 캐릭터 커스터마이징과 하우징을 즐기고 이를 예쁘게 담아 이미지로 공유하는 유저들이 많습니다. 이를 위한 Camera Mode(스샷 모드)는 멋진 화면을 남길 수 있는 기능을 지원합니다. 캐릭터 시선 위치를 바꾸고 슬로우 모션으로 스샷을 찍는다거나, DOF(Depth of Field) 조절, FOV(Field of View) 조절, 필터를 이용한 Color Grading을 지원합니다. 그리고 유저는 비네팅, 노이즈, 플레어 같은 post process를 사용할 수 있습니다.



검은사막 리마스터링

리마스터링의 목표는 좀 더 사실적이고 아름다운 검은사막을 만드는 것입니다. 기존 리소스 수정 없이 해당 과제를 해결하기 위해서 옵션, 렌더링 품질, 성능은 그대로 유지한 채 울트라 옵션에서 진행하기로 했습니다.


‘무엇을’ 리마스터링하는지 구체적으로 말씀드리면, 앞서 이야기한 HDR을 Float 16 RT 포맷으로 더 큰 범위의 휘도를 표현합니다. Tone mapping과 Glare는 YEBIS를 이용해 개선했습니다.

다음으로 PBR을 개선하고 있습니다. 실시간으로 HDR 포맷의 Pre-filltered ENV 맵을 만들어 재질의 roughness(거친 정도)를 개선합니다. 아래의 그림은 runtime ENV 맵에 대한 예시입니다.


또한, 실리콘 스튜디오의 YEBIS를 사용해 post-process를 업그레이드합니다. YEBIS가 무엇인지 물어보시는 분들이 간혹 있어 예시 이미지를 준비했습니다.


첫 번째가 Depth of field입니다. 초점 바깥쪽의 블러 효과와 간직 모양의 보케를 볼 수 있습니다. 두 번째가 glare 이미지입니다. YEBIS glare는 볼륨, 렌즈 플레어, 애나모픽 렌즈 효과 등 다양한 glare 모양을 볼 수 있습니다. 세 번째가 god ray 효과입니다.

마지막으로 SH Lighting의 단점을 보완하기 위해 full size로 조명을 계산합니다. 그밖에 AO, AA, SSR, Scattering, Volumetric Cloud, Indoor GI 등을 개선할 예정이며, 현재 개발 중입니다.


끝으로, 펄어비스에서 소개되는 영상들은 리마스터 버전으로 제작되고 있으니 많은 기대 부탁드립니다.