Files
PythonInUnreal/README.md
T
2026-10-31 17:21:00 +01:00

12 KiB
Raw Blame History

Python w Unrealu — warsztat na godzinę

UE 5.7, Windows / Linux. Biblioteka ue_workshop automatyzuje scenę, Sequencer, Movie Render Queue i składanie MP4. Nie wymaga kompilacji C++ ani pip. Pierwsze ćwiczenie korzysta wyłącznie z brył silnika. Blender jest opcjonalny.

Jeśli używasz wcześniejszej kopii projektu z C++ i edytor zgłasza Target Upgrade Required, zamknij UE i usuń pozostałości starej kompilacji: Binaries/, Intermediate/Build/ oraz Intermediate/TargetInfo.json. Nowy projekt nie ma własnego targetu C++ i nie wymaga aktualizacji Target.cs.

Przygotowanie przed spotkaniem

  1. Zainstaluj UE 5.7 i otwórz ExampleProject.uproject. Poczekaj na kompilację shaderów.
  2. Zainstaluj FFmpeg z enkoderem libx264 i dodaj do PATH, jeżeli chcesz MP4. Bez FFmpeg można renderować PNG: render.start(shot, mp4=False).
  3. Zwykły Python 3.10+ jest potrzebny tylko do launchera z terminala.
  4. Sprawdź python tools/run_workshop.py --check i wykonaj ćwiczenie próbnie.

W projekcie są już włączone Python Editor Script Plugin, Editor Scripting Utilities, Sequencer Scripting, Movie Render Queue oraz Interchange. Python jest narzędziem automatyzacji edytora; nie służy tu do gameplayu.

Pierwszy skrypt w edytorze

Zapisz aktualną mapę. Wybierz File → Execute Python Script i wskaż exercises/my_shot.py. Możesz też wpisać w konsoli UE:

py "C:/sciezka/do/projektu/exercises/my_shot.py"

Powstanie prosta postać, podłoga, trzy światła, kamera i dwusekundowa animacja. Obejrzyj ją w Sequencerze. Zmień kolor, head_scale, kamerę albo klucze i uruchom plik ponownie. Skrypt jest odczytywany ponownie z dysku.

Ustaw RENDER = True, aby wyrenderować film. Domyślny preset preview to 640×360, 24 FPS, 48 klatek. final to 1280×720 i więcej próbek. Szybkie sprawdzenie obrazu: zamiast pełnego renderu użyj renderer.render(shot, single_frame=24).

Własne ustawienia wpisujesz bezpośrednio w skrypcie uczestnika:

from ue_workshop import Renderer

renderer = Renderer(width=1920, height=1080, samples=8, warmup=32, mp4=True)
renderer.render(shot)
# Albo zamiast filmu: renderer.render(shot, single_frame=24)

width i height to piksele, samples to liczba próbek przestrzennych na klatkę, a warmup to liczba klatek rozgrzewki. Wymiary i próbki muszą być dodatnimi liczbami całkowitymi, rozgrzewka może wynosić zero. FPS pochodzi z sekwencji. Można też użyć Renderer.from_preset("final", width=1920, height=1080): argumenty nadpisują wybrane wartości presetu. Obiektu użyjesz ponownie do kolejnych sekwencji po zakończeniu poprzedniego renderu. Ustawienia są zapisane w result.json. Dotychczasowe render.start(...) nadal działa jako skrót do presetów.

Wyniki: renders/MyShot/<czas_i_id>/frames/, film.mp4, result.json. Każdy render ma nowy katalog. Nieudane kodowanie zachowuje klatki. MP4 powstaje dopiero po zakończeniu MRQ; nie zamykaj wtedy edytora. Na czas przebudowy sceny i renderowania biblioteka zamyka kartę Sequencera. Render startuje po powrocie ze skryptu. Sekwencję można ponownie otworzyć z Content Browser; ponowne uruchomienie ćwiczenia też ją otwiera.

Z terminala, bez okna edytora

Drugi plik obok ćwiczenia uruchamia my_shot.py bez okna UE, czeka na zakończenie renderu oraz kodowania MP4 i automatycznie zamyka uruchomiony proces edytora:

python exercises/my_shot_headless.py

Uruchamiaj go zwykłym Pythonem z terminala, nie przez Execute Python Script w Unreal. Korzysta z obiektu renderer i ustawień zapisanych w my_shot.py. Wymusza render również przy RENDER=False. Wynik trafia do tego samego renders/MyShot/<czas_i_id>/film.mp4. Można dopisać --editor, --timeout lub --check; ścieżka skryptu jest ustalana względem pliku launchera.

Domyślnie konsola pokazuje etapy: uruchamianie UE, przygotowanie sceny, renderowanie, składanie MP4 i zamykanie UE, a na końcu wynik i ścieżkę do logu. Podczas renderowania podaje liczbę zapisanych PNG; przy dłuższym oczekiwaniu co 10 sekund potwierdza, że proces nadal działa. To nie jest szacowany procent całego zadania — rozgrzewka, zapis klatek i kodowanie mają różne czasy wykonania. Pełne logi trafiają do Saved/Workshop/<id>.log, także przy błędzie lub timeout. Żeby widzieć logi UE na żywo w terminalu, dodaj:

python exercises/my_shot_headless.py --verbose

Ścieżki filmu i logu są klikalne w obsługujących to terminalach, m.in. Windows Terminal i terminalu VS Code (zwykle Ctrl+klik). W pozostałych konsolach oraz przy przekierowaniu wyjścia do pliku wypisywane są zwykłe ścieżki. Można wymusić linki opcją --links always lub wyłączyć je przez --links never.

Ogólny launcher do pozostałych skryptów:

python tools/run_workshop.py --check
python tools/run_workshop.py exercises/my_shot.py --render
python tools/run_workshop.py exercises/my_shot.py --single-frame 24

Bez --render launcher tylko wykonuje skrypt i zapisuje scenę (chyba że sam skrypt uruchamia render). Zwraca kod 0 przy powodzeniu i 1 przy błędzie. Domyślny limit to 900 sekund; można zmienić --timeout. Nie używaj -nullrhi do renderowania. Tryb bez okna nadal wymaga GPU, sterowników i na Linuksie działającego Vulkan. Obsługa Linuksa jest przygotowana w kodzie; trzeba sprawdzić ją na docelowej maszynie.

Ścieżki programów można ustawić zmiennymi środowiskowymi:

$env:WORKSHOP_UNREAL = 'C:\Program Files\Epic Games\UE_5.7\Engine\Binaries\Win64\UnrealEditor-Cmd.exe'
$env:WORKSHOP_BLENDER = 'C:\Program Files\Blender Foundation\Blender 5.1\blender.exe'
$env:WORKSHOP_FFMPEG = 'C:\tools\ffmpeg\bin\ffmpeg.exe'
export WORKSHOP_UNREAL=/opt/UnrealEngine/Engine/Binaries/Linux/UnrealEditor
export WORKSHOP_BLENDER=/usr/bin/blender
export WORKSHOP_FFMPEG=/usr/bin/ffmpeg
python3 tools/run_workshop.py --check --blender

Ścieżki nie są zapisane na sztywno w bibliotece. Launcher ma domyślną lokalizację instalacji UE 5.7 na Windows; na Linuksie korzysta ze zmiennej lub PATH.

Wybór postaci i model pobrany z internetu

W exercises/my_shot.py wybierz MODEL:

Wartość Postać
"primitive" Dotychczasowa postać z brył, bez importu.
"robot" RobotPolice z dołączonego DemoAssets.
"pilot" Humanoid z DemoAssets/pilot.
"file" Własny plik wskazany w MODEL_FILE.

Przykład własnego modelu:

MODEL = "file"
MODEL_FILE = PROJECT / "source_assets/models/my_character.glb"
MODEL_HEIGHT = 200
MODEL_ROTATION = (0, 0, 90)

Rozpakuj pobrany model razem z teksturami. Możesz użyć ścieżki absolutnej albo ścieżki względem projektu. GLB z osadzonymi teksturami PNG/JPEG pozwala przenieść podstawowe materiały PBR w jednym pliku. FBX i OBJ wymagają zachowania plików tekstur i powiązanych FBM/MTL. Nie wczytujemy ZIP ani plików .uasset. Import zawsze odbywa się do wydzielonego katalogu generowanych assetów.

Biblioteka łączy części modelu, ustawia jego wysokość w centymetrach i przesuwa podstawę na Z=0. MODEL_HEIGHT=None zachowuje rozmiar źródłowy. Jeśli model leży na boku, popraw MODEL_ROTATION (roll, pitch, yaw); obrót jest stosowany przed dopasowaniem wysokości. Pivot animacji znajduje się na środku podstawy.

Dla pojedynczego atlasu FBX/OBJ można dołączyć mapy NazwaModelu_BC.png, _N, _R, _M, _E (również JPG/JPEG). Biblioteka odtworzy z nich jeden materiał dla wszystkich slotów. Robot i pilot korzystają z tej konwencji. Bez pliku _BC pozostają materiały zaimportowane przez UE. W GLB zachowywany jest osobny materiał dla każdego slotu.

Po zmianie postaci reszta skryptu działa tak samo: klucze location, rotation i scale animują cały model. W przykładzie jest też opcjonalny podskok. Modele z rigami są w tej wersji importowane jako statyczna geometria: animacje kości, chodzenie z Mixamo i retargeting nie są jeszcze obsługiwane. Wybrany model działa zarówno w edytorze, jak i przez my_shot_headless.py.

Blender → UE → film

Własną kopię wybierzesz też bezpośrednio w my_shot.py:

MODEL = "file"
MODEL_FILE = PROJECT / "source_assets/character/character_custom.blend"

Zapisz zmiany w Blenderze i ponownie uruchom ćwiczenie. Za każdym razem plik jest eksportowany w tle i aktualizuje ten sam asset CustomCharacter w UE. Nie trzeba ręcznie usuwać poprzedniego modelu. Eksport obejmuje kolekcję Character. Na Windows biblioteka wykrywa też standardowe instalacje w Blender Foundation, jeśli Blender nie jest w PATH; WORKSHOP_BLENDER pozwala wybrać inną instalację.

Przykładowy model znajduje się w source_assets/character/character.blend. Można go też odtworzyć (generator nie nadpisuje istniejącego pliku):

blender --background --python-exit-code 1 --python tools/create_character.py

Otwórz model w Blenderze, powiększ obiekt Head, zmień kolor materiału i zapisz. Uruchom examples/blender_character.py w UE albo:

python tools/run_workshop.py examples/blender_character.py

Skrypt uruchamia osobny proces Blendera, eksportuje kolekcję Character do GLB, aktualizuje model i materiały w UE, buduje sekwencję i renderuje MP4. Blender nie musi być otwarty. Eksport czyta ostatni zapis z dysku.

Umowa dla modelu: statyczne siatki w kolekcji Character, metry w Blenderze, stopy na Z=0, przód w +X. Modyfikatory są uwzględniane, obiekty łączone do jednej siatki z zachowaniem slotów materiałów. Origin eksportu to zero świata. Podstawowe PBR: Principled BSDF, kolory, roughness, metallic, obsługiwane tekstury. Tekstury PNG/JPEG są wyciągane z GLB i aktualizowane w wydzielonym katalogu WorkshopTextures. Parametry PBR synchronizujemy jawnie, ponieważ standardowy reimport siatki w UE zachowuje wcześniejsze materiały. Zmiany w tych importowanych materiałach wykonuj w Blenderze; skrypt nadpisuje wspierane parametry ich źródłem. Dowolne grafy proceduralne, rig, animacje szkieletowe, włosy i shader skóry nie wchodzą w zakres v1. Materiały proceduralne należy wypalić do tekstur.

Układ i zasady

  • Content/Python/ue_workshop/ — biblioteka, automatycznie dostępna w Pythonie UE.
  • exercises/my_shot.py — jedyny wymagany plik uczestnika; zrób kopię przed edycją.
  • examples/ — dodatkowa kamera i Blender; ćwiczenie startowe jest też rozwiązaniem bazowym.
  • tools/ — launcher, eksport/generator Blendera i testy integracyjne.
  • docs/ — ściąga API i scenariusz spotkania.
  • Content/Workshop/Generated/ — mapy, sekwencje, importy i materiały generowane w UE.
  • build/, renders/ — pliki pośrednie i wyniki, pomijane przez Git.
  • archive/legacy_python/ — stare skrypty; poza ścieżką importu UE.
  • DemoAssets/ — zachowane źródłowe modele z poprzedniego projektu, opcjonalne.

Scene("MyShot") zarządza mapą /Game/Workshop/Generated/MyShot/Map. Ponowne wykonanie usuwa w niej tylko aktorów z tagiem Workshop, a sekwencję odbudowuje. Własną scenę nazwij inaczej, np. Scene("AniaShot"). Generowana sekwencja jest w całości zastępowana: ręczne zmiany zachowaj w jej kopii. Mapy spoza warsztatu nie są czyszczone; przy niezapisanej obcej mapie skrypt prosi o zapis. Nie usuwaj całego folderu Generated podczas pracy — zawiera aktualnie używane assety.

Weryfikacja

python -m unittest discover -s tests -v
python tools/run_workshop.py tools/smoke_scene.py
python tools/run_workshop.py tools/smoke_blender.py
python tools/run_workshop.py tools/smoke_renderer.py

Pierwszy test integracyjny wykonuje ćwiczenie dwa razy, sprawdza duplikaty, renderuje dwie klatki i koduje MP4. Drugi wymaga Blendera i sprawdza powtórny import zmienionej geometrii oraz materiałów i render. Opis sprawdzonego środowiska: docs/validation.md.