Приёмка текстур с альфа-вырезом (растительность, грязь, декали, наклейки, листва, дым) от любого генератора — ComfyUI/Stable Diffusion, рендера, фотосканов. Два независимых числа вместо разглядывания превью — ореол подложки на кромке и качество самой кромки, — плюс объяснение, почему альфу нельзя достать из одной картинки над одним фоном. Используй, когда решаешь принимать или вернуть набор с прозрачностью; когда пятно в игре читается «вырезанным ножницами» или обведённым светлым контуром; когда исполнитель спорит с вердиктом приёмки; когда надо сформулировать требование к альфе числом, а не словами «чтобы красиво сходило на нет».
Resources
2Install
npx skillscat add sashkosoft/godot-skilled/alpha-cutout-acceptance Install via the SkillsCat registry.
Приёмка альфа-выреза числом
Собран на проекте, где три сессии поставляли ассеты в общий пайплайн, а
приёмка смотрела превью. Дважды ошиблись в разные стороны: один раз
вернули годный файл, один раз приняли негодный — и он полторы недели
стоял в игре (см. ORIGIN.md).
Главное правило
Превью на белом или сером фоне не показывает ни одного дефекта альфы.
Оба дефекта видны только над тёмным (0.10–0.15) — и оба меряются числом за
секунду, без единого рендера.
Дефекта ровно два, они независимы, и лечатся по-разному:
| Дефект | Как выглядит в игре | Метрика |
|---|---|---|
| Ореол | каждый лист обведён светлым, куст «заиндевел» | scripts/halo.py |
| Ножевая кромка | пятно обрывается ровной линией, «вырезано ножницами» | scripts/alpha_edge.py |
Ореол: мерить ЛОКАЛЬНО, иначе забракуешь годное
Ореол — это цвет подложки, оставшийся на полупрозрачных пикселях. Соблазн
померить его так: средняя яркость кромки (0.05 < a < 0.5) минус средняя
яркость ядра (a > 0.9) по всему файлу. Эта метрика врёт. Она смешивает
ореол с настоящей структурой: тонкая сухая метёлка и правда светлее
затенённой глубины куста, и файл с идеальной альфой получит большой плюс.
Мерить надо локально: каждый кромочный пиксель против среднего ядра в своей
окрестности 9×9. Ореол — эффект локальный, подложка светлеет вплотную к листу.
Проверка на реальном наборе, один и тот же файл:
moss_edge глобально +0.2174 локально −0.0013Глобально — «половина прежнего ореола, вернуть на переделку». Локально —
ореола нет вовсе. Вернули зря, исполнитель был прав и прямо об этом написал.
Порог: локально хуже +0.01 — возврат. Глобальное число в вердикт не
писать вообще, оно только путает.
Кромка: два числа, и оба обязаны сойтись
альфа_на_рамке максимум альфы в полосе 2 px по краю холста
кайма/периметр сколько полупрозрачных пикселей на один пиксель периметра- Альфа на рамке > 0 — растение упирается в край картинки. Что бы ни
делал движок, наклейка обрежется по границе своего бокса ровной линией.
УDecalв Godot боковой растушёвки нет вовсе; в других движках её
тоже обычно нет. Лечится только альфой в файле. - Кайма/периметр < 1 — альфа почти бинарная, мягкого перехода нет.
Нож даже в середине холста.
Калибровка по двум наборам из одного проекта:
| Набор | альфа на рамке | кайма/периметр |
|---|---|---|
| рендер, Karma (годный) | 0.000 | 26 … 550 |
| керинг картинки (негодный) | 1.000 | 0.11 … 0.28 |
Разница в два-три порядка. Промежуточных значений на практике не бывает:
либо альфа снята с рендера, либо угадана по яркости.
Порог: альфа на рамке = 0 по полосе 4 px; кайма/периметр — десятки.
Почему «покрасить на белом и вычесть фон» не работает никогда
Генератор рисует объект на подложке и отдаёт один RGB-кадр. Восстановить из
него альфу нельзя в принципе: три уравнения (R, G, B) против четырёх
неизвестных (c_r, c_g, c_b, α). «Расстояние от белого» — это догадка о
покрытии, а не измерение.
Отсюда практические следствия:
- на тёмном плотном листе догадка хорошая, на светлой соломенной метёлке
плохая — она почти неотличима от подложки, и покрытие систематически
занижается; - вычитание подложки (
c = (rgb − (1 − α)) / α) при малой альфе неустойчиво
и ореол не убирает; - протяжка цвета из ядра наружу (push-pull fill) убирает белизну кромки, но
альфу не чинит — это обход, а не решение; - у рендера проблемы нет вовсе: он знает истинное покрытие пикселя и отдаёт
его прямо.
Вывод для пайплайна: вырез по альфе заказывать там, где есть геометрия и
рендер. Генератору картинок оставлять то, где альфа не нужна или заведомо
плотная.
Как этим пользоваться
python scripts/halo.py "delivery/**/*_albedo_*.png"
python scripts/alpha_edge.py "delivery/**/*_albedo_*.png"Обе печатают строку на файл и помечают подозрительные. Числа кладутся прямо
в раздел приёмки — тогда спор с исполнителем идёт о цифре, а не о вкусе.
В задание требование пишется так же числом: «альфа = 0 по всей рамке в 4 px,
кайма/периметр в десятки, превью собрать над тёмным 0.10–0.15». И просить
свой замер от исполнителя — тогда расхождение видно на сдаче, а не через
две недели в игре.
Рабочие привычки
- Мерить до того, как открыл превью. Превью потом — для стиля, не для альфы.
- Вернул набор — приложи числа. Вернул без чисел — скорее всего вернул зря.
- Исполнитель спорит с метрикой — проверь метрику, а не настаивай.
В этом проекте спорящий был прав, а приёмка неправа. - Дефект альфы не чинится настройками движка. Можно замаскировать
(подмешивание вместо полной замены альбедо), но это лечение следствия.