Skip to content

Instantly share code, notes, and snippets.

@NathoSteveo
Created October 6, 2026 18:10
Show Gist options
  • Select an option

  • Save NathoSteveo/b80cb0eb7c9cb23a64af3bd0a31524f6 to your computer and use it in GitHub Desktop.

Select an option

Save NathoSteveo/b80cb0eb7c9cb23a64af3bd0a31524f6 to your computer and use it in GitHub Desktop.
import unreal
# ---- CONFIG ----
INSTANCE_PREFIX = "MI_"
TEXTURE_PREFIX = "T_"
# texture suffix -> parent material parameter name (case-sensitive!)
PARAMS = {"D": "D", "N": "N", "R": "R", "M": "M"}
# ----------------
eal = unreal.EditorAssetLibrary
mel = unreal.MaterialEditingLibrary
def get_selected_folder():
"""Return the folder selected in the Content Browser."""
folders = unreal.EditorUtilityLibrary.get_selected_folder_paths()
if folders:
path = folders[0]
# UE5 can return paths like "/All/Game/..."
if path.startswith("/All/"):
path = path[4:]
return path
# Fallback: use the folder of the first selected asset
assets = unreal.EditorUtilityLibrary.get_selected_assets()
if assets:
pkg = assets[0].get_path_name().split(".")[0]
return pkg.rsplit("/", 1)[0]
return None
def pkg_path(asset_path):
# "/Game/Folder/Name.Name" -> "/Game/Folder/Name"
return asset_path.split(".")[0]
def configure_texture(tex, suffix):
"""Set sRGB / compression to match the texture's role."""
if suffix == "D":
tex.set_editor_property("srgb", True)
tex.set_editor_property("compression_settings", unreal.TextureCompressionSettings.TC_DEFAULT)
elif suffix == "N":
tex.set_editor_property("srgb", False)
tex.set_editor_property("compression_settings", unreal.TextureCompressionSettings.TC_NORMALMAP)
else: # R, M
tex.set_editor_property("srgb", False)
tex.set_editor_property("compression_settings", unreal.TextureCompressionSettings.TC_MASKS)
eal.save_loaded_asset(tex)
def run():
import_folder = get_selected_folder()
if not import_folder:
unreal.log_error("Select a folder (or an asset) in the Content Browser first.")
return
unreal.log(f"Processing folder: {import_folder}")
all_paths = eal.list_assets(import_folder, recursive=True, include_folder=False)
# index textures and instances by name
textures, instances = {}, []
for p in all_paths:
asset = eal.load_asset(p)
if isinstance(asset, unreal.Texture2D):
textures[asset.get_name()] = asset
elif isinstance(asset, unreal.MaterialInstanceConstant):
instances.append(asset)
for mi in instances:
old_name = mi.get_name()
base = old_name[len(INSTANCE_PREFIX):] if old_name.startswith(INSTANCE_PREFIX) else old_name
# assign textures
for suffix, param in PARAMS.items():
tex = textures.get(f"{TEXTURE_PREFIX}{base}_{suffix}")
if tex:
configure_texture(tex, suffix)
mel.set_material_instance_texture_parameter_value(mi, param, tex)
else:
unreal.log_warning(f"[{base}] missing texture {TEXTURE_PREFIX}{base}_{suffix}")
mel.update_material_instance(mi)
eal.save_loaded_asset(mi)
# rename last (rename_asset fixes references, e.g. on the static mesh)
if not old_name.startswith(INSTANCE_PREFIX):
old_path = pkg_path(mi.get_path_name())
folder = old_path.rsplit("/", 1)[0]
new_path = f"{folder}/{INSTANCE_PREFIX}{base}"
if not eal.rename_asset(old_path, new_path):
unreal.log_warning(f"Could not rename {old_path}")
unreal.log(f"Processed {len(instances)} material instances")
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment