"""Uruchom plik w UE: File > Execute Python Script. Zmieniaj i uruchamiaj ponownie.""" import importlib import sys # Ponowny import bibliotek (ue cachuje zaimportowaną biblioteke i jeśli nie bedzie # jawnego reloadu/restartu edytora to będzie wykonywał stary kod) if "ue_workshop" in sys.modules: _render_module = sys.modules.get("ue_workshop.render") if _render_module is not None and _render_module.is_rendering(): raise RuntimeError("Poczekaj na zakonczenie renderu przed przeladowaniem biblioteki.") # Najpierw zaleznosci, potem moduly, ktore z nich korzystaja. for _name in ("paths", "animation_clip", "animation_catalog", "animations", "progress", "video", "materials", "camera", "lighting", "assets", "_gltf", "blender", "characters", "skeletal", "root_motion", "scene", "sequence", "render"): _module = sys.modules.get("ue_workshop." + _name) if _module is not None: importlib.reload(_module) importlib.reload(sys.modules["ue_workshop"]) from ue_workshop import Scene, Sequence, Renderer, camera, lighting, materials from ue_workshop.paths import PROJECT from ue_workshop.characters import FIGHTER_MODEL, CREATURE_MODEL # WYBOR POSTACI: "fighter", "creature", "primitive" lub "file". MODEL = "fighter" REIMPORT = False # True: ponowny import modelu i klipow; False: istniejace assety UE ANIMATION = "great_sword_attack" # wszystkie nazwy: docs/animations.md; creature: mutant_swiping MODEL_FILE = PROJECT / "source_assets/character/my_mixamo_character.fbx" SKELETAL = True # dla MODEL="file"; False dla statycznego GLB/FBX/OBJ/.blend ANIMATION_FILE = None # None: animacja w MODEL_FILE; albo FBX Without Skin tej samej postaci MODEL_HEIGHT = 200 # centymetry; None zachowuje oryginalny rozmiar MODEL_ROTATION = (0, 0, 180) # roll, pitch, yaw; obrot modeli Mixamo przodem do kamery # 1. MODEL I SCENA. Jednostki: centymetry. Os Z wskazuje gore. scene = Scene("MyShot") floor = materials.color("Floor", rgb=(0.07, 0.08, 0.11)) if MODEL == "primitive": blue = materials.color("Character", rgb=(0.04, 0.35, 0.8), metallic=0.2) character = scene.character(material=blue, head_scale=1.0) else: presets = { "fighter": (FIGHTER_MODEL, "Fighter"), "creature": (CREATURE_MODEL, "Creature"), } if MODEL in presets: source, name = presets[MODEL] character = scene.skeletal_model(source, name=name, height=MODEL_HEIGHT, rotation=MODEL_ROTATION, reimport=REIMPORT) elif MODEL == "file": if SKELETAL: character = scene.skeletal_model(MODEL_FILE, name="CustomCharacter", height=MODEL_HEIGHT, rotation=MODEL_ROTATION, animations={"custom": ANIMATION_FILE} if ANIMATION_FILE else None, reimport=REIMPORT) else: character = scene.model(MODEL_FILE, name="CustomCharacter", height=MODEL_HEIGHT, rotation=MODEL_ROTATION, reimport=REIMPORT) else: raise ValueError("MODEL: fighter, creature, primitive lub file.") scene.primitive("Cube", name="Floor", location=(0, 0, -10), scale=(20, 20, 0.2), material=floor) lighting.studio(scene, key_color=(1.0, 0.75, 0.5), fill_color=(0.3, 0.6, 1.0)) cam = camera.create(scene, location=(450, -550, 300), fov=40) # 2. ANIMACJA. 120 klatek przy 24 FPS = 5 sekund. Ostatnia klatka ma numer 119. shot = Sequence(scene, fps=24, frames=120) shot.camera(cam) if MODEL in ("fighter", "creature"): idle = "great_sword_idle" if MODEL == "fighter" else "mutant_idle" shot.animation(character, idle, start=0, end=60) shot.animation(character, ANIMATION, start=48, end=120) elif MODEL == "file" and SKELETAL: shot.animation(character, "custom" if ANIMATION_FILE else None) else: shot.transform_key(character, 0, rotation=(0, 0, 0)) shot.transform_key(character, 119, rotation=(0, 0, 360)) # Rotacja: (roll, pitch, yaw), w stopniach. # Klucze transformacji dzialaja tez razem z animacja kosci. # Opcjonalny podskok: # shot.transform_key(character, 0, location=(0, 0, 0), interpolation="auto") # shot.transform_key(character, 60, location=(0, 0, 80), interpolation="auto") # shot.transform_key(character, 119, location=(0, 0, 0), interpolation="auto") shot.save() # 3. WYNIK. Najpierw obejrzyj animacje w Sequencerze, potem zmien RENDER na True. RENDER = False renderer = Renderer(width=1920, height=1080, samples=4, warmup=32, mp4=True) # Mozesz tez zaczac od presetu i nadpisac wybrane wartosci: # renderer = Renderer.from_preset("final", width=1920, height=1080) if RENDER: renderer.render(shot) # Szybki podglad zamiast filmu: renderer.render(shot, single_frame=24)