본문으로 건너뛰기

노멀맵 만들기 사이트 · 2D 스프라이트용 생성기

스프라이트를 열면 노멀맵이 바로 만들어져 있습니다. 투명한 가장자리에서 안쪽으로 베벨을 세우고, 밝기나 직접 그린 높이 맵으로 디테일을 더한 뒤, 끌어서 옮기는 점광원으로 비춥니다. 조명은 Godot 4의 2D 계산식 그대로라서 미리보기가 곧 엔진 화면입니다.

스프라이트 노멀맵은 스프라이트와 같은 크기의 PNG 한 장으로, 픽셀마다 표면이 어느 쪽을 향하는지를 RGB로 담습니다. 그래서 평평한 그림도 2D 조명 아래에서 입체처럼 음영이 생깁니다. 투명 배경 스프라이트를 넣으면 Studio 텍스처 작업 공간이 투명한 가장자리에서 안쪽으로 올라오는 베벨과 밝기 디테일로 곧바로 노멀맵을 만들고, Godot 4의 2D 계산식 그대로 비춰 보여 준 뒤 _n.png(OpenGL, Y+), _n_dx.png(DirectX), 또는 엔진에서 확인한 Godot 4·Unity 6 URP 2D 번들로 내보냅니다.

스프라이트, 스프라이트 시트 또는 반복 텍스처(PNG)를 끌어다 놓으세요
빈 Studio 열기
브라우저에서 처리하며 파일은 업로드되지 않습니다.
Studio 텍스처 작업 공간: 6프레임으로 자른 도트 횃불을 생성한 노멀맵과 점광원으로 비춘 화면
CC0 에셋(OpenGameArt)을 연 실제 Studio 화면입니다.
내보내기 대상
  • Godot 4 2D lights검증됨· Godot 4.7.2
  • Unity 6 URP 2D검증됨· Unity 6000.5.3f1 (URP 17.5)
  • PNG set + JSON일반 파일

스프라이트 노멀맵에 담기는 것과 입체감의 출처

탄젠트 공간 노멀맵은 픽셀마다 단위 벡터 하나를 색으로 저장합니다. 빨강은 X(이미지 오른쪽), 초록은 Y(Godot와 Unity가 쓰는 OpenGL 방식에서는 위쪽), 파랑은 Z(화면 밖)입니다. 각 성분은 (n + 1) ÷ 2 × 255로 기록되므로 정면을 보는 픽셀은 모든 노멀맵에서 보이는 연보라색 (128, 128, 255)이고, 오른쪽으로 45° 기운 면은 (218, 128, 218)입니다.

그림에는 깊이가 없으니 어떤 생성기든 높이를 추측한 뒤 그 기울기를 구합니다. Nerulio는 투명한 가장자리에서 솟아오르는 베벨(실루엣까지의 거리에 둥근·직선·부드러운·오목·턱 모양을 적용)과, 선택적으로 밝기에서 얻은 디테일로 높이를 만듭니다. 밝기 디테일은 칠이 곧 형태는 아니므로 화면에 근사치라고 표시됩니다. 같은 크기의 높이 맵(16비트 포함)을 더할 수도 있습니다.

노멀은 그 높이의 기울기입니다. 행을 아래로 세는 이미지 좌표에서 n ∝ (−강도·∂h/∂x, 강도·∂h/∂y, 1)을 길이 1로 정규화합니다. 높이는 픽셀 단위라서 강도 1이면 1픽셀당 1픽셀 오르는 경사가 45° 면이 됩니다. 커널(Pixel·Sobel·Scharr·Sobel 5×5)은 기울기를 얼마나 부드럽게 할지만 정합니다.

2D 조명은 픽셀마다 N·L, 즉 노멀과 조명 방향 사이 각도의 코사인만큼 밝게 합니다. 조명이 스프라이트 평면에서 얼마나 높이 있는지가 빛이 들어오는 각도를 정하므로, 같은 맵도 높은 조명 아래에서는 거의 평평하고 낮게 스치는 조명 아래에서는 깊게 파인 듯 보입니다.

탄젠트 공간
스프라이트 표면 기준의 방향. X는 오른쪽, Y는 위, Z는 보는 사람 쪽.
평평한 노멀
(128, 128, 255). 기울기가 없어 노멀맵이 없는 것처럼 비춰집니다.
베벨
투명한 가장자리에서 안쪽으로 올라오는 높이. 얇고 둥근 테두리나 전체가 부푼 모양.
강도
모든 기울기에 곱하는 값. 입체의 위치는 그대로 두고 면을 더 가파르게 합니다.

예시: 베벨 가장자리 하나의 숫자

스프라이트의 왼쪽 테두리, 즉 오른쪽으로 갈수록 몸통 쪽으로 1픽셀당 1픽셀씩 높아지는 곳을 Pixel 커널로 계산하면:

기울기 ∂h/∂x = 1 px/px          n ∝ (−s·1, 0, 1)
강도 0.5 → 기울기 26.6°         RGB ( 70, 128, 242)
강도 1   → 기울기 45.0°         RGB ( 37, 128, 218)
강도 2   → 기울기 63.4°         RGB ( 13, 128, 185)

조명이 왼쪽 64px, 높이 64px → L = (−0.707, 0, 0.707)
강도 1:  N·L = 0.707·0.707 + 0.707·0.707 = 1.00 → 가장 밝음
조명이 오른쪽 64px:             N·L = max(0, −0.5 + 0.5) = 0 → 주변광만

빛을 향한 테두리는 빛나고 반대쪽 테두리는 어두워지는데, 이 대비가 효과의 전부입니다. 강도는 모든 면을 한꺼번에 가파르게 하므로 몸통을 날카롭게 말고 둥글게 보이게 하려면 베벨 폭을 넓히세요. Studio는 128px 이하 프레임에 1.5px, 그보다 큰 스프라이트에는 대표 내접 반지름의 약 0.9배를 추천합니다.

이렇게 작동합니다

  • 실루엣 베벨: 폭과 높이(px), 둥근·직선·부드러운·오목·턱 모양. 추천 폭은 128px 이하 도트가 1.5px, 큰 스프라이트는 전체가 둥글게 부푼 모양입니다.
  • 밝기로 디테일 추가(근사치라고 표시되며, 어두운 망토를 구멍으로 읽지 않도록 넓은 음영 무시 옵션이 있음) 또는 같은 크기의 높이 맵(16비트 PNG 포함).
  • 텍스처 작업 공간의 높이 브러시(B): 추측이 틀린 곳을 올리고·내리고·부드럽게·평평하게·지웁니다. 한 번 칠하면 되돌리기 한 번이고 프레임 밖으로 넘어가지 않습니다.
  • 점광원 최대 8개(색·세기·높이·반경·감쇠), 앰비언트, 스페큘러. WebGL2 미리보기는 CPU 기준과 1/255 이내로 같았고 Godot 4.7.2도 마찬가지였습니다.
  • 도트용 노멀은 모든 픽셀을 4·8·16·32방향 × 1~4단계 기울기로 맞춰 그림체를 해치지 않습니다.

사용 방법

  1. 투명한 배경의 스프라이트 PNG를 넣습니다(시트라면 먼저 스프라이트 작업 공간에서 프레임을 자릅니다).
  2. 노멀맵 패널에서 추천 베벨을 그대로 쓰거나 폭과 모양을 바꿉니다.
  3. Lit 보기에서 빛을 끌어 보고 C로 평면과 조명을 비교하며, 어색한 곳은 높이 브러시로 칠합니다.
  4. Godot 4 씬, Unity 6 URP 2D 번들, 또는 OpenGL·DirectX PNG로 내보냅니다(Ctrl+E).

엔진에서 노멀맵 쓰기

  1. Godot 4: 스프라이트 텍스처로 쓰는 CanvasTexture의 Normal Map Texture에 _n.png를 넣고, PointLight2D의 Height를 0보다 크게 둡니다(기본값 0). 내보낸 _lit.tscn 씬은 이미 연결되어 있습니다. 자세한 내용은 Godot 2D 노멀맵 페이지.
  2. Unity 6 URP 2D: _n.png를 스프라이트의 보조 텍스처 _NormalMap으로 붙이고, Sprite-Lit-Default 머티리얼을 쓰며, Light 2D의 Normal Map Quality를 Fast나 Accurate로 바꿉니다(기본값 Disabled). 텍스처 쪽은 함께 내보내는 임포터가 처리합니다. Unity 2D 노멀맵 페이지 참고.
  3. DirectX 방식 초록을 읽는 엔진: PNG 세트의 _n_dx.png를 쓰세요. _n.png와는 초록(255 − g)만 다릅니다.
  4. 애니메이션 시트: 먼저 스프라이트 작업 공간에서 프레임을 잘라야 프레임마다 입체가 따로 계산됩니다. 스프라이트 시트 노멀맵 참고.

결과 확인

  • Lit 보기에서 조명을 스프라이트 둘레로 한 바퀴 끌어 보세요. 밝은 테두리가 조명을 따라가야 합니다. 먼 쪽 테두리가 밝아지면 다른 규약으로 읽히고 있는 것입니다.
  • C로 평면과 조명 화면을 나눕니다. 조명 쪽이 평면 쪽보다 어두운 곳은 모든 조명에서 등을 돌린 면이니, 그늘져야 할 자리인지 확인하세요.
  • 높이 보기로 바꿉니다. 어두운 망토나 외곽선이 움푹 파여 보이면 밝기를 형태로 읽은 것입니다.
  • _n.png를 아무 뷰어로 열어 보세요. 투명한 부분이 알파가 꽉 찬 (128, 128, 255)인 것은 의도된 것이고, 가장자리 노멀을 2px 밖으로 복사해 실루엣에서 필터링해도 엉뚱한 벡터가 섞이지 않습니다.

그림 종류별 시작 설정

Studio는 투명 여부로 스프라이트·반복 텍스처를 제안합니다. 아래는 보통의 출발점입니다.

그림시작 설정확인할 것
도트 스프라이트(프레임 128px 이하)베벨 1.5px, 둥근 모양, Clamp 가장자리, Pixel 커널, 필요하면 도트용 노멀Lit 보기에서 빛을 돌려 밝은 가장자리가 빛을 따라가는지
크거나 채색한 스프라이트베벨 ≈ 대표 내접 반지름 × 0.9(부푼 모양), 넓은 음영 무시를 켠 밝기 디테일어두운 부분이 구멍처럼 보이지 않는지, 높이 브러시로 보정
반복 텍스처(투명 없음)Wrap 가장자리, 밝기 디테일 또는 높이 맵Wrap 테스트 0 = 이음새 없음, 3×3 타일 보기(T)
이미 있는 노멀맵생성 대신 원본으로 사용점검 패널 판정 후 "It is OpenGL / It is DirectX", 스프라이트는 빨강 뒤집힘이면 Flip red(X−)

문제 해결

증상유력한 원인확인 방법해결
어두운 칠(망토, 외곽선)이 구멍처럼 보임밝기 디테일이 어두운 곳을 낮은 곳으로 읽음높이 보기에서 그 부분이 파여 있음밝기 높이를 낮추거나 "이보다 넓은 명암 무시" 값을 줄이거나, 높이 브러시(B)로 올리기
스프라이트가 테두리만 빛나는 납작한 판처럼 보임큰 채색 스프라이트에 도트용 1.5px 테두리가 적용됨노멀 보기에서 1~2px 고리에만 색이 있음베벨을 내접 반지름의 약 0.9배로 넓히거나 둥근 모양 선택
엔진에서 반대쪽이 밝아짐엔진이 다른 초록 규약을 읽거나, 다른 툴이 빨강을 뒤집어 저장함조명을 위에 두면 윗가장자리가 밝아져야 함Godot·Unity에는 _n.png 사용. 다른 곳에서 받은 맵은 OpenGL·DirectX 판별 참고
엔진에서 아무 변화가 없음렌더러가 읽는 자리에 맵이 없거나, 조명이 노멀맵을 무시함Godot는 CanvasTexture의 노멀 칸, Unity는 _NormalMap과 Light 2D 품질내보낸 씬이나 임포터를 쓰거나 엔진별 페이지를 따라 하기
손으로 찍은 도트가 조명을 켜면 더 어색함양식화된 음영은 색에서 계산해 낼 수 없음C로 평면 화면과 비교높이 브러시로 입체를 칠하거나 양자화한 도트 노멀을 쓰거나, 맵을 직접 그리기

다른 방법

방법이럴 때 더 낫습니다
Laigter(데스크톱, GitHub의 무료 GPL-3 빌드)프리셋, 스페큘러·오클루전·패럴랙스 맵, 명령줄이 있는 데스크톱 앱이 필요할 때. 3D로 렌더한 스프라이트에서는 기본 돔 모양이 가장 가까웠습니다(18.3°, Studio 20.0°). Laigter 비교 참고.
3D 모델에서 굽기3D로 렌더한 스프라이트라면 구운 노멀이 정답이고, 생성기는 그것을 흉내 낼 뿐입니다.
노멀맵을 손으로 그리기양식화된 도트 그림. 손으로 칠한 CC0 횃불에서는 Nerulio를 포함한 모든 생성기가 원작자의 맵과 37~42° 차이 났습니다.
높이 → 노멀 생성기(텍스처 랩)이미 높이 맵이나 회색 이미지가 있고 베벨이나 조명 없이 기울기만 필요할 때.

엔진별 내보내기와 검증 방법

"검증됨"은 실제 CC0 에셋으로 내보낸 파일을 해당 엔진·도구가 직접 불러와 원본과 비교했다는 뜻입니다. 불러오지 않은 형식은 그렇게 표시합니다.

대상파일검증
Godot 4 2D lights_lit.tscn · CanvasTexture .tres · normal / specular PNG검증됨 Godot 4.7.2실제 CC0 사례 6개를 Godot(gl_compatibility)가 렌더링했고, 확인한 모든 프레임이 Studio 조명 미리보기와 1/255 이내로 같았습니다. 초록을 뒤집은 같은 렌더는 3.8~37단계 어긋나므로 잘못된 규약을 잡아낼 수 있습니다.
Unity 6 URP 2DPNG · nerulio-texture.json · Editor/NerulioNormalMapImporter.cs검증됨 Unity 6000.5.3f1 (URP 17.5)12회 중 12회 통과(사례 6개 × 감마·리니어 색 공간): URP가 적용한 조명이 내보낸 노멀맵과 일치합니다(평균 오차 0.0037~0.0085). 빛의 감쇠는 URP 방식이라 밝기는 미리보기가 아니라 Unity 기준입니다.
PNG set + JSONalbedo · _n (OpenGL) · _n_dx (DirectX) · 16-bit height · AO · specular · manifest일반 파일어떤 엔진이나 도구에서도 쓰는 일반 파일이며, 엔진 실행 검증은 주장하지 않습니다.

검증 근거

Godot 4.7.2가 실제 CC0 사례 6개(도트, HD 스프라이트, 반복 텍스처, 가져온 DirectX 맵)를 렌더링했고 확인한 모든 프레임이 Studio 미리보기와 1/255 이내였습니다. Unity 6000.5 URP 2D: 12회 중 12회 통과(사례 6개 × 감마·리니어). 규약을 아는 실제 맵으로 OpenGL/DirectX 판별: 1K 전체 맵 128개 100% 정답, 표본 1,562개 중 틀린 "높음" 판정 0건(초록이 밝으면 OpenGL이라는 단순 규칙은 46%).

한계

  • 입체는 실루엣과 색에서 추측한 것이지, 작가가 생각한 형태가 아닙니다.
  • 미리보기의 림 라이트는 내보내지 않습니다. 커스텀 셰이더 없이 그리는 엔진이 없기 때문입니다.
  • Unity의 밝기 곡선은 URP 자체 감쇠이며, 검증한 것은 노멀맵 항(N·L)입니다.
  • 투명한 가장자리가 없는 그림(반복 텍스처)에서는 빨강이 뒤집힌 것과 DirectX 초록을 구별할 수 없습니다. 점검 패널이 이를 알리고 "빨강 뒤집기"를 제공합니다.
  • 시트는 스프라이트 작업 공간에서 프레임을 자르기 전까지 그림 하나로 조명됩니다. 텍스처 작업 공간은 프레임을 자르지 않습니다.
  • 림 라이트는 미리보기 전용이며, Unity로는 스페큘러 맵을 내보내지 않습니다(Godot는 내보냄).
  • Unity는 자체 빛 감쇠를 씁니다. 내보낸 노멀맵은 Unity에서 검증했지만 밝기 곡선은 Unity 방식입니다.

버전과 출처

Nerulio: Godot 4 번들은 Godot 4.7.2(Compatibility 렌더러)가 실제 CC0 사례 6건을 렌더했고 확인한 모든 프레임이 미리보기와 1/255 이내였습니다. Unity 6 번들은 Unity 6000.5.3f1·URP 17.5에서 12회 중 12회 통과했습니다(N·L 평균 오차 0.0037~0.0085). 실제 기준 노멀과의 각도는 2026-09-24 비교 측정 결과입니다. 바이트 인코딩과 Y+ 규약은 아래 Unity·Godot 문서를 따릅니다.

참고한 공식 문서

자주 묻는 질문

도트 그림에도 쓸 수 있나요?

네. 128px 이하 프레임은 기본 1.5px 테두리, Pixel 커널은 부드럽게 만들지 않고, 도트용 노멀로 방향을 맞출 수 있습니다. 다만 손으로 그린 도트 조명은 어떤 생성기에도 어렵습니다. CC0 횃불에서는 Nerulio·Laigter·PBR Forge 모두 원작자의 맵과 37~42° 차이 났습니다.

OpenGL과 DirectX 중 무엇이 필요한가요?

고도 엔진과 유니티는 OpenGL식 초록(Y+)을 읽으며 이것이 기본값입니다. PNG 세트는 _n(OpenGL)과 _n_dx(DirectX)를 둘 다 씁니다. 기존 노말맵을 가져오면 점검 패널이 규약을 판별하되, "It is OpenGL / It is DirectX"를 누르기 전에는 아무것도 바꾸지 않습니다.

엔진용 내보내기에는 무엇이 들어 있나요?

Godot 4는 Sprite2D, CanvasTexture, 앰비언트용 CanvasModulate, 빛마다 PointLight2D, 프레임용 AnimationPlayer가 든 _lit.tscn입니다. Unity 6은 PNG, JSON, 그리고 노멀맵을 _NormalMap 보조 텍스처로 넣고 조명 미리보기를 만드는 편집기 스크립트입니다.

무료인가요? 계정이 필요한가요?

이 페이지의 기능은 모두 무료이며 계정 없이 쓸 수 있습니다. 워터마크나 막혀 있는 내보내기가 없습니다.

스프라이트가 업로드되나요?

아니요. Studio는 이 브라우저 탭 안에서 디코딩·패킹·내보내기를 합니다. 프로젝트는 브라우저(IndexedDB)에 자동 저장되며 .nerulio 파일로 저장할 수 있습니다.

Aseprite나 엔진 플러그인을 설치해야 하나요?

아니요. .aseprite 파일은 브라우저에서 읽고 씁니다. 엔진별 번들에는 그 엔진에 필요한 것이 들어 있습니다(Godot는 가져오기 설정과 씬, Unity와 Godot 타일셋은 작은 편집기 스크립트).