advanced example

This commit is contained in:
Vysyr committed 2026-10-31 20:16:32 +01:00
1 parent 8c0a639fba
commit 6fe57915e8
99 files changed
+1329 -56

No files matched your search

+111
View File
@@ -0,0 +1,111 @@
# Animacje postaci
`scene.skeletal_model(...)` automatycznie znajduje każdy FBX z folderu postaci
poza plikiem samego modelu: 51 klipów fighter i 12 klipów creature.
Wykorzystuje funkcję `_clips()` z `Content/Python/ue_workshop/characters.py`.
Nowy FBX dodany do folderu zostanie uwzględniony przy następnym uruchomieniu skryptu.
Trzymaj model i animacje tej samej postaci w osobnym folderze.
Nazwy poniżej są kluczami do `animations` i `shot.animation(...)`.
Spacje i nawiasy z nazw plików są zamieniane na podkreślenia. Nie ma skrótów
`idle`, `walk` i `attack`; używaj nazw takich jak `great_sword_idle` czy `mutant_swiping`.
Pełny przykład `examples/mixamo_characters.py` importuje wszystkie klipy.
Plik zadania `exercises/animation_starter.py` importuje tylko dwie wybrane animacje.
Aby udostępnić wszystkie klipy, pomiń argument `animations`:
```python
character = scene.skeletal_model(CREATURE_MODEL, name="Creature", reimport=False)
shot.animation(character, "mutant_jumping", start=240, end=360)
```
Opcjonalne `animations={...}` ogranicza wybór do wskazanych plików;
`animations={}` pozostawia tylko klipy osadzone w samym modelu.
Krótsze klipy zapętlają się w swoim zakresie. Nakładanie zakresów automatycznie
tworzy płynne przejście z Pythona:
```python
shot.animation(character, "mutant_idle", start=0, end=60)
shot.animation(character, "mutant_swiping", start=48, end=120)
```
Wspólny zakres 48–60 miesza obie animacje przez 12 klatek (0,5 s przy 24 FPS).
Nowy klip narasta od wagi 0 do 1, a poprzedni zanika od 1 do 0.
Dodawaj klipy w kolejności odtwarzania. Długość blendu wynika wyłącznie z zakresów.
Klipy stykające się końcami przechodzą bez blendu; zakresy nie mogą być identyczne
ani całkowicie zawierać się jeden w drugim.
Obsługiwane są przejścia między dwiema animacjami; trzy jednoczesne klipy są odrzucane.
## Fighter
| Clip | FBX |
|---|---|
| `draw_a_great_sword_1` | `draw a great sword 1.fbx` |
| `draw_a_great_sword_2` | `draw a great sword 2.fbx` |
| `great_sword_180_turn` | `great sword 180 turn.fbx` |
| `great_sword_180_turn_2` | `great sword 180 turn (2).fbx` |
| `great_sword_attack` | `great sword attack.fbx` |
| `great_sword_blocking` | `great sword blocking.fbx` |
| `great_sword_blocking_2` | `great sword blocking (2).fbx` |
| `great_sword_blocking_3` | `great sword blocking (3).fbx` |
| `great_sword_casting` | `great sword casting.fbx` |
| `great_sword_crouching` | `great sword crouching.fbx` |
| `great_sword_crouching_2` | `great sword crouching (2).fbx` |
| `great_sword_crouching_3` | `great sword crouching (3).fbx` |
| `great_sword_crouching_4` | `great sword crouching (4).fbx` |
| `great_sword_crouching_5` | `great sword crouching (5).fbx` |
| `great_sword_crouching_6` | `great sword crouching (6).fbx` |
| `great_sword_high_spin_attack` | `great sword high spin attack.fbx` |
| `great_sword_idle` | `great sword idle.fbx` |
| `great_sword_idle_2` | `great sword idle (2).fbx` |
| `great_sword_idle_3` | `great sword idle (3).fbx` |
| `great_sword_idle_4` | `great sword idle (4).fbx` |
| `great_sword_idle_5` | `great sword idle (5).fbx` |
| `great_sword_impact` | `great sword impact.fbx` |
| `great_sword_impact_2` | `great sword impact (2).fbx` |
| `great_sword_impact_3` | `great sword impact (3).fbx` |
| `great_sword_impact_4` | `great sword impact (4).fbx` |
| `great_sword_impact_5` | `great sword impact (5).fbx` |
| `great_sword_jump` | `great sword jump.fbx` |
| `great_sword_jump_2` | `great sword jump (2).fbx` |
| `great_sword_jump_attack` | `great sword jump attack.fbx` |
| `great_sword_kick` | `great sword kick.fbx` |
| `great_sword_kick_2` | `great sword kick (2).fbx` |
| `great_sword_power_up` | `great sword power up.fbx` |
| `great_sword_run` | `great sword run.fbx` |
| `great_sword_run_2` | `great sword run (2).fbx` |
| `great_sword_slash` | `great sword slash.fbx` |
| `great_sword_slash_2` | `great sword slash (2).fbx` |
| `great_sword_slash_3` | `great sword slash (3).fbx` |
| `great_sword_slash_4` | `great sword slash (4).fbx` |
| `great_sword_slash_5` | `great sword slash (5).fbx` |
| `great_sword_slide_attack` | `great sword slide attack.fbx` |
| `great_sword_strafe` | `great sword strafe.fbx` |
| `great_sword_strafe_2` | `great sword strafe (2).fbx` |
| `great_sword_strafe_3` | `great sword strafe (3).fbx` |
| `great_sword_strafe_4` | `great sword strafe (4).fbx` |
| `great_sword_turn` | `great sword turn.fbx` |
| `great_sword_turn_2` | `great sword turn (2).fbx` |
| `great_sword_walk` | `great sword walk.fbx` |
| `great_sword_walk_2` | `great sword walk (2).fbx` |
| `spell_cast` | `spell cast.fbx` |
| `two_handed_sword_death` | `two handed sword death.fbx` |
| `two_handed_sword_death_2` | `two handed sword death (2).fbx` |
## Creature
| Clip | FBX |
|---|---|
| `left_turn_45` | `left turn 45.fbx` |
| `mutant_breathing_idle` | `mutant breathing idle.fbx` |
| `mutant_dying` | `mutant dying.fbx` |
| `mutant_flexing_muscles` | `mutant flexing muscles.fbx` |
| `mutant_idle` | `mutant idle.fbx` |
| `mutant_jumping` | `mutant jumping.fbx` |
| `mutant_left_turn_45` | `mutant left turn 45.fbx` |
| `mutant_right_turn_45` | `mutant right turn 45.fbx` |
| `mutant_right_turn_45_2` | `mutant right turn 45 (2).fbx` |
| `mutant_run` | `mutant run.fbx` |
| `mutant_swiping` | `mutant swiping.fbx` |
| `mutant_walking` | `mutant walking.fbx` |
+35 -4
View File
@@ -2,6 +2,15 @@
Import: `from ue_workshop import Scene, Sequence, Renderer, camera, lighting, materials, assets, blender, render`
`REIMPORT=False` w plikach ćwiczeń używa istniejących assetów UE; brakujące są importowane.
`REIMPORT=True` ponownie importuje modele i klipy, także po edycji `.blend`.
Własny skrypt: `scene.skeletal_model(..., reimport=True)` lub `scene.model(..., reimport=True)`.
Nie ma automatycznego wykrywania zmian źródeł.
`camera.create(..., fov=60)` ustawia poziomy kąt widzenia w stopniach: większy FOV
daje szerszy kadr. Zakres: `0 < fov < 180`. Domyślne `43.6` odpowiada obiektywowi
45 mm na sensorze o szerokości 36 mm.
| Operacja | Przykład |
|---|---|
| Własna mapa | `scene = Scene("MyShot")` |
@@ -15,7 +24,7 @@ Import: `from ue_workshop import Scene, Sequence, Renderer, camera, lighting, ma
| Korekta osi modelu przed dopasowaniem | `actor = scene.model("hero.fbx", rotation=(0, 0, 90))` |
| Światła studyjne | `lights = lighting.studio(scene)` |
| Pojedyncze światło | `lighting.area(scene, location=(200, -200, 350), intensity=10000, color=(1, 0.5, 0.2))` |
| Kamera | `cam = camera.create(scene, location=(450, -550, 300), target=(0, 0, 100), focal_length=45)` |
| Kamera | `cam = camera.create(scene, location=(450, -550, 300), target=(0, 0, 100), fov=43.6)` |
| Zmiana kierunku | `camera.look_at(cam, (0, 0, 150))` |
| Sekwencja | `shot = Sequence(scene, fps=24, frames=48)` |
| Aktywna kamera | `shot.camera(cam)` |
@@ -37,9 +46,31 @@ Cały obrót: klucze 0 i 360, nie 0 i 0. Kamera i modele to oryginalne obiekty U
możesz wywoływać ich metody, np. `actor.set_actor_label("MyHero")`.
`shot.asset` to oryginalny LevelSequence, `shot.bind(actor)` zwraca binding UE.
W `my_shot.py`: `MODEL="robot"` lub `MODEL="pilot"` wybiera dołączony model.
`MODEL="file"` wczytuje `MODEL_FILE`. Obiekt z `scene.model()` ma pivot na podstawie
i zachowuje materiały; animacja dotyczy całego modelu, nie jego kości.
W `my_shot.py`: `MODEL="fighter"` lub `MODEL="creature"` wybiera postać ze szkieletem.
Nazwy klipów pochodzą z plików, np. `great_sword_walk` i `mutant_swiping`.
`scene.skeletal_model(...)` samo znajduje wszystkie FBX obok modelu — bez `animations`.
Dostępne jest 51 animacji fighter i 12 animacji creature; [pełny katalog](animations.md).
Własny FBX lub `.blend`
z Armature: `MODEL="file"`, `SKELETAL=True`, `MODEL_FILE=...`.
`ANIMATION_FILE=None` odtwarza animację z pliku modelu; można wskazać osobny FBX
z animacją dla tego samego szkieletu. Dla statycznego modelu ustaw `SKELETAL=False`.
```python
character = scene.skeletal_model("source_assets/character/my_character.fbx", name="Hero")
shot.animation(character) # tylko gdy postac ma jedna dostepna animacje
# Gdy jest ich wiecej: shot.animation(character, "nazwa_pliku_animacji")
# Albo nazwane klipy: scene.skeletal_model(..., animations={"walk": walk_fbx, "idle": idle_fbx})
# shot.animation(character, "walk", start=0, end=48, speed=1.0)
# shot.animation(character, "idle", start=48, end=120)
# Plynne przejscie: pierwszy klip 0..60, drugi 48..120:
# shot.animation(character, "walk", start=0, end=60)
# shot.animation(character, "idle", start=48, end=120) # automatyczny blend 12 klatek
```
Krótsza animacja zapętla się w swojej sekcji. `transform_key` porusza całym aktorem
równolegle z animacją kości. Do własnych tras wybieraj klipy In Place.
Blender: kolekcja `Character`, siatki przypisane do jednego Armature, aktywna akcja
i zakres klatek sceny. Zapisz plik przed ponownym uruchomieniem skryptu w UE.
Przy pojedynczym podglądzie nie uruchamiaj dodatkowo pełnego renderu:
jednocześnie może pracować tylko jeden renderer warsztatowy.
+62
View File
@@ -38,3 +38,65 @@ Nie uruchamiano testów na Linuksie ani na Blenderze 4.x.
Uruchamianie sprawdzeń jest opisane w README. Wyniki każdego renderu są zapisane
w jego `result.json`; logi UE znajdują się w `Saved/Logs`.
Skrypty integracyjne generują własne mapy i assety w `Workshop/Generated`.
## Postacie szkieletowe — 31 października 2026
- 13 testów poza UE: w tym zakresy klipów, wykrywanie nakładania, prędkość,
wybór klipu i odrzucanie animacji z innym szkieletem.
- UE 5.7: import fighter i creature jako SkeletalMesh z materiałami i teksturami,
własny szkielet każdej postaci oraz klipy idle, walk i attack z osobnych FBX.
- W klipach walk sprawdzone rzeczywiste zmiany rotacji kości między klatkami.
- Ponowny import tych samych assetów po restarcie UE oraz zapis zależności
(szkielet, materiały, tekstury). FBX używa importera zgodnego z FbxImportUI;
poprzednia wartość flagi Interchange jest przywracana po imporcie.
- Sequencer: klipy w kolejnych zakresach, prędkość 0.75 i jednoczesne klucze
transformacji rodzica. Render 48 klatek, 640×360, dla obu postaci.
- Blender 5.1.2: wczytanie fighter i chodzenia z nowych FBX wyeksportowanych
przez UE, zmiana geometrii z zachowaniem wag, zapis `.blend`, eksport Armature
i aktywnej akcji, import do UE i render 24 klatek, 640×360.
- Dołączone źródła są w FBX 6.1, nieobsługiwanym przez importer Blendera 5.1;
bezpośredni import w UE działa. Test Blendera korzysta z eksportu UE do FBX 7.3.
Odtworzenie testu Blendera (po teście `smoke_skeletal.py`):
```text
blender --background --python-exit-code 1 --python tools/create_skeletal_fixture.py
python tools/run_workshop.py tools/smoke_skeletal_blender.py --render
```
Eksport szkieletowy obejmuje jedną postać i aktywną akcję w zakresie sceny.
Nie sprawdzano retargetingu, Animation Blueprintów ani eksportu wielu akcji/NLA.
## Pliki na zajęcia i pełne katalogi
- `tools/smoke_workshop_files.py`: w UE zaimportowano wszystkie 51 klipów fighter
i 12 klipów creature; sprawdzono kompletność słowników i dodatnią długość klipów.
- `exercises/basics.py`: eksport własnego `.blend`, 192 klatki kamery na okręgu,
stały promień, zgodne końce trasy i ciągły yaw obejmujący pełne 360°.
- `exercises/animation_starter.py`: jedna postać, dokładnie dwa klipy, 360 klatek.
- Wszystkie trzy sceny zostały zbudowane i zapisane w oddzielnych mapach.
## Blendowanie z Pythona
- 17 testów poza UE: dodatkowo poprawne nakładanie, wagi obu klipów, zachowanie
wejścia i wyjścia środkowego klipu oraz odrzucanie trzech równoczesnych klipów.
- `tools/smoke_blending.py`: w UE 5.7 utworzono przejścia idle → attack → walk,
po 12 klatek każde. Sprawdzone zapisane klucze Weight i wyrenderowana klatka 54,
w środku pierwszego przejścia, równolegle z kluczami pozycji rodzica.
- Przejście korzysta z kanałów wag; chronione pola MovieSceneEasingSettings
nie są modyfikowane. Modele i klipy są ponownie używane z `reimport=False`.
## Automatyczne wykrywanie bez aliasów
- 23 testy poza UE: dodatkowo pomijanie pliku modelu, nazwy z plików, wykrywanie
kolizji nazw, automatyczny wybór wszystkich klipów, jawny wybór i puste `animations={}`.
- Sprawdzone przekazywanie `reimport=False`/`True` oraz użycie istniejącego modelu.
- `tools/smoke_workshop_files.py` zaliczony w UE: obie postacie wczytane bez
argumentu `animations`, pełne 51 + 12 klipów i plik zadania z dwoma pełnymi nazwami.
## Automatyczny blend
- 26 testów poza UE: blend wynika ze wspólnego zakresu, także przy jednej klatce
nakładania; stykające się klipy nie dostają fade. Sprawdzone łańcuchy trzech
klipów oraz odrzucanie niejednoznacznych zakresów i dodawania w odwrotnej kolejności.
- Parametr `blend_in` usunięty z API i przykładów. Zakresy scen pozostają takie same.