언리얼 엔진 공식 홈페이지 온라인 러닝 프로젝트 중 <Oculus와 언리얼 엔진을 사용한 VR개발>에 대한 요약 및 정리입니다.
블루프린트로 진행되며, 프로젝트를 하는데 필요한 에셋은 모두 제공됩니다. 코스 설명대로 따라하면 다운받을 수 있습니다.
추후 C++로 바꿔볼 예정입니다.
관련 링크 : https://www.unrealengine.com/en-US/onlinelearning-courses/vr-development-with-oculus-and-unreal-engine
개요 및 라이팅 렌더링
VR 렌더링 시 고려해야할 점
프레임별 포함될 ms 수, 해상도
픽셀당 라이트 수 그리고 필요하거나 선호할 새도 메서드 등
머터리얼 복잡도와 언리얼 엔진에서 사용할 안티 에일리어싱 방식 등
Quality VR Experiences Utilize
높은 해상도
높고 안정적인 프레임 속도
Classic Forward Rendering
지오메트리는 각 커버 픽셀의 채널과 함께 렌더링 됨. GPU는 텍스처 머티리얼 속성 및 라이팅 데이터를 기반으로 최종 GPU을 정확하게 계산해야함.
Lighting Best Practice
라이트는 제어 및 퍼포먼스가 좀 더 까다로움. 로컬 라이트는 감쇠 범위로 제한하는 것이 일반적임. 덕분에 개발자는 오브젝트가 영향을 받는 라이트 수를 제한할 수 있음.
Forward Rendering Lighting Consideration
라이팅 솔루션은 더 작게 제한을 해주어야 함. 오브젝트에 라이트가 거의 닿지 않더라도 해야함.
전체 오브젝트는 하나의 라이트로 렌더링 되어야 함.
Deferred Rendering Techniques
다양한 기법이 존재하는데 모두 스크린 스페이스 정렬된 텍스처나 렌더 타겟에 대한 데이터 저장을 기반으로 함. 즉 각 화면 픽셀마다 머티리얼, 컬러,러프니스와 서피스 노멀 등 머트리얼 어트리뷰트를 저장하는 텍스처가 있다는 뜻임.
일부 디퍼드 기법은 채널 몇 개만 있으면 됨. 예를 들어 첫번째 새도와 포그의 경우 Z버퍼에 대한 엑세스만 있으면 됨.
모든 디퍼드 기법에 공통적으로 나타나는 요소는 뒤따르는 패스로부터 이런 어트리뷰트를 읽어들인다는 점임. 그래서 머티리얼 세이더로부터 스스로 효과적으로 디커플링함. 덕분에 보다 단순하고 세련된 코드가 가능해서 씬에서 더 나은 퍼포먼스와 유연성을 보여주는 결과물이 나옴. 하지만 읽고 쓰는데 메모리가 더 필요하다는 단점이 있음. 해상도가 높을수록 영향을 많이 미치고, 모바일 VR처럼 대역폭이 낮은 하드웨어에는 더 큰 영향이 있음.
Classic Deffered Shading Passes
모든 오브젝트가 픽셀 세이더 아웃풋을 내놓는 머티리얼 및 지오메트리 어트리퓨트로 렌더링되어 G버퍼에 들어감. 또 다른 디퍼드 패스에서는 세이딩이 G버퍼와 라이팅 정보를 사용해서 계산이 되는데 그 이유는 라이팅 복잡도가 머티리얼 복잡도를 제공한다면 디퍼드 세이딩은 많은 라이트와 함께 복잡한 머티리얼을 쓸 때도 깔끔한 단순성과 퍼포먼스를 제공하기 때문임.
단점 중 하나는 안티 에일리어싱임. MSAA를 사용해서도 G버퍼를 렌더링할 수는 있지만 복잡도와 필요 메모리를 훨씬 더 추가하기 때문에 퍼포먼스도 떨어지게 되어서 현재는 언리얼 엔진에서 지원하지 않음.
Temporal Anti-Aliasing
이제는 템포럴 안티 에일리어싱, 즉 템포럴 AA를 이런 문제의 솔루션으로 활용함. 잠깐의 프레임만으로도 멋진 결과로 변환해냄. 즉 아직 화면에 없던 콘텐츠가 몇 프레임동안 흐릿하게 나왔다가 곧 뚜렷해진다는 뜻임. 또한 빠른 움직임이나 모션 오버 노이즈가 있는 콘텐츠는 뭉개져 나타날 수 있음. 템포럴 AA는 디퍼드 셰이딩과 함께 다루기에 아주 매력적인데 스페큘러 에일리어싱과 같은 문제를 MSAA보다 더 잘 해결합니다. 이런 메서드는 풀 스크린 버퍼링을 기반으로 하여 VR의 퍼포먼스 면에 더 큰 영향을 끼침.
Fast Approximate Anti-Aliasing
FXAA, 일명 빠른 추정 안티 에일리어싱은 같은 문제이 대한 최신 솔루션으로 여타 제약이나 지연 변환이 나타나지 않음.
위 두가지 안티에일리싱 방법은 렌더 타깃 콘텐츠를 읽어오는데 의존하기 때문에 메모리 대역폭이 한정된 모바일에서는 손해를 보게됨.
Pros and Cons ( 장점과 단점 )
첫번째 셰이딩의 경우 다양한 기능 활용에 큰 이점을 줌.
VR의 경우 고해상도와 높은 프레임 속도를 목표로 해서 필요한 기능을 매우 한정적으로 사용해야 함.
Clustered Forward Rendering
기존의 메서드를 뒤튼 최신 방식인데 언리얼 엔진 4에서 포워드를 선택할 때 사용됨.
다이내믹 브랜칭과 프레임별 라이트 계층구조 활용을 통해 Clustered Forward Rendering으로는 퍼포먼스에 큰 영향을 주지 않고도 G버퍼와 같은 중간 버퍼로부터 효율적인 라이트 컬링이 가능해 RGB 컬러를 직접 도출 할 수 있음. 이를 통해 메모리 대역폭 낭비를 방지할 수 있으며 추가적인 이점으로는 이걸로 GPU 내장 하드웨어를 MSAA로 활용할 수 있음.
Anti-Aliasing은 고해상도 이미지 렌더링으로 구현될 수 있음.
Note for MSAA
MSAA는 프래그먼트 셰이더 비용이 4배가 되는 걸 피하고 프리미티브의 서브 픽셀 커버 여부에 따라 컬러 값을 4가지 서브 픽셀 리전으로 복제하면서 더 효율적인 됨. 추가 서브 픽셀은 프래그먼트 셰이더 실행을 아끼지만 여전히 3배 더 많은 메모리를 사용함.
즉 MSAA는 프리미티브 에일리어싱만 해결하지 텍스처나 셰이딩으로부터의 에일리어싱에는 아무 효과도 없단 뜻임.
Note for Mipmap Generation
언리얼 엔진 4의 경우 두 텍스처에서 제곱인 아닌 경우 밉맵 생성을 비활성화 한다는 걸 명심해두어야 함, 그럼 에일리어싱만 일어날 뿐만 아니라 렌더링도 느려짐. 때문에 텍스처의 X, Y축이 2의 제곱수인지 확실히 확인해야한다. 예를 들어보면 256, 512, 1024정도 됨. 꼭 정사각형일 필요는 없음.
Specular Shimmering and Composite Textures
스페큘러 시머링은 MSAA가 해결하지 못하는 세이딩 에일리어싱 유형임.
언리얼 엔진 4는 스페쿨러 시머링을 컴포짓 텍스처로 고정하는 기법을 구현함.
애플리케이션을 디퍼드에서 포워드 렌더링으로 바꾸면 복잡한 씬에서의 퍼포먼스 개선을 딱히 확인하지 못할 수도 있음. 하지만 크 특징을 제한할 때에는 효과가 확실하게 드러나는데 그 예로는 거울 같은 오브젝트에만 리플렉션을 쓰고 문고리에는 쓰지 않거나, 스카이 박스에는 애초에 그림자가 있을 리가 없으니 새도가 나타나지 않게 할 때 처럼임
Design Best Pratices
만약 초고사양의 복잡한 비주얼을 목표로 삼는다면 FXAA와 디퍼드 렌더링의 사용을 고려해야 할 수도 있음.
여기서 명심할 점은 언리얼 엔진 4의 포워드 렌더러의 기능이 한정되어 있다는 것임. 그 기능 중에는 포워드 렌더러에 엄청난 퍼포먼스 영향을 끼쳐서 사용해서 안되는 것도 있음. 그 외는 아직 구현이 안된 것도 있음.
언리얼 엔진의 선택 방식은 일반적인 경우를 구현하는 위버 세이더를 작성하고 일명 세이더 순열이라는 세이더 배리언트를 갖추는 것임.
Shader Permutations
자동으로 생성되는 것이고 프로그래머의 작업 시간을 줄여주며 효율적인 세이더를 제공할 수 있지만 대신 컴파일 시간이 길고 세이더 배리언트에 메로리가 더 필요해진다는 점을 명심해야함.
Case In Mobile Platform Like Quset
신규 애플리케이션을 프로그래밍 한다면 표준 모델보다 훨씬 더 단순한 라이팅 모델을 사용하게 될 수도 있음. 이런 경우에는 프로젝트를 처음 시작할 때부터 미리 프로젝트 세팅의 렌더링 카테고리에서 복잡한 셰이더의 순열을 거의 다 해제하는게 좋음 이런 기능 중 일부는 조심해서 사용할 수도 있겠지만 그냥 처음부터 꺼놓고 시작하는게 더 나음. 모바일의 경우에는 컴파일 시간이 길어지고 프로젝트 패키지 규모가 커질 수 도 있기 때문임.
포워드 셰이딩은 이런 문제가 더 부각됨
Shading
Light types
Material types
Tone mapping + 더 많은 기능이 패키징되어 있기 때문임.
디퍼드 셰이딩의 경우 라이팅, 톤매핑을 서로 다른 패스로 분할하여 기능별 토글에 따른 문제를 훨씬 줄였음.
To Toggle Features
다이내믹 브랜칭은 셰이더나 컴파일러 특화 셰이더 중 어느 곳에서든 사용할 수 있음. 많은 경우 언리얼 엔진에 의해 처리됨.
스태틱 스위치가 있는 머테리얼을 사용한다면 이런 문제에 배수를 더하는 거라서 또 관리가 필요해짐. 그래서 보통 머티리얼은 작은 수를 사용하 작은 빈도로 쓰는 편이 나음. 그러면 효율적인 최적화가 이루어지면서 렌더링도 훨씬 효율적이 되는데 머티리얼의 종류와 숫자가 많을 때보다 셰이더를 자주 바꿀 필요가 없기 때문임. 이건 대부분 CPU 퍼포먼스에 영향을 미치기 때문에 Quset 같은 모바일 하드웨어나 저사양 PC 가상현실 어플리케이션에서 더 극명하게 나타남.
For 90 FPS
FPS가 90일 때는 프레임을 놓치기 전에 CPU 시간이 딱 11ms만 주어진다는 것임.
Lighting
라이팅은 VR 렌더링에서 퍼포먼스에 가장 큰 영향을 주는 요소 중 하나임. 이 점은 특히 모바일 렌더링에서 분명하게 나타나는데 라이팅 퍼포먼스에 엄청난 영향을 끼칠 뿐만 아니라 런타임 도중 그 어떤 프로퍼티도 조정할 수 없어지기 때문임. PC에서 실행되는 VR도 마찬가지로 다이내믹 라이트의 수를 줄여 씬을 최적화하는게 최선임.
라이트는 총 세가지 유형으로 나뉘는데 각각 스태틱, 스테이셔너리 그리고 다이내믹임.
Static Lighting
스태틱 씬의 라이팅 메서드 중에서 계산량이 가장 적음. 그렇기 때문에 라이트 중 대다수는 바로 이 방식이 차지함.
스태틱 라이트의 기여도는 단순히 라이트 매스가 간접광을 계산할 때 추가되며 텍스처로 구워짐. 즉 런타임에는 이런 라이트들을 렌더링할 고정 퍼포먼스 값이 생기게 됨. 이런 Baking 프로세스는 개발 과정에서 일어나기 때문에 오로지 반복처리 시간과 프로젝트가 사용하는 공간량을 통해서만 영향을 미칩니다.
스태틱 라이트는 모든 컬러와 밝기를 가질 수 있으며 Point, Directional, Spot, Rectangle 등 사전 정의된 라이트 형태 중 무엇이든 될 수 있음.
새도와 간접광도 계산할 수 있어서 숙련된 라이팅 아티스트라면 스태틱 라이트만 가지고도 아주 실감나는 라이트를 만들어 냄.
스태틱 라이틑 퍼포먼스가 높지만 퀄리티는 낮은 선택임. 다이내믹 오브젝트에는 영향을 주지 않음. 다이내믹 오브젝트의 경우 언리얼에서 비슷한 효과를 낸 다음 그 앰비언트 라이팅을 저장함. 이렇게 가장 정확하게끔 계산된 라이팅이 무버블 오브젝트에 적용됨.
스태틱 라이팅이 타 라이팅과 다른 점은 새도가 표면에 구워지는 방식과 그 표면을 움직였을 때 나타나는 결과임. 스태틱 요소를 움직이면 라이트 맵이 무효화가 되면서 라이팅을 다시 구워야함. 라이팅을 다시 구우면 다시 올바르게 보임.
Dynamic Lights
다이내믹 라이트는 모든 계산을 런타임에서 진행함. 그렇기 때문에 가능한 최소화하는게 최선임. 좋은 예로는 손전등이나 횃불처럼 움직이는 오브젝트나 캐릭터에 쓰는 것임.
다이내믹 새도는 새도 맵 렌더링 기법으로 구현됨. 이 방법에는 그림자 영향권 내에서 그림자를 드리우는 모든 요소에 추가 렌더링 패스가 필요함. 이로 인해 프레임별 퍼포먼스에 상당한 영행이 미치게 됨. 그러니 이 선택지는 스테이셔너리 라이트에 다이내믹과 스태틱 라이트의 효과가 모두 필요할 때만 사용해야함.
Stationary Lights
두 라이트(+ Dynamic Lights)는 오브젝트의 표면 디테일에 나타날 때 모든 오브젝트에 라이트를 드리움.
Free Computed Bounce Lighting도 만들 수 있음
스테이셔너리 라이트나 다이내믹 라이트가 렌더러에 오버랩될 경우 추가 작업이 많이 필요하다는 것임.
스테이셔너리 라이트는 네개까지만 오버랩 될 수 있으며 그런 다음에는 다이내믹 라이트로 자동 변환됨. 이 경우에 PC 에디터에서 경고가 표시됨. 그러니 다이내믹 라이트의 최대 렌더링 거리를 꼭 정의해 두고 영향 반경을 최대한 줄여야함.
Reflection Capture는 씬의 360도 스냅샷을 취해 해당 스냅샷의 라이팅 디테일을 다이내믹, 스태틱 오브젝트에 적용함. 여기서 짚고 넘어갈 점은 리플렉션 캡처의 세팅이 모든 프레임을 캡처하도록 설정되면 안된다는 것임.
HMD에 뭔가 그려지기 전에 언리얼 엔진은 애초에 뭐가 렌더링 될지 결정해야함.
기본 개념은 씬에 있는 오브젝트가 플레이어에게 보이지 않을 거라면 렌더링에서도 제외될 수 있다는 것임. 그래서 CPU 및 GPU 시간을 모두 절약할 수 있음.
GPU Time
렌더링해야하는 트라이앵글이 줄어들면 감소하여 계산 및 메모리 액세스 시간도 함 줄어듬.
Quest와 같은 모바일 GPU의 경우 이건 배터리 절약에도 기여할 수 있음.
CPU Time
렌더링해야하는 트라이앵글이 줄어들면 언리얼 엔진에 구성될 데이터가 줄고 그래픽 API로 보내지기 때문임.
DirectX 12 이전 버전이나 OpenGL과 같은 구형 그래픽 API의 경우 CPU, 그래픽 API와 드라이버 퍼포먼스에 큰 영향을 주는 요인들 중에서 엔진만으로 제어할 수가 없는게 있음. 여기서 DirectX와 Vulcan이 렌더링 처리 방식에 대한 제어권을 더 제공하여 상당한 절약의 여지를 남겨줌.
View Frustum Culling
뷰 프러스텀 컬링은 각 오브젝트 주변의 Lighting Free Computed Bounding box를 view frustum에서 테스트함.
화면 가장자리와 VR 카메라의 위치에 의해 이루어짐. 엔진은 양쪽 눈에 대한 단일 프러스텀을 계산할 수 있음. 타이트 바운딩 박스를 지닌 오브젝트 다수로 거대한 레벨 구조체를 만든다면 효율적인 뷰 프러스텀 컬링을 보장할 수 있음. 하지만 지오메트리를 지나치게 많은 메시로 나눈다면 부작용이 발생해서 드로 콜수와 CPU 시간을 높이고 퍼포먼스를 낮추는 부작용이 발생할 수 있단 걸 명심해야함.
일반적으로는 대부분의 메시에 트라이앵글을 300개 이상 두는게 좋습니다. 또 하나 염두해둘 점은 소형 오브젝트 하나를 여러번 중복 사용해 구성하면 단일 드로콜 만으로 한꺼번에 일괄 처리할 수 있음. 이 역시 크게 절약 할 수 있지만 뷰 프러스텀 바깥에 있는 오브젝트까지도 한꺼먼에 드로 되므로 결국 퍼포먼스에 영향을 미칠 수 있다는 점도 명심해야함. 여기에 오클루전 컬링으로 리소스를 더 절약할 수 있지만 여기에는 퍼포먼스에 대한 더 큰 영향이 따름.
Occlusion Culling
본질적으로 오브젝트간 오클루전 여부에 대한 실시간 확인임. 그러니까 굳이 안보이는 오브젝트를 렌더링할 필요는 없다는 걸 파악하여 씬이 퍼포먼스를 높이는 것임. 하지만 상세 묘사된 방처럼 오클루전이 적은 씬의 경우 오클루전 컬링만으로는 큰 퍼포먼스 개선을 내지 못합니다.
언리얼 엔진의 기본 설정은 복잡한 씬에는 잘 적용되지만 콘텐츠에 따라 조정하거나 비활성화하는게 더 나을 수 있음
이상적으로 자신의 콘텐츠를 분석한 다음 다수 프레임에 따른 퍼포먼스 영향을 살펴보고 언리얼 엔진의 오클루전 컬링이 다수의 프레임에 걸친 CPU 시간 급증을 방지하는데 도움이 되는지 확인한 다음 적용하는게 좋음.
PreComputed Visibility Volume
오클루전 컬링의 대체제
월드 세팅에서 활성화해야함. 또한 비저빌리티 셀 크기를 조정할 수 있는데 셀 크기가 작을수록 컬링 효율성은 더 나아지지만 대신 대량의 데이터를 생성해 내므로 메모리 소모와 빌드시간이 크게 증가함.
빌드가 끝나면 레벨에는 오브젝트의 비저빌리티를 위해 트레이스된 소구모 볼륨이 다수 포함되었을 것임.
이 프로세스는 오브젝트가 시야에 있는지 없는지 미리 결정함.
PreComputed Visibility Volume은 기존 모바일 게임에는 필수적이고 VR 타이틀에서 드로수를 줄이는데 굉장히 유용함.