노멀맵 변환 · OpenGL ↔ DirectX (초록 채널 반전)
두 규약의 차이는 초록 채널 하나입니다. 변환은 255 − g이며 그 자체가 역변환이라, 변환한 맵을 다시 변환하면 같은 바이트가 됩니다.

- Channel PNGs측정 확인· numpy
- Normal map측정 확인· numpy
- Packed mask / ORM측정 확인· Pillow
- Engine import미검증
이렇게 작동합니다
- 초록 채널만 바꾸는 OpenGL ↔ DirectX 변환(채널별로 확인).
- 어느 엔진이 어떤 규약을 기대하는지와 그 근거 문서(Unreal의 −Y는 추정으로 표시).
- 노멀맵 검증: 평균 길이, 최대 오차, 가장 낮은 파랑.
- Sobel·Scharr·Sobel 5×5와 반복 텍스처용 wrap으로 높이 → 노멀 생성.
사용 방법
- 노멀맵을 끌어다 놓습니다.
- 목표 규약을 고릅니다.
- 검증 수치를 확인합니다.
- 변환한 맵을 받습니다.
출력 파일과 검증 방법
"측정 확인"은 내려받은 파일을 페이지 밖에서(Pillow·numpy·별도 파서) 다시 열어 그 속성을 측정했다는 뜻입니다. 게임 엔진에서 불러오는 것은 시험하지 않았습니다.
| 대상 | 파일 | 검증 |
|---|---|---|
| Channel PNGs | <name>-r/g/b/a.png (8-bit grey) | 측정 확인 numpy채널마다 바이트가 같고 완전히 투명한 텍셀 아래의 RGB도 유지됩니다. |
| Normal map | PNG · OpenGL (+Y) or DirectX (−Y) | 측정 확인 numpy디코딩한 벡터가 단위 길이(최대 오차 0.0002)이고, OpenGL과 DirectX는 초록 채널만 다릅니다. |
| Packed mask / ORM | Unity HDRP mask · URP metallic · ORM (glTF, Godot) | 측정 확인 Pillow패킹된 바이트 확인: ORM 프리셋, AO 10 / 러프니스 80 / 메탈릭 220 → (10, 80, 220, 255). |
| Engine import | Unity · Unreal · Godot | 미검증어떤 엔진에서도 불러오지 않았습니다. |
검증 근거
채널 분리가 네 채널 모두 바이트 동일(최대 차이 0), 투명 텍셀 2048개가 RGB 유지. 가장자리 번짐은 알파 0인 텍셀 448개만 바꾸고 알파 바이트는 하나도 건드리지 않음. OpenGL ↔ DirectX는 초록(255 − g)만 다름. 변환한 노멀은 단위 벡터.
한계
- 정확한 채널 바이트는 PNG에서만 보장됩니다. JPEG·WebP는 브라우저가 디코딩하며 "바이트 동일 아님"으로 표시합니다.
- 인터레이스 PNG와 16비트 출력은 지원하지 않습니다. 정확 경로는 3,355만 픽셀까지입니다.
- 노멀맵의 규약은 픽셀로 알아낼 수 없고 변환만 할 수 있습니다.
- Unity·Unreal·Godot에서 불러오지 않았습니다. 채널 순서는 각 문서와 엔진 소스에 근거합니다.
자주 묻는 질문
내 맵이 어떤 규약인지 알 수 있나요?
아니요. 둘 다 올바른 노멀맵입니다. 랩은 어느 엔진이 무엇을 기대하는지 알려 주고 변환하지만, 감지한다고 주장하지 않습니다.
변환에 손실이 있나요?
없습니다. 초록이 255 − g가 되고, 두 번 변환하면 원래 바이트가 됩니다.
무료인가요? 계정이 필요한가요?
이 페이지의 기능은 모두 무료이며 계정 없이 쓸 수 있습니다. 워터마크나 막혀 있는 내보내기가 없습니다.
스프라이트가 업로드되나요?
아니요. Studio는 이 브라우저 탭 안에서 디코딩·패킹·내보내기를 합니다. 프로젝트는 브라우저(IndexedDB)에 자동 저장되며 .nerulio 파일로 저장할 수 있습니다.
Aseprite나 엔진 플러그인을 설치해야 하나요?
아니요. .aseprite 파일은 브라우저에서 읽고 씁니다. 엔진별 번들에는 그 엔진에 필요한 것이 들어 있습니다(Godot는 가져오기 설정과 씬, Unity와 Godot 타일셋은 작은 편집기 스크립트).