Кодеки текстур

Nighthogg Image Codec (NHI)

Блочный кодек с потерями для сжатия текстур. Похож на ETC2 и ASTC.

Базовое использование

// Кодирование текстуры
var image = new RawImage(width, height, pixelData);
byte[] encoded = NighthoggImageCodec.Encode(image);

// Декодирование
var decoded = NighthoggImageCodec.Decode(encoded);

Параметры качества

var encoded = NighthoggImageCodec.Encode(
    image,
    colorBits: 6,              // точность цветности (0-8)
    luminanceBits: 8,          // точность яркости (0-8)
    alphaBits: 4,              // точность альфа (0-8)
    alphaMultiplierBits: 2,    // точность множителя альфа (0-8)
    compressionMethod: CompressionMethod.Deflate
);

Больше бит = лучше качество, но больше размер.

Как это работает

  1. Разделение на блоки 2×2 — обрабатывает 4 пиксела за раз
  2. Преобразование в YUV — отдельно яркость и цветность
  3. Выбор лучшего паттерна — группирует пиксели по похожести
  4. Квантизация — округляет значения до нужного количества бит
  5. Сжатие DEFLATE — финальное сжатие результата

Типичное соотношение сжатия: 10:1 – 20:1 в зависимости от параметров.

Логирование

// Установить логгер для кодека
NighthoggImageCodec.Logger = Igdrasil.GetLogger("TextureCodec");

// Теперь кодек будет логировать ошибки (если они случатся)

Оптимизированная версия (NighthoggImageCodecOptimized)

Для больших текстур используйте оптимизированную версию:

// С параллельной обработкой блоков
var encoded = NighthoggImageCodecOptimized.Encode(
    image,
    colorBits: 6,
    luminanceBits: 8,
    useParallel: true   // параллельная обработка на многоядерных ПК
);

var decoded = NighthoggImageCodecOptimized.Decode(encoded);

Улучшения:

Когда использовать:

LoraCrunch Image Codec

Альтернативный кодек для экспериментов:

// Похожий API
var encoded = LoraCrunchImageCodec.Encode(image);
var decoded = LoraCrunchImageCodec.Decode(encoded);

Используйте для сравнения размера/качества с Nighthogg.

Интеграция с загрузкой ресурсов

public class CompressedTextureLoadingTask : GraphicsLoadingTask
{
    private readonly string _path;
    private Texture _texture;
    
    protected override void OnLoad()
    {
        try
        {
            // Загружаем исходное изображение
            var original = Image.Load(_path);
            
            // Кодируем в NHI
            byte[] encoded = NighthoggImageCodecOptimized.Encode(
                original,
                useParallel: true
            );
            
            // Сохраняем в кеш (опционально)
            string cachePath = _path.Replace(".png", ".nhi");
            File.WriteAllBytes(cachePath, encoded);
            
            // Декодируем обратно для GPU
            var decoded = NighthoggImageCodecOptimized.Decode(encoded);
            _texture = CreateTexture(decoded);
            
            Igdrasil.Logger.Info("Loaded compressed: {0} ({1}B)", _path, encoded.Length);
        }
        catch (Exception ex)
        {
            Igdrasil.Logger.Error("Failed to load {0}: {1}", _path, ex.Message);
            throw;
        }
    }
    
    protected override void OnUnload()
    {
        _texture?.Dispose();
    }
}

Рекомендации

Сценарий Кодек Параметры
Фон, ландшафт Nighthogg luminanceBits=8, colorBits=4
Нормал-мап Nighthogg luminanceBits=6, colorBits=4
UI-иконки Nighthogg luminanceBits=8, colorBits=6
Мобиль (качество) Nighthogg+ useParallel=false
ПК (скорость) Nighthogg+ useParallel=true
Экспериментирование LoraCrunch стандартные

Версия: 1.0