"""Integration check: export/import, changed geometry/material, stable asset paths, MRQ.""" import os from pathlib import Path import subprocess import unreal from ue_workshop import Scene, Sequence, blender, camera, lighting, render from ue_workshop.paths import PROJECT, executable source = PROJECT / "source_assets/character/character.blend" if not source.is_file(): raise RuntimeError("Wygeneruj przykladowa postac: blender --background --python tools/create_character.py") mesh = blender.import_character(source, name="SmokeCharacterV1") asset_path = mesh.get_path_name() old_bounds = mesh.get_bounds().box_extent.z old_materials = {str(item.material_slot_name): item.material_interface.get_path_name() for item in mesh.static_materials} assert len(old_materials) == 3, old_materials assert all(old_materials.values()) # Change a COPY of the source, never the student's .blend. variant = PROJECT / "build/smoke/character_variant.blend" variant.parent.mkdir(parents=True, exist_ok=True) code = ("import bpy; bpy.data.objects['Head'].scale *= 2; " "bpy.data.materials['Head_Orange'].node_tree.nodes.get('Principled BSDF')." "inputs['Base Color'].default_value = (0.02, 0.8, 0.05, 1); " "image = bpy.data.images.new('BodyPattern', width=2, height=2); " "image.pixels = [0.1, 0.3, 0.8, 1] * 4; image.pack(); " "tree = bpy.data.materials['Body_Blue'].node_tree; " "node = tree.nodes.new('ShaderNodeTexImage'); node.image = image; " "tree.links.new(node.outputs['Color'], tree.nodes.get('Principled BSDF').inputs['Base Color']); " f"bpy.ops.wm.save_as_mainfile(filepath={str(variant)!r})") completed = subprocess.run([executable("blender"), "--background", str(source), "--python-exit-code", "1", "--python-expr", code], capture_output=True, text=True, timeout=120) if completed.returncode: raise RuntimeError((completed.stdout + completed.stderr)[-4000:]) updated = blender.import_character(variant, name="SmokeCharacterV1") assert updated.get_path_name() == asset_path, "Import created a different mesh asset" assert updated.get_bounds().box_extent.z > old_bounds + 5, "Geometry was not updated" new_materials = {str(item.material_slot_name): item.material_interface.get_path_name() for item in updated.static_materials} assert new_materials == old_materials, "Material identities changed" assert all(unreal.load_asset(path) for path in new_materials.values()) green_found = False texture_found = False for path in new_materials.values(): material = unreal.load_asset(path) for parameter in unreal.MaterialEditingLibrary.get_vector_parameter_names(material): color = unreal.MaterialEditingLibrary.get_material_instance_vector_parameter_value(material, parameter) if color.g > 0.7 and color.r < 0.1 and color.b < 0.1: green_found = True for parameter in unreal.MaterialEditingLibrary.get_texture_parameter_names(material): texture = unreal.MaterialEditingLibrary.get_material_instance_texture_parameter_value(material, parameter) if texture and texture.get_path_name().startswith("/Game/Workshop/Generated/Imports/SmokeCharacterV1/"): texture_found = True assert green_found, "Updated green material was not imported" assert texture_found, "Embedded Blender texture was not imported and assigned" scene = Scene("BlenderSmoke") actor = scene.mesh(updated, name="UpdatedCharacter") lighting.studio(scene) cam = camera.create(scene) shot = Sequence(scene, frames=2) shot.camera(cam) shot.transform_key(actor, 0, rotation=(0, 0, 0)) shot.transform_key(actor, 1, rotation=(0, 0, 30)) render.start(shot)