[임지웅] DX - 법선맵핑 (Normal map)

Programming/DirectX 2010. 6. 10. 21:31 Posted by 알 수 없는 사용자

법선맵핑이란?
 법선 맵핑이란 텍스처의 텍셀(텍스처의 각 픽셀)에 RGB값대신 그 해당 텍셀의 법선 벡터가 들어간 법선맵텍스쳐를  사용해서 특수하게 맵핑하는 기법이다.

법선 맵핑을 사용하는 이유는?
  3D 모델링한 오브젝트는 결국은 2D화면에 출력되는데 미세한 요철(凹凸)등의 부분은 많은 폴리곤을 써서 고퀄리티로 만들더라도 실제로 표현될때는 픽셀단위로 표현되기때문에 세세하게 모델링된 폴리곤을 표현할수가 없다. 게다가 표현이 되지 않더라도 요철부분의 폴리곤들도 모두 연산되기때문에 메모리공간도 많이 잡아먹고 불필요한 부하가 걸리게 되므로 몹시 비효율 적이다.
 이런 문제를 해결하기 위해서 나온 효과적인 방법중하나로 법선맵핑이다.

요철(凹凸)을 표현하는 방법.
 요철이 요철로 보이는 이유는 튀어나온 부분과 들어간 부분에서 생기는 그림자 때문인데 그림자가 생기는 것은 광원과 밀접한 관계가 있다.
 광원처리에는 보는눈에 방향인 시점 벡터와 광원의 방향인 광원벡터, 그리고 오브젝트의 법선벡터가 필요한데, 광원 벡터와 법선벡터를 이용해서 빛의 반사를 계산해서 결국은 시점벡터에 보이게 되는것이므로 요철부분의 법선벡터만 있다면 음영을 만들어 요철처럼 표현할수있다.
 미세요철의 음영은 결국 픽셀에 그린 결과로 나오기만 하면 되므로, 픽셀단위로 법선벡터를 얻을 수 있으면 된다. 픽셀단위의 법선벡터를 얻기위해선 텍스쳐를 사용하면 된다.

법선맵(Normalmap) 텍스처
 텍스처를 입히면 텍스처의 텍셀의 보관된 RGB컬러 값을 화면에 그리는데, 텍스처의 텍셀의 컬러값에 RGB값대신 법선벡터의 값을 넣어두고 그 텍셀에서의 법선벡터값과 광원과의 광원처리 즉 반사를 연산하면 픽셀단위로 조명이 들어가기 때문에 미세요철의 음영을 표현할 수 있다.

텍스처의 텍셀에 RGB값대신 벡터(x.y.z)값을 넣는다.
 일반적인 텍스처의 텍셀의 경우 ARGB의 컬러값이 들어가는데 A(투명도)값을 제외한 RGB대신 벡터의 x, y, z,성분을 넣어준다.

R -> x  ,  G -> y  ,  B -> z

이렇게 텍셀에 법선벡터를 RGB값대신 넣어두는 텍스처를 법선맵(Normalmap)이라고 한다. 랜더링시에 이 법선맵의 법선벡터를 이용해서 광원처리를 한다.

법선맵의 종류
 법선맵 텍스처는 2D상의 법선벡터를 저장하고있지만 3D상의 오브젝트 폴리곤의 법선방향은 고려하지 않고있으므로 바로 사용할수는 없고 좌표계 통일을 위한 변환이 필요하다. 여기서 기준 좌표계에따라서 오브젝트 공간 법선맵과 접선공간 법선맵으로 나뉜다.

-오브젝트공간 법선맵
 법선벡터가 기준으로 삼는 좌표계가 오브젝트의 로컬 좌표계이다. 즉 오브젝트의 원점이 법선벡터들의 원점이된다. 이 기법은 오브젝트가 몰핑(다른 오브젝트등에 묻히는)되지않는 벽면이나 바닥 갑옷등에 사용하면 좋다. 하지만 케릭터등의 오브젝트는 애니메이션될때 스키닝기법을 써서 정점을 몰핑하는데 몰핑되면 법선벡터의 방향이 바껴야 되서 오브젝트공간 법선맵은 사용할수가없다. 또 좌우대칭되는 오브젝트의 경우 텍스처를 반쪽만 만들어서 대칭으로 맵핑하는 기법을 사용하는데, 오브젝트공간 법선맵은 기준좌표계가 오브젝트의 로컬 좌표계이기 때문에 대칭점에서 법선벡터가 달라서 전체에 대해서 법선맵을 만들어줘야된다.

-접선공간 법선맵
 정점공간 법선맵이라고도 한다. 이 방법은 모든 법선벡터를 각 정점이 원점이되는 접선공간으로 변환해서 보관하는 방식인데 잘 모르겠으요 -_-; 나중에 뒤에서 나온답니다;;

법선맵핑의 효과
  법선맵핑은 저폴리곤 모델을 고폴리곤처럼 보여주는 기법이다. 일반적으로 1000개 정도의 폴리곤에 법선맵을 적용할경우 20000~30000개의 폴리곤으로 모델링한것 이상의 효과를 볼수있다.
 즉 저폴리곤 모델 + 법선맵 = 고폴리곤 모델

법선맵 생성하기
 -놉이맵에 의한 생성법
 텍스처를 흑백으로 변환하면 높이맵이 생성된다 (흰색은 높고 검은색은 낮은걸로 치면 0~255의 높이맵이된다). 이 높이맵에서 인접한 텍셀들간의 고저차를 비교해서 기울기를 나타내는 미분벡터를 만든다.(미분하면 기울기가 나온다) 이렇게 만들어진 미분벡터 2개(x방향으로의 미분벡터, y방향으로의 미분벡터)를 외적하면 법선벡터가 만들어지는데 이 법선벡터가 그 텍셀의 법선벡터가 된다.

-오브젝트 비교에 의한 생성법
 오브젝트를 저폴리곤과 고폴리곤으로 두 개를 만들고 두 모델의 차이를 비교해서 법선맵을 만드는 방법이다. 저폴리곤 모델의 텍셀에서 고폴리곤으로 직선을 쏴서 접하는 지점의 법선벡터를 저장하는 방법이다.
 요즘에는 이방법을 사용하는 추세다.

벡터를 RGB로 변환하는 방법
 법선벡터는 단위벡터이므로 단위 벡터 v 를 RGB로 변환한다.
 ARGB중에 투명값을 나타내는 A값은 제외하고 RGB값에 각각 벡터v의 (x, y, z)값이 들어가게되는데 벡터는 단위벡터이므로 -1 에서 +1의 값이고 RGB값은 각각 8비트이므로 0 에서 255사이의 값이다. 그래서 -1 -> 0 ,  1 -> 255에 대응되게 해야되는데 그 함수는 다음과 같다.

R = (DWORD) (127.0 * x + 128.0)
G = (DWORD) (127.0 * y + 128.0)
B = (DWORD) (127.0 * z + 128.0)

Color = ( (R<<16) | (G<<8) | B )

이렇게 하면 Color값에는 벡터 v = (x, y, z)의 정보가 RGB값으로 변환되어 들어가게 된다.
# ARGB에 각각 8비트씩 할당해서 값을 저장하지않고 A값과 B의 값을 제외하고 R,G값에 x, y 를 각각 16비트씩 변환하면 보다 정밀도를 높게 할 수 있다. z값은 벡터 v가 단위벡터이므로 루트(x^2 + y^2 + z^2) = 1임을 이용해서 얻을 수 있는
z = 루트( 1 - (x^2 + y^2) ) 식으로 x, y값을 이용해 z값을 넣어주면된다.

# 법선맵 디자인툴에는 Z-BRUSH등이 있다.

===============================================================================================================
결국 오브젝트에 텍스처 + 법선맵 텍스처를 혼합해서 적용해서 픽셀당 조명효과로 오브젝트의 요철을 효과적으로 표현하는 방법이었습니다 !!
일단 간단(?)하게 정리해봤는데요. 좀이라도 도움이 됬음 좋겠네요;; 소스는 첨부파일

<-