[한정현 컴퓨터 그래픽스] 15장 쉐도우 매핑

이한결·2025년 3월 19일
0

[KUOCW]Computer Graphics

목록 보기
14/16

출처: https://www.youtube.com/watch?v=kCuEtQh91U8&list=PLYEC1V9tJOl03WLDoUEKbiYW_Xt4W6LTl&index=16
한정현님의 컴퓨터그래픽스 15장 강의를 기반으로 제작한 블로그입니다.

Shadow

모든 물체는 광원이 존재한다면 그림자가 생길 것 입니다. 그림자는 장면에서 물체를 이해하는데 도움을 줄 수 있는 요소이기도 합니다.

Shadow Mapping

GPU Rendering을 한번 진행하는 것을 하나의 pass라고 했을 때 shadow mappingtwo-pass algorithm 입니다.

첫번째 pass에서는 어느 부분이 빛을 받는지 조사하는 단계 입니다. Shadow map에는 빛을 받는 부분(하늘색)에 대해서 광원으로부터 얼마나 떨어져있는지(z)를 저장해둡니다.

두번째 pass에서는 실제로 그림자를 생성합니다. 우리가 q1q_1에 대해서 그림자를 생성할지 여부를 정하기 위해서 해당 점에서 광원까지 선을 긋습니다. 이때 해당 점의 shadow map의 z1z_1값과 방금 그은 선의 길이 d1d_1을 비교해서 선의 길이가 더 길다면 해당 점 이전에 어떤 물체가 존재한다는 것을 알 수 있습니다.

실제로 shadow mapping을 통해서 나타난 결과가 오른쪽과 같습니다. 바닥 부분은 빛을 받는 영역인데 검은색과 흰색이 번갈아 나타나면서 잘못된 결과가 나타난 것을 알 수 있습니다.

잘못된 결과가 나온 이유를 한번 살펴보겠습니다. 우리가 조사하고 싶은 점이 q1q_1이라고 했을 때 fragment이기 때문에 인접한 픽셀인 왼쪽 빨간색 점을 선택(nearest point sampling)합니다. 빨간색 점의 shadow map 값은 z1z_1이고, q1q_1에서 광원까지의 거리 d1d_1보다 작기 때문에 q1q_1은 그림자가 생깁니다. 실제로 물체가 없기 때문에 그림자가 생기면 안되는데 인접 픽셀로 이동하면서 문제가 발생한 것입니다.

q2q_2의 경우는 인접한 픽셀의 z2z_2값이 더 멀기 때문에 그림자가 생기지 않습니다. 이와 같은 이유로 위에서 바닥면에서 빛을 받는 영역과 안 받는 영역이 공존하게 됩니다.

해결 방법은 간단합니다. 원래 거리에서 bias만큼 빼줘서 실제로 z값보다 작아지게 만드는 것입니다.

간단한 방법에도 불구하고 위와 같이 결과가 잘 나타나는 것을 확인할 수 있습니다. 하지만 bias값이 설정해야 되는 값이기 때문에 어떤 값을 정하느냐에 따라서 결과의 퀄리티는 달라질 수 있습니다.

Shadow Map Filtering

픽셀의 수가 텍셀의 수보다 많기 때문에 8장에서 배운 nearest point smapling 방식을 이용해서 인접한 텍셀을 선택하도록 해보겠습니다. 이때의 결과가 오른쪽의 구인데 아래 보이는 사진처럼 nearest point sampling의 문제 anti aliasing 현상이 발생하는 것을 확인할 수 있습니다(약간 계단 형식의 결과)

이제 그러면 bilinear interpolation을 사용한 결과도 확인을 해야겠죠? 왼쪽 그림을 보시면 z값을 bilinear interpolation을 통해서 64라는 값을 얻었습니다. 이전에 nearest sampling을 할 때도 그림자가 없다고 판정되고, bilinear interpolation으로 64를 얻어도 80보다 작기 때문에 결과가 동일합니다.

이때문에 0과 1로만 빛을 표현하지말고 소수점 단위로 표현하자는 percentage closer filtering(PCF) 개념을 도입했습니다. 텍셀들의 각점에 대해서 z값과 d값을 비교해서 빛을 받으면 1, 받지 않으면 0으로 둡니다. 그리고 이 0과 1점들에 대해서 bilinear interpolation을 이용해서 q의 점을 0.58이라는 값을 얻게 됩니다. 이렇게 하면 이전보다 더 부드러운 결과를 얻게 됩니다.

Shadow Mapping implementation

실제로 shadow mapping 과정이 어떻게 진행되는지 살펴보도록 하겠습니다. 이전에 제가 shadow mapping은 two-pass algorithm 이라고 했는데, 강의에서는 첫번째 pass에서 어떻게 보이는 부분만 가려내는지 확인하는 알고리즘만 설명해주셨습니다.

우선 world space에 놓인 물체들에 대해서 광원으로부터 거리(d)와 z값을 구하기 위해서 light space로의 변환이 필요합니다. 기존에 view transform이 world → camera space 였다면 지금은 world → light space로의 변환을 합니다. 이 과정을 위해서 오른쪽에 lightViewMat(view transform) 과 lightProjMat(fov, ratio..) 값이 지정된 것을 알 수 있습니다.

이렇게 vetex shader를 진행하면 출력값을 gl_Position만 나오고 texture나 normal 값은 나오지 않습니다. 따라서 fragment shader는 할 역할이 없어지고, 이 position 값은 바로 output merger로 들어가서 z-buffering을 수행합니다. Z-buffering 과정에서 z 값을 비교하면서 어떤 부분에 빛이 다다르는지 필터링을 하는 과정을 진행하게 됩니다.

profile
열정으로 가득할 페이지

0개의 댓글