Graphics Programming
OpenGL 렌더링 엔진 일지 (2022.08 ~ 2022.09) 본문
나도 참 이 사이드 프로젝트를 징글징글하게 오래 붙잡고 있다. 최근에 여유 시간이 많아짐에 따라 미뤄뒀던 개인 프로젝트를 여러 개 나열해놓고 고민하다가, 이 OpenGL 프로젝트 먼저 집중적으로 진행하고 있다. 어느 정도 만족스러운 결과물이 나오면 CUDA, DX12/Vulkan 모던 아키텍처, 기타 렌더링과 무관한 프로젝트들로 옮겨갈 생각이지만, 다시 시간이 모자라게 되면 여가 시간에 내가 과연 이 모든 걸 할 수 있을까 모르겠다.
일루미네이션 리팩토링
이 작업으로 비주얼이 개선된 것은 아니지만, 여러 라이트 소스에 의한 direct lighting + indirect lighting (IBL) 을 모두 셰이더 실행 하나에서 처리하던 것을 개별 패스들로 분리했다. 추후 라이팅 패스를 개선하기 위한 준비작업이다.
// 예전 라이팅 의사 코드
Uniform UBO {
dirLights[MAX_DIR_LIGHTS];
pointLights[MAX_POINT_LIGHTS];
} ubo;
// 1. Read GBuffer
GBufferData gbuffer;
readGBufferData(gbuffer, texelXY);
// 2. Local illumination
vec3 radiance = vec3(0.0);
for each dirLight in ubo.dirLights:
radiance += calcDirLight(dirLight, gbuffer);
for each pointLight in ubo.pointLights:
radiance += calcPointLight(pointLight, gbuffer);
// 3. Global illumination (IBL)
radiance += getSkyIBL();
// 4. SSAO
radiance *= sampleSSAOMap();
원래는 이런 식으로 돌아갔는데, 먼저 direct lighting과 indirect lighting 패스를 분리해서 direct lighting 결과를 라이팅 렌더 타겟에 출력하고, indirect lighting은 그 렌더 타겟에 color blending ADD로 더한다. 지금은 indirect lighting이 아주 단순한 형태지만 추후 무거운 GI를 구현하게 될 경우 indirect lighting은 더 낮은 스크린 해상도에서 계산하고 업샘플링을 해야 할 것이다.
그 다음은 루프를 돌면서 광원마다 direct lighting 계산하던 것을, 셰이더 퍼뮤테이션을 분리하고 한번에 광원 하나만 계산하도록 바꿨다. 역시 렌더 타겟에 color blending ADD로 더한다. directional light는 계속 풀스크린으로 놔두고, 로컬 라이트들은 attenuation radius가 있기 때문에 화면 전체를 커버하지 않는 경우가 많다. 그래서 영향이 없는 픽셀들에서는 애초에 픽셀 셰이더를 실행하지 않아야 한다. 그 외에도 이렇게 하면 매번 gbuffer를 읽어야 해서 루프를 돌던 때보다 텍스처 샘플링 비용이 늘어난다. 포워드+ 셰이딩 엔진에서들 쓰는, 라이트 그리드 만들어서 컬링하는 방법도 있고... 아무튼 전부 장면에 광원이 너무 많아서 효율이 문제가 될 때의 이야기고, 단순히 토이 프로젝트니 그런 최적화는 나중에 해야겠다. 무엇보다 맨날 리팩토링만 했더니 막상 비주얼은 대학교 1학년 과제 수준이어서 최근에는 비주얼 개선에 집중하고 있다.
빌드 시간 단축
Sebastian Aaltonen가 새로운 렌더러를 만들면서 트위터에 개발 일지를 자주 적는데 CompileScore 플러그인을 이용해서 빌드 시간을 분석하면서 전체 솔루션 리빌드를 3초로 줄였다고 한다. (다시 찾아볼려고 해도 언제쯤 쓴 건지 못 찾겠다. 트위터 말고 블로그에 정리해줬으면...) 내 프로젝트는 빌드하면 1분이 넘게 걸렸는데, 문제가 되는 헤더를 알고는 있었지만 CompileScore를 돌려보니 해당 헤더가 빌드 시간에 주는 여파가 생각보다 더 컸다. GL device call을 래핑하기 위한 16000 ~ 20000줄 짜리 자동 생성 헤더를 2개 쓰고 있는데, 이것들을 include하는 헤더가 있고, 그 헤더를 렌더링 관련된 대부분 헤더에서 다시 include하고 있다. 애초에 이렇게 include하지 않도록 고칠 수도 있지만 그러려면 공수가 너무 커서 일단은 무거운 헤더들을 PCH에 넣었다. 지금은 대략 70초에서 30초로 줄었는데 궁극적으로는 10초 미만으로 줄이고 싶다.
여담이지만 언리얼 엔진도 빌드 시간 줄이는데 투자 좀 했으면 좋겠다. 회사에서 빌드 머신이나 인크레디빌드로 컴파일하지 않는 한 개인 PC에서 언리얼 엔진 개발 브랜치를 받아다 실시간으로 수정해서 컴파일하고 PR 날리고 하는 것이 너무 비효율적이라 할 엄두가 안 난다.
CPU 프러스텀 컬링
기초적인 기능이지만 귀찮아서 묵혀두다가 드디어 처리했다. 라이젠 6800U 노트북을 구매한 김에 노트북에서 돌려봤더니 렌더 쓰레드도 GPU도 비용이 너무 컸다. 베이스 패스와 옴니 섀도우맵 패스에서 안 보이는 물체들을 대충 컬링했고 특히 옴니 섀도우맵 패스의 경우 데모 월드에서 GL 디바이스 콜이 몇만 번 → 몇천 번으로 크게 줄었다. 궁극적으로는 GPU에서 컬링하고 indirect draw를 해야겠지만 이것도 비주얼 개선이 아니라 최적화일 뿐이라 나중에.
Transform Hierarchy
역시 기초적인 기능이지만 필요가 없어서 묵혀두다가 이번에 처리했다.
Area Lights
오랜 기간 열악한 퀄리티의 point light만 지원했는데 GPU Pro 5, SIGGRAPH 등을 참고해서 point light는 sphere light로 바꾸고 rect light를 추가했다.
|
|
|
기존 포인트 라이트 | 감쇠 개선 | point light → sphere light rect light 추가 |
조금 그럴듯해졌지만 아직도 관련 작업은 많이 남았다.
- IES 프로필 지원.
- 소프트 섀도우 지원. CSM과 달리 omni shadowmap은 필터링을 전혀 하지 않고 있다.
- rect light용 섀도우맵 지원.
- spot light, tube light 등 다른 형태의 광원.
- 섀도우맵 아틀라스를 통한 adaptive shadowmap resolution. 지금은 omni shadowmap을 cubemap array에 저장해서 모든 광원의 섀도우맵 해상도가 같다.
스크린 스페이스 리플렉션
이것도 GPU Pro 5를 보고 만들고 있는데 아직 버그가 많다.
HiZ 트레이싱에 버그가 있는 건 확실하고 책에 일부 설명이 틀렸거나 누락된 경우가 많아서 삽질을 하고 있다. 무엇보다 책에 동봉된 샘플 코드를 참고하라고 써있는데 책 홈페이지 가보면 정작 그 샘플이 없다. 책에 CD 끼워 팔던 때는 있었는데 소실된 것인지... 인터넷을 찾아보면 GPU Pro 5의 해당 챕터를 기반으로 구현을 시작했지만 예외 케이스가 있거나 예제 코드가 틀려서 직접 보완해야 했다는 개발 일지가 몇 개 있다.
그래픽스 프로그래밍을 처음 시작했을 때 GPU Pro, GPU Gems 같은 책을 읽고 원리는 알겠는데 구현은 못 하겠는 경우가 아주 많았는데, 물론 내가 부족했던 탓도 있지만 사실은 책 내용 자체가 부실했던 것이 아닐까 싶다. 지금 Gems류 책들을 읽어보면 오타도 빈번하고 설명도 SIGGRAPH 자료들에 비해 상당히 빈약한 경우가 많다.
한편 올해 SIGGRAPH의 루멘 자료를 보니 루멘의 HiZ 트레이싱도 내가 참고했던 GPU Pro 5의 바로 그 챕터에 기반하고 있었다. UE5 소스 코드에서 스크린 트레이스 패스가 어디 있는지는 금방 찾아낼 수 있지만, 안 보고 고치고 싶다.
그나저나 가장 오른쪽 사진의 경우에는 실내에 sky IBL이 차폐 없이 적용되어서 지나치게 밝고 플랫한 문제도 있다. 이건 언제 고치나... -.-;; 스카이 오클루전 솔루션을 구현하거나 로컬 라이트 프로브를 실시간으로 생성하고 로컬 프로브의 fallback으로서 sky IBL을 읽어오면 되는데 둘 다 공수가 큰 작업이다.
미친듯이 쌓여있는 백로그
언제 해볼지 기약이 없음
안티 앨리어싱 (TAA 직접 구현)수퍼 레졸루션 (FSR 통합)머티리얼 셰이더 어셈블리 시스템톤 매핑 리워크 + HDR 디스플레이- 랜드스케이프 + 폴리지
- 디퍼드 데칼
- Atmosphere (multiple scattering)
- 볼류메트릭 포그
- visibility buffer
- GPU skinning
- GPU 리소스 라이프사이클 관리 + 스마트 포인터
- 헤어 셰이딩
- 반투명
- 워터 렌더링
- ...