🎮 Sprite2Normal

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

🇬🇧 English 🇷🇺 Русский


🇬🇧 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

pip install onnxruntime pillow numpy

2. Inference script

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.

🇷🇺 Русский

Нажмите, чтобы свернуть / развернуть русский текст

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

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

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

✨ Особенности

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

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

1. Установка библиотек

pip install onnxruntime pillow numpy

2. Скрипт запуска

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.

📄 License / Лицензия

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

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support