LifePlay-Revival/Tools/HairMaterials.py
2026-10-02 19:02:33 +02:00

88 lines
4.9 KiB
Python

# Protocole de conversion d'une coiffure (Docs/Migration/13_Protocole_Coiffure.md), etape 4 : textures et materiaux.
#
# Importe les textures de la coiffure, cree deux materiaux enfants de /Game/Heavy/Daz/Bridget/Hairs/DazHair (le
# materiau des coiffures Daz : parametres HairColor et HairThickness pilotes par le jeu) et les affecte aux
# emplacements du SkeletalMesh produit par LPHairFromStaticMesh :
# <Nom>_Cap : emplacements listes dans cap= (calotte) ; opacite cap_opacity= ou "white" (calotte opaque)
# <Nom>_Strands : tous les autres emplacements (meches) ; opacite strands_opacity=
# Controle final : dependances du SkeletalMesh (squelette et ces deux materiaux seulement).
#
# Usage :
# UnrealEditor-Cmd.exe <projet> -run=pythonscript "-script=<projet>/Tools/HairMaterials.py mesh=/Game/Heavy/New5/Hairs/Nom
# diffuse=<couleur.png> strands_opacity=<masque.jpg> cap_opacity=white cap=Hair_Base [thicken=1]" -unattended -nopause -nosplash
# Les fichiers de textures sont des chemins sur disque ; les textures sont creees a cote du SkeletalMesh.
# Sortie : lignes "HAIRMAT" du journal.
import os
import sys
import unreal
eal = unreal.EditorAssetLibrary
mel = unreal.MaterialEditingLibrary
tools = unreal.AssetToolsHelpers.get_asset_tools()
args = dict(a.split("=", 1) for a in sys.argv[1:] if "=" in a)
def import_texture(file, folder, name):
task = unreal.AssetImportTask()
task.filename = file.replace("\\", "/")
task.destination_path = folder
task.destination_name = name
task.automated = True
task.replace_existing = True
task.save = True
tools.import_asset_tasks([task])
return unreal.load_asset(folder + "/" + name)
def make_mic(folder, name, parent, diffuse, opacity, thicken):
path = folder + "/" + name
mic = unreal.load_asset(path) if eal.does_asset_exist(path) else tools.create_asset(
name, folder, unreal.MaterialInstanceConstant, unreal.MaterialInstanceConstantFactoryNew())
mel.set_material_instance_parent(mic, parent)
mel.set_material_instance_texture_parameter_value(mic, "MapDiffuse", diffuse)
mel.set_material_instance_texture_parameter_value(mic, "MapOpacity", opacity)
mel.set_material_instance_scalar_parameter_value(mic, "Thicken", thicken)
mel.update_material_instance(mic)
eal.save_loaded_asset(mic, only_if_is_dirty=False)
return mic
mesh_path = args.get("mesh")
if not mesh_path or not args.get("diffuse") or not args.get("strands_opacity"):
unreal.log_error("HAIRMAT usage : mesh=/Game/... diffuse=<fichier> strands_opacity=<fichier> [cap_opacity=<fichier>|white] [cap=Slot1,Slot2] [thicken=1]")
else:
folder, name = mesh_path.rsplit("/", 1)
thicken = float(args.get("thicken", "1"))
cap_slots = [s for s in args.get("cap", "").split(",") if s]
parent = unreal.load_asset("/Game/Heavy/Daz/Bridget/Hairs/DazHair")
diffuse = import_texture(args["diffuse"], folder, name + "_Diffuse")
strands_opacity = import_texture(args["strands_opacity"], folder, name + "_StrandsOpacity")
strands = make_mic(folder, name + "_Strands", parent, diffuse, strands_opacity, thicken)
# Calotte : seulement si un emplacement lui est attribue (Pocolov 11 : emplacement unique, pas de calotte).
cap = None
if cap_slots:
cap_arg = args.get("cap_opacity", "white")
cap_opacity = unreal.load_asset("/Engine/EngineResources/WhiteSquareTexture") if cap_arg == "white" else import_texture(cap_arg, folder, name + "_CapOpacity")
cap = make_mic(folder, name + "_Cap", parent, diffuse, cap_opacity, 1.0)
# Affectation : modifier les elements puis reaffecter le tableau entier et sauvegarder sans condition
# (une affectation Python ne marque pas l'asset modifie).
mesh = unreal.load_asset(mesh_path)
materials = []
used = set()
for slot in mesh.get_editor_property("materials"):
slot_name = str(slot.get_editor_property("material_slot_name"))
slot.set_editor_property("material_interface", cap if slot_name in cap_slots else strands)
materials.append(slot)
used.add(folder + "/" + (cap if slot_name in cap_slots else strands).get_name())
unreal.log_warning("HAIRMAT emplacement %s -> %s" % (slot_name, (cap if slot_name in cap_slots else strands).get_name()))
mesh.set_editor_property("materials", materials)
eal.save_loaded_asset(mesh, only_if_is_dirty=False)
registry = unreal.AssetRegistryHelpers.get_asset_registry()
registry.scan_modified_asset_files([unreal.Paths.convert_relative_path_to_full(unreal.Paths.project_content_dir()) + mesh_path[len("/Game/"):] + ".uasset"])
options = unreal.AssetRegistryDependencyOptions(include_soft_package_references=True, include_hard_package_references=True)
deps = [str(d) for d in registry.get_dependencies(mesh_path, options) if not str(d).startswith("/Script/")]
expected = {mesh_path + "_Skeleton"} | used
unreal.log_warning("HAIRMAT dependances de %s : %s -> %s" % (name, deps, "OK" if set(deps) == expected else "A VERIFIER"))