---
title: "법선 하나가 밝기를 정한다"
description: "셰이더는 면이 진짜 어떻게 생겼는지 모릅니다. 각 자리의 법선이 어느 쪽을 보는지만 알고, 밝기는 거기서 나옵니다."
author: "유니얼"
pubDate: 2026-09-14
category: "game-dev/graphics"
tags: ["렌더링", "셰이더"]
canonical: https://blog.unialgames.com/posts/normal-map-what-is-normal/
---
삼각형 하나를 화면에 그리면 위치와 모양은 정해집니다. 그런데 그 삼각형이
**어떤 밝기로 칠해질지**는 위치만으로는 안 정해집니다. 같은 자리에 있는 벽도
빛을 정면으로 받으면 밝고 비스듬히 받으면 어둡습니다.

그 밝기를 정하는 값이 법선입니다.

## 법선은 "이 면이 어느 쪽을 보는가" 입니다

법선(normal)은 면에 수직으로 서 있는 화살표입니다. 길이는 1로 맞춰 둡니다.
길이는 쓸 일이 없고 방향만 필요해서입니다.

중요한 건 **법선이 위치가 아니라 방향**이라는 점입니다. 책상 위의 법선은
천장을 봅니다. 벽의 법선은 방 안쪽을 봅니다. 같은 벽이면 어느 자리든 같은
방향입니다.

## 왜 각도가 밝기를 정하나

손전등을 벽에 정면으로 비추면 작고 밝은 원이 생깁니다. 같은 손전등을
비스듬히 비추면 그 빛이 길쭉하게 늘어나면서 어두워집니다.

빛의 양은 그대로인데 **퍼지는 면적이 넓어져서** 단위 면적이 받는 양이
줄어든 것입니다. 램버트 코사인 법칙이라고 부르는 게 이겁니다.

퍼지는 정도는 면이 빛을 향해 얼마나 돌아서 있는지, 즉 **법선과 빛 방향
사이의 각도**로 정해집니다.

## 각도를 곱셈 한 번으로

각도를 재서 코사인을 구하는 대신, 두 단위 벡터의 내적을 씁니다.
단위 벡터끼리의 내적이 곧 사잇각의 코사인이라서 결과가 같고 훨씬 쌉니다.
곱셈 세 번과 덧셈 두 번이면 끝납니다.

```hlsl
float ndotl = saturate(dot(N, L));
float3 color = albedo * lightColor * ndotl;
```

`N` 이 법선, `L` 이 그 자리에서 광원 쪽을 가리키는 방향입니다.
정면으로 받으면 1, 90도로 스치면 0, 빛을 등지면 음수가 나옵니다.
음수는 "빛을 뺀다" 는 뜻이 되어 버리므로 `saturate` 로 0에서 자릅니다.

아래에서 빛이 좌우로 움직입니다. 위쪽 띠가 화면에 칠해지는 결과이고,
아래가 그 면을 옆에서 자른 모습입니다. 파란 화살표가 법선입니다.

<x-lit>
<script type="application/json">
{
  "label": "빛이 움직이면 같은 면이 얼마나 달라지나",
  "modes": ["flat"],
  "note": "법선과 빛 방향이 이루는 각도만 바뀌었습니다. 면은 한 번도 안 움직였습니다."
}
</script>
</x-lit>

면은 가만히 있는데 빛의 각도가 바뀌는 것만으로 띠 전체가 같이 밝아지고
어두워집니다. 법선이 모든 자리에서 똑같이 위를 보고 있어서 밝기도 자리마다
같습니다.

## 법선은 정점에 들어 있습니다

메시는 정점마다 좌표, UV, 그리고 법선을 들고 있습니다. 픽셀 하나하나가
자기 법선을 갖고 있는 게 아닙니다.

래스터라이저가 삼각형을 픽셀로 쪼갤 때 세 정점의 법선을 무게중심 좌표로
섞어서 각 픽셀에 넘겨줍니다. 이 보간 덕분에 각진 저폴리 구체도 둥글게
보입니다. 실제 모양은 각졌는데 법선이 부드럽게 변하니까요.

여기서 이 이야기의 핵심이 나옵니다.

> **밝기를 정하는 건 실제 모양이 아니라 법선입니다.**
> 조명 계산은 면이 진짜로 어떻게 생겼는지 묻지 않습니다.
> 이 자리의 법선이 어디를 보느냐만 묻습니다.

각진 구체가 둥글어 보이는 것도 같은 원리입니다. 모양은 그대로 두고
법선만 거짓말을 시킨 것입니다.

## 정점이 부족하면 거기서 막힙니다

문제는 법선이 정점에 붙어 있다는 점입니다. 한 삼각형 안에서 법선이
자리마다 다르게 꺾이려면 그 자리마다 정점이 있어야 합니다.

벽돌 벽의 줄눈 하나를 법선으로 표현하려면 줄눈 하나마다 정점이 여러 개
필요합니다. 벽 한 장에 정점이 수만 개가 됩니다. 정점이 늘면 정점 셰이더
호출, 메모리, 전송량이 전부 같이 늡니다.

## 정리

- 법선은 면이 어느 쪽을 보는지를 가리키는 길이 1짜리 방향 벡터입니다.
- 밝기는 법선과 빛 방향의 내적에서 나옵니다. 정면이면 1, 스치면 0, 등지면 음수라 0으로 자릅니다.
- 각도로 밝기가 갈리는 이유는 같은 양의 빛이 비스듬할수록 넓게 퍼지기 때문입니다.
- 법선은 정점에 저장되고 픽셀에는 보간된 값이 갑니다. 각진 구체가 둥글어 보이는 게 이 보간 덕분입니다.
- 조명 계산은 진짜 모양을 모릅니다. 법선만 봅니다. 그래서 법선이 세밀해지려면 정점이 그만큼 많아야 합니다.