Tangent Basis 벡터 계산

tangent, bitangent 벡터 구하는 방법을 간단하게 설명해 보겠습니다.

tangent space (texture space) 에 있는 (s, t) 벡터를 world space 로 변환하면 삼각형의 edge 벡터가 된다는 사실로부터,

    \[\begin{bmatrix} \vec{T} & \vec{B} \end{bmatrix} \begin{bmatrix} s_1 \\ t_1 \end{bmatrix} = \vec{e}_1\]

    \[\begin{bmatrix} \vec{T} & \vec{B} \end{bmatrix} \begin{bmatrix} s_2 \\ t_2 \end{bmatrix} = \vec{e}_2\]

이 식은 (s, t) 벡터를 \vec{T}, \vec{B} 가 기저인 world space (column space) 로 변환하는 식입니다.
식을 하나로 합치면,

    \[\begin{bmatrix} \vec{T} & \vec{B} \end{bmatrix} \begin{bmatrix} s_1 & s_2 \\ t_1 & t_2 \end{bmatrix} = \begin{bmatrix} \vec{e}_1 & \vec{e}_2 \end{bmatrix}\]

이것은 미지수가 6 개인 6 개의 연립 일차 방정식입니다.

    \[\begin{bmatrix} \vec{T} & \vec{B} \end{bmatrix} = \frac{1}{s_1 t_2 - s_2 t_1} \begin{bmatrix} \vec{e}_1 & \vec{e}_2 \end{bmatrix} \begin{bmatrix} t_2 & -s_2 \\ -t_1 & s_1 \end{bmatrix}\]

앞의 상수로 해가 존재하는지 알 수 있고, 해를 계산할 때는 어차피 normalize 할 것이기 때문에 부호만 보면 됩니다.
마지막으로 \vec{T}, \vec{B}, \vec{N} 벡터가 서로 직교한다는 보장이 없기 때문에 Gram-Schmidt 직교화를 한번 해줘야 합니다.

실제 polygon mesh 에 적용할 때는 smooth 한 normal 을 구할 때와 마찬가지로, 삼각형들이 공유하는 tangent 벡터들을 평균을 내서 적용합니다.

참고:
http://www.terathon.com/code/tangent.html

Rendering in Linear Color Space

# sRGB 컬러 공간

sRGBColorSpace

우리가 사용하는 대부분의 디지털 이미지 장비들(디카, 스캐너, 모니터, 프린터) 은 표준 non-linear 색 공간인 sRGB 를 사용하도록 정해져있다. 따라서 사진이나 그림파일들도 그에 맞추어진 형태로 저장된다.

보통 이미지를 합성(필터링, 블렌딩, 쉐이딩,..) 할때 우리는 색공간이 linear 하다고 생각하지만, 실제 저장된 파일은 sRGB 에 맞춰져 있기 때문에 연산 전에 먼저 linearize 해줘야 정확한 컬러 연산이 가능해진다고 할 수 있다. 모니터 역시 sRGB 에 맞춰져 있기 때문에 연산 후 sRGB 색공간으로 변환해줘야 한다.

변환 수식은 아래와 같다. (gamma 2.2 에 근접)

Linear2sRGB&sRGB2Linear

대부분의 이미지 프로세싱 유틸리티나 게임들은 이를 무시하고 구현하고 있다. 자신이 작업한 텍스쳐가 실제 엔진에서 (포스트 프로세싱 끄고) 왠지 모르게 칙칙하고 어둡게 느껴진다면?… 100% 임다 -_-;

# sRGB 읽기

텍셀을 fetch 할 때 sRGB -> linear 변환

DX10 카드에서는 텍스쳐를 GPU 쪽으로 로딩할때 linear space 로 자동 변환되게 할 수 있다. (변환될 때 색 손실을 막기 위해 채널 당 8bit 이미지가 내부적으로 12bit 나 16bit 로 저장된다고 한다) – 로딩 타임에 변환되므로 텍스쳐 필터링도 linear space 에서 하게 된다.

DX9 카드에서도 지원하지만 로딩 타임이 아닌 쉐이더에서 텍셀을 fetch 할때 linear space 로 변환되게 된다. –
필터링은 non-linear space 에서 하게 되므로 미묘하게 색이 변하게 된다.

주의. 컬러 이미지 외에 선형적인 데이터(노멀맵, 스페큘러맵, 하이트맵,…) 들은 이미 linear space 에 있기 때문에 따로 처리할 필요는 없다. – 생각해보니 스페큘러맵이 linear data 라고는 할 수 없겠다..

# sRGB 쓰기 & 블렌딩 쓰기

프레임 버퍼에 write 할 때 linear -> sRGB 변환
블렌딩 모드라면 프레임 버퍼에서 src 를 가져올때 sRGB -> linear 변환한 결과를 블렌딩 후 다시 sRGB 로 변환

DX10 이상의 카드에서 하드웨어적으로 지원한다.

지원하지 않는다면 픽셀 쉐이더에서 직접 처리해 줄 수 있다. – 하지만 블렌딩 할때 정확한 연산이 이루어지지 않는다.
(먼저 sRGB 프레임 버퍼를 읽어와서 linearize 해야 하므로..)

주의. 중간 단계 맵 (굴절맵, 반사맵, 거울맵, …) 들은 다시 linear space 에서 사용될 것이므로 linearity 를 유지 한다.

# 적용

첫번째 스크린샷이 linear space 쉐이딩, 두번째가 일반적인 non-linear space 쉐이딩
첫번째 스크린샷 보다 두번째 스크린샷의 텍스쳐가 좀 더 칙칙하고 어둡게 나오고, 스펙큘러 하이라이트 부분은 더 강렬하게 나온다. 라이트 세기를 밝게할 수록 더 확연하게 차이가 나는 걸 볼 수 있었다.

LinearSpaceLighting

NonLinearSpaceLighting

원본 디퓨즈 텍스쳐
diffuseTexture

참고 자료:
http://en.wikipedia.org/wiki/SRGB
GPU Gems 3. Chapter 24 : The Importance of Being Linear
http://msdn.microsoft.com/en-us/library/ee418639(VS.85).aspx
http://alex.vlachos.com/graphics/Vlachos-GDC08-PostProcessingInTheOrangeBox.pdf
http://www.opengl.org/registry/specs/EXT/texture_sRGB.txt
http://www.opengl.org/registry/specs/EXT/framebuffer_sRGB.txt
http://renderwonk.com/blog/index.php/archive/adventures-with-gamma-correct-rendering/

Deferred Lighting with YCoCg LitAcc Buffer

Color= Ambient + Shadow * Att * (N.L * DiffColor * DiffIntensity * LightColor +R.V^n * SpecColor * SpecIntensity * LightColor)

기본적인 방식은 Wolfgal Engel 의 Light pre-pass renderer 에서 출발한다

diffuse term 과 specular term 을 저장할 공간이 부족한 것을 해결해야 하는데..

아래 6개의 값이 있다.

NdotL * Att * Light.r
NdotL * Att * Light.g
NdotL * Att * Light.b
NdotH * Att * Light.r
NdotH * Att * Light.g
NdotH * Att * Light.b

6개의 채널값을 하나의 버퍼에 담을 수 없게 된다.

* 방법 #1 diffuse rgb + specular intensity (CryEngine3)

diffuse term 은 rgb 로 저장하고 specular term 은 강도(intensity) 값만 저장
차이는 보이나 다행히 크게 어색하지 않다.

a0008416_4ac4326da791e

a0008416_4ac43286036c1

* 방법 #2 interaced YCoCg (내가 생각한 방법)

diffuse/specular term rgb 를 각각 YCoCg 로 변환한다음
Y(luma) 정보는 매 픽셀 write 하고 CoCg(chroma) 정보를 라인마다 엇갈려 write 한다

픽셀 쉐이더에서 VPOS(gl_FragCoords.xy) 로 위치를 정할 수 있다

light accumulation 버퍼 2×2 layout

(dY, dCo, sY, sCo) (dY, dCo, sY, sCo)
(dY, dCg, sY, sCg) (dY, dCg, sY, sCg)

라이팅 패스에서 4 개의 픽셀을 읽어 rgb 정보로 reconstruct

chroma 정보가 1/2 로 유실되나 눈으로 거의 차이를 못느낄 것임

참고 자료:
http://diaryofagraphicsprogrammer.blogspot.com/2008/03/light-pre-pass-renderer.html
http://www.crytek.com/fileadmin/user_upload/inside/presentations/2009/A_bit_more_deferred_-_CryEngine3.ppt
http://aras-p.info/texts/CompactNormalStorage.html
http://software.intel.com/sites/products/documentation/hpc/ipp/ippi/ippi_ch6/ch6_Intro.html
http://developer.nvidia.com/object/real-time-ycocg-dxt-compression.html