Post Lists

2018년 12월 6일 목요일

Shadows in deferred rendering

https://gamedev.stackexchange.com/questions/25436/shadows-in-deferred-rendering

질문:
나는 deferred rendering에 관한 몇 가지 자료들을 읽었고, 나는 그것의 요지를 이해했다고 생각한다. 그러나 내가 이해하지 못한 것은 그것이 어떻게 쉐도우를 성취하냐 이다. 내가 알기로, G-buffer는 각 light에 대해 shadow map을 만드는 것을 포함하지 안흔다. 그래서 나는 lighting pass가 각 픽셀이 가려져있는지를 인식하는 것에 대해서 혼동이 된다. 결국, 카메라의 관점에서 보이는 주어진 픽셀이 실제로 어떤 주어진 light의 관점으로 부터 보이지 않을지도 모른다, 그리고 그 가려진 도형은 카메라의 관점으로부터 안보일지도 모르고, 그러므로 그것에 대해 G-buffer에 쓸 게 없다.

만약 너가 shadow maps를 렌더링하기 시작한다면, 그러면 그것은 forward rendering과 꽤 같은 것처럼 보인다. 너는 모든 light가 shadow maps를 그리도록 scene에서 모든 기하들을 렌더링한다.

그래서 어떻게 deferred rendering이 forward rendering과 같은 shadows를 해내냐?

답변1:
Deferred shading은 그맂마에 대해 어떤 특별한 것을 하지 않는다. 너는 여전히 그 shadow maps을 보통 렌더링할 필요가 있고, 그러고나서 각 light를 적절한 shadow map이 texture로 바인딩 된 채로 렌더링 할 필요가 있다.

그것은 forward rendering보다 더 좋은데, 왜냐하면 너는 main view에서 lighting을 적용하기 위해 그 scene을 다시 그릴 필요가 없기 때문이다. shadow map을 그리는 것은 main view에서 더 많은 passes를 그리는 것 보다 훨씬 더 싸다. 왜냐하면 너는 어떤 픽셀 쉐이딩도 할 필요가 없기 때문이다. 그리고 shadow maps는 종종 scene보다 덜 포함한다 (너는 많은 것들을 버릴 수 있다).

사람들은 가끔씩 한 개의 light에 대해 deferred shadows를 한다, 일반적으로 main directional light. 이것을 하는 주된 이유는, cascaded shadow maps 또는 같은 light에 대한 다양한 shadow maps를 사용하는 또 다른 접근법을 사용하려고 하는 것이다. 너는 G-buffer에서 shadow mask에 대한 한 채널을 보유할 수 있따 (비춰지면 white, 그림자가 있으면 검은색) 그리고 모든 cascaded shadow maps를 이 G-buffer channel에 적용한다; 그러고나서 그 light에 대한 쉐이더는 그 shadow mask를 일고, 그것을 light color와 곱한다. 이것은 shading으로부터 shadows를 분리시키기 때문에 좋다. 그러나 너는 여전히 모든 같은 shadow maps를 그리고 있다.

답변2:
음, shadow map이 무엇일까? shadow map은 텍스쳐인데, 간단한 질문에 답하는 texels들이다: light로 부터 무슨 거리에서, texel에서 나타내어지는 방향을 따라, 그 light가 가려지는가? 텍스쳐 좌푣르은 다양한 projective texturing 수단ㄷ들을 사용하여 생성되고, 특정한 shadow mapping algorithm에 의존한다.

Projective texturing은 간단히 한 오브젝트를 텍스쳐의 공간으로 변환시키는 방법이다 (그리고 그렇다, 나는 그것이 뒤로 가는 걸로 들린다는 것을 안다, 그러나 그것이 작동하는 방식이다). 쉐오두 매핑 알고리즘은 몇 가지 다른 종류의 transform을 사용한다. 그러나 궁극적으로, 이러한 것들을 한 공간에서 다른 곳으로의 변환이다.

shadow map을 렌더링할 때, 너는 너의 도형들의 정점을 취하고, 그것들을 standard 렌더링 파이프라인을 통해 변환한다. 그러나 카메라와 projecion 행렬들은 너의 light position과 direction을 위해 설계되어져있따, view position과 방향이 아닌.

shadow map으로 forward rendering을 할 때, 너는 그 오브젝트들을 보통 렌더링하는데, 그 정점을 view camera space로 변환시키고, viewing projection matrix로 변환시킨다. 그러나, 너는 그 정점들을 너의 light camera and projection matrices로 변환시킨다, 그리고 그섣르을 fragment shader에 per-vertex data로서 넘긴다. 그것은 projective texturing을 통해 shadow texture에 접근하기 위해 그것들으 사용한다.

여기에 중요한 점이 있다. projective texture access는 그것이 텍스쳐에 접근하는 위치가 그 표면에서 점과 light 사이의 방향을 나타내도록 설게되어져 있다. 그러므로 , 그것은 fragment가 렌더링되었을 때 occlusion이 발생한 깊이를 나타내느 texel를 가져온다.

그러나 이 파이프라인에 특별한 것은 없다. 너는 그 정점 위치들을 shadow texture로 바꿀 필요가 없고, 그것들을 fragment shader로 보낼 필요가 없다. 너는 world-space veretx positions을 fragment shader로 넘기고, 그러고나서 fragment shader가 그것들을 shadow texture의 projective space로 변환하도록 한다. 당연히, 너는 많은 성능을 버릴것이다, 왜냐하면 너는 정확히 같은 텍스쳐 좌표를 쓸 것이기 때뭉니다. 그러나 그것은 수학적으로 실행가능하다.

참으로, 너는 그 view camera-space vertex positions를 fragment shader에 보낼 수 있따. 그러고나서 그것을 그것들을 world로 변환하고, 그러고나서 light camera-space로 바꿀 수 있고, 그러고나서 projective shadow texture로. 너는 모든 그러한 transformation을 한 행렬에 넣을 수 있다 (너의 shadow projection algorithm에 따라). 또 다시, 이것은 너에게 너가 이전에 가졌떤 것을 정확히 준다, 그래서 forward rendering할 떄, 그것을 할 이유가 없다.

그러나 deferred rendering에서, 너느 이미 view camera-space vertex positions을 가지고 있다. 너는 많은 메모리와 bandwidth를 낭비한다, 그것들을 한 buffer에 써넣어서, 또는 너는 똑똑해서, 그것들을 재 계산한다, 그 depth buffe와 다양한 수학을해서 (나는 여기까지 안와봤찌만, 온라인에서 다뤄진다).

어느 방법이든, 너는 view camera-space positions를 가진다. 그리고 위에서 명시되었드싱, 우리는 한 행렬을 적용하여 view camera-space에서 shadow projective texture space로 변환한다. 그러고나서 ㅇㄴㄻㄴㅇ리ㅏ언ㄹ

--------------------------------------------
내가 찾는 것은 shadow map을 할 때 어떻게 draw call을 줄이는 것이다.

그러니까  코드로 하자면

for( all object in world)
    dirLight.renderDepthShadowMap();

for(all object in world)
    deferred.rederGbuffer();

이렇게 될 텐데, 저 두 for문을 합쳐야 draw call을 줄이게 되고, 성능을 아끼지 않을 까 생각이든다.

댓글 없음:

댓글 쓰기