공부/Graphics, DirectX, 포트폴리오 구조

그림자 매핑(Shadow Mapping)

sudo 2022. 9. 17. 16:05

여기서 소개할 그림자 매핑은 최근 사용되는 그림자 매핑 기법중에 가장 기본이되는 기법이다. 사실 이 기법을 기반으로 발전된 여러가지 고급 기법들이 다음과 같이 이미 나와있다.

  • 캐스케이드 그림자 맵 : 그림자 매핑의 해상도 문제를 해결하기 위하여 영역별로 여러개의 그림자맵을 만드는 기법
  • 퍼센티지 클로저 필터링 : 그림자의 외곽선을 부드럽게 필터링 해주는 기법
  • 배리언스 그림자맵 : 하드웨어 텍스처 필터링이 가능하도록 깊이 값을 저장하는 방법

그림자가 생기는 원리

아래 그림 기준으로 1번 빛에서는 D앞에 가리는 물체가 없으므로 그림자가 생기지 않는다. 2번 빛은 B앞에 A라는 물체가 가리고 있으므로 2번 광선이 B의 표면에 만나는 지점에 그림자가 생길 것이다. C도 마찬가지로 A, B 물체에 가리니까 그림자가 생길 것이다. 단 중요한 것은 C의 표면에 그림자가 생기는 데에는 B 물체의 유무가 중요하지 않다. 이미 A의 존재만으로도 C와 3번 광선이 만나는 지점에서 그림자가 생길테니까. 

빛의 위치의 0이라고 하고 빛이 최대 비추는 거리를 1로두면 다음과 같이 상대적인 거리를 표현하면 다음과 같다

이것은 사실 빛의 위치에 카메라를 두고 깊이값을 계산한 것과 다름없다. 사실 그림자 구현도 이렇게 빛의 위치에 카메라를 두고 깊이값을 계산해서 써놓은 그림자 맵(Shadow Map)을 미리 만들어놓고, 실제 렌더링할 때 이 그림자 맵을 보면서 그림자를 그려줘야할 픽셀인지 아닌지 판단하는 것이다.

 

 

셰도우 맵에 깊이 값을 저장해주고 있는 셰이더. 이미 광원 위치에서의 뷰,투영 행렬을 C++코드에서 상수버퍼로 넘겨준 상태이다
Load로 가져온 텍스처는 이전에 그려 놓은 Shadow Map 텍스쳐이다

g_ShadowBias는 float같은 실수형 타입의 계산에서는 '==' 연산이 정밀도 이슈로 불안정하기 때문에 Bias를 둬서 Bias 범위 만큼의 허용 가능한 오차를 줘서, 현재 그리려는 픽셀의 깊이가 ShadowMap의 깊이 + 오차보다 크다면 그림자를 그리게 될 것이다.

 

* Shadow Map의 해상도가 높을 수록 좀 더 퀄리티가 나은 그림자가 나올 것이다

* Directional Light같은(ex. Sun) 경우, 투영 행렬을 만들 때 직교 투영 행렬을 만드는 것이 자연스럽다