File size: 6,203 Bytes
8ffc963
 
0b07206
 
 
 
 
 
 
 
 
 
 
8ffc963
0b07206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
---
license: apache-2.0
tags:
- gamedev
- normal-map
- image-to-image
- computer-vision
- sprites
- pixel-art
- onnx
- 2d-lighting
pipeline_tag: image-to-image
library_name: onnx
---

<div align="center">

# 🎮 Sprite2Normal

**AI-powered Tangent-Space Normal Map Generator for 2D Sprites & Pixel Art**

[ 🇬🇧 English ](#-english) • [ 🇷🇺 Русский ](#-русский)

</div>

---

<a name="-english"></a>
## 🇬🇧 English

**Sprite2Normal** is an ultra-lightweight neural network (~7 MB) designed to instantly generate tangent-space **Normal Maps** from flat 2D sprites, textures, and pixel art.

Built for indie game developers to easily add dynamic 2D lighting to their games without manually drawing height or normal maps.

Trained completely from scratch with a custom lightweight U-Net architecture.

### ✨ Features
- **Ultra-Compact:** Model file is only **~7 MB** in ONNX format.
- **CPU & GPU Friendly:** Runs in **3–10 ms** on standard CPUs without requiring a dedicated GPU.
- **Engine Compatible:** Generates standard OpenGL tangent-space normal maps (X: Red, Y: Green, Z: Blue), ready for **Godot, Unity, GameMaker, Unreal Engine**, and custom shaders.
- **Dynamic Resolution:** Fully convolutional architecture supporting sprites of any size.

### 🚀 Quick Start (Python)

#### 1. Install dependencies
```bash
pip install onnxruntime pillow numpy
```

#### 2. Inference script
```python
import numpy as np
from PIL import Image
import onnxruntime as ort

session = ort.InferenceSession("sprite2normal.onnx", providers=["CPUExecutionProvider"])
input_name = session.get_inputs()[0].name
output_name = session.get_outputs()[0].name

img = Image.open("character.png").convert("RGB")
orig_w, orig_h = img.size

img_resized = img.resize((128, 128), Image.Resampling.BILINEAR)
arr = np.array(img_resized, dtype=np.float32) / 255.0
arr = np.transpose(arr, (2, 0, 1))
input_tensor = np.expand_dims(arr, axis=0)

output = session.run([output_name], {input_name: input_tensor})[0][0]

pred = (output + 1.0) * 0.5 * 255.0
pred = np.clip(pred, 0, 255).astype(np.uint8)
pred = np.transpose(pred, (1, 2, 0))

normal_map = Image.fromarray(pred).resize((orig_w, orig_h), Image.Resampling.BILINEAR)
normal_map.save("character_normal.png")
print("Saved to character_normal.png!")
```

### 🕹️ Game Engine Integration
- **Godot Engine:** Place `character.png` and `character_normal.png` in your project folder. Assign the normal map to the **Normal Map** slot of your `Sprite2D` node and add a `PointLight2D`.
- **Unity (URP 2D):** Set texture type of `character_normal.png` to **Normal Map**. Assign it to **Secondary Textures** of your Sprite Renderer.

---

<a name="-русский"></a>
## 🇷🇺 Русский

<details open>
<summary><b>Нажмите, чтобы свернуть / развернуть русский текст</b></summary>
<br>

**Sprite2Normal** — это сверхлёгкая нейросеть (~7 МБ), предназначенная для мгновенной генерации карт нормалей (**Normal Maps**) из плоских 2D-спрайтов, текстур и пиксель-арта.

Создана специально для инди-разработчиков игр, чтобы быстро добавлять динамическое 2D-освещение без необходимости вручную прорисовывать объём каждого кадра анимации.

Обучена полностью с нуля на специализированной компактной архитектуре U-Net.

### ✨ Особенности
- **Минимальный вес:** Модель весит всего **~7 МБ** в формате ONNX.
- **Работает без мощной видеокарты:** Время инференса всего **3–10 мс** на обычном офисном процессоре (CPU).
- **Готовность к игровым движкам:** Создаёт стандартные OpenGL-карты нормалей (X: Красный, Y: Зелёный, Z: Синий), совместимые с **Godot, Unity, GameMaker, Unreal Engine** и кастомными шейдерами.
- **Любое разрешение:** Свёрточная архитектура принимает спрайты произвольного размера.

### 🚀 Быстрый старт (Python)

#### 1. Установка библиотек
```bash
pip install onnxruntime pillow numpy
```

#### 2. Скрипт запуска
```python
import numpy as np
from PIL import Image
import onnxruntime as ort

session = ort.InferenceSession("sprite2normal.onnx", providers=["CPUExecutionProvider"])
input_name = session.get_inputs()[0].name
output_name = session.get_outputs()[0].name

img = Image.open("character.png").convert("RGB")
orig_w, orig_h = img.size

img_resized = img.resize((128, 128), Image.Resampling.BILINEAR)
arr = np.array(img_resized, dtype=np.float32) / 255.0
arr = np.transpose(arr, (2, 0, 1))
input_tensor = np.expand_dims(arr, axis=0)

output = session.run([output_name], {input_name: input_tensor})[0][0]

pred = (output + 1.0) * 0.5 * 255.0
pred = np.clip(pred, 0, 255).astype(np.uint8)
pred = np.transpose(pred, (1, 2, 0))

normal_map = Image.fromarray(pred).resize((orig_w, orig_h), Image.Resampling.BILINEAR)
normal_map.save("character_normal.png")
print("Сохранено в character_normal.png!")
```

### 🕹️ Интеграция в движки
- **Godot Engine:** Поместите спрайт и карту нормалей в проект. В ноде `Sprite2D` в поле **Normal Map** выберите созданный файл и добавьте `PointLight2D`.
- **Unity (URP 2D):** В настройках текстуры укажите тип **Normal Map** и назначьте её во вкладку **Secondary Textures** компонента Sprite Renderer.

</details>

---

## 📄 License / Лицензия
This project is open-sourced under the **Apache-2.0** License.  
Проект распространяется под открытой лицензией **Apache-2.0**.