Tuesday, April 27, 2010

Pixar’s Ed Catmull

"I don’t like hard rules at all. I think they’re all bullshit."

http://www.scottberkun.com/blog/2010/inside-pixars-leadership/

Friday, April 23, 2010

32 bit depth and super-whites as output for compositing

넓은 의미의 Compositing은 3D space에서 이루어지는 models와 lights의 illumination 현상을 rendering을 통한 2D space의 image-based caches로 매체의 전환후에 이루어지는 illumination + alpha의 연장선(post-process)이라 말 할 수 있겠다. signal processing 측면에서 본다면 point sampling-based process에서 pixel imaging-based process로 매체 전환과 3D space에서 2D space의 공간 전환으로 생기는 Aliasing errors을 최소한으로 줄이며 연결 시켜야 3D rendering 부터 시작된 그 data의 저니가 compositing 후 final output 도착 할때까지 손실 없이 성공적으로 이루어 질 것이다.

공간적인 측면의 전환으로 생기는 여러 aliasing errors는 3D rendering 과정 내부에서 효과적인 sampling과 reconstructing으로 최대한 최소화 시키 넘겨 주지만 point sampling-based process에서 pixel imaging-based process로 전환으로 오는 aliasing은 지금부터 얘기할 부분이 될 것 같다.

우리는 최대한 3D rendering 당시의 모습 그대로의 data를 image에 담아 내야 하지만 하드웨어의 한계와 display devices에 맞춘(gamma까지!) 기존의 여러 image format방식으로는 그 data를 가지고 가공이 이루어 지기에 post-process로써 compositing에서 다루기에는 모니터에서 확인 할수 없는 여러 aliasing errors에 시달리게 될 것이다. 특히 영화 film을 최종 목적지로 달려갈때나 전체 pipeline상에서 후반 작업, 즉 compositing 과정을 많이 의지 할때는 더더욱 그럴것이다. (개인적으로는 single-pass rendering을 선호하지만...)

그래서 결론적으로 우리는 3D rendering 과정안에서 가장 가깝게 접근한 환경을 가지고 있는 floating point를 기반으로 하는 high dynamic range, super-white 그리고 linear space가 지원하는 image file format 사용해야만 point-sampling based process에서 pixel-imaging based process로의 매체 전환으로 생기는 여러 aliasing errors와 현 standard image formats 자체에 기생하는 errors를 최소화 할 수 있을 것이다.
 
먼저 32bit floating point를 3D rendering output image format으로 쓰는 장점부터 얘기를 하자면, Color 값을 high dynamic range로 저장 할 수 있다는 것 뿐만 아니라 일반 display로 확인이 안 될 뿐이지 super-white 즉, over pure white, color(1 1 1) 넘는 값도 clipping 없이 저장이 된다는 것이다. (모든 integer image format은 shading and rendering 과정을 끝낸후 얻은 floating point pixel value를  post-image processing 과정에서 integer로 converting시 tone mapping 없이 자연스럽게(?) clipping이 이루어 지게 된다. (tone mapping에 대한 옵션이 min/max로 주어졌지만 특정한 경우를 빼고는 거의 사용 안하기에, 그리고 특히 8bit integer에서는 아주 빈약한 low dynamic range로 강 비츄!)

참고로 Mental Ray에서 32bit floating point tif로 저장시 위에 언급한 pixel로 전환후에 이루어지는 모든 post-image processing을 생략하기에 모든 것을 shading과정에서 해결해야만 한다. 그렇기 때문에 gamma를 조절 하기 위해서는 primary frame buffer가 아닌 mia_exposure_photographic, 혹은 mia_exposure_simple lens shaders를 사용해야만 하는 이유가 된다.

다시 본론으로 돌아와서,
반면 8bit와 16bit에서는 integer가 아닌 floating point로 저장을 한다고 해도 super-white는 clipping 되어 over white는 날아가 버리게 될 것이다. (예외로 오직 openEXR만이 16bit floating point에서도 저장이 가능.)

pure white 넘어로 짤린 부분이 전혀 필요 없이 3D rendering이 final output for TV screen을 위한 작업이라면 상관 없겠지만 3D rendered images를 가지고 후반 작업을 진행 해야 할시에는 얘기가 달라진다. 특히 illumination 영역을 compositing까지 확장시켜 다룰때 밝은 부분의 수학적 계산을 정확하게 하기 위해서는 꼭 필요 하게 되는데, 간단한 산수 예를 들면 color( 0.8 1.2 2.0) * 0.5 = color( 0.4 0.6 1.0) 이 되지만 clipping이 이루어진 color( 0.8 1.0 1.0)를 계산할 경우에는 color( 0.8 1.0 1.0) * 0.5 = color( 0.4 0.5 0.5) 로 상당히 다른 결과를 얻게 될 것이다. 다시말해 모니터 상에서는 color( 0.8 1.2 2.0)나 color( 0.8 1.0 1.0)나 똑 같이 color( 0.8 1.0 1.0)로 보여주지만 계산후 결과는 서로 전혀 다른 color를 모니터에서도 볼 수 있게 될 것이다.

또한 32 bit color depth는 3D rendering에서 보내준 color value를 tone mapping 없이 거의 그대로 가져 오기에 curve functions을 이용해 color depth range를 늘려야 할지라도 마지막 final output에 aliasing error 없이 충분한 color depth를 이어 가게 만들어 줄 것이다.

약간 벗어난 예로 digital camera에서 쓰이는 raw 파일과 비유하면 raw를 지원하는 photo editing tool에서 exposure를 낮출시에 하얗게 날라가 있던 하늘이나 구름의 형태와 칼라가 다시 복원되는 예를 들 수 있을 것이다.(Typically, two f-stop increments) raw는 8bit 이상인 11, 10, 12, 14, 혹은 16 bit color depth(회사, 기종마다 다름)까지 CCD에서 받은 순수 원색을 interpolation 없이 linear color space로 camera setting information meta file과 함께 uncompressed 저장 된 파일 형태이다. post-editing 작업을 원할 경우 이 raw를 jpeg 보다 강력히 추천되는 이유는 위의 내용과 동일하다고 말할 수 있겠다. Interpolation 없다는 것은 3D rendering으로 치면 weighted filtering 된 pixel 이전 상태인 color 값을 가진 sub-samples 상태의 points가 되겠고 11bit부터 16bit까지의 color depth는 linear color space에서 two f-stops을 오가는 상황에서도 충분한 color depth를 받쳐주게 되는 것이다.

이로써 linear work flow가 지원하는 photo editing tool을 사용 한다면 디지탈 카메라 안에서 계산되는 정확한 illumination과 연관된 exposure 매커니즘을 안방에 있는 모니터 앞에서 즐기게 해 줄 것이다. 참고로 photo editing tool에서 raw file을 위한 linear work flow를 지원 한다는 것은 마치 compositing tool에서 pre-multiply by alpha를 위해 거의 모든 effects or functions의 input과 output에 pre-divide, post-multiply 하는 것과 같이 gamma를 풀고 계산후 다시 gamma를 주는 방식으로 계산 될 것이라 예상 된다.

반면 photo image를 jpeg로 저장하여 후반 작업을 할 경우는 위의 예와 반대로 exposure를 조절시 clipping 된  white와 gamma correction issue에 의해 조금만 건드려도 민감하게 highlight 부분이 날아가 버리겠고 쉽게 saturated 되어 버려 어느 순간부터는 비현실적인 모습을 드러 낼 것이다. (뭐 이게 스타일이라고 주장하면 할 말은 없겠지만 알고는 주장을 해야 하지 않을까 해서....) 약간 중심에서 벗어 났지만 전체적인 이해를 위해서는 좋은 예가 아닐까 한다.

다시 3D world로 돌아와,
3D rendering process와 마찬가지로 compositing tool 안에 있는 모든 effects의 수학적 calculation은 linear space에서 clipping 안된 상태의 floating point를 기준으로 이루어 진다. 이런 기준에 미치지 못하는 image를 input으로 쓰게 된다면 계산시 미묘한 error를 가져다 주면서 noticeable artifacts가 조금씩 쌓이면서 final output에서는 사실적인 룩과는 점점 거리가 멀어 지게 될 것이다.

참고로 8bit integer image에 대해서 말하자면 8bit는 일반 모니터 상에서조차도 부족한 color depth이기에 인간의 logarithmic visual perception 원리를 이용해 과거 브라운관에 맞춘 비스므리한 gamma curve를 사용하여 풀어 나갈 수 있었던 것이다. 2.2 Gamma corrected image을 linear로 쫙 펴서 8bit image를 보면 부족한 칼라수로 인해 어두운 부분에서 banding현상이 일어날 것이다.

위에서 언급 했듯이 open EXR가 인기(?)를 끌고 있는 이유 중에 하나가 유일하게 16bit(정확하게는 15 bit color depth) 이면서도 floating point in linear space를 지원 한다는 것이다. 물론 super-white에 대한 clipping 없이. 최종 아웃풋이 film인 우리에게 사실 32bit까지의 color depth가 필요하진 않다. film이 수용할수 있는 한계가 12bit color depth이기 때문이다.

Thursday, April 15, 2010

Light Radius vs. Light Angle as attribute of ray-tracing soft shadow

Maya 혹은 Mental ray에서 Distribution Ray tracing Soft Shadow를 만들때 shadow의 softness를 조절하는 옵션으로 쓰이는 것을 자세히 보면 약간의 함점(?)이 있다고 할 수 있겠다.

Point Light와 Spot Light에서는 'Light Radius' 라는 말로 쓰이지만 Directional Light에서는 'Light Angle' 이란 말로 쓰인다는 것이 어감이 비슷해 대강 넘어 갈수도 있지만 그 어원적인 차이를 이해하면 방식의 차이를 알게 될 것이라 생각 된다.

모든 ray-tracing shadow 계산 방식의 시작은 제일 먼저 camera view에 들어온 objects을 골라 illuminated된 surface의 각 point P로 부터 Light Emitter쪽을 향해 역방향으로 shadow rays를 travel 시켜 그 rays가 출발지점이였던 light emitter까지 거침 없이 도달하느냐 아님 any geometry에 blocking 당하느냐에 따라 shadow 생성 여부를 판단하게 되는데 soft shadow를 위해서는 그 illuminated P점에서 역방향으로 travel 시킬때 그 P점을 중심으로 한 solid angle안에서 random하게 multi rays를 쏴 hit test 하여 최종 그 light emitter까지 도달한 ray의 개수를 총 ray 개수로 나눈 퍼센트 value가 shadow가 되는데 그 solid angle의 radius size가 shadow의 softness를 결정하게 되겠다.

이  illuminated P점에서 solid angle radius를 결정하는 방법적인 차이가 light Radius와 light Angle가 나오게 된 배경이 되겠다.

 먼저 간단히 Parallel ray를 가진 distance light 보면 말 그대로 light Angle의 의미는 light 위치와 상관없이 어느 illuminated P점에서나 동일한 solid angle radius와 같다고 보면 된다.

반면 spot light와 point light에 있는 Light Radius는 distance light와 달리 light emitter origin을 중심으로한 가상의 정원을 만들어 그 illuminated P점에서 solid angle의 중심은 light origin을 향하는 콘을 형성하는데 그 solid angle radius는 그 가상의 원을 radius 크기만큼 열리게 되어 soft shadow를 만들게 된다. 따라서 그 light emitter origin을 중심으로 한 가상의 원의 radius가 solid angle의 radius를 지배하게 된다. 그래서 여기서는 light radius라는 이름으로 쓰이게 된 것이다.

여기서 간혹 문제가 생기는 것이 spot light cone에 들어 있지 않지만 그 Light emitter에 가까이 object가 있어 soft shadow 계산시 생성되는 가상의 원 radius 범위 안에 들어 왔다면 모든 shadow rays는 그 object를 shadow 영향 범위 안에 넣어 계산이 되어 전체적으로 noise를 형성되는 shadow가 생성될 것이다.

shadow의 softness의 조절은 결국 shadow ray의 solid angle radius를 넓혀 주어야 하는데 distance light는 위치와 크기에 상관 없이 light angle로 고정된 solid angle radius를 주기에 무조건 light angle을 따르게 되어 있지만, spot light와 point light는 상대적으로 light emitter를 중심으로 한 가상의 원의 radius가 shadow ray의 direction and solid angle radius를 결정하기에 light emitter 위치 즉, 거리와 light radius가 light scale과 연결되어 있다면 light의 크기 값까지 영향을 받게 되어 상당히 상대적으로 조절하게 되는 것이다.

Friday, April 2, 2010

The structure of light shaders for interactive local illumination

RenderMan은 현재 5가지 방식의 shading을 지원하는데, 이는 다들 알고 있는 surface shading, light shading, displacement shading, volume shading, 그리고 imager shading로 (예전에는 transform shading이 하나 더 있었다고 함) 그 중 개인적으로 가장 간단한 구조를 가지고 있다고 생각하는 local illumination에서의 Light Shading 구조에 대해 오늘 얘기를 해 볼까 한다. shading script coding 하기 나름이라고 반문 할 수도 있겠지만 내가 말하는 부분은 local illumination models and lights 관계에서 light shader의 기본적인 역할이 생각보다 간단하다는 것이다. 이에 반해 light shader에서 보낸 정보를 받아 반사해야 하는 surface shading에서의 illuminance loops 역할이 상대적으로 복잡해 진다고 말 할 수 있겠다.

RenderMan같은 Reyes algorithm renderers뿐만 아니라 Ray-tracing기반의 renderers를 포함 거의 모든 renderers에서 light shader와 surface shader의 이런 interactive illumination관계의 기본적인 구조는 쓰인 언어만 다를뿐 거의 같다고 자신 있게 말 할 수 있겠다. 물론 단순히 수학적으로 트릭 시킨 BRDF 관계가 아닌 Ray-tracing 기반의 ray traveling 방식의 illumination 계산이 필요로 할시에는 다소 복잡해지겠지만 오늘은 거기까지 가지는 않기에 이부분은 무시하고 가 보기로 하겠다.(RenderMan에서는 이 ray-tracing관련의 functions도 Op-codes로 단순화 시켜 버렸지만....)

Local illumination models and lights 관계에서 흔이들 쉽게 오해 하는 부분이 light emitters에서 빛 입자, 즉 photon을 발산하는 시뮬레이션을 하여 surface에 반사해 color값을 알아 내는 것으로 알고 있는데 사실 같은 이치를 수학적 트릭으로 계산해 거의 같은 결과를 얻어 내는 것이지 그렇다고 ray-tracing처럼 ray samples를 쏴 물리적인 reflection 시뮬레이션 같은 것을 하는것은 절대 아니다.

그럼, 다 아는 얘기겠지만 실제 local illumination에서 models and lights 계산 원리를 대강 살펴 보면
1. light emitter origin에서는 point light emitter의(point emitting light source로만 국한시켜 보면: area emitting light source는 오늘은 접어 놓겠다.) position 값과 light color 값만 가지고,
2. camera view frame에서 결정된 계산 해야 할 object의 surface 위의 한점인 P에서 계산된 normal vector N과,
( light distance 값과 light ray의 angle 값은 쉽게 light origin point와 surface point P를 그냥 연결시킨 vector에서 쉽게 얻을수 있겠다.)
3. 최종 ,그 두 light vector L과 surface normal vector N의 angles만 가지고 거의 대부분의 local illumination 계산이 이루어지게 된다고 볼 수 있겠다. 물론 specualer reflection에 가까울 수록 camera vector I와의 계산이 필요 하게 되겠지만...

BRDF(bidrectional reflection distribution function)중에 diffuse() reflection function만 보면 그 둘의 각도, 즉 light vector and surface normal vector의 cosine 값에(단위 벡터의 내적, lambert's law) 최종 light에서 보내준 color와 surface shader의 color을 multiply 하는 과정을 illuminance loops시켜 계산 하겠고, specular reflection function을 보면 하나 더 camera 단위 vector I가 추가되어 해당 point P에서 surface normal을 중심으로 light vector가 incoming light vector(입사각)과 outgoing reflected light vector(반사각)가 같은 앵글을 그릴때 그 반사각에 camera vector I가 가까을수록 highlight가 강해지게 계산해 내 광원에 대한 specualr 효과를 표현 하게 되겠다.

정리하면 simple light shader가 output으로 surface shader에 건내 주는 것은 light emitter의 position값과 light intensity가 multiply된 최종 light color 값만 줄 뿐이다. 이 outputs를 토대로 surface shader에서 반사값을 수학적 fake로 계산해 light ray를 쏜 것 같은 시뮬레이션을 연출 하게 되는 것이다. (이거 말로만 하려니 더 복잡! shading code를 보는게 더 쉬울 것 같기도...... 나중에 RSL에 대해 얘기할때 자세히 얘기하기로 하고....)

그럼 light shader가 복잡해 지는 이유는 Lighting의 cinematic control을 위한 shaping과 Distance fallofff functions이 추가 되어 있기 때문이라고 보면 된다.(Shadowing과 관련된 추가적인 부분들은 나중에 따로 얘기하기로 하고, 우선 통과!)

여기서 shaping이란 light coordinate space에서 X,Y plane 위에서만 놀아나는 2D functions을 써 shaping을 제어하여 마치 projection 같은 (Z축에 변화를 주지 않기에 ,배트맨 라이트 같은 효과라고나 할까?) 효과를 주는 것을 말 한다. spot light의 penumbra 효과가 가장 대표적인 예로 spot light cone 중심에서 형성된 원의 경계를 smooth function으로 제어하는 가장 단순한 방법이고 다른 예를 들면 star-shaped function 쓴다거나 혹은 pattern generating functions과 같이 써 별무리 같은 shaping을 적용해 procedual cookies or slides 효과를 연출 한다든지 더나가 u-ber light shader에서 쓰이는 super ellipse function을 써 cinematic 연출을 위해 사각과 원의 shaping을 자유로이 넘나들수도 있게 할 수도 있겠다.

X,Y plane에 대한 제어로 shaping을 했다면 이번엔 light coordinate space의 Z축을 기준으로 제어하는 Distance falloff 부분이 있겠는데 distance falloff는 Z축으로 camera origin으로부터 거리에 따라 제어 하는 부분으로 shadping 보다 훨씬 간단한 function으로 제어 할 수가 있겠다. 우리가 흔히 쓰는 빛의 거리에 따른 물리적인 기본 성질인 '거리 2제곱의 반비례'가 여기에 쓰이게 되는데 나름 원한다면 다른 여러 math curve functions을 여기에 써서 간단하게 적용 할 수도 있겠다. 참고로 우리가 Maya spot light에서 흔히 쓰는 효과 또한 Z축으로 near/far clipping을 smooth function로 각 경계면을 제어 하면 간단히 표현 할 수도 있겠다.


그럼, light coordinate space기준으로 X,Y,Z 축 전부로 3D space내에서 control이 가능 하지 않겠냐고 물어 올 수도 있겠는데 물론 가능하다. 주로 volumetric shader와 연결된 light shader에 turbulence 같은 noise-based function을 이 3D space로 흘려 보내 흐르는 안개속을 비추는 헤드라이트 같은 효과를 줄 때 사용 할 수 있겠고 더 나가 제 3의 local coordinate system을 이용해 그 좌표계 origin으로 부터 정의된 X,Y,Z 축 영역을 light coordinate space로 전환해 계산하면 결과적으로 3D world space 내에서 light intensity 변수를 local coordsys로 volumetric control이 가능해 질 수 있겠다. 눈치가 빠르다면 cinematic lighting의 꽃인 shadow blockers 얘기인지 알아챘으리라 본다. 사실 엄연히 따지면 depth map을 사용하는 shadowing 또한 여기에 속한다고 말 할 수 있겠다. 제어하는 메터리얼이 수학적 functions이 아닌(사실 이것도 가능, 예: projected shadow blockers) X,Y,Z space에 대한 정보를 이미지화 시킨, 즉 shadow camera 좌표계로 map의 가로세로가 X,Y축이 되고 pixel의 luminance value가 Z축의 depth value가 되는 엄연한 3D space 내의 light intensity 변수에 대한 projected volumetric control 인 것이다. 물론 전에도 얘기 했듯이 shadowing 계산을 위한 z-depth 대조 작업을 위해 real rendering camera 좌표계와 일치 시켜야 한다. 

위의 두 부분, shaping과 distance falloff을 빼서 light shader를 쨔면 자연 스럽게 정말 간단한 simple point Light shader가 되겠다. 여담이지만 poing light는 촛불과 같이 부드럽운 효과를 위해 쓴다는 얘기를 종종 듣게 되는데 불행하게도 그런 감성적인 차이는 우리 기분일 뿐이지 기술적으로 spot light와 아무런 차이를 주지 않는다. 그냥 한정된 지역의 shaping이 필요하거나 낭비 없는 shadowing을 쓰기 위해서 point light 대신 spot light를 쓰는 것 뿐이다.

그럼 Distance (Directional) Light는? 하고 질문이 생길 수도 있겠는데, distance light는 더더욱 간단하여 light의 position 값이 필요 없이 하나로 통일된 parallel ray angle 값만으로 surface normal vector와 계산된다고 볼 수 있다. positional data가 있기는 하지만 이건 그냥 shadow camera 용으로 쓰기 위한 것일뿐 illumination계산에 아무런 영향을 주지 않는다. 이런 이유로 distance light 또한, point light shader처럼 정말 간단하게 쨔여 진다. shaping control도 distance fall off control이 아예 필요 없기 때문이다. 구지 원한다면 위에서 언급 했듯이 제 3의 local coordsys를 이용해 3D space 특정 범위 내에서 volumatric shaping을 할 수 있는 shadow blocker 기능을 쨔 넣을 수도 있겠지만....

마지막으로 light attributes 중에 있는 non-diffuse, non-specular 기능에 대해 설명하자면 이것 또한 surface shader의 diffuse(), specular() functions 내에서 coding되어 illuminance loops시 light shader에서 전해준 그 파라미터의 값만 전달 받어, 즉 light shader에서 surface shader를 제어하는 Message passing 메카니즘을 구현해 계산하는 것이다. 이 Message passing은 renderman의 아주 강력한 기능 중의 하나로 서로 다른 종류의 shader들간에 variables를 교류 시킬수 있는 메카니즘이다.

공개된 light shaders 중 아직까지도 가장 확장된 cinematic flexibility를 가지고 있는 U-ber light shader를 예를 들면, A4 3,4 페이지가 넘는 스크립트로 아주 복잡하지만 사실 분석해 보면 각 부분의 functions이 복잡한 것이지 위의 기본 골격은 그대로 유지한다는 것을 알 수가 있을 것이다.

아무리 복잡한 shader라도 기본 구조를 이해한 상태로 분석해 본다면 더이상 복잡해 보이지 않는 다는 것이다. 이는 light shading에만 국한 된게 아니라고 본다.
이로써 light shading이 다른 종류의 shading들보다 훨씬 간단한 기본구조를 지녔다고 말하는 이유를 이해 했으리라 믿는다. (더 복잡하게 만든건 아닌지....음)