Post Lists

2018년 12월 5일 수요일

Shadow Mapping하기 in Deferred Rendering

http://www.codinglabs.net/tutorial_opengl_deferred_rendering_shadow_mapping.aspx

Deferred Rendering Shadow Mapping

이 튜토리얼에서, 나는 deferred renderer에서 구현된 shadow mapping 기법을 보여줄 것이다. 이 튜토리얼은 이전의 것인 Simple Deferred Rendering in OpenGL에 기반을 둔다; 나는 강하게 너가 이 튜토리얼을 나가기전에 읽을 것을 추천한다, 대부분의 코드가 공유되기 때문이고, 나는 다른 튜토리얼에서 이미 다뤄진 것을 보여주지 않을 것이다.

Shadow Mapping은 실시간 렌더링 엔진에서 오늘날 가장 널리 사용되는 기법이다. 거의 모든 게임은 그것의 그림자들을 렌더링하기 위해 일종의 shadow mapping technique을 사용한다. 비록 종종 실제 구현은 우리가 이 튜토리얼에서 보게될 basic shadow mapping의 확장에 의존할지라도. 몇 가지 좀 더 고급 구현은 Cascade Shadow Mapping, Soft Shadow Mapping, Parallel Split Shadow Mapping, 등이 있다. 이 튜토리얼에 대해, 우리는 모든 이러한 기법들이 사용하는 기본 아이디어를 이해하려고 할 것이다. 그리고 이 기본 기법은 그림자를 렌더링하는데 유용한 정보를 인코딩하는 texture(map)을 사용할 것이다.

한 픽셀이 그림자에 있는지 또는 만약 그것이 주어진 빛으로 비춰지고 있는지를 결정하는 것은 visibility problem이다. 우리가 테스트하기 원하는 것은 만약 world에 있는 그 특정한 점이 보이거나 또는 light point of view로 부터 보이지 않는다면, 우리는 우리가 스크린에 그리려는 모든 픽셀에 이 아이디어를 적용한다. 따라서 우리가 하려고 하는 것은 각 픽셀이 world space에서 어떤 위치에 매핑되어있는지를 계산하는 것이다. 우리가 position만 가지기만 한다면, 우리는 light로 다시 ray를 날릴 수 있다. 만약 그 ray가 방해되는 거 없이 light에 도달할 수 있다면, 그 pixel은 빛 안에 있고, 그렇지 않다면 그림자 안에 있다. 아래의 사진을 보아라 (Figure 1). 너는 그 두 점이 카메라로부터 둘 다 보이지만, light로부터는 하나만 보인다.

그래서 이제 우리는 그 원리를 알았다. 우리는 연습해볼 수 있다. pixel이 (world에서 다시 매핑되는) light position에서 보이는지 안보이는지를 결정하는가? 많은 방법들이 있지만, 우리가 구현하려는 것은 scene의 depth를 렌더링하는 GPU의 능력을 이용하는 것이다. 그래서 만약 우리가 LIGHT POSITION에서 상상의 카메라를 설정하고 우리가 light로부터 보이듯이 scene의 depth를 렌더링한다면, 우리가 얻는 것은 많은 거리를 포함하는 텍스쳐이다. 이 shadow map의 모든 픽셀은 world space에서 다시 매핑될 수 있고, 너에게 그 light가 무슨 픽셀을 보는지, 그 점이 light 그 자체로부터 얼마나 멀리있는지를 말해줄 것이다. 아래의 그림 2를 보아라. 첫 번째 P1은 카메라와 라이트의 뷰로부터 둘 다 보인다. 그래서 만약 우리가 그것을 렌더링한다면, 우리는 또한 그것의 월드 위치를 계산하고, 그러나서 빛으로부터 거리를 계산한다면, 우리는 shadow map에서 저장된 거리와 비교할 수 있다. 우리가 P1의 거리를 비교한다면, 우리는 우리가 계산한 값이 map에 포함된 같은 값이라는 것을 알 것이다 (map에서 우리가 depth를 저장하는 방식 떄문에 몇 가지 에러가 있다). 이것은 왜냐하면 그 픽셀이 light의 관점으로부터 보이기 떄문이다. ~~ (basic shadow mapping)

이게 shadow mapping을 구현하는데 필요한 모든 것이다. 샘플 코드를 봐보고, 그것을 가능한 명확하게 만들자.

1 나는 처음 부터 마지막까지 코드를 보여주려고 않을 것이지만, 대신에 다양한 기능을 고르고, 무엇을 하는지 설명할 것이다. 그래서 렌더링 함수로부터 시작해보자.

시작해서, 우리는 shadow map을 얻길 원한다. 그러므로, 우리는 카메라를 light 포지션에 위치시키고, 그것을 scene을 바라보도록 방향을 바꾼다. 우리는 또한 shadow mapping을 할 때 CCW에서 CW로 flip을 한다.  이것은 모든 오브젝트가 "closed"되는한 작동하는 좋은 트릭이다. CW로 바꾸는 것은 그 오브젝트를 "inside out으로 렌더링하는데, 이것은 우리가 거리를 비교하는데 back face를 사용할 것을 의미한다. 이것은 일반적으로 shadow mapping에 나타나는 shadow acne를 줄인다. 이것은 반드시 해야하는 것은 아니다. 그것은 대부분의 겨웅에 조금 도움이 된다, 그러나 다른 곳에서 악화된다.

우리는 그러고나서 모든 모델들을 shadow map에 렌더링한다. 우리는 그 shadow map이 한 순간에 어떻게 만들어지는지를 체크할 것이다. 왜냐하면 이제 우리가 알 필요가 있는 모든 것은 여기에서우리가 모든 모델들의 depth를 텍스쳐에 렌더링하는 것이기 때문이다. 일단 우리가 shadow map으로 하는게 끝나기만 하면, 우리는 그 행렬을 저장하고 모든 것을 reset한다.

우리는 어떤 local 변수들에서 행렬들을 저장하는데, 왜냐하면 우리가 그것들을 world에서 pixel들을 재 사영시키는데 쉐이더에게 보낼필요가 있기 떄문이다. 그리고 light clip/projection space로도 보내야 한다. 우리가 또한 그 renderer를 face를 CCW로 렌더링하도록 되돌려야 하는 것에 주목해라.

-------------------------------------------------------------------------------------------
뭐 이정도면 내가 생각해놓았던 파이프라인이 맞다고 생각한다.
나는 내 쉐이더에 DirLight가 여러개가 될 수 있도록 해놓았는데,
그에 따라서 해당 DirLight의 LightViewProjMatrix를 또 보관해야할 것이다.

댓글 없음:

댓글 쓰기