"""Automated static mesh imports using the engine's enabled import pipelines.""" from pathlib import Path import unreal from .paths import GENERATED, slug def import_model(filename, name="Character"): source = Path(filename).resolve() if not source.is_file(): raise FileNotFoundError(f"Brak modelu: {source}") if source.suffix.lower() not in {".glb", ".gltf", ".fbx", ".obj"}: raise ValueError("Model musi byc plikiem GLB, glTF, FBX lub OBJ.") destination = f"{GENERATED}/Imports/{slug(name)}" task = unreal.AssetImportTask() task.set_editor_property("filename", str(source)) task.set_editor_property("destination_path", destination) task.set_editor_property("destination_name", name) task.set_editor_property("automated", True) task.set_editor_property("replace_existing", True) task.set_editor_property("replace_existing_settings", True) task.set_editor_property("save", True) task.set_editor_property("async_", False) if source.suffix.lower() in {".glb", ".gltf"}: # Defaults reuse existing materials without updating them. Our generated # import folder belongs to the source file, so apply source properties. template = unreal.load_asset("/Interchange/Pipelines/DefaultGLTFAssetsPipeline") pipeline = unreal.load_asset(GENERATED + "/Pipelines/GLTFWorkshop") if pipeline is None: pipeline = unreal.AssetToolsHelpers.get_asset_tools().duplicate_asset( "GLTFWorkshop", GENERATED + "/Pipelines", template) pipeline.set_editor_property("reimport_strategy", unreal.ReimportStrategyFlags.APPLY_PIPELINE_PROPERTIES) pipeline.material_pipeline.set_editor_property("import_materials", True) # PBR images are imported explicitly into WorkshopTextures below. This # avoids Interchange's dependency-preserving material reimport behavior. pipeline.material_pipeline.texture_pipeline.set_editor_property("import_textures", False) pipeline.set_editor_property("scene_name_sub_folder", True) pipeline.set_editor_property("asset_type_sub_folders", True) pipeline.material_pipeline.set_editor_property( "search_location", unreal.InterchangeMaterialSearchLocation.DO_NOT_SEARCH) pipeline.material_pipeline.set_editor_property( "material_import", unreal.InterchangeMaterialImportOption.IMPORT_AS_MATERIAL_INSTANCES) unreal.EditorAssetLibrary.save_loaded_asset(pipeline) options = unreal.InterchangePipelineStackOverride() options.set_editor_property("override_pipelines", [ unreal.SoftObjectPath(pipeline.get_path_name()), unreal.SoftObjectPath("/Interchange/Pipelines/DefaultGLTFPipeline.DefaultGLTFPipeline")]) task.set_editor_property("options", options) if source.suffix.lower() == ".fbx": options = unreal.FbxImportUI() options.set_editor_property("import_as_skeletal", False) options.set_editor_property("mesh_type_to_import", unreal.FBXImportType.FBXIT_STATIC_MESH) options.set_editor_property("automated_import_should_detect_type", False) options.static_mesh_import_data.set_editor_property("combine_meshes", True) task.set_editor_property("options", options) unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) meshes = [obj for obj in task.get_objects() if isinstance(obj, unreal.StaticMesh)] if len(meshes) != 1: raise RuntimeError( f"Import {source.name}: oczekiwano jednego StaticMesh, otrzymano {len(meshes)}. " "Polacz obiekty przed eksportem albo uzyj workshop.blender.import_character().") if source.suffix.lower() in {".glb", ".gltf"}: # UE preserves material edits on mesh reimport. In this workflow Blender # owns the look; explicitly synchronize the supported PBR parameters. from ._gltf import link_textures link_textures(source, meshes[0], destination) return meshes[0]