Clothes and hairs

This commit is contained in:
2026-05-30 20:04:07 +03:00
parent a553621c7f
commit 765dffbed0
14 changed files with 331 additions and 72 deletions
+86 -3
View File
@@ -355,10 +355,27 @@ for mapping in[CommandLineMapping()]:
for slot in obj.material_slots:
if slot.material:
mat = slot.material
# 3. Check if material already has the prefix
# 3. Normalize material name: strip Blender auto-suffixes
# (.001,.002 from name collisions, .### from dupes)
# before applying the armature prefix. This prevents
# duplicate .material files with unpredictable names
# (e.g. male_male-clothes-ed.001 vs male_male-clothes-ed)
# that cause submeshes to reference missing materials
# at runtime.
import re
clean = re.sub(r'\.\d{3}$', '', mat.name)
if clean != mat.name:
old = mat.name
mat.name = clean
# If Blender added .001 again because the clean
# name is already taken, keep the suffixed name.
print(f"Normalized material '{old}' -> '{mat.name}'"
f" on object '{name}'")
# 4. Check if material already has the prefix
if not mat.name.startswith(prefix):
mat.name = prefix + mat.name
print(f"Renamed material '{mat.name}' on object '{name}'")
print(f"Renamed material '{mat.name}'"
f" on object '{name}'")
# 3. Export custom properties to json
save_data = {}
for key in obj.keys():
@@ -446,15 +463,81 @@ for mapping in[CommandLineMapping()]:
armobj = bpy.data.objects.get(mapping.armature_name)
armobj.data.name = armobj.name
# ---- Fix: sync Image filepath to Image name ----
# Blender silently reuses existing Images when appending
# from libraries, so the Image's filepath may still point
# to the old texture even after the user renamed it.
# blender2ogre writes the filepath to .material files,
# so we must update filepath to match the Image name.
import re as _re
seen_imgs = set()
for name in obj_names:
obj = bpy.data.objects.get(name)
if obj and obj.type == 'MESH':
for slot in obj.material_slots:
if slot.material and slot.material.node_tree:
for node in slot.material.node_tree.nodes:
if node.type == 'TEX_IMAGE' and node.image:
img = node.image
if img.name not in seen_imgs:
seen_imgs.add(img.name)
# Strip Blender auto-suffix (.NNN)
clean = _re.sub(
r'\.\d{3}$', '', img.name)
# Extract just the filename from
# the current filepath
old_name = os.path.basename(
img.filepath)
if old_name != clean and clean:
# Rebuild filepath with new
# filename
dirpart = os.path.dirname(
img.filepath)
new_path = os.path.join(
dirpart, clean)
print(f" Updating Image "
f"'{img.name}': "
f"filepath "
f"'{old_name}' -> "
f"'{clean}'")
img.filepath = new_path
# ---------------------------------------------------
bpy.ops.ogre.export(filepath=mapping.gltf_path.replace(".glb", ".scene"), EX_SELECTED_ONLY=False, EX_SHARED_ARMATURE=True, EX_LOD_GENERATION='0', EX_LOD_DISTANCE=20, EX_LOD_LEVELS=4, EX_GENERATE_TANGENTS='4')
ogre_export_dir = os.path.dirname(mapping.gltf_path.replace(".glb", ".scene"))
# Fix alpha_rejection values in ALL generated .material files.
# blender2ogre 0.9.0 writes float values (e.g. "127.5") for
# alpha_rejection thresholds, but OGRE 14 expects an integer
# in the range 0-255. Float values are truncated to integer
# during material compilation, causing 127.5 -> 127 when 128
# was intended. This makes submeshes with alpha < 128 in the
# texture atlas completely invisible.
import glob as _glob
_mat_files = _glob.glob(os.path.join(ogre_export_dir, "*.material"))
for _mf in _mat_files:
with open(_mf, 'r') as _f:
_content = _f.read()
if 'alpha_rejection' in _content:
import re as _re
_new = _re.sub(
r'alpha_rejection (\S+) (\d+\.?\d*)',
lambda m: 'alpha_rejection ' + m.group(1) +
' ' + str(int(float(m.group(2)))),
_content)
if _new != _content:
with open(_mf, 'w') as _f:
_f.write(_new)
print(f" Fixed alpha_rejection in {_mf}")
# Post-process exported OGRE meshes to fix normal/tangent seams between
# body parts. Even with identical custom normals in Blender, the OGRE
# exporter's calc_tangents() produces slightly different tangents for
# matching vertices because BodyTop and BodyBottom have different face
# topologies. This causes a visible lighting seam with normal mapping,
# especially when shape keys (like "fat") are applied.
ogre_export_dir = os.path.dirname(mapping.gltf_path.replace(".glb", ".scene"))
fix_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fix_ogre_mesh_seams.py")
if os.path.exists(fix_script):
print(f"\nPost-processing OGRE meshes in {ogre_export_dir}...")