Add fish-pipeline skill

This commit is contained in:
emil28092005
2026-11-09 18:23:06 +03:00
parent 50151743a0
commit 6cd9967566
3 changed files with 345 additions and 0 deletions
+17
View File
@@ -58,3 +58,20 @@ git clone https://git.shanaty.ru/Emil_Shanaty/skills.git
mkdir -p ~/.agents/skills mkdir -p ~/.agents/skills
cp -r skills/game-designer ~/.agents/skills/ cp -r skills/game-designer ~/.agents/skills/
``` ```
## fish-pipeline
Перенос рыбы из Blender в Unity с физическим скелетом, skinning и независимыми
morph/shape-key анимациями. Содержит экспорт GLB, настройку Rigidbody/ConfigurableJoint,
нормализацию morph-весов, проверки через BakeMesh и правила адаптации к новым моделям и API.
- [Инструкции скилла](fish-pipeline/SKILL.md)
- [Проверенный опыт](fish-pipeline/references/experience.md)
### Установка
```sh
git clone https://git.shanaty.ru/Emil_Shanaty/skills.git
mkdir -p ~/.agents/skills
cp -r skills/fish-pipeline ~/.agents/skills/
```
+268
View File
@@ -0,0 +1,268 @@
---
name: fish-pipeline
description: >-
Переносит рыбу из Blender в Unity с физическим скелетом, skinning и независимыми
morph/shape-key анимациями. Использовать для FishGen, импорта GLB, ретопологии,
настройки Rigidbody/ConfigurableJoint, BlendShape loop, исправления надувания и
чрезмерных morph-деформаций. Адаптируется к модели и версиям API и обновляет
собственные инструкции только после проверенных результатов.
---
# Fish Pipeline
Перенос рыбы из Blender в Unity с двумя независимыми уровнями деформации:
- физический скелет двигает тело и хвост через `Rigidbody` и `ConfigurableJoint`;
- morph-анимация меняет только `blendShape`-веса в собственном loop и не управляет костями.
Не считать задачу завершённой только по успешному импорту. Проверять геометрию,
материалы, физику, morph-веса и фактическую деформацию через `BakeMesh`.
## Самообновление и адаптация
При каждом вызове:
1. Сначала читать этот файл и `references/experience.md`.
2. Проверять версии Unity, `com.unity.cloud.gltfast`, `com.unity.pipeline`, Unity CLI и Blender.
Использовать локальную документацию установленных пакетов и introspection API, а не память.
3. Не копировать параметры прошлой рыбы вслепую. Определять по данным модели:
- продольную ось и направление головы;
- размеры и масштаб;
- тип `Renderer`;
- число костей и morph targets;
- `GetBlendShapeFrameWeight` и диапазон значений кривых;
- пути `AnimationClip` и привязки кривых.
4. Если API отличается, сначала найти рабочий вызов через документацию или RNA/командную схему.
5. После успешной проверки обновлять этот skill и `references/experience.md`:
- записывать только подтверждённые симптомы, причины, исправления и способы проверки;
- устаревшие инструкции заменять, а не накапливать противоречия;
- неудачные попытки сохранять только как краткие предупреждения с итогом;
- объединять повторы и поддерживать файл компактным.
6. Приглашение пользователя к исправлению считать ошибкой pipeline. Сначала найти причину,
затем менять код или настройки. Не маскировать ошибку простым уменьшением анимации.
7. После подтверждения пользователем рабочего результата зафиксировать его как текущий baseline.
Ограничения самообновления:
- обновления выполняются только во время вызова skill и в рамках запроса пользователя;
- не запускать фоновые процессы, goals или cron для самообновления;
- не делать commit/push без явной просьбы;
- не менять пользовательские модели и анимации без необходимости;
- перед опасными изменениями сохранять исходники или делать отдельную рабочую копию;
- не записывать секреты, токены и личные данные;
- не отключать телеметрию и не менять настройки приватности.
## Текущий проверенный контур
- Unity: `6000.6.8f1`.
- `com.unity.cloud.gltfast`: `6.20.0`.
- `com.unity.pipeline`: `0.10.0-exp.1`.
- Blender: `5.2.3 LTS`.
- UPM-пакет: `/home/emil/Projects/Unity-tools/fish-gen`.
- Тестовый Unity-проект: `/home/emil/Projects/FishingGame`.
- Текущий модуль привязки: `fish-gen/Editor/FishModelBinder.cs`.
- Текущая morph-модель: `fish-gen/Models/Mesh0Animated.glb`.
Это отправная точка, а не обязательные пути для других проектов. В другом проекте сначала
определить его корень и расположение FishGen через `unity status` и Package Manager.
## 1. Подготовка модели в Blender
Сохранять исходник отдельно. Для игровой рыбы предпочтительна чистая топология и UV.
При ручной ретопологии:
- сохранять петли вдоль позвоночника и у оснований плавников;
- строить низкополигональную поверхность поверх исходника;
- использовать Shrinkwrap и перенос/запекание текстур;
- проверять границы, non-manifold рёбра и тонкие плавники.
При автоматической ретопологии не считать Decimate достаточным для анимации. Если QuadriFlow
отклоняет mesh, проверять manifold и нормали. Для сложной модели допустим Voxel/Sharp ReMesh,
но результат проверять визуально и по топологии.
### Shape keys и маски
- `Basis` не редактировать.
- Vertex Group ограничивает существующую деформацию, но не создаёт её.
- Для движения глаз и рта создавать отдельные shape keys и плавные маски.
- Для независимого morph-loop не использовать костную анимацию.
- Проверять крайние значения ключей на пересечения и растяжения кожи.
При UV Data Transfer в Blender учитывать направление: для переноса из выделенных исходников
в активный target использовать `use_reverse_transfer=True`. Предварительно проверять RNA:
имена enum и поведение оператора зависят от версии. При ошибке восстанавливать исходник,
а не продолжать с повреждёнными UV.
## 2. Экспорт GLB с morph-анимацией
Перед экспортом убедиться, что shape keys имеют кривые. Экспортировать только нужный объект.
Пример для проверенной Blender-версии:
```python
import bpy
bpy.ops.object.select_all(action='DESELECT')
obj = bpy.data.objects["Mesh_0"]
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
bpy.ops.export_scene.gltf(
filepath="/home/emil/Projects/Unity-tools/fish-gen/Models/Mesh0Animated.glb",
export_format='GLB',
use_selection=True,
export_animations=True,
export_animation_mode='ACTIVE_ACTIONS',
export_frame_range=True,
export_force_sampling=True,
export_morph=True,
export_morph_animation=True,
export_apply=False)
```
Для другой модели заменить имя, путь и режим экспорта после чтения её action/NLA.
Не запекать shape keys в mesh.
## 3. Импорт и проверка данных в Unity
Использовать `unity-cli`, `unity-pipeline` и `unity-package-management`, если они доступны.
Пакеты добавлять через Package Manager, не редактировать `manifest.json` вручную.
```bash
unity command script eval 'AssetDatabase.ImportAsset(
"Packages/com.shanaty.fish-gen/Models/Mesh0Animated.glb",
ImportAssetOptions.ForceUpdate); return "Imported";'
```
Проверить:
- `SkinnedMeshRenderer` и материал;
- `mesh.blendShapeCount` и имена форм;
- наличие `AnimationClip`;
- `AnimationUtility.GetCurveBindings(clip)`;
- размеры mesh и направление головы.
glTFast импортирует morph-анимации, но их проигрывание и назначение путей требует
отдельной настройки.
## 4. Физический скелет
Текущий рабочий режим Fish Editor: **Tools → Fishing → Fish Editor → Test Hanging**.
Для каждого сегмента:
- `Rigidbody`;
- `CapsuleCollider` с фактическими размерами сегмента;
- `ConfigurableJoint` с предыдущим сегментом;
- ограничения углов, пружина и damping.
Первый сегмент соединять с kinematic `Mouth Anchor`. Не задавать непропорциональный
`localScale` физическому телу: размер задаётся коллайдеру, а визуальный mesh остаётся
отдельным дочерним объектом. Для короткой цепочки отключать self-collision между сегментами.
`Tail Impulse` должен прикладывать силу к кончику последнего Rigidbody через
`AddForceAtPosition`, поочерёдно меняя направление.
## 5. Skinning без повреждения morph targets
Для текущей модели ось `+Y` соответствует голове, а скелет идёт от головы к хвосту по `+X`.
Для неё используется поворот `Quaternion.Euler(0, 0, 90)`. Для другой рыбы сначала определить
ориентацию — не применять этот поворот автоматически.
Базовые правила:
- позиции вершин: поворот, равномерный масштаб и перенос начала координат;
- нормали и tangents: только поворот;
- веса вершин: плавная смесь двух ближайших костей по продольной координате;
- `bindposes[i] = bones[i].worldToLocalMatrix * visual.localToWorldMatrix`;
- источник может быть как `MeshRenderer`, так и `SkinnedMeshRenderer`.
Для каждого morph target копировать все кадры через `GetBlendShapeFrameVertices` и
`AddBlendShapeFrame`:
- `deltaVertices`: поворот и тот же равномерный масштаб, что у базовых вершин;
- `deltaNormals` и `deltaTangents`: только поворот;
- исходный `AnimationClip` не изменять.
### Два разных веса — не смешивать
**Morph-frame weight** и **animation-curve weight** — разные вещи.
В проверенном glTFast `GetBlendShapeFrameWeight` возвращал `1`, тогда Unity ожидал `100`.
Это вызывало экстраполяцию и надувание. При переносе определять диапазон и нормализовать его
к `0–100`. Если исходный диапазон `0–1`, умножать frame weight на `100`; если уже `0–100`,
не умножать повторно.
Кривые morph-анимации также могут иметь диапазон `0–1`, тогда как Unity BlendShape использует
`0–100`. Вычислять коэффициент по фактическим ключам. Текущий пользовательский уровень
амплитуды — `20%` от исходной, но сначала исправлять нормализацию и только затем настраивать
силу анимации.
## 6. Независимый morph-loop
Использовать `Animation` на том же GameObject, где находится `SkinnedMeshRenderer`.
Для каждого исходного клипа:
1. Создать новый `AnimationClip` с `legacy = true` и `wrapMode = Loop`.
2. Копировать только кривые `SkinnedMeshRenderer` с `blendShape.*`.
3. Transform-кривые исключать, чтобы анимация не боролась с физикой.
4. Путь кривой заменить на `""`, поскольку renderer находится на том же объекте.
5. Ключи копировать в новый `AnimationCurve`, не мутируя исходный клип.
6. Установить кривую через `loopClip.SetCurve`.
7. Добавить клип в `Animation`, включить loop и `playAutomatically`.
Исходный путь вида `Mesh_0` нельзя оставлять без проверки: он относится к иерархии Blender,
а не к созданному `Fish Visual`.
## 7. Обязательная проверка
После изменения C#:
```bash
unity command script recompile --project-path <project>
unity command script recompile_status --project-path <project>
```
Запустить `Test Hanging` и проверить:
- создание Rigidbody, joints, mesh и материалов;
- `blendShapeCount` и имена форм;
- `Animation.isPlaying`;
- все кривые loop указывают на `""` и только на `blendShape.*`;
- веса форм меняются во времени;
- `Tail Impulse` двигает последний сегмент одновременно с morph-loop.
Сравнить `BakeMesh` до и после morph или импульса. Для текущего baseline при `Breath = 10`
максимальное смещение вершины должно быть примерно **0.00178 м**, а не 0.17772 м.
Проверить консоль:
```bash
unity command console status --project-path <project>
unity command console get --level error --project-path <project>
```
После теста остановить Play Mode, снять временный Run In Background override и удалить
временные probe-скрипты и тестовые объекты.
## 8. Диагностика
| Симптом | Сначала проверить |
|---|---|
| Рыба надувается | `GetBlendShapeFrameWeight`, экстраполяцию и фактический `BakeMesh` |
| Анимация почти незаметна | Диапазон ключей `0–1` против Unity `0–100` |
| Глаза/рот не двигаются | `legacy`, `Animation.isPlaying`, имена форм и пути кривых |
| Анимация ломает физику | Наличие transform-кривых вместо только `blendShape.*` |
| Mesh внизу/боком | Ось модели, bindposes и направление головы |
| Текстуры испорчены | UV, направление Data Transfer, активную UV-развёртку |
| Суставы дрожат | Масштаб Rigidbody, массы, solver iterations и self-collision |
## 9. Фиксация результата
После успешной проверки:
- сохранить `.meta` вместе с ассетами;
- обновить этот skill и `references/experience.md` по правилам выше;
- убедиться, что временные probe-файлы удалены;
- commit/push выполнять только по явному запросу пользователя.
+60
View File
@@ -0,0 +1,60 @@
# Проверенный опыт Fish Pipeline
Обновлять только после подтверждения. Повторяющиеся записи объединять. Устаревшие правила
заменять в `SKILL.md`, а здесь сохранять краткую историю причин и проверок.
## 2026-11-09 — Базовый физический скелет
- Создана цепочка из 6 Rigidbody и 6 ConfigurableJoint с kinematic mouth anchor.
- Нестабильность уменьшается, когда физический transform не масштабируется, а размер задаётся
CapsuleCollider. Визуальная капсула находится в дочернем объекте.
- Tail Impulse через `AddForceAtPosition` к кончику последнего сегмента успешно раскачивает цепь.
## 2026-11-09 — GLB и skinning
- `com.unity.cloud.gltfast` импортирует mesh, материалы, morph targets и AnimationClips.
- Для первой модели 6 костей и 6194 вершины успешно деформировались после импульса.
- Направление модели нужно определять отдельно; поворот `Z +90` подходит только для проверенной
ориентации `head +Y` к `tail +X`.
## 2026-11-09 — Независимая morph-анимация
- Shape keys `Eye_Look_Left`, `Eye_Look_Right`, `Open_mouths`, `Breath` экспортированы из Blender
с `export_morph=True`, `export_morph_animation=True`, `ACTIVE_ACTIONS`.
- В Unity найден один 4-секундный клип с кривыми `blendShape.*`.
- Для независимого loop создан новый legacy `AnimationClip`, путь кривой изменён на пустой,
transform-кривые отброшены. Физика и morph-анимация работают одновременно.
## 2026-11-09 — Нормализация morph-frame
Симптом: рыба сильно надувалась, `Breath = 10` давало смещение вершины `0.17772 м`.
Причина: glTFast вернул `GetBlendShapeFrameWeight = 1`, тогда Unity ожидал диапазон `0–100`.
Копирование значения `1` приводило к экстраполяции в 10 раз.
Исправление: нормализовать frame weight к `0–100` при создании target mesh.
Проверка после исправления: при `Breath = 10` максимальное смещение стало `0.00178 м`.
Не уменьшать анимацию до такой проверки — сначала исправить frame weight.
## 2026-11-09 — Значения кривых
- Исходные morph-кривые имеют диапазон `0–1`, Unity BlendShape использует `0–100`.
- При переносе ключи копируются в новый `AnimationCurve`; исходный клип не изменяется.
- Текущая пользовательская сила воспроизведения — 20% от исходной амплитуды. Это настройка после
исправления frame weight, а не решение проблемы надувания.
## 2026-11-09 — UV Data Transfer в Blender
- В Blender 5.2 направление оператора критично: для selected source → active target требуется
`use_reverse_transfer=True`.
- Неправильное направление повредило UV исходника в текущей сцене; источник восстановлен из
отдельной сохранённой копии.
- Перед вызовом читать RNA: допустимые enum для `layers_select_src/dst` зависят от контекста.
## 2026-11-09 — Ретопология
- Простой Decimate не признан подходящим для анимации этой рыбы.
- QuadriFlow отклонил исходную поверхность; Voxel/Sharp ReMesh дал 16166 квадов и сохранил форму.
- UV восстановлены через Data Transfer в правильном направлении. Для скелета нужна отдельная
проверка non-manifold участков.