Files
skills/fish-pipeline/SKILL.md
T
2026-11-09 18:23:06 +03:00

269 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 выполнять только по явному запросу пользователя.