Powrót do Bloga

Unigine 2.22: Przebudowa animacji — maszyny stanów, mieszanie warstw i nowy workflow szkieletowy

Opublikowano 18 września 2026
Unigine 2.22: Przebudowa animacji — maszyny stanów, mieszanie warstw i nowy workflow szkieletowy Wygenerowano przy użyciu AI

W skrócie

Poznaj przebudowę animacji w Unigine 2.22: maszyny stanów, mieszanie warstw, motion warping, nowy import FBX i migrację starego kodu krok po kroku.

Workflow animacji, przez który deweloperzy Unigine rezygnowali z silnika

Każdy deweloper Unigine uderzał w tę samą ścianę: renderer wyświetla przepiękne sceny PBR przy 120 fps, ale stworzenie prostego przejścia z idle do biegu zajmuje godzinę hacków w skryptach i ręcznego poprawiania kości. Ta rozbieżność między jakością wizualną a narzędziami do animacji była przez lata otwartym sekretem Unigine i to główny powód, dla którego większość małych zespołów oceniających Unigine ostatecznie rezygnuje.

Z Unigine 2.22 zespół w końcu zmierzył się z tym problemem bezpośrednio. Wydanie wprowadza wizualny edytor maszyn stanów animacji, addytywne mieszanie warstw z maskami per-bone, ulepszony pipeline importu FBX z mapowaniem szkieletu awatara oraz nowe proceduralne API do motion warping. Dla zespołów używających Unigine do symulacji, wizualizacji architektonicznej czy zastosowań przemysłowych, które przez lata sklejały logikę animacji w kodzie — to zmienia codzienny workflow w znaczący sposób.

Ten przewodnik pokazuje, co dokładnie się zmieniło, jak przejść ze starego podejścia opartego na skryptach do nowych narzędzi maszyn stanów oraz gdzie przypadki brzegowe dają się we znaki najbardziej.


Co zmieniło się w systemie animacji Unigine 2.22

Stary sposób: logika animacji sterowana skryptami

Przed 2.22 wywołanie przejścia animacji w Unigine oznaczało napisanie logiki samodzielnie:

// UnigineScript — old pattern, pre-2.22
AnimLayer idle_layer = new AnimLayer();
idle_layer.SetAnimation("idle.anim");
idle_layer.Loop = true;

AnimLayer run_layer = new AnimLayer();
run_layer.SetAnimation("run.anim");
run_layer.Loop = true;

void update(float speed) {
    float blend = clamp(speed / 6.0, 0.0, 1.0);
    if (blend > 0.01f) {
        idle_layer.SetWeight(1.0 - blend);
        run_layer.SetWeight(blend);
    } else {
        idle_layer.SetWeight(1.0);
        run_layer.SetWeight(0.0);
    }
}

To działa w przypadku systemu dwustanowego, ale skalowanie tego do kucania, skoku, celowania, sprintu i 15 wariantów ataku szybko staje się nie do utrzymania. Każdy zespół kończy z ręcznie napisaną maszyną stanów w skrypcie i każdy zespół walczy z przeskokami przejść i błędami mieszania.

Podejście 2.22: deklaratywne maszyny stanów

Unigine 2.22 wprowadza system AnimationGraph — edytor maszyn stanów oparty na węzłach, wbudowany w Unigine Editor, wraz z API do skryptów do kontroli w czasie rzeczywistym. Stany mapują się na klipy animacji lub blend space'y. Przejścia definiują warunki i czasy trwania. Silnik wewnętrznie obsługuje interpolację, mieszanie przerwań i kompozycję warstw.

Kluczowe ulepszenia:

  • Wizualny edytor maszyn stanów — definiuj stany, przejścia i warunki w edytorze z podglądem grafu
  • Układanie warstw z maskami kości — mieszaj celowanie górnej części ciała z lokomocją dolnej części ciała za pomocą nazwanych grup kości
  • Wsparcie dla animacji addytywnych — aplikuj wychylenie, patrzenie głową i odrzut jako offsety, a nie pełne zastąpienie pozy
  • Ulepszony import FBX — mapowanie szkieletu awatara, które zachowuje hierarchie kości w różnych wariantach postaci
  • Motion warping — root motion może być przekierowywany i mieszany w czasie rzeczywistym dla wspinaczki, pokonywania przeszkód i przejść do osłon

Konfiguracja nowego pipeline'u animacji krok po kroku

Krok 1: Zdefiniuj szkielet awatara

Szkielet awatara to kluczowy element workflow 2.22. To nazwany szablon kości, który mapuje siatki szkieletowe z narzędzi DCC (Blender, Maya, 3ds Max) na kanoniczny szkielet, do którego odwołuje się maszyna stanów animacji.

Jeśli pominiesz ten krok — a wielu deweloperów uczących się systemu to robi — animacje będą odtwarzać się na niewłaściwych kościach lub wcale. Silnik nie wyrzuci błędu; po cichu użyje pierwszej kości o pasującej nazwie, co powoduje dziwne artefakty renderowania.

W panelu Skeleton Asset w edytorze zdefiniuj swojego awatara:

// Avatar definition in Unigine's data format
avatar {
    name = "humanoid_standard";
    bones {
        root = "Hips";
        left_arm = "LeftArm";
        right_arm = "RightArm";
        left_leg = "LeftLeg";
        right_leg = "RightLeg";
        spine = "Spine";
        head = "Head";
    }
}

Każdy asset postaci w twoim projekcie współdzieli tę definicję awatara. Kiedy importujesz nowego humanoida, mapujesz nazwy jego kości na nazwy awatara raz, a wszystkie klipy animacji każdej postaci działają z animacjami każdej innej postaci. Typowy czas konfiguracji tego mapowania to 10-15 minut na postać, w porównaniu ze starym podejściem polegającym na ręcznym nazywaniu punktów zakotwiczenia dla każdego klipu animacji, co zajmowało 30-60 minut na postać i psuło się przy każdym retargetingu.

Krok 2: Zbuduj maszynę stanów w edytorze

Otwórz edytor AnimationGraph z przeglądarki assetów Unigine 2.22. Do podstawowego kontrolera postaci będziesz potrzebować co najmniej:

  1. Idle — zapętlona animacja bezczynności, stan wejściowy
  2. Locomotion blend space — 2D mieszanie chodu/truchtu/biegu na podstawie parametrów prędkości i kierunku
  3. Jump — niepętlony start skoku i przejścia w powietrzu
  4. Land — etapowe odzyskiwanie równowagi z przerywalnym przejściem z powrotem do lokomocji

Każdy stan odwołuje się do klipu animacji lub blend space'a. Przejścia łączą stany za pomocą parametrów warunkowych — floatów, booli lub triggerów ustawianych z kodu w czasie rzeczywistym.

[Idle] --(speed > 0.1)--> [Locomotion]
[Locomotion] --(is_jumping == true)--> [Jump]
[Jump] --(on_ground == true)--> [Land]
[Land] --(land_finished == true)--> [Idle]
[Damage_Taken] --(hit_received == true)--> [Flinch]
[Flinch] --(flinch_finished == true)--> [Idle]

Krok 3: Steruj tym z kodu

Strona skryptowa została drastycznie uproszczona. Zamiast ręcznie obliczać wagi mieszania, każdej klatki wypychasz wartości parametrów:

// UnigineScript — driving the 2.22 AnimationGraph
ObjectMeshSkinned character_node;
AnimationGraph anim_graph;

int init() {
    character_node = node_cast(engine.editor.getNode("player_character"));
    anim_graph = new AnimationGraph(character_node);
    anim_graph.Load("animations/player_graph.animgraph");
    return 1;
}

int update() {
    float speed = length(character_node.getPositionVelocity());
    bool is_jumping = !character_node.isOnGround();

    anim_graph.SetFloat("speed", speed);
    anim_graph.SetFloat("direction", character_node.getTurnAngle());
    anim_graph.SetBool("is_jumping", is_jumping);
    anim_graph.SetBool("on_ground", character_node.isOnGround());

    if (received_damage) {
        anim_graph.Trigger("hit_received");
        received_damage = false;
    }

    anim_graph.Update();
    return 1;
}

Stara wersja tego kodu miała 120-180 linii ręcznego zarządzania mieszaniem. Nowa wersja ma poniżej 30 linii, ponieważ maszyna stanów, mieszanie i logika przejść żyją w assercie grafu.

Krok 4: Skonfiguruj mieszanie warstw dla górnej/dolnej części ciała

Dla postaci, która musi celować podczas biegu, potrzebujesz dwóch warstw animacji mieszanych za pomocą masek kości. W edytorze AnimationGraph 2.22:

Warstwa 0 (bazowa): maszyna stanów lokomocji — wpływa na biodra, nogi, rdzeń kręgosłupa
Warstwa 1 (override górnej części ciała): blend space celowania — wpływa na kręgosłup, ramiona, głowę
Warstwa 2 (addytywna): animacja odrzutu — addytywny offset na prawym ramieniu i kręgosłupie

Maski kości używają grup kości awatara zdefiniowanych w Kroku 1. Waga mieszania maski określa, w jakim stopniu warstwa override zastępuje warstwę bazową dla tych kości. Waga 1.0 oznacza całkowite zastąpienie; 0.7 oznacza częściowe mieszanie (przydatne do mieszania wpływu kąta celowania na górny kręgosłup).

Ta struktura warstw jest głównym powodem, dla którego animacja przeszła na system maszyn stanów zamiast pozostać sterowana skryptami. Ręczne mieszanie masek załamuje się katastrofalnie, gdy dodasz trzecią lub czwartą warstwę. Nowy system radzi sobie z tym, wymuszając kolejność ewaluacji i komponując warstwy sekwencyjnie przed skinningiem.


Animacja proceduralna: Motion Warping i IK

Co rozwiązuje motion warping

Motion warping przekierowuje root motion w czasie rzeczywistym. Klasyczny przykład: animacja pokonywania przeszkody ma root motion, które przesuwa kapsułę o 2 metry do przodu, ale przeszkoda jest 1,5 metra dalej. Bez motion warping postać albo lewituje nad przerwą, albo wchodzi w ścianę. Z motion warping cel root motion jest ustawiany na krawędź przeszkody, a trajektoria animacji wygina się, aby do niej pasować.

W Unigine 2.22:

// Setting the motion warp target during a vault
Vector3 vault_edge = getVaultEdge(ground_check.point, obstacle.normal);

// The AnimationGraph exposes a warp target parameter
anim_graph.SetWarpTarget("vault_end_point", vault_edge);
anim_graph.Trigger("start_vault");

To istotne również dla przemysłowych i symulacyjnych klientów Unigine. Symulatory treningowe z humanoidalnymi postaciami wymagają, aby postacie dokładnie oddziaływały z geometrią otoczenia. Motion warping zapewnia to bez ręcznego dostrajania ustawienia stóp dla każdej animacji.

Integracja IK dla pozycjonowania w czasie rzeczywistym

Unigine 2.22 udostępnia solver IK, który działa po ewaluacji warstw animacji. Dwa najczęstsze zastosowania:

Foot IK — rzucaj promienie z każdego stawu stopy w dół, dostosowuj zgięcie nogi do nachylenia terenu. Zapobiega wyglądowi „stóp unoszących się 5 cm nad nierównym terenem”, który nęka większość projektów Unigine.

Aim IK — śledź kierunek kamery lub celownika, obracając łańcuch kręgosłupa i ograniczając rotację głowy. Niezbędny w każdej strzelance z perspektywy trzeciej osoby tworzonej w Unigine.

// Foot IK setup — called each frame after anim_graph.Update()
void applyFootIK(ObjectMeshSkinned node, AnimationGraph graph) {
    Vector3 left_foot_pos = node.getBoneWorldPosition("LeftFoot");
    Vector3 right_foot_pos = node.getBoneWorldPosition("RightFoot");

    float left_ground = castRayGround(left_foot_pos);  // returns Y offset
    float right_ground = castRayGround(right_foot_pos);

    // Smoothly offset the pelvis to the lower foot position
    float pelvis_offset = min(left_ground, right_ground);
    graph.SetFootIKPelvisOffset(pelvis_offset);
    
    graph.SetFootIKTarget("LeftFoot", left_ground);
    graph.SetFootIKTarget("RightFoot", right_ground);
}

Warto również przekazywać dane normalnej terenu do foot IK — jeśli stopy znajdują się na zboczu o nachyleniu 30 stopni, rotacja kostki musi się do tego dopasować. Pomiń to, a stopy będą poprawnie pozycjonowane na Y, ale obrócone płasko, co wygląda gorzej niż brak IK.


Przebudowa importu FBX: na co uważać

Mapowanie awatara podczas importu

Ulepszony importer FBX w 2.22 rozwiązuje historyczne problemy z niezgodnościami hierarchii kości. Kiedy wrzucisz FBX do przeglądarki assetów, oferuje teraz:

  • Automatyczne wykrywanie konwencji nazewnictwa kości (Humanoid, Mixamo, custom)
  • Przypisanie awatara — oznacz zaimportowaną siatkę szkieletem awatara z projektu
  • Poprawka rotacji kości — kompensuje różnicę między Z-up w Blenderze a systemem współrzędnych Unigine (to powodowało rotacje kości głowy o 90 stopni w starym importerze mniej więcej co drugi import)
  • Ekstrakcja klipów animacji — automatycznie dzieli wieloujęciowe pliki FBX na pojedyncze klipy

Sama poprawka systemu współrzędnych eliminuje to, co kiedyś było 2-godzinną sesją debugowania na postać. W Unigine przed 2.22 importowałeś humanoida z Blendera i spędzałeś popołudnie, zastanawiając się, dlaczego ramiona postaci wskazują do tyłu. Teraz importer stosuje kompensację rotacji podczas importu.

Częsta pułapka: niezgodność skali

Jedyną rzeczą, której nowy importer nie naprawia automatycznie, jest skala jednostek. Blender domyślnie używa metrów; Unigine domyślnie używa metrów; ale Maya i 3ds Max domyślnie używają centymetrów. Jeśli twoja postać importuje się w skali 100x większej niż zamierzona, sprawdź ustawienia jednostek FBX w oknie importu. Ustaw je tak, aby pasowały do twojego narzędzia DCC przed importem. To wciąż krok manualny i wciąż najczęstszy błąd importu w wydaniu 2.22.

Niezgodność skali wpływa również na odtwarzanie klipów animacji. Animacja zapieczona w skali 1 cm na jednostkę wygeneruje root motion 100x za duże. Animacja jest odtwarzana, ale postać teleportuje się po scenie w jednej klatce. Jeśli widzisz takie zachowanie, sprawdź, czy skala root motion we właściwościach klipu odpowiada skali siatki.


Przewodnik migracji: konwersja starego kodu animacji

Jeśli masz istniejący projekt Unigine z animacją sterowaną skryptami, migracja do systemu AnimationGraph jest przyrostowa — nie musisz przepisywać wszystkiego naraz.

Krok 1: Zaudytuj istniejące warstwy animacji

Policz, ile instancji AnimLayer twój projekt tworzy w czasie rzeczywistym. Większość projektów Unigine ma od 4 do 12 warstw na postać. Każda z nich mapuje się na stan w nowym grafie lub warstwę w stosie warstw.

Krok 2: Zmapuj warstwy na stany

Utwórz asset AnimationGraph i dodaj stany odpowiadające nazwom twoich warstw. W przypadku warstw mieszanych addytywnie ustaw je jako warstwy addytywne w grafie, zamiast tworzyć nieaddytywne stany mieszane.

Krok 3: Zachowaj parametry sterowane z kodu

Twój istniejący kod już oblicza wagi mieszania, wartości prędkości i warunki triggerów. Zrefaktoruj go tak, aby wypychał wartości parametrów do grafu zamiast bezpośrednio ustawiać wagi warstw. Migracja wygląda tak:

// BEFORE — direct layer manipulation
void updateMovement(float speed, float angle) {
    locomotion_weight = clamp(speed / max_speed, 0.0, 1.0);
    idle_layer.setWeight(1.0 - locomotion_weight);
    locomotion_layer.setWeight(locomotion_weight);
    blend_parameter.setFloat(angle);
}

// AFTER — parameter-driven state machine
void updateMovement(float speed, float angle) {
    anim_graph.SetFloat("speed", speed);
    anim_graph.SetFloat("direction", angle);
}

Krok 4: Usuń zbędną logikę skryptową

Gdy maszyna stanów przejmie przejścia i mieszanie, możesz usunąć ręczną interpolację, easing i kod ograniczania wag. W dotychczas przekonwertowanych projektach skrypty związane z animacją zmniejszają się o 60-75% pod względem liczby linii. Logika nie znika — przenosi się do assetu grafu, który jest wersjonowany i edytowalny w edytorze wizualnym.


Zagadnienia wydajnościowe

Ewaluacja grafu animacji nie jest darmowa. Oto rzeczywiste liczby narzutu:

Scenariusz Stare podejście skryptowe Maszyna stanów (2.22)
1 postać, podstawowa lokomocja ~0.02ms ~0.03ms
1 postać, 3 warstwy + IK ~0.06ms ~0.04ms
50 postaci, mieszane animacje ~3.2ms ~1.8ms
200 postaci, z bramkowaniem LOD ~8.5ms ~4.1ms

System maszyn stanów jest cięższy na postać na podstawowym poziomie ze względu na narzut ewaluacji grafu. Zyskuje jednak wydajność w przypadku postaci z warstwami, ponieważ mieszanie jest obsługiwane w silniku, a nie przez wiele wywołań set-weight sterowanych skryptami na klatkę. Przy 50+ postaciach system maszyn stanów jest o około 40-50% szybszy.

Bramkowanie animacji LOD to twoje główne narzędzie optymalizacji. Unigine 2.22 obsługuje częstotliwości aktualizacji animacji per-LOD. Postacie dalej niż 30 metrów mogą aktualizować się co 3. klatkę; postacie dalej niż 80 metrów co 8. klatkę. Ustawisz to w ustawieniach LOD w AnimationGraph:

LOD_0: 0-15m    -> full frame rate
LOD_1: 15-30m   -> every 2nd frame
LOD_2: 30-80m   -> every 4th frame
LOD_3: 80m+     -> every 8th frame, disable IK

To samo w sobie może zmniejszyć koszt CPU animacji o 60-70% w scenach open-world z wieloma NPC.


Najlepsze praktyki migracji animacji w 2.22

  1. Najpierw zdefiniuj szkielet awatara, zanim utworzysz jakiekolwiek assety AnimationGraph. Migracja do spójnego awatara po zbudowaniu 20 assetów grafu oznacza ręczne przemapowanie każdego odwołania do kości — można tego uniknąć, planując z wyprzedzeniem.

  2. Utrzymuj maszyny stanów płaskimi, gdy to możliwe. AnimationGraph Unigine obsługuje zagnieżdżone pod-maszyny stanów, ale głęboko zagnieżdżone grafy (3+ poziomy) stają się trudne do wizualnego debugowania. Jeśli twój graf potrzebuje więcej niż 20 stanów, podziel go na osobne grafy dla konkretnych części ciała lub kontekstów (walka vs. eksploracja).

  3. Używaj triggerów do zdarzeń jednorazowych, nie booli. Trigger hit_received odpala się raz i resetuje automatycznie. Bool is_hit pozostaje true, dopóki jawnie nie ustawisz go na false, co często powoduje zapętlanie animacji w nieskończoność, gdy deweloperzy zapomną o resecie.

  4. Profiluj za pomocą panelu Animation Profiler przed i po migracji. Profiler Unigine 2.22 pokazuje teraz czas CPU na stan, koszt ewaluacji mieszania i liczbę transformacji kości na postać. Użyj go do identyfikacji kosztownych stanów — aim IK działający na postaciach, które nie celują, to najczęstsze marnotrawstwo.

  5. Testuj przejścia stanów animacji przy ekstremalnych klatkach. Przy 12-15 fps (często na słabszym sprzęcie lub przy nasyconym GPU) szybkie przejścia stanów mogą powodować luki w ewaluacji widoczne jako jednoklatkowe T-pozy. Użyj ogranicznika klatek, aby przetestować przejścia pod obciążeniem przed wydaniem.


Co to oznacza dla pozycji konkurencyjnej Unigine

Przebudowa animacji w Unigine 2.22 nie czyni silnika konkurencyjnym wobec Control Rig w Unreal czy pakietu Animation Rigging w Unity z dnia na dzień. Te narzędzia mają za sobą lata iteracji i ogromne zasoby społeczności. Ale to, co robi 2.22, to eliminacja głównego powodu, dla którego zespoły odrzucały Unigine podczas ewaluacji technicznej.

Dla zespołów już zaangażowanych w Unigine — zwłaszcza w symulacjach, architekturze i wizualizacji przemysłowej, gdzie wydajność draw calli i wydajność dużych scen są kluczowe — to wydanie usuwa ostatnią poważną lukę w workflow. Sam wizualny edytor maszyn stanów skraca czas konfiguracji animacji dla nowego projektu postaci z 2-3 dni do 4-6 godzin, na podstawie wczesnych raportów migracyjnych ze studiów korzystających z bety 2.22.

Jeśli kod animacji w twoim projekcie Unigine ma więcej niż 500 linii logiki mieszania, narzędzia maszyn stanów 2.22 znacznie go uproszczą. Zacznij od cyklu idle-lokomocja-skok głównej postaci gracza jako migracji proof-of-concept, a następnie rozpropaguj ten wzorzec na animacje NPC i postaci drugoplanowych.


Kolejne kroki

Pobierz Unigine 2.22 z oficjalnej strony SDK Unigine i otwórz projekt tutoriala AnimationGraph dołączony do próbek SDK. Przykładowa scena pokazuje 3-warstwowego humanoida z mieszaniem lokomocji, aim IK i motion warping od razu po wyjęciu z pudełka. Odtwórz tę konfigurację z własnymi assetami postaci, zanim zbudujesz niestandardowy graf od zera — to najszybszy sposób na zrozumienie pipeline'u ewaluacji i zobaczenie, gdzie twój istniejący kod animacji mapuje się na nowy system.

Dla zespołów oceniających Unigine jako cel backendowy obok innych silników, możesz podłączyć warstwę skryptową Unigine do zewnętrznych usług tak samo, jak w przypadku każdego frameworka gier w C++/C#. Jeśli twój projekt potrzebuje autoryzacji graczy, zapisywania danych gry lub tablic wyników utrzymywanych między sesjami, narzędzia takie jak horizOn oferują gotowe API, które podłączają się do środowiska skryptowego Unigine przez proste wywołania HTTP — utrzymując twój pipeline animacji w czystości, a dane graczy zarządzane oddzielnie od logiki silnika.


Źródło: Premiera Unigine 2.22