Saturday, May 8, 2010

Signal processing with post-filtering in RenderMan (1)

3D Rendering algorithms에 대해 깊숙히 들어가다 보면 renderer 성격과 상관없이 어디에서나 만나게 되는 것중에 하나가 이 signal processing과 연관된 anti-aliasing이 아닐까 한다. 넓게 보면 2D, 3D를 떠난 모든 raster computer graphics 전반에 걸쳐 있을 뿐만 아니라 3D CG rendering 과정은 물론이고 연관된 여러 illumination algorithms에 있어 중요한 부분이 아닐 수가 없다. 더나가 이런 signal processing에서 파생된 spherical hamonics 원리를 이용한 여러 illumination 효과까지, 그 이해의 필요성은 말 할 것도 없을 것이다.

Rasterization, 즉 The process of generating an image from a model in raster-space로 간단하게 Rendering in 3D computer graphics을 정의 할 수 있 듯이 결국 original signal with vector information in 3d space을 raster-space로 perspective projection 시키는 point sampling의 최종 목적지, 즉 the intensity of the image at some X-Y coordinate point within the pixel로 가면서 aliasing은 늘 따라 다니는 동반자가 될 수 뿐이 없게 되지만 우리 눈이 capture 할 수 없는 영역 밖으로 그 aliasing을 minimalize 시키므로 극복해 나갈 수 있게 되는 것이다. 그 중 오늘은 signal processing과 연관해서 point sampling 후 이어지는 post-filtering에 중점을 두어 얘기를 시작 하도록 하겠다.

먼저 일반적인 rendering in 3D CG에서 signal precessing을 전체적으로 크게 보면 아래와 같을 것이다.

original signal -> pre-filtering -> point sampling -> post-filtering -> final pixel.

Original signal을 sampling and reconstructing을 통해 aliasing 없이 최종 pixel에 도달하게 만들어야 하는데 있어 가장 중요한 목적은 low frequency signal은 손실 없이 그리고 aliasing의 주범인 high frequency signal을 aliasing and detail lose 사이에서 가장 적절하게 capture하여 pixel로 reconstructing을 하는데 있다고 볼 수 있겠다.

Nyquist frequency theory (It has to be sampled at more than twice the frequency of the original signal.)에 의해 A pixel안에 다수의 samples(surper-sampling, sub-sampling 혹은 multi-sampling이라고도 함)을 capture하게 되는데 이는 up sampling으로써 high frequency data까지 capture가 가능하게 되지만 여러 aliasing errors을 피하기 위해 다시 역으로 low pass filtering을 통해 down sampling 하게 하므로 그 capture 해온 high frequency data에서 생기는 aliasing을 막는 동시에 lower frequency data는 잃지 않게 하면서 amplitude(color) reproduce를 해야한다. 그래서 rendering에서는 weighted average of samples from both inside and outside the area covered by the pixel 로 post-filtering을 해주게 되어 final pixel를 얻게 되는 것이다.

여기서 위의 up sample된  sub-samples를 filter weighting function을 거쳐 가게 하는데 있어 이런  signal(data) 다루기 편한 상태로 만들어야 하는게 우선시 되겠다. signal은 읽혀지는 방식에 따라 time domain(CGI에서는 observing signals in sptial domain, like as pixels on a screen)과 frequency domain이 존재 하는데 대부분의 신호 처리는 연산량과 편리함을 위하여 fourier transform(fft)을 통하여 time(or spatial) domain을 frequency domain으로 변환 혹은 inverse Fourier transform 후 계산을 하게 된다.

Fourier theory states, that a periodic signal can be seen as a sum of sine waves with different ferquencies, amplitudes, and phases. More important is to understand that some operations are much easier to do in the frequency domain than in spatial domain, and vice versa.

즉, time(spatial) domain은 가로축이 time(space)이고 frequency domain은 가로축이 주파수가 되는데 (세로축은 amplitude(color)) 따라서 spatial domain에서는 time(space)에 따라 신호가 어떻게 변하는지를 볼수 있고 frequency domain에서는 이 신호에 각각의 주파수 성분들이 얼마나 많이 들어 있는지를 볼 수 있게 된다.

이는 filtering 시 그 signal은 frequency domain 안에서 쉽게 higher frequency data를 없앨수 있지만 time(sparial) domain에서는 그리 쉽지가 않다. 그래서 filter weighting function(weighted average of the signal in the area of the pixel)는 Fourier transform 통해 frequency domain로 전환후 적용을 하게 되는 것이다. Frequency domain에서 가장 이상적인 filter의 모습은 step 형태가 되겠는데 이는 간단하게 higher frequency signals을 lower frequency data의 손실 없이 제어를 하게 되겠다.

To perform the filtering, we need to calculate the distance from the center of the pixel being filtered, to each sample point location, and use that to get a sample weight. The data for that sample is then accumulated using the weight. When the samples have all been processed in this way, the result is divided by the total weights of all samples that contributed and this will be the final data stored on the pixel, and passed onto the exposure stage. 

다음 글에는 RenderMan과 직접적으로 연관해서 post-filtering에 대해서 한번 살펴 보도록 하겠다.                    
계속.....

Monday, May 3, 2010

Memory considerations for speed/memory trade-offs in RenderMan

우연히 모 CG싸이트에 답글을 올리다 생각난 김에 memory consumption in renderman에대해 구체적으로 정리를 해 보겠다. 구체적인 주제는 renderman에서 rendering 과정시 motion blur가 memory consumption 측면에서 어떻게 영향을 미치는지가 되겠는데 motion blur는 상황에 따라 너무 다르기에 rendering 외적인 요소는 제외하고 시작 하겠다.

또 하나 일반적으로 알려져 있는 bucket size/maximum grid size를 통한 deal은 어디서나 쉽게 찾아 참조 할 수 있으니 넘어 가겠는데 참고로 하나만 얘기 하자면 bucket size는 rendering 시작부터 끝까지 전반에 걸친 기준이 되지만 grid size는 shading 과정에서 SIMD execution시 계산하는 unit이 되어 shading 속도와 밀접한 관련이 있겠다. (물론 dicing 후의 sub-geometry, 즉 a grid size와도 연관되지만 그리 shading에서의 영향력과 비교 될 정도는 아니기에....) Larger grids require larger temporary variable buffers for shading and produce large increases in the number of active micropolygons.

직접적으로 motion blur와 관련된 유일한 option으로 motion factor가 있겠는데 이는 blur되는 현상에 high frequency shading rate가 그만큼 필요로 하지 않기에 motion path 길이에 따라 shading rate를 높여 shading에 드는 memory, CPU, 비용을 optimization 한 것이다. (Increases shading rate based on length of primitive blur in screen space.) shading rate를 높이면 생성해야 하는 micropolygons 개수는 줄어 들어 shading processing을 좀 더 가볍게 가겠지만 sampling processing에서 생성되는 또 하나의 memory 포식자인 visible-point lists에는 아무런 영향을 주지는 않을 것이다.

무엇보다 간단히 memory consumption during rendering이 많이 이루어지는지 processing 별로 간단히 살펴 보면, 먼저 geometry processing에서는 grids and micropoygons의 개수가 가장 큰 영향을 끼칠 것이고, shading process에서는 각종 image-based caches(예:textures, shadow, etc) and point-based caches(예:point cloud, brick map, etc)와 shading code and variables이 있겠고 마지막으로 memory  포식자인 sampling & hiding 과정시에 생성되는 visible-point lists가 있겠다. 여기에서 rederman의 강력한 특징증에 하나인 Grids and micropolygons are discarded in memory as soon as processed 효과는 memory 공간을 많이 잡아 먹는 visible-point lists를 위한 공간 확보로 이어지면서 renderman만의 효율적인 memory 사용이 가능해 지게 되는 것이다.

자, 그럼 motion blur가 어떻게 memory에 영향을 주는지 살펴보면 우선 shutter angle내에 움직이는 motion path만큼 geometry의 bounding box가 커지면 displacement bounding box가 커지는 것과 같은 이치로 memory를 잡아 먹게 되는데 이는 더 많은 geometry를 dicing과정에 끌어들이게 되면서 memory consumption이 오게 되는 것이다.

여기서 또 하나의 renderman만의 강력한 매력이 있겠는데 shading 과정내에서는 motion blur와 상관없이 똑 같은 계산이 이루어진다는 것이다. shading processing에서 motion blur 때문에 엄청 버거워지는 pure ray-tracing based renderers와 상당히 비교되는 부분이 아닐수 없다.

마지막으로 위에 언급 했던 visible-point lists의 증가가 있겠는데, 이는 motion blur을 쓰게 되면 자연스럽게 sampling rate를 감소 시키면서 samples의 개수가 늘어 나게 되는데, 늘어나는 sample 개수 마다 visible-point lists도 덩달아 늘어 나게 되면서 memory usage를 증가 시킬 것이다. 만약 그 geometry에 transparency가 많이 쓰였다면 기하 급수적인 visible-point lists의 증가는 막을 수 없을 것이다. 이런 transparency geometry가 층층히 쌓이는 대표적인 예가 hair나 fur가 있겠는데 이런 memory 소모를 막고 싶다면 opacity culling threshold로 낮게 설정해 hider에서 opacity culling을 시켜 주어야 한다. 다만 hair에 있는 transparency 효과는 줄어 들 것을 감수해야만 할 것이다. 그렇치 않으면 bucket size를 줄여 주는 수 밖에....

이외에도 memory consumption을 optimization 하는 방식은 rendering 과정 밖에서도 여러가지 찾을 수 있겠는데 간단히 예를 들면 geometry 자체의 optimization, 불필요한 textures and shadow maps의 제거,  mip-map과 tiling이 가능한 caching의 사용 등등등....

hardware, software가 눈부시게 발전하여 rendering 시 더 많은 memory 사용이 가능한다 할지라도 지금까지 보왔듯이 날로 복잡해지는 scene과 photorealistic으로 가는 illumination 방식의 발전으로 지금이나 앞으로도 The issues of running out of memory during rendering은 모든 renderers가 늘 가지고 가야 하는 짐이라 말 할 수 있겠다. 이에 memory usage를 rendering 과정별로 이해하고 있다면 그에 따른 right solutions을 그때 그때 내릴 수 있게 될 것이라 생각한다.