Friday, March 19, 2010

Comparing Shadow Algorithms including deep shadow maps, traditional shadow maps, and ray-tracing shadow.

Lighting 하면서 가장 많은 문제를 일으키는 부분중에 하나가 shadow가 아닐까 생각 한다. 그런 부분일수록 그에 따른 원리를 이해하고 있다면 문제 발생시 배를 산에 올려 고치는 일은 없을 것이다.

먼저, 가장 오래되고(시대에 처진 느낌은 들지만) 아직도 유용하게 쓸 수 있는 Depth map shadow방식을 얘기한다면, 이는 shadow를 생성할 light를 shadow camera origin으로 놓고 그 camera로부터 해당 object사이의 distance 값, 즉 camera depth 값을 single sample per a pixel, image based buffer로 rendering 후 저장하여 해당 light에서 shadow 계산시 이를 real render camera에서 얻은 depth값을 같은 coordsys로 전환시키고 shadow bias 값만큼 z 방향으로 살짝 밀어 넣어 light에 hit 당한 object의 P 점에서 real render camera에서 본 z values와 대조하여 보다 멀면 light color값을 보다 보다 가까우면 shadow color 값을 가지게 하는방식이다.

70년대부터 쓰던 구닥다리 방식이라 여러 단점을 가지게 되는데 그 중에서도 single sample per a pixel로 비교 해야 할 sample 수의 부족으로 soft shadow를 갖기 위해선 일반적인 texture의 pre-filtering과 달리 선 대조 후 filtering(post-filtering) 과정을 percentage Closer filtering방식으로 aliasing 한 그 depth map 값에서 anti-aliasing 끌어 내어 soft한 shadow를 가지게 만든다는 것이다. 그래서 image based caching임에도 불구하고 위에 얘기 했듯이 sample 수 부족으로 선대조를 해야 하기에 pre-filtering (mip-mapping)의 이점도 못 얻어 먹어 불필요한 메모리 소모에서 대응 하질 못 하고 오직 tiling 효과만으로 미흡적인 메모리 사용에 대용 해야 했다. 그리고 라이팅 아티스트의 최대적인 매번 bias(depth map pixel + bias value)을 상황에 따라 적절하게 조절해야 한다는 것이다. 물론 과거의 하드웨어에서 오는 한계점을 극복한 많은 장점도 (camera view independent, re-usable, simple calculation, decoupling during rendering process, and cinematic flexibility) 많았기에 과거부터 쭈욱 잘 써왔던 것도 사실이다.

(참고로 만약 directional(distance) light shadow depth maps을 렌더링 할때 Auto focus 기능을 썼을 경우 자동으로 geometry의 bounding box를 체크하여 shadow map fame의 범위를 정해 주므로 만약 어떤 지오메트리가 큰 모션으로 shadow 영역에서 크게 움직이거나 필요 없이 멀리 있는 물체가 포함되어 있다면 shadow에 여러 문제점을 일으키는 원인이 될 것이다. renderman을 쓴다면 꼭 local coordsys를 shadow camera와 연결시켜 영역과 위치를 제어하여 쓰길 바란다. 생각외로 이 auto focus기능 때문에 많은 이들이 shadow를 생성 못해 불평하는 소리를 많이 들었다.)

하지만 현시대에 유행처럼 모든 것이 복잡해지고 photoreal로 가는 상황에서 high quality shadows로 가기에는 여러모로 부족하기에 기존의 traditional depth maps방식의 절차상의 장점들을 유지하면서도 상당히 파워풀하게 발전 되어 나온 것이 renderman의 deep shadow maps 방식이다.

이는 위의 traditional depth maps방식에서 거의 모든 단점들을 보완 했다고 보면 될 듯 싶다. x,y plane으로써 보면 무엇보다 single sample per a pixel 였던게 multi sub samples per pixel on a jittered grid가 가능해지므로 pixel보다 작아지는 detailed geometry상황(예: hair)에서 self-shadowing까지 noise artifacts 없이 정확성을 갖게 되었고 z 축으로 보면 z-depth로부터 sampling이 가능해져 visibility functions for each pixel을 계산해 내서  (The visibility function for each pixel is computed by taking a weighted combination of the transmittance functions as nearby sample points) 이를 different visibility function을 각각의 color channel과 함께 저장이 가능하기에 semitransparent surfaces and volumetric primitives(volumetric위한 transmittance functions은 따로 계산 후 합침)의 shadow가 가능하게 되었다. 그리고 traditional shadow depth maps에서 못 하던 prefiltering 즉 Tiling Mip-mapping으로 compression 시켜 caching을 하기에 lookup costs를 효과적으로 줄이게 되며 자칫 늘어나는 데이타량과 메모리관리에 효율적으로 접근 할 수 있게 되었다. 그외에서도 motion blurred shadow 지원 그리고 shadow bias에 좀 더 자유로워진 것 등등이 있겠다.

이런 advanced shadow가 가능하게 된 것은 micropolygon과 함께하는 Reyes Algorithm 있기에 가능 하다고 말 할 수 있겠다. 다수의 samples per pixel과 다수의 depth samples이 요구되는 deep shadow maps에서 shading과정이 없는 한 이런 scanline renderer에서는 traditional shadow depth maps과 비교 했을시 그리 힘든 것이 아니다. decoupling 된 sampling과정과 rendering과정에 이미 생성된 각각의 micropolygons의 z값을 갖다 쓰면 되기 때문이다. Mental ray도 detail shadow라고 말을 조금 바꿔서 나오긴 했는데 아무래도 ray-tracing based라 multi sampling에 한계가 있는 듯하고 자신들도 명확하게 설명을 못해 논것 같다. (써보니 정말 한숨만....)

이 deep shadow maps을 처음 나왔을때 써보고 space chimps에서 다시 사용하게 되었는데 놀랬던것은 traditional shadow map처럼 renderman viewer에서 preview가 가능 했던 것이다. 물론 visibility function value를 볼 수 있는 것은 아니지만 이것으로 troubleshooting에 쉽게 접근 할 수 있게 되었다. 사실 좀더 깊이 있게 이해하고 싶었지만 자료 부족과( 달랑 몇장짜리 픽사의 논문 하나) 이해력 부족, 특히 visibility function를 transmittance function이 어떻게 해나가고 filtering은 거기에 어떻게 적용 되는지 아직도 모르겠다.

위의 shadow map based 방식과 가장 많이 비교되는 Ray-tracing based shadow 방식은 빛과 그림자의 물리적인 성질에 가깝게 직관적으로 만들었기 때문에 코딩자체가 보다 간단하고 straight-forward 하다고 볼 수 있다. 가장 정확한 shadow를 얻지만 그런 만큼 이런 저런 단점 또한 갖게 되고 때론 너무 정확해서 문제가 된다. 원리를 간다히 얘기하자면 빛이 닿은 surface의 P점에서 역으로 ray를 light source를 향해 쏠 때 만약 다른 object에의해 block 되었다면 shadow color 값을,아무 거침 없이 light source까지 도달 한다면 illuminated shading 절차로 넘어 가게 될 것이다. soft shadow를 위해서는 distributed multi-sample rays를 쏴서 hit test를 해야 하는데 전에 언급을 했기에 생략 하겠다.

간단히 point light emitter에서 single ray만 쏠 경우는 지나치게 비현실적인 sharp한 shadow가 생성될 것이고 area light emitter에서 soft한 shadow를 생성하고자 할 경우는 콘볼륨의 다수의 rays를 light emitter를 향해 쏘아 blocking hit test를 해야 하기에 rendering time은 드라마틱하게 늘어나게 될 것이다.(전에 area light shadow의 계산 방식에 대해 얘길 했기에 여기선 생략 하겠다.) 게다가 ray-tracing shadow 연산은 rendering과정에서 구조상 가장 복잡한 shading 과정 내에서 계산을 하게 되므로 rendering시 메모리부터 CPU에까지 상당한 무리를 주게 되고 cinematic lighting flexibility에 자유롭지가 못하고 재사용이 가능한 상황에서도 재계산을 해야 하므로 비효율적인 소비가 이루어 지게 된다.

알겠지만 camera view dependent로 illuminated된 object가 camera가까이 오기라도 한다면 계산해야할 P점 개수가 늘어나기에 당연히 느려지겠고 반면 camera에서 멀어져 작은 빛 받는 면적이 적어 지면 depth shadow 방식보다 더 빨른 계산을 할 수 있게 될 것이다.

마지막으로 shadow의 종류라고 개인적으로 주장하지만 light emitter와 상관없이 독립적으로 계산되는 ambient occlusion과 reflection occlusion을 얘기 하면 원리는 multi-samples로 hit test를 하는 area light shadow algorithms과 비슷하겠지만 light emitter를 향해 쏘는 대신 전자는 surface normal을 중심으로 즉 R= normalize(faceforwad(N, I):을, 대신 후자는 R=reflection (I, N):를 써서 마지막에 hit한 ray의 개수를 총 ray 개수로 나누기 해서 얻은 퍼센트지 값의 invert 값을 luminance 값으로 쓰게 하는 방식이 되겠다. (개인적으로는 wrap light의 shadow를 위해 ambient occlusion 계산 방식으로 쓰고 있다. intersection test시 shading의 Oi 계산이 없기에 더 빠르다.)

(에고~ 이거 숨차네.)

1 Comments:

Blogger Unknown said...

많이 배워갑니다.

April 2, 2018 at 10:35 AM  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home