"""Run inside Unreal Editor's Python console or Execute Python Script. Imports the supplied Phase 3 reference plates and places them as emissive gallery panels in the pax-coder repository sandbox. This is a visual reference scene, not a photogrammetry reconstruction. """ import pathlib import unreal PROJECT_DIR = pathlib.Path(unreal.Paths.project_dir()) SOURCE_DIR = PROJECT_DIR / "ReferenceSource" / "NeonReflections" DESTINATION = "/Game/RealityScene/NeonReflections" REPOSITORY_ID = "pax-coder" REFERENCE_SET_ID = "neon-reflections-v15" IMAGE_FILES = ["3087.webp", "3089.webp", "3090.webp", "3092.jpg"] def import_reference_images(): asset_tools = unreal.AssetToolsHelpers.get_asset_tools() imported = [] for file_name in IMAGE_FILES: source_file = SOURCE_DIR / file_name if not source_file.is_file(): unreal.log_warning("Missing reference plate: %s" % source_file) continue task = unreal.AssetImportTask() task.set_editor_property("filename", str(source_file)) task.set_editor_property("destination_path", DESTINATION) task.set_editor_property("destination_name", pathlib.Path(file_name).stem) task.set_editor_property("automated", True) task.set_editor_property("replace_existing", True) task.set_editor_property("save", True) asset_tools.import_asset_tasks([task]) imported.extend(task.get_editor_property("imported_object_paths")) return [unreal.load_asset(path) for path in imported] def make_emissive_material(texture, name): asset_tools = unreal.AssetToolsHelpers.get_asset_tools() package_path = DESTINATION + "/Materials" factory = unreal.MaterialFactoryNew() material = asset_tools.create_asset(name, package_path, unreal.Material, factory) if not material: return None material.set_editor_property("two_sided", True) material.set_editor_property("shading_model", unreal.MaterialShadingModel.MSM_UNLIT) sample = unreal.MaterialEditingLibrary.create_material_expression( material, unreal.MaterialExpressionTextureSampleParameter2D, -400, 0 ) sample.set_editor_property("parameter_name", "ReferenceTexture") sample.set_editor_property("texture", texture) unreal.MaterialEditingLibrary.connect_material_property( sample, "RGB", unreal.MaterialProperty.MP_EMISSIVE_COLOR ) unreal.MaterialEditingLibrary.layout_material_expressions(material) unreal.EditorAssetLibrary.save_loaded_asset(material) return material def place_gallery_panel(mesh, material, location, rotation, scale, label): actor = unreal.EditorLevelLibrary.spawn_actor_from_object( mesh, unreal.Vector(*location), unreal.Rotator(*rotation) ) actor.set_actor_label(label) actor.set_actor_scale3d(unreal.Vector(*scale)) component = actor.get_component_by_class(unreal.StaticMeshComponent) if component and material: component.set_material(0, material) return actor def run(): textures = import_reference_images() if not textures: raise RuntimeError("No reference plates imported from %s" % SOURCE_DIR) plane = unreal.load_asset("/Engine/BasicShapes/Plane.Plane") if not plane: raise RuntimeError("Engine plane mesh is unavailable") placements = [ ((0.0, 1800.0, 900.0), (90.0, 0.0, 0.0), (12.0, 8.0), "NeonRef_North"), ((0.0, -1800.0, 900.0), (-90.0, 0.0, 180.0), (12.0, 8.0), "NeonRef_South"), ((1800.0, 0.0, 900.0), (90.0, 0.0, 90.0), (12.0, 8.0), "NeonRef_East"), ((-1800.0, 0.0, 900.0), (90.0, 0.0, -90.0), (12.0, 8.0), "NeonRef_West"), ] for texture, placement in zip(textures, placements): material = make_emissive_material(texture, "MI_" + texture.get_name()) place_gallery_panel(plane, material, *placement) repo_class = unreal.load_class(None, "/Script/GitWorldUnreal.GitWorldRepoWorld") if repo_class: repo_actor = next( ( actor for actor in unreal.EditorLevelLibrary.get_all_level_actors() if actor.is_a(repo_class) and actor.get_editor_property("repository_id") == REPOSITORY_ID ), None, ) if repo_actor: repo_actor.set_editor_property("reference_set_id", REFERENCE_SET_ID) repo_actor.set_editor_property("reference_images", textures) unreal.EditorAssetLibrary.save_loaded_asset(repo_actor) unreal.EditorLevelLibrary.save_current_level() unreal.log("GitWorld Phase 3 reference gallery placed: %s" % REFERENCE_SET_ID) run()