Экспорт в движки

Окно «Экспорт»

Экспорт (Ctrl+E) находится сразу после Импорт в заголовке окна и открывает окно, оформленное так же, как окно импорта (D51):

  1. Конвейер ассета — для начала тот, что показывает выбор «Ассет» в заголовке. То, что он записывает, проектируется в графе ассета.
  2. Папка экспорта — введите путь или Выбрать… папку. Проект ее запоминает.
  3. Экспортировать сейчас — проект в том виде, в каком он открыт, сохранен он или нет: экспорт никогда его не сохраняет, а безымянный проект экспортируется как есть.

Окно экспорта: конвейер ассета, папка, файлы, которые будут записаны, и кнопка «Экспорт»

Прежде чем вы нажмете «Экспорт», окно перечисляет все файлы, которые запишет экспорт, так, как их называет pxr names: каждый по пути в папке и виду (спрайт-лист, JSON, GIF…), с пометкой будет заменен у файла, который в папке уже есть. Список находится заново — с небольшим индикатором загрузки, никогда не блокируя окно, — когда вы меняете конвейер ассета, папку или проект. Конвейер, который нельзя экспортировать как есть (например, два выхода пишут один файл), объясняет там почему, и «Экспорт» ждет, пока это не исправят.

После нажатия эти же строки на своих местах и есть экспорт: у каждой индикатор загрузки, пока она не записана, затем галочка, ее размер, Открыть (в программе, которой ее открывает ваша система) и Показать папку. Если что-то идет не так, об этом сказано на файле, на котором все остановилось. Стоп прерывает экспорт на полпути: записанное остается, а файл, который записывался, удаляется. Окно можно закрыть во время работы; «Экспорт» откроет его снова.

Он запускает ровно то же, что и командная строка: pxr render PROJECT --pipeline NAME -o FOLDER в отдельном процессе, чтобы Pixor оставался отзывчивым, — на снимке проекта в том виде, в каком он открыт, записанном в папку созданных файлов (с абсолютными путями к его файлам) и удаляемом после завершения экспорта. Файлы называются так, как pxr render называет файлы этого проекта: по проекту, а у безымянного — по его модели. Каждый файл записывается заново из конвейера: то, что Создать делают узлы графа ассета, никогда не копируется.

Каждый файл попадает в папку. Лист берет имя файла из PNG-узла проекта (out/hero.png записывает FOLDER/hero.png); файл, путь которого лежит внутри папки листа, сохраняет свое место внутри FOLDER, а у любого другого пути (архив, анимация, иконки с другим именем) остается только последняя часть.

Что записывает экспорт

Каждый экспорт записывает лист: один ряд на каждое действие и сторону, один столбец на кадр, все ячейки одного размера, опорная точка в каждой на одном и том же пикселе. Добавьте к листу узлы «Файл» в графе ассета (или используйте --export в командной строке), чтобы получить рядом файлы с тем же именем. Каждый из них — узел, подключенный к листу, со своими параметрами. --export all записывает все форматы ниже, кроме p8 и video, которые записываются только по имени: картридж вмещает только лист, сделанный под него, а несжатое видео всех клипов и сторон может занимать гигабайты. Никакие два из них не пишут один файл: pxr names отклоняет проект, где это случилось бы.

Формат Файл Для
png name.png лист — индексированный PNG (индекс 0 прозрачный)
json name.json прямоугольники ячеек, длительности кадров, тег на каждое действие и сторону, опорная точка. Формат «array» Aseprite, поэтому его читают импортеры, написанные для Aseprite
aseprite name.aseprite индексированный файл Aseprite: слои final, lines, flat и по одному на каждый дополнительный выход графа стиля; тег на каждое действие и сторону; длительности кадров; срез pivot
обычный name_normal.png карта нормалей с той же раскладкой, для 2D-освещения
глубина name_depth.png глубина с той же раскладкой: белое — ближайшее, темное — самое дальнее, одна шкала на весь лист (meta.pixor.depth дает обе границы в метрах); прозрачно там, где ничего нет. Для сортировки, тумана и 2.5D-освещения
свечение name_emission.png каждый светящийся пиксель своим цветом, настолько ярким, насколько он светится (светящийся материал или карта свечения модели); прозрачно в остальных местах. Для свечения и блума
слои name_lines.png, name_flat.png и name_LAYER.png для каждого дополнительного выхода графа стиля слои линий и плоского цвета как листы, а также изображение узла, если граф стиля его называет
палитра name.hex, name.gpl палитра (форматы Lospec и GIMP)
godot name.tres ресурс SpriteFrames для Godot 4
gif name_walk_Southeast.gif, … по анимированному GIF на каждое действие и сторону, удержания — как задержки кадров, для публикации и превью
apng name_walk_Southeast.apng, … то же, что анимированные PNG, с точными задержками в миллисекундах
видео name_walk_Southeast.avi, … по видео на каждое действие и сторону: несжатый AVI, каждый пиксель как есть, для трейлера или страницы магазина
light-kit name_ramps.png, name_normal.png, name_light.png, шейдеры освещение с правильной палитрой в движках (см. ниже)
отчет name_report.png лист с отмеченными находками каждой проверки (см. ниже)
p8 name.p8 картридж PICO-8 (см. Режимы консоли)
zip путь на его узле узел Архив ZIP в графе ассета: подключенные к нему файлы или все, что записал экспорт

Строка называется по своему действию и стороне: walk_Southeast.

Какие кадры берет лист, как они расположены и сколько файлов записывает один рендер — это дело графа ассета: один узел «Лист» и его узлы файлов, пока вы его не пересоедините.

Как называются кадры и что они собой представляют

У каждого кадра в листе есть имя и id, и они отвечают на два разных вопроса.

Имя — это шаблон, образец из собственных слов вашего проекта, поэтому простой вариант по умолчанию — это то, что нужно новичку, а студия может следовать соглашению, которое выбирала не она:

{project}_{action}_{side}_{index:2}.{ext}     hero_walk_East_00.png

Слова: {project}, {object}, {action}, {side}, {layer}, {set} (набор частей, которым узел «Спрайты» нарисовал кадр), {size}, {index} и {ext}. {index:3} дополняет число нулями до трех цифр. {{ и }} пишут фигурную скобку. Незнакомое Pixor слово — ошибка при вводе шаблона, а не файл с именем hero_{genre}_00.png, а пустое слово убирает вместе с собой разделитель перед ним, так что спрайт без стороны — это hero_Static_00.png.

Значение, которое не может быть частью имени файла (/ \ : * ? " < > |), отклоняется, а не заменяется молча; пробел становится _. Единственное исключение — собственное слово Pixor: клип библиотеки с именем lib:walk в имени становится lib-walk, потому что это двоеточие принадлежит Pixor, а не вам.

Два кадра, которые получили бы одно и то же имя, отклоняются еще до начала рендера. Задайте шаблон через --names в командной строке или храните его в проекте:

pxr project set hero.pixor --names '{object}/{action}-{side}-{index:3}.{ext}'
pxr names hero.pixor                  # what it will write, without rendering
pxr names hero.pixor --json           # the same, for a build script

Id говорит, что такое кадр, а не где он оказался. Это хеш объекта, действия, стороны, времени в действии и слоя, и он записывается рядом с каждым кадром в JSON и в пользовательских данных .aseprite. Перепаковка листа, добавление клипа или изменение отступов двигают прямоугольники, но не трогают id, поэтому сборка, ссылающаяся на кадры по id, не ломается при каждом запуске упаковщика. Пересэмплирование клипа с другой частотой кадров меняет его id, потому что это уже другие кадры.

Листы меньше

На узле Расположить графа ассета (или в командной строке):

  • «Обрезать пустое место» (--trim) обрезает каждый кадр до его пикселей. JSON указывает место каждого кадра в полной ячейке (spriteSourceSize, trimmed: true), а файл Godot задает margin каждого кадра, поэтому движки по-прежнему ставят каждый кадр на опорную точку.
  • «Хранить повторяющиеся кадры один раз» (--dedupe): полностью одинаковые кадры (удерживаемые позы, стороны неподвижного объекта) занимают одно место.
  • Макс. ширина листа (--max-width 4096) начинает новую строку, прежде чем лист станет шире, — для движков и GPU с ограничением размера текстуры.
  • Макс. высота листа (--max-height 2048) делит более высокий лист на страницы, целые клипы на страницу: hero_1.png, hero_2.png, каждая со своим JSON и остальными файлами рядом.
  • Кадров в ряду (--columns 8) ставит в ряд столько кадров, и каждый клип идет вслед за предыдущим: контактный лист или фиксированная сетка, которую требует импортер движка.
  • Сторона, нарисованная из другой (узел Отразить графа ассета): симметричная слева направо модель выглядит слева так же, как отраженный вид справа, поэтому западную сторону вообще можно не рендерить — возьмите спрайты восточной камеры, отразите их как West, и в листе будет walk_West, нарисованный из walk_East, с отраженными пикселями, нормалями, рамками и root motion. Рендерьте только различающиеся камеры, остальные отражайте.
  • Градусы каждой стороны есть в JSON: в каждом кадре (pixor.degrees) и для всех сразу в meta.pixor.sides ({"South": 0, "Southeast": 45, ...}): градусы от фронта, против часовой стрелки при взгляде сверху, в том виде, в каком их принимает --sides. По этой таблице игра превращает угол в строку.

Слой теней

«Слой теней» (--shadow contact или --shadow drop) записывает name_shadow.png, разложенный как лист: черный там, где падает тень, прозрачный в остальных местах. Contact — пятно под ногами размером с опору модели; Drop — силуэт, отброшенный на землю в сторону от ключевого света. Рисуйте его под спрайтами с нужной непрозрачностью или сортируйте отдельно. Узел «Слой» графа ассета может назвать shadow, а «Наложение» помещает его под спрайт в одном листе (Граф ассета).

Цикл цветов во время игры

С циклическими материалами JSON перечисляет каждый из них в meta.pixor.cycles ("material" и его "indices" в палитре, в порядке цикла), а Pixor записывает name_index.png — лист в виде индексов палитры. Движок может вращать эти элементы палитры на каждом такте вместо хранения лишних кадров. Другие материалы с теми же оттенками зацикливаются вместе с ними, как при любом цикле палитры; дайте циклическому материалу собственные цвета, чтобы отделить его.

Сцены из нескольких моделей и параллакс-фоны

Проект может содержать больше одного объекта: модели, расставленные на плоскости земли и отрендеренные как одно изображение, с одним светом и тенями между ними, — уголок деревни, комната подземелья, лагерь, арт для страницы магазина из бесплатной библиотеки.

Каждый из них — предмет: модель, место, где она стоит, направление, куда она смотрит, и ее размер — узел Item графа сцены, добавленный в конец его цепочки, который повторяют кольцо или разброс после него. В командной строке каждый --item — это один предмет:

pxr project new camp.pixor \
  --item tent.glb@-1.8,-1.6,25,1.2 \
  --item campfire.pixoritem@0,0 \
  --item barrel.glb@2,1,0,1,2 \
  --ground 7,5,#5d7a45 \
  --size 200
pxr render camp.pixor

@x,z[,yaw[,scale[,layer]]] — где стоит предмет (в метрах, x вправо, z к камере); --ground W,D[,#rrggbb] кладет под них плоскость земли. Добавьте :clip[,phase] — и этот предмет проигрывает собственный клип со своего момента, пока соседние стоят на месте. Пути указываются относительно проекта.

Слои параллакса (узел файла «Слои параллакса», от 2 до 8 слоев, или --parallax N) разделяют изображение по глубине на слои для прокручиваемого фона: каждый рендерится отдельно на той же сцене и в той же палитре, а дальние слои темнеют и синеют к цвету дымки (--haze) — так выглядит расстояние (выключенная «Дымка дальних слоев» или --haze none оставляет каждый слой в палитре как есть — для игры с фиксированной палитрой). layer предмета помещает его в слой (0 — самый дальний); остальные распределяются по глубине. Pixor записывает name_layer0.png, name_layer1.png, …, name_parallax.json (изображение каждого слоя и рекомендуемая скорость прокрутки, от 0.25 для самого дальнего до 1 для ближайшего) и name_parallax.png — слои, сложенные вместе. Разделить можно любую модель, а не только сцену из нескольких. Узел «Слой» графа ассета называет слой как layer0, layer1, …, чтобы вывести его на отдельный лист (Граф ассета). pxr project set --parallax N --haze #rrggbb|none задает и то и другое для проекта.

Режимы консоли

Для homebrew и фэнтезийных консолей выберите Консоль в разделе «Стиль» (или --console). Тогда Pixor использует собственные цвета консоли и ее ограничения:

Консоль Цвета На спрайт Заметки
Game Boy оттенки зеленого: 4 3 + прозрачный оттенки по светлоте
NES основная палитра из 54 цветов 3 + прозрачный проверяется также для каждого тайла 8 × 8
PICO-8 его 16 все 16 экспортировать картридж .p8 (отметьте p8; лист должен поместиться в 128 × 128: задайте максимальную ширину 128)
TIC-80 его 16 (Sweetie 16) все 16 импортируйте PNG через import sprites в TIC-80
C64 его 16 3 + прозрачный многоцветные спрайты: пиксели двойной ширины; держите ширину четной (спрайты C64 — 24 px)

Там, где спрайту можно использовать только три цвета, Pixor выбирает три цвета консоли, лучше всего покрывающие вашу модель в тени, базовом цвете и на свету, так что каждый кадр и каждая сторона используют одни и те же три. Раздел «Стиль» сообщает, подходит ли кадр на экране; pxr console check sheet.png проверяет весь лист (цвета, цвета на кадр и на тайл, пары двойной ширины, размер) и читает консоль из рецепта внутри листа. Каждый рендер в режиме консоли выполняет ту же проверку для записанного листа и завершается ошибкой (код выхода 1, с перечнем проблем), если тот не подходит. Ваша собственная палитра сохраняется в режиме консоли, а не заменяется палитрой консоли, — так что о шестнадцатицветной палитре на Game Boy будет громко сказано, а не тихо подменено четырьмя зелеными. Цвета NES Pixor вычисляет из видеосигнала консоли, остальные — опубликованные значения консолей.

Освещение с сохранением палитры в движках

Движки освещают спрайты по картам нормалей с плавным затенением, что приносит цвета, которых в вашей палитре никогда не было. Отметьте Набор света (или --export light-kit), и спрайты будут реагировать на игровой свет, а каждый освещенный пиксель останется на ступени своей цветовой рампы — с полосами, сдвигом оттенка и бликами Pixor. Pixor записывает рядом с листом:

Файл Что это такое
name_ramps.png цветовая рампа каждого пикселя (номер рампы + 1 в красном канале; 0 для пикселей, которых не касается свет, например линий)
name_normal.png нормали в пространстве вида: x вправо, y вверх, z к камере
name_light.png таблица: строка на каждую рампу, столбец на каждый уровень света, затем цвет блика, затем два столбца, которые вовсе не цвета, — собственные пороги бликов этой рампы, потому что глянцевый или металлический материал получает блик легче, чем матовый
pixor_palette_light.gdshader, name_light.tres шейдер Godot и материал со всеми заданными текстурами: назначьте материал на Sprite2D или AnimatedSprite2D
PixorPaletteLight.shader шейдер Unity: создайте с ним материал для SpriteRenderer и задайте его три карты
pixor_palette_light.fsh, .vsh шейдер GameMaker; комментарии показывают, как привязать карты

Шейдеры освещают одним ключевым светом (light_dir, направление к свету, в пространстве нормалей), заполняющим светом пресета, а также бликами и контровой подсветкой, пороги которых берутся из текстуры-таблицы, для каждой рампы, как это делал сам Pixor. Значение specular или rim от -1 до 1 переопределяет их для всего спрайта; больше 1 — выключает эти блики; меньше -1 (по умолчанию) — использует значения таблицы. Блик рисуется, только если блик получает и один из четырех соседних пикселей, — это собственное правило Pixor против одинокого яркого пикселя; min_highlight 1 его выключает. Двигайте свет из сценария, например к факелу: material.set_shader_parameter("light_dir", dir). Импортируйте три карты без фильтрации, без сжатия и без MIP-уровней. Чтобы увидеть результат до экспорта, включите Превью 2D-освещения (L) над спрайтом и выберите Свет как: набор света: свет поворачивается к указателю, и кадр освещается через ту же таблицу по тем же правилам (блики только рядом с другими, пиксели без рампы не трогаются), что и в шейдерах. Со светом рендера кадр выглядит точно так, как нарисовал его Pixor (исключение — несколько пикселей на краях полос); отбрасываемые тени, дизеринг и сглаживание мерцания анимированных листов есть только в Pixor, поэтому выключайте отбрасываемые тени для листов, которые освещаете в движке. JSON перечисляет файлы и свет в meta.pixor.light_kit.

Варианты палитры

Добавить вариант (--variant NAME, можно повторять) экспортирует тот же лист в других цветах. Pixor рисует индексами палитры, поэтому вариант меняет только палитру: каждый пиксель, линия и оттенок остаются на месте.

  • Эффекты: hit-flash, frozen, poisoned, petrified, burning, silhouette, selected, время суток dawn, noon, dusk, night и времена года autumn и winter (зелень становится оранжевой либо бледной и заснеженной).
  • Цвета команд: team:blue (или red, green, yellow, purple, orange, teal, pink, white, black или team:#3050e0) перекрашивает только цвет команды — материалы или цвета, отмеченные через --team или в разделе «Материалы», — а кожу, сталь и золото оставляет как есть. Каждый оттенок сохраняет светлоту, поэтому рампа по-прежнему читается. Четыре команды из одного спрайта: --team cloth --variant team:red --variant team:blue --variant team:green --variant team:yellow. JSON перечисляет индексы палитры команды в meta.pixor.team — для движков, которые перекрашивают во время игры через текстуру подстановки (см. ниже).
  • Каждый цвет повернут: hue:120 поворачивает каждый цветной оттенок на 120 градусов; серые остаются серыми.
  • Другие палитры: palette:pixor-8 или palette:my-colours.hex переводит каждый цвет в ближайший цвет этой палитры, сохраняя разделение светлого и темного.

Каждый вариант — это name_<variant>.png. При любом варианте Pixor также записывает два файла для замены палитр во время выполнения, так что один лист обслуживает все уровни и команды:

  • name_index.png: лист, где индекс палитры каждого пикселя записан оттенком серого (0 — прозрачный);
  • name_lut.png: текстура подстановки шириной 256 пикселей, по строке на палитру (строка 0 — собственная палитра листа, строка k — вариант k).

Шейдер выполняет поиск lut(index / 255, row). JSON перечисляет варианты и их строки в meta.pixor.variants.

Рецепт внутри каждого экспорта

Каждый файл, экспортированный Pixor, помнит проект, который его создал: лист, его листы слоев и карты (_lines, _flat, _normal, _depth, _emission, _shadow), его варианты палитры и индексный лист, .aseprite, каждый GIF (в комментарии) и APNG. Перетащите любой из них в Pixor (или выберите в Открыть проект), чтобы вернуть проект: файл .pixor, если он еще на месте, или новый проект, восстановленный по рецепту. Пути хранятся относительно экспортированного файла; путь, который нельзя сделать относительным, сохраняет только имя файла, поэтому в листе, которым вы делитесь, не видно названий ваших папок. Снимите флажок Рецепт в файлах (или передайте --no-recipe), чтобы не записывать его.

Godot 4

  1. Скопируйте name.png и name.tres в свой проект, рядом друг с другом.
  2. .tres загружает лист из res://name.png. Если вы положили его в другое место, передайте --godot-path res://path/name.png при экспорте из командной строки или исправьте путь в начале .tres.
  3. Создайте AnimatedSprite2D и укажите в его Sprite Frames файл name.tres. Каждое действие и сторона — отдельная анимация, зацикленная, с удержаниями кадров.
  4. Для четких пикселей установите Texture > Filter в Nearest.

Unity

  • С пакетом Aseprite Importer (2D Aseprite Importer): перетащите name.aseprite в Assets. Каждый тег становится анимационным клипом; используйте слой final.
  • Без него: импортируйте name.png как Sprite (Multiple), Filter Mode Point, Compression None и нарежьте по размеру ячейки (размер ячейки указан в name.json в meta.pixor.cell). Опорная точка — в meta.pixor.pivot, в пикселях от левого верхнего угла ячейки.

GameMaker

Импортируйте name.png как полосу спрайтов: используйте экспорт с раскладкой Strip (--layout strip) для каждой анимации или нарежьте сетку по размеру ячейки. Установите начало координат в опорную точку из name.json.

Aseprite

Откройте name.aseprite или нажмите Открыть на узле файла Aseprite (Pixor находит Aseprite в PATH и в обычных папках Steam и itch, а иначе спрашивает, где он). Теги перечисляют все действия и стороны. Слой final видим; lines и flat — скрытые вспомогательные слои для ручной доработки, как и каждый дополнительный выход, который называет граф стиля, — над final. Файл в индексированном режиме с палитрой Pixor.

Рисуйте поверх и сохраняйте свою работу. Добавьте свои слои и рисуйте, затем измените модель или облик в Pixor и выполните повторное запекание:

pxr rebake out/hero.aseprite

Pixor владеет тем, что записал сам, и ничем другим. Повторное запекание заново рендерит проект и:

  • заменяет пиксели слоев, созданных Pixor (final, lines, flat), там, где на них никто не рисовал;
  • оставляет ваши слои в точности такими, как есть, — никогда не перемещая, не переименовывая, не переупорядочивая и не перекрашивая, — с каждым нарисованным кадром-слоем на том кадре, где он был нарисован. Каждый кадр несет идентификатор, составленный из того, что он собой представляет (действие, сторона, время), так что если в середине ходьбы появятся три новых кадра, нарисованные вами глаза останутся на своих позах, а не съедут на новые, — и повторное запекание сообщает об этом покадрово: moved your paint on frame 1 is on frame 2 now, а также какие кадры новые (moved и new_at в --json);
  • сохраняет каждый цвет, которым вы рисовали, на его индексе, добавляя новые цвета в конец палитры, — или, если в Aseprite вы перевели лист в оттенки серого или RGB, записывает рендер соответственно в оттенках серого или в цвете;
  • сохраняет ваши срезы и их ключи на тех кадрах, где они были, куда бы эти кадры ни переместились;
  • помечает тегом кадры, где модель ушла из-под вашей прорисовки, pxr check, и оставляет прорисовку на месте.

Две вещи он не станет решать сам и сохраняет оба варианта, пока не решите вы:

Что случилось Что делает повторное запекание
Вы рисовали на одном из собственных слоев Pixor Слой Pixor получает новый рендер; ваша правка переносится на ваш собственный слой final edits прямо над ним; кадр помечается тегом pxr conflict
Нарисованного вами кадра нет в новом рендере (клип стал короче) кадр сохраняется в конце, с вашей прорисовкой, с тегом pxr removed

В любом случае ничего не теряется. pxr rebake завершается с кодом 7, пока вы не скажете, как поступить: --resolve keep сохраняет ваши правки как ваши собственные слои, --resolve pixor берет рендер Pixor и отбрасывает их. --dry-run сообщает, что сделает повторное запекание, ничего не записывая, а --json сообщает это для инструмента; расширение задает вам тот же вопрос в диалоге.

GIF и APNG

Каждое действие и сторона становятся отдельным зацикленным файлом (незацикленный клип проигрывается один раз). Кадры используют палитру спрайта, индекс 0 прозрачный. Масштаб на узле GIF или APNG (--anim-scale K) увеличивает их в целое число раз, от 1 до 16, так что спрайт 64 px можно вывести как GIF 256 px с идеально четкими пикселями.

GIF хранит задержки в сотых долях секунды, поэтому задержка каждого кадра округляется, но общая длина клипа сохраняется. Браузеры показывают задержки меньше 20 мс как 100 мс, поэтому ни один кадр GIF не короче 20 мс: выше 50 fps GIF пропускает кадры, которые показывались бы меньше, и играет столько же, сколько клип. APNG хранит точные миллисекунды, округленные по нарастающему итогу, как в JSON, поэтому кадры клипа на 12 fps длятся 83 и 84 мс. Переименуйте файл .apng в .png, если сайт принимает только PNG. Клип, нарисованный узлом Layer графа ассета, анимирует этот слой — только линии, плоские цвета — так, как его показывает лист; слой карт нормалей, глубины или свечения анимирует спрайт, поскольку GIF содержит только цвета палитры.

Видео

«Видео на каждый клип» записывает каждое действие и сторону как name_walk_Southeast.avi: несжатый AVI, 24-битный цвет, который открывает любой редактор и конвертер и который ничего не теряет — ни один кодек не размажет пиксель. У его узла три параметра:

  • «Масштаб» (от 1 до 16, по умолчанию 4): сколько пикселей видео составляет один пиксель рисунка.
  • Кадров в секунду (от 1 до 100, для начала 30): видео идет с одной частотой, поэтому кадр спрайта записывается столько раз, сколько он длится, и клип сохраняет длину с точностью до одного кадра видео.
  • Фон: то, что за спрайтом. У видео нет прозрачности.

--export video в командной строке берет начальные значения или --video-scale K, --video-fps N и --video-background #RRGGBB. --export all не включает видео: укажите их явно.

Оно не сжато, поэтому большое — спрайт 64 px с масштабом 4 занимает около 200 КБ на кадр, — а видео больше гигабайта не записывается, а отклоняется. Чтобы выложить его в сеть, конвертируйте: ffmpeg -i hero_walk_South.avi -crf 0 hero_walk_South.mp4.

Простые движки и ваш собственный код

Читайте name.json: frames[i].frame — прямоугольник ячейки, а frames[i].duration — ее удержание в миллисекундах; meta.frameTags группирует кадры в анимации, а тег, который проигрывается один раз, а не по кругу, несет "repeat": "1", как пишет Aseprite. frames[i].pixor указывает tag кадра (имя его тега), его index в нем, его action и side, его id и его pivot — точку в ячейке, на которую движок ставит спрайт; это точка листа, если только узел Tag не дал клипу собственную. Срез опорной точки в meta.slices имеет ключ везде, где опорная точка меняется, и срез опорной точки в файле .aseprite — те же ключи.

Root motion

У клипа, экспортированного «На месте», есть еще два значения на кадр, в пикселях с сохранением дробной части (x вправо, y вниз):

  • frames[i].pixor.root: где был бы корень модели, относительно его положения в начале клипа.
  • frames[i].pixor.root_delta: насколько корень сдвигается до следующего кадра. Для последнего кадра это сдвиг до конца клипа, поэтому зацикленная ходьба продолжается с той же скоростью.

Чтобы двигать персонажа так, как это делал клип, прибавляйте root_delta к позиции спрайта каждый раз, когда кадр заканчивается.

Иконки инвентаря

pxr icons (или узел «Иконки» в графе ассета, создаваемый при экспорте проекта) превращает модели в согласованные иконки инвентаря: каждая модель с одного и того же ракурса ¾ при схеме освещения Studio, размером 16, 24, 32 и 48 пикселей (или --sizes), с силуэтом цвета ее редкости (--rarity common|uncommon|rare|epic|legendary) и, с --framed, на тайле с рамкой, как ячейка инвентаря. Каждая иконка — PNG, а для каждого размера создается атлас icons_N.png с icons_N.json, где указано место каждой иконки. Укажите папку, чтобы превратить целый пак в набор иконок, — в приложении перетащите папку на окно и включите «Иконки вместо спрайтов»: там есть размеры, редкость (из имени каждого файла, если вы не выберете ее сами) и рамка, а рецепт сохраняется рядом с иконками как icons.pixoricons:

pxr icons library/pickups --out icons --rarity epic --framed

--rarity from-name дает каждой модели редкость, которую называет слово в имени ее файла (potion_rare.glb, Sword-Epic.glb; без такого слова — обычная), а JSON указывает редкость каждой иконки. Файлы берутся в порядке имен, так что атлас одинаков, в каком бы порядке папка их ни перечисляла.

Рецепт сохраняет пак: --save pack.pixoricons записывает папки и параметры (пути относительно рецепта), а pxr icons pack.pixoricons собирает пак заново, байт в байт. Реквизит, добавленный в папку, войдет в следующий запуск; флаг после рецепта меняет один параметр на этот запуск (pxr icons pack.pixoricons --sizes 64).

Воксели и стопки спрайтов

Файл MagicaVoxel .vox открывается как любая другая модель: каждая модель его сцены там, куда ее ставит граф сцены (повернутая и сдвинутая так, как показывает MagicaVoxel), его палитра и светящиеся воксели светящегося материала. Воксель считается десятой долей метра, +Z вверх.

pxr voxels MODEL -o hero.vox --height 32 превращает любую модель в воксели высотой 32: поверхность берется из ее текстур и цветов, внутренность заполняется, каждый воксель — в собственной палитре облика (--preset, --palette и другие параметры облика), так что воксели совпадают со спрайтами. С --stack он также записывает стопку спрайтов: hero_stack.png — модель, разрезанную на горизонтальные срезы, уложенные рядом, снизу вверх, каждый вид сверху, — и hero_stack.json с размером и числом срезов. Игра рисует срез k на пиксель выше среза k - 1 и поворачивает их все вместе — так sprite stacking имитирует 3D.

pxr voxels knight.glb -o knight.vox --height 32 --stack --preset selout

Проверка, что все совпадает

pxr audit folder --style game.pixorkit читает каждый экспортированный PNG и файл .aseprite в папке и сверяет его с набором по рецепту внутри каждого файла: пресет, схема освещения, вид, наклон камеры, ключевой свет, полосы света, линии, палитра и пиксели на метр, а также то, что каждый используемый цвет есть в палитре набора. Без набора эталоном служит первый файл. Каждое отличие выводится в списке; любое отличие делает код выхода 1, поэтому команда может охранять сборку.

В приложении доска согласованности (кнопка с тремя фигурами, Доска согласованности: все стороны сразу, или B) показывает текущий кадр со всех сторон рядом на одной линии земли, с отмеченным верхом каждого силуэта и его шириной, высотой и числом цветов под ним. Под кнопкой:

  • «Силуэты» рисует каждую сторону только ее формой, одним цветом: поза, которая не читается как силуэт, не читается и в игровом размере.
  • «Опорные точки» отмечают пиксель, на котором стоит и вокруг которого поворачивается каждая сторона. Сторона, ноги которой не на нем, съезжает, когда спрайт поворачивается.
  • Число цветов записывает число для каждой стороны; панель сообщает, когда высоты различаются между сторонами больше чем на пиксель (Высоты различаются … между сторонами) или когда у одной стороны на несколько цветов больше, чем у другой (обычно из-за света, который ловит только одна сторона).

pxr audit выше — вторая половина, для всей папки: каждый лист сверяется с одним набором.

Что нашли проверки — прямо на тех пикселях, о которых речь

Каждая проверка Pixor — одиночные пиксели, углы линий в один пиксель, толстые линии, цвет вне палитры, тайл или кадр с большим числом цветов, чем позволяет консольный режим, — отмечает пиксели, о которых идет речь, а не только печатает строку текста при экспорте.

  • В приложении: кнопка Проверки над спрайтом (предупреждающий треугольник) рисует отметки на кадре, а раздел Отчет на шагах «Стиль» и «Ассет» перечисляет все находки во всех отрендеренных до сих пор кадрах. Нажмите на находку, и Pixor перейдет к этому кадру и стороне с включенными отметками. Под списком для каждого вида находок указано, какой параметр за это отвечает: одиночные пиксели — очистка, зубчатые углы — линии, цвета — палитра, ограничения консоли — консольный режим, отраженная сторона, не совпадающая с отражением при экспорте, — и Перейти открывает этот параметр.
  • Отраженные стороны: при узле «Отразить» в графе ассета сторона, которая будет нарисована отражением, сравнивается с той, которую она отражает, и там, где модель недостаточно симметрична для этого, меняющиеся пиксели отмечаются, пока вы еще выбираете, — а не только предупреждением при экспорте.
  • При экспорте: отметьте Отчет (или --export report), и Pixor запишет рядом с листом name_report.png: лист со всеми отмеченными находками. Отдельные пиксели закрашиваются; тайл или кадр обводится рамкой, чтобы было видно, о чем речь.
Цвет Что
голубой одиночный пиксель (сирота)
желтый линия, поворачивающая за угол в одном пикселе
пурпурный блок линии два на два: толстая линия
красный пиксель вне палитры
оранжевый тайл 8 x 8, в котором больше цветов, чем допускает консоль
темно-оранжевый кадр, в котором больше цветов, чем допускает консоль
розовый цвет, которого нет у консоли
фиолетовый пиксель, отличающийся от стороны, с которой он отражен
зеленая коробка часть, нарисованная простым цветом, потому что нет файла ее текстуры: положите файл рядом с моделью

Пиксельные эффекты

Узел «Эффект» графа сцены (в Структуре в разделе «Эффекты») добавляет эффект, нарисованный из 3D-частиц: Explosion, Hit-spark, Slash, Magic-burst, Heal, Portal, Smoke-puff, Dust, Fire-loop, Rain, Snow, Fireflies и Falling-leaves. Каждый — отдельное действие (fx-explosion, …), отрендеренное тем же конвейером, что и модель, поэтому он берет палитру, размер пикселя, свет и линии спрайта и выглядит частью той же игры. Задайте его кадры, размер, энергию, положение и сид (один и тот же сид всегда дает одни и те же пиксели); заставьте его следовать за костью (удар из руки, вспышка у дула) и воспроизводиться поверх клипа (замах под ударом или клип с ключами, созданный в Pixor); отметьте «Только эффект», чтобы рисовать его без модели, отдельным слоем, выровненным с листом персонажа. «Кадр удара» отмечает кадр, в котором удар достигает цели: JSON перечисляет его в meta.pixor.hits. В командной строке: --effect fireflies:12 --effect-clip shatter --effect-hit 6, причем клип тоже создан в Pixor — осколки, разлетающиеся по ключам под блеском. «Создать эффект» на экране пустого проекта, рядом с «Импорт…» и «Бесплатные модели» (или pxr effect explosion -o fx.png), создает эффект вовсе без модели.

Хитбоксы, хёртбоксы и точки крепления

«Куб» части в Инспекторе (или --hitbox, --hurtbox) делает ее хитбоксом (она наносит удары: меч) или хертбоксом (по ней можно ударить: тело), а «Точка крепления в JSON» кости (или --socket) делает ее точкой крепления (рука, дуло). Тогда JSON каждого кадра содержит pixor.boxes (part, kind, x, y, w, h в пикселях ячейки, по пикселям, которые каждая часть действительно покрывает) и pixor.sockets (положение каждой кости в пикселях ячейки), поэтому код игры может проверять попадания и крепить эффекты без догадок. Файл модели тоже может помечать части (pxr.box).

Слои бумажной куклы

С прикрепленным реквизитом Слои бумажной куклы (--paper-doll) записывает также name_base.png — модель без реквизита на том же холсте — и по слою на каждый предмет реквизита (name_sword.png): его видимые пиксели вместе с линиями вокруг них. Сложенные стопкой, начиная с основы, они дают полный лист; замена слоя предмета меняет снаряжение. name_stacked.png — это они, сложенные так, как их сложит движок: превью, показывающее, что они совпадают. Пиксели каждой детали — собственные пиксели листа; основа — это тело, нарисованное без деталей, поэтому от листа она отличается лишь в нескольких пикселях от края детали и там, где деталь отбрасывает тень на тело, — выключите отбрасываемые тени (--no-shadow), чтобы слои складывались точно. Строки, которые узел «Спрайты» рисует с набором частей, относятся к собственному листу этого узла, а не к слоям. (Приложение создает их с помощью pxr из сохраненного проекта, сначала сохраняя его, если он изменился, так что слои соответствуют тому, что на экране.)

Снаряжение, которое является частью модели, — шлем, щит, плащ, смоделированные вместе с персонажем, а не прикрепленные как реквизит, — это деталь:

pxr render knight.glb --clip all --paper-doll --piece helmet:Knight_Helmet --piece gear:Round_Shield,1H_Sword
pxr project set knight.pixor --paper-doll --piece helmet:Knight_Helmet

Каждый элемент называет части, из которых состоит (так, как их перечисляет панель «Структура»), и становится отдельным слоем, name_helmet.png, точно как у реквизита (в приложении его делает таким параметр части Собственный слой бумажной куклы, а называется он по ней): только видимые его пиксели, так что щит за телом скрыт там, где его закрывает тело. Основа рендерится без всех элементов и реквизита, поэтому то, что закрывал шлем, — голова под ним — там нарисовано. --no-pieces убирает их из проекта. Узел Layer графа ассета указывает в качестве своего слоя base или элемент либо реквизит по имени, чтобы раскладывать слои как угодно (граф ассета).

Попробуйте то, что описано на этой странице, на своей модели — бесплатно в браузере.

Попробовать в браузере Получить Pixor