그래픽스에서 오브젝트에 명암을 부여하기 위해 빛을 연산하는 방식은 크게 3가지가 있다.
바로 포워드 렌더링, 디퍼드 렌더링, 포워드+ 렌더링이다.
(참고로 이 셋은 레스터화 렌더링에서 사용하는 것이고 레이트레이싱은 아예 다른 방식으로 렌더링을 수행한다.)
포워드 렌더링
포워드 렌더링이란, 오브젝트를 렌더링할 때 빛을 바로바로 적용하는 방식이다. 하나의 오브젝트를 렌더링할 때, 레벨에 30개의 광원이 있다면 모든 광원에 대해 빛을 계산하여 색상을 결정짓게 된다. 가장 단순하면서 기본적인 렌더링 방식이다. 이 렌더링 방식은 구현이 단순하지만, 단점이 하나 있다. 바로 모든 오브젝트의 빛 계산을 수행한다는 것이다.
예를 들어, 이런 상황을 보자. 뒤쪽에 사람이 있는데 앞에 있는 건물에 의해 가려진다고 해보자. 이 경우 건물에 대해서도 빛 연산을 수행하고 사람에 대해서도 빛 연산을 수행하지만 실제로 사람의 색상은 모두 버려지게 된다. (깊이 테스트에 의해 건물의 색상만 남는다.)
그러므로, 불필요한 빛 연산이 수행된 것이다. 완전히 가려지는 경우라면 오클루전 컬링 등으로 아예 렌더링에서 제외할 수 있겠지만 반만 걸쳐있는 경우라면? 이 경우 사람의 반쪽에 해당하는 픽셀에 대해선 불필요한 연산이 들어갈 수 밖에 없다.
이처럼 연산을 했음에도 실제로 렌더링이 되지 않는 경우가 발생하기 문제를 개선하기 위해 디퍼드 렌더링이 탄생하였다.
디퍼드 렌더링
디퍼드 렌더링이란 이름 그대로 렌더링을 늦추는 것이다. 오브젝트의 드로우 콜이 발생하면 바로 빛을 적용하고 렌더타겟에 그리는 것이 아니라, 화면에 실제로 그려지는 부분만 추출하여 빛을 적용하는 것이다. 즉, 가려지는 부분에서 연산의 낭비가 발생하지 않는 것이다.
그렇다면 어떻게 이런 것을 할까?
이렇게 멀티 렌더타겟 기능을 활용하는 것이다. 빛 연산을 바로바로 적용하는 것이 아니라 각 오브젝트의 렌더링을 수행할 때 DiffuseColor, Normal, Specular, Depth를 각각의 타겟에 기록한다.
모든 오브젝트가 다 기록되면, 마지막에 4개의 타겟을 이용해 하나로 합치는 것이다. DiffuseColor에 Specular, Normal, Depth를 활용해 빛을 적용하여 최종 렌더타겟에 출력하는 방식으로 말이다.
포워드 렌더링의 경우 드로우 콜이 발생한 오브젝트가 그려지는 픽셀 개수의 합이 Sum(P)이고 N개이고 광원이 M개라면 Sum(P) * N * M 만큼의 빛 연산이 발생한다.
하지만, 디퍼드 렌더링의 경우 오브젝트가 몇개든 화면 픽셀 개수 * M 만큼의 빛 연산만 발생하게 된다. 오브젝트 개수와 관계 없이 빛 연산이 수행되는 것이다.
이러한 특징으로 인해, 디퍼드 렌더링은 한 화면에 렌더링되는 오브젝트가 많을수록 포워드 렌더링에 비해 현저히 빠른 렌더링 속도를 보여준다. 하지만, 반대로 말하면 렌더링되는 오브젝트가 적다면 포워드 렌더링이 더 빠를 확률이 높다.
또한, 디퍼드 렌더링은 한 번의 렌더링에서 여러개의 렌더타겟을 사용하는 만큼 GPU와 CPU 사이의 높은 대역폭을 필요로 한다. 현대의 하드웨어 성능에서 사실 문제되는 부분은 아니지만 이게 모바일 환경에서는 조금 얘기가 다르다. 본인도 하드웨어를 잘 아는 건 아니지만 높은 대역폭을 요구할수록 발열이 심해지고 이로 인해 전력 효율을 크게 감소시킨다고 한다. 그래서 모바일 환경에선 디퍼드 렌더링을 잘 사용하지 않는다고 한다.
이 외에도 디퍼드 렌더링은 치명적인 문제가 하나 있는데, 반투명 물체를 처리하는 것이 매우 까다롭다는 것이다. 포워드 렌더링은 반투명 물체를 렌더링할 때 기존의 색상과 블렌드해주면 그만이지만 디퍼드 렌더링은 깊이만을 사용해 물체를 기록하기 때문에 반투명한 물체가 제대로 기록되지 않는다.
이러한 문제를 해결하기 위해 본인은 과거 프로젝트에서 렌더링 패스를 활용했었다. 불투명한 물체의 포워드 렌더링을 먼저 수행하고, 불투명한 물체의 디퍼드 렌더링을 수행하고, 마지막에 반투명 물체를 렌더링하는 것이다. (디퍼드 렌더링 자체에서 반투명을 해결하는 것이 매우 힘들다고 판단하여, 아예 반투명 물체는 별도로 렌더링한 것이다.)
반투명 물체를 먼저 렌더링하게 되면 디퍼드 렌더링 과정에서 그 뒤에 그려져야 하는 대상을 클리핑하기 때문에 반투명 물체를 가장 마지막에 렌더링해주었다.
포워드+ 렌더링
포워드 렌더링과 디퍼드 렌더링을 보면 둘 다 명확한 장단점이 있다.
포워드 렌더링은 오브젝트와 광원의 수가 많아질수록 빛 연산의 부담이 엄청 커지지만, 반투명 물체 등을 정확하게 렌더링할 수 있다. 반면 디퍼드 렌더링은 빛 연산이 오브젝트의 개수에 독립적으로 수행되기 때문에 상황에 따라 빛 연산을 크게 줄일 수 있지만 반투명 물체를 제대로 렌더링하지 못하는 등의 문제가 발생할 수 있다.
그렇다면, 포워드 렌더링에서 빛 연산을 최대한 줄일 수 있다면, 가장 좋은 결과가 아닌가? 하는 아이디어에서 나온 것이 포워드+ 렌더링이다.
먼저, 포워드 렌더링을 수행할 때 광원을 무식하게 모두 렌더링하는 것이 아니라 라이트 컬링을 한 뒤에 렌더링을 수행한다. 렌더링 전에 오브젝트에 실제로 적용이 될 광원만 걸러내 쉐이더에 전달하는 것이다. 이를 통해 불필요한 빛 연산을 줄일 수 있게 된다. 하지만, 하나의 오브젝트에서도 위쪽에는 광원이 20개가 적용되는데 아래쪽에는 10개만 적용되는 등의 상황을 생각해보면 불필요한 빛연산이 모두 사라지는 것은 아니다.
이를 위해 화면을 여러개의 타일로 쪼개고, 각 타일별로 적용될 광원을 걸러내는 것이 포워드+ 렌더링이다.
위의 그림처럼 화면을 타일로 쪼갠 뒤, 각 타일별로 적용되는 광원을 추출하고 해당 광원에 대해서만 연산을 수행하는 것이다. 이를 통해 오브젝트에서 수행하는 빛 연산을 최소한으로 줄일 수 있게 되는 것이다.
이 방식도 물론 단점은 존재하는데, 타일을 너무 크게 쪼개면 불필요한 빛 연산이 포함되는 수가 많아지고, 타일을 너무 작게 쪼개면 메모리 사용량이나 타일 처리 과정에서 발생하는 연산 횟수가 증가한다는 것이다.
즉, 너무 잘게 쪼개면 감소한 빛 연산보다 오히려 타일 관리 부분에서 더 큰 오버헤드가 발생할 수도 있다는 것이다. 그래서 적절한 타일 크기를 구성하는 것이 중요하다고 한다.
모바일 게임에서 높은 퀄리티의 그래픽 품질을 구현하려면 연산 부담을 최소화 해야 하는데, 디퍼드 렌더링의 경우 빛 연산이 감소하더라도 높은 대역폭 요구치로 인한 문제가 더 크게 발생할 수 있어 포워드 렌더링이 거의 강제되는 상황이었는데 Forward+ 렌더링을 잘 활용하면 훨씬 높은 수준의 최적화를 달성할 수 있어서 모바일 게임에서 종종 사용된다고 한다.
'그래픽스' 카테고리의 다른 글
컴퓨터 그래픽스 - 노말 매핑 (로컬 스페이스, 탄젠트 스페이스) (1) | 2024.12.02 |
---|---|
컴퓨터 그래픽스 - 우버 쉐이더 (Uber Shader) (1) | 2024.10.09 |
컴퓨터 그래픽스 - 투명도 처리 (알파 테스팅, 알파 블렌딩, 알파 소팅) (0) | 2024.06.18 |
컴퓨터 그래픽스 - LOD (Level Of Detail) (0) | 2024.06.16 |
컴퓨터 그래픽스 - 드로우 콜(Draw Call)과 배칭(Batching) (1) | 2024.05.21 |