CS/그래픽스

Normal Map

tae-woong 2025. 11. 4. 19:07

참고 영상

노말맵이란 무엇인가?

노말 맵을 사용하여 폴리곤 수 증가 없이 디테일을 표현하는 모습.

  • 사용 단계 : 렌더링 파이프라인의 프래그먼트 셰이더(Fragment = Pixel Shader) 단계
  • 역할 : 프래그먼트마다 조명을 계산할 때, 표면의 진짜 법선(Normal) 대신 텍스처에 저장된 가짜 법선 정보를 사용하여 디테일한 입체감을 만듭니다.
  • 핵심 원리 (페이크) : 실제 모델의 형태를 바꾸는 것이 아니라, 빛이 표면에 반응하는 방식을 '속여서' 평평한 면이 울퉁불퉁하게 보이도록 만듭니다.
  • 필요성 (가성비) : 적은 수의 폴리곤(로우폴리 모델)을 사용하면서도 하이폴리 모델처럼 디테일한 표면을 구현할 수 있습니다. 이는 게임과 같은 실시간 렌더링 환경, 특히 모바일에서 성능 비용을 획기적으로 절약하는 핵심 기술입니다.

 

노멀맵을 만드는 과정으로는

  1. 원본 (High-Poly) : 아주 많은 폴리곤을 사용해 디테일이 풍부하고 울퉁불퉁한 '하이폴리 모델'을 만듭니다.
  2. 사본 (Low-Poly) : 폴리곤 수를 획기적으로 줄인 '로우폴리 모델'을 만듭니다. (게임에서 실제 사용)
  3. 정보 저장 (Baking) : 하이폴리 모델의 복잡한 표면 방향 정보를 노말맵(텍스처)에 미리 구워서 저장합니다.
  4. 계산 시 사용 (Rendering) : 실제 게임에서는 로우폴리 모델을 띄우지만, 빛 계산을 할 때는 로우폴리 모델의 밋밋한 표면 방향 대신 노말맵에 저장된 복잡한 방향 값을 참조합니다.

결론적으로 "로우폴리 모델을 쓰면서도 라이팅 계산은 하이폴리 모델처럼" 하게 만드는 기술입니다. 그래서 빠른 속도높은 디테일을 둘 다 잡는 것입니다.

 

빛과 '노말(Normal)'의 관계

빛의 방향과 법선 벡터의 내적을 통해 표면의 밝기가 결정됩니다.

노말맵을 이해하려면 먼저 '노말'이 무엇인지 알아야 합니다.

  • 노말(Normal)이란? : 면이 바라보는 '방향'을 의미하는 벡터(Vector) 값입니다.
  • 라이팅 계산 : 표면의 밝기는 빛의 방향과 표면의 노말 방향이 이루는 각도에 따라 결정됩니다. 빛을 정면으로 받는 면은 밝고, 비스듬히 받는 면은 어두워집니다.
  • 핵심 연산 (내적) : 컴퓨터 그래픽스에서는 이 밝기를 효율적으로 계산하기 위해 두 벡터(빛 방향, 표면 노말 방향)의 내적(
    두 벡터가 얼마나 같은 방향을 바라보고 있는지를 구하는) 연산을 사용합니다.

 

노말맵은 왜 파란색인가?

노말 맵은 벡터(X, Y, Z) 정보를 RGB 색상 채널에 저장하므로 푸른색을 띱니다. Z는 음수가 될 일이 없다.

노말맵 텍스처는 특유의 푸른색을 띱니다.

  • 이유 (데이터 텍스처) : 노말맵은 눈에 보이는 색상(알베도)이 아니라, 방향 '데이터'를 저장하는 텍스처이기 때문입니다.
  • RGB = XYZ : 텍스처의 R, G, B(Red, Green, Blue) 채널에 각각 벡터의 X, Y, Z 방향 값을 저장합니다.
  • 푸른 이유 (Z축) : Z축(Blue 채널)은 '표면에서 바깥쪽을 향하는 방향'을 의미합니다. 대부분의 디테일은 표면에서 미세하게 튀어나온 형태이므로 Z값이 거의 항상 양수(0.5~1 사이)가 됩니다. 따라서 Blue 채널 값이 항상 높아 전체적으로 푸른색을 띠게 됩니다. (= 노말 벡터는 길이가 1(X²+Y²+Z²=1)이라는 특성을 이용해, X, Y값만 알면 Z값을 수학적으로 복원할 수 있기 때문입니다.)

 

핵심 이론 : 탄젠트 스페이스 (Tangent Space)

유니티 쉐이더 그래프 세부 버전
유니티 쉐이더 그래프 압축 버전(Transform으로 간단하게 사용 가능)

가장 중요하고 복잡한 개념입니다. 노말맵은 '표면 기준'으로 방향을 저장했는데, 3D 모델은 구부러져 있어 '월드(세상) 기준'의 방향과 다릅니다.

  • 문제 제기 : 평평한 텍스처에 저장된 방향 값(예: "위로 튀어나옴")을 구부러진 모델 표면에 적용할 때, 각 지점의 '위'가 어디인지 알려줄 기준이 필요합니다.
  • 해결책 (TBN) : 모델 표면의 각 지점(픽셀)마다 고유한 '좌표계(Tangent Space)'를 설정합니다.
  • 좌표계 구성 (TBN 행렬) : 이 좌표계는 3개의 수직축으로 이루어집니다.
    1. Normal (N) : 원래 표면이 향하는 방향 (Z축 역할)
    2. Tangent (T) : UV 좌표의 U방향(가로)을 따르는 접선 (X축 역할)
    3. Bitangent (B) : N과 T에 모두 수직인 방향 (Y축 역할, '외적'으로 계산)
  • 변환 : 쉐이더는 이 TBN 행렬(Matrix)을 사용해 노말맵 텍스처에 저장된 '표면 기준 방향''월드 기준 방향'으로 변환시킵니다.
  • 최종 계산 : 이렇게 변환된 최종 노말 값과 실제 조명(월드 기준)을 '내적'하여 올바른 표면 밝기를 계산합니다.

 

💡 쉽게 이해하기 (비유)

  • 월드 스페이스 노말 (World Space) : "이 흉터는 북쪽을 향해 튀어나와 있어."라고 기록하는 방식입니다. -> 캐릭터가 남쪽으로 회전하면 흉터 방향 정보가 틀려서 사용할 수 없습니다.
  • 탄젠트 스페이스 노말 (Tangent Space) : "이 흉터는 피부 표면에서 수직으로 튀어나와 있어."라고 기록하는 방식입니다. -> 캐릭터가 회전하든 덤블링을 하든, 흉터는 항상 피부 위에서 올바르게 튀어나와 보입니다. (재사용 가능)

 

유니티 노말맵 임포트와 압축

유니티에서 노말맵 텍스처는 반드시 "Normal Map" 타입으로 설정해야 합니다.

  • 이유 1 (감마 보정 제외) : 노말맵은 색상이 아닌 '데이터'이므로, 사람의 눈에 맞게 밝기를 조절하는 '감마 보정(Gamma Correction)'을 건너뛰어야 벡터 값이 정확하게 유지됩니다.
  • 이유 2 (고품질 압축 - Z축 복원) :
    • 유니티는 노말 맵을 압축할 때(DXT5nm 등), R채널과 G채널(X, Y값)만 저장하고 B채널(Z값)은 버립니다.
    • 복원 원리 : 벡터의 길이는 항상 1이라는 피타고라스 정리 (x^2 + y^2 + z^2 = 1)를 이용해, 쉐이더 내부에서 z = sqrt{1 - x^2 - y^2} 공식으로 Z값을 다시 만들어냅니다.
    • 이렇게 하면 용량은 줄이면서도 Z축의 디테일을 잃지 않을 수 있습니다.
  • 효과 : 2개 채널만 사용하므로 데이터를 더 효율적으로 압축(예: DXT5nm, ASTC)하여 용량을 줄이고 품질을 높일 수 있습니다.

 

다른 기술과의 비교

기본 / 노멀 맵 / 패럴랙스팹 맵
디스플레이스먼트 맵

  • 패럴랙스 맵핑 (Parallax) : 노말맵보다 깊이감을 더 주지만(하이트맵 사용), 연산 비용이 높고 시각적으로 불안정하여 '가성비'가 떨어집니다.
  • 디스플레이스먼트 맵핑 (Displacement) : 실제로 정점(Vertex)을 이동시켜 가장 현실적입니다. 하지만 '테셀레이션' 기술이 필수라 하드웨어 요구 사양이 매우 높습니다.
  • 결론 : 노말맵이 현재 모바일을 포함한 대부분의 실시간 렌더링 환경에서 '가성비(성능 대비 품질)'가 가장 좋은 기술입니다.