Files
PythonInUnreal/Content/Python/ue_workshop/assets.py
T
2026-10-31 17:03:41 +01:00

69 lines
3.9 KiB
Python

"""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]