# Lot O4 : mipmaps et streaming des textures 3D qui en sont privees. # # Candidates : Texture2D de /Game dont MipGenSettings = NoMipmaps ou NeverStream = True, de dimensions en puissance # de 2, referencees par au moins un materiau (Material, MaterialInstanceConstant) et par aucun widget ni Blueprint. # Les textures d'interface ou chargees par nom (sans reference de materiau) ne sont jamais touchees. # Modification : MipGenSettings = FromTextureGroup, NeverStream = False. Rien d'autre. # # Usage : # UnrealEditor-Cmd.exe -run=pythonscript -script="/Tools/FixTextureMips.py [-apply]" # Sans -apply : simulation (liste ecrite dans Saved/Audit/o4_candidats.txt). import os import sys import unreal apply = "-apply" in sys.argv registry = unreal.AssetRegistryHelpers.get_asset_registry() registry.search_all_assets(True) opts = unreal.AssetRegistryDependencyOptions(include_soft_package_references=True, include_hard_package_references=True, include_searchable_names=False, include_soft_management_references=False, include_hard_management_references=False) MATERIAL_CLASSES = {"Material", "MaterialInstanceConstant"} def pow2(n): return n > 0 and (n & (n - 1)) == 0 candidates, skipped = [], {} for a in registry.get_assets_by_class(unreal.TopLevelAssetPath("/Script/Engine", "Texture2D"), False): pkg = str(a.package_name) if not pkg.startswith("/Game/"): continue mips = str(a.get_tag_value("MipGenSettings") or "") never = str(a.get_tag_value("NeverStream") or "") if mips != "TMGS_NoMipmaps" and never != "True": continue dims = str(a.get_tag_value("Dimensions") or "0x0").split("x") if len(dims) != 2 or not (pow2(int(dims[0])) and pow2(int(dims[1]))): skipped["dimensions non puissance de 2"] = skipped.get("dimensions non puissance de 2", 0) + 1 continue classes = set() for ref in registry.get_referencers(a.package_name, opts) or []: for ra in registry.get_assets_by_package_name(ref): classes.add(str(ra.asset_class_path.asset_name)) if not (classes & MATERIAL_CLASSES): skipped["aucun materiau"] = skipped.get("aucun materiau", 0) + 1 continue if classes - MATERIAL_CLASSES: key = "reference aussi par " + ",".join(sorted(classes - MATERIAL_CLASSES)) skipped[key] = skipped.get(key, 0) + 1 continue # Cheveux et masques de transparence exclus : les mipmaps y amincissent les meches et les decoupes a distance. name = pkg.rsplit("/", 1)[1] if "/Hairs/" in pkg or any(t in name for t in ("TR", "Trs", "Trans", "CUT", "_DO", "Cap")): skipped["cheveux ou masque de transparence"] = skipped.get("cheveux ou masque de transparence", 0) + 1 continue candidates.append((pkg, mips, never, "x".join(dims))) out = os.path.join(unreal.Paths.project_saved_dir(), "Audit", "o4_candidats.txt") with open(out, "w", encoding="utf-8") as f: for c in candidates: f.write(";".join(c) + "\n") unreal.log_warning("FixTextureMips : {} candidate(s), ecartees {} -> {}".format(len(candidates), skipped, out)) if apply: errors = 0 for pkg, _, _, _ in candidates: tex = unreal.EditorAssetLibrary.load_asset(pkg) tex.set_editor_property("mip_gen_settings", unreal.TextureMipGenSettings.TMGS_FROM_TEXTURE_GROUP) tex.set_editor_property("never_stream", False) if tex.get_editor_property("mip_gen_settings") != unreal.TextureMipGenSettings.TMGS_FROM_TEXTURE_GROUP \ or tex.get_editor_property("never_stream"): errors += 1 unreal.log_error("FixTextureMips : echec sur " + pkg) continue if not unreal.EditorAssetLibrary.save_loaded_asset(tex, only_if_is_dirty=False): errors += 1 unreal.log_error("FixTextureMips : sauvegarde impossible " + pkg) unreal.log_warning("FixTextureMips : {} texture(s) modifiee(s), {} erreur(s)".format(len(candidates) - errors, errors))