--- 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 ---
# 🎮 Sprite2Normal **AI-powered Tangent-Space Normal Map Generator for 2D Sprites & Pixel Art** [ 🇬🇧 English ](#-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 ```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. --- ## 🇷🇺 Русский
Нажмите, чтобы свернуть / развернуть русский текст
**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.
--- ## 📄 License / Лицензия This project is open-sourced under the **Apache-2.0** License. Проект распространяется под открытой лицензией **Apache-2.0**.