fix BBod Shapekeys liboverride and copy values
This commit is contained in:
File diff suppressed because it is too large
Load Diff
+81
-6
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from ..utils import descendants
|
from ..utils import descendants, collection_containing_armature
|
||||||
|
|
||||||
|
|
||||||
def get_pair_manual(context):
|
def get_pair_manual(context):
|
||||||
@@ -151,13 +151,64 @@ def run_step_5(orig, rep, rep_descendants, orig_to_rep):
|
|||||||
m.object = rep
|
m.object = rep
|
||||||
|
|
||||||
|
|
||||||
|
def _base_body_name_match(ob):
|
||||||
|
"""True if object looks like the base body mesh (MESH, name has body+base)."""
|
||||||
|
if ob.type != "MESH":
|
||||||
|
return False
|
||||||
|
name_lower = (ob.name + " " + (ob.data.name if ob.data else "")).lower()
|
||||||
|
return "body" in name_lower and "base" in name_lower
|
||||||
|
|
||||||
|
|
||||||
|
def _objects_in_collection_recursive(coll):
|
||||||
|
"""Yield all objects in collection and nested collections."""
|
||||||
|
for ob in coll.objects:
|
||||||
|
yield ob
|
||||||
|
for child in coll.children:
|
||||||
|
yield from _objects_in_collection_recursive(child)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_base_body(armature, descendants_iter, rep_base_name=None):
|
||||||
|
"""Return the base body mesh: in descendants (armature mod), or in armature's collection(s), matched by name."""
|
||||||
|
def gather_candidates(ob_iter):
|
||||||
|
candidates = []
|
||||||
|
for ob in ob_iter:
|
||||||
|
if not _base_body_name_match(ob):
|
||||||
|
continue
|
||||||
|
if ob.modifiers:
|
||||||
|
for m in ob.modifiers:
|
||||||
|
if m.type == "ARMATURE" and m.object == armature:
|
||||||
|
return ob, candidates
|
||||||
|
candidates.append(ob)
|
||||||
|
return None, candidates
|
||||||
|
|
||||||
|
found, candidates = gather_candidates(descendants_iter)
|
||||||
|
if found:
|
||||||
|
return found
|
||||||
|
# Fallback: base body may be in same collection as armature but not parented to it (e.g. linked).
|
||||||
|
if not candidates:
|
||||||
|
for coll in [collection_containing_armature(armature)] + list(getattr(armature, "users_collection", []) or []):
|
||||||
|
if not coll:
|
||||||
|
continue
|
||||||
|
found, candidates = gather_candidates(_objects_in_collection_recursive(coll))
|
||||||
|
if found:
|
||||||
|
return found
|
||||||
|
if candidates:
|
||||||
|
break
|
||||||
|
if not candidates:
|
||||||
|
return None
|
||||||
|
if rep_base_name:
|
||||||
|
base = rep_base_name.rsplit(".", 1)[0] if "." in rep_base_name else rep_base_name
|
||||||
|
for ob in candidates:
|
||||||
|
if ob.name == base or ob.name.startswith(base + ".") or (ob.data and ob.data.name == base):
|
||||||
|
return ob
|
||||||
|
return candidates[0]
|
||||||
|
|
||||||
|
|
||||||
def run_step_6(orig, rep, rep_descendants, context=None):
|
def run_step_6(orig, rep, rep_descendants, context=None):
|
||||||
"""Replacement base body: library override (fully editable when context given), then shape-key action."""
|
"""Replacement base body: library override (fully editable when context given), copy shapekey values, then shape-key action."""
|
||||||
|
orig_descendants = list(descendants(orig))
|
||||||
for ob in list(rep_descendants):
|
for ob in list(rep_descendants):
|
||||||
if ob.type != "MESH":
|
if not _base_body_name_match(ob):
|
||||||
continue
|
|
||||||
name_lower = (ob.name + " " + (ob.data.name if ob.data else "")).lower()
|
|
||||||
if "body" not in name_lower or "base" not in name_lower:
|
|
||||||
continue
|
continue
|
||||||
if ob.modifiers:
|
if ob.modifiers:
|
||||||
for m in ob.modifiers:
|
for m in ob.modifiers:
|
||||||
@@ -165,6 +216,7 @@ def run_step_6(orig, rep, rep_descendants, context=None):
|
|||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
orig_base = _find_base_body(orig, orig_descendants, rep_base_name=ob.name)
|
||||||
# Debug: base body mesh state before override handling.
|
# Debug: base body mesh state before override handling.
|
||||||
_lib = getattr(ob.data, "library", None)
|
_lib = getattr(ob.data, "library", None)
|
||||||
_ol = getattr(ob.data, "override_library", None)
|
_ol = getattr(ob.data, "override_library", None)
|
||||||
@@ -211,6 +263,29 @@ def run_step_6(orig, rep, rep_descendants, context=None):
|
|||||||
_sys2 = getattr(_ol2, "is_system_override", None) if _ol2 else None
|
_sys2 = getattr(_ol2, "is_system_override", None) if _ol2 else None
|
||||||
print(f"[DLM step6] {ob.name} after: override={_ol2 is not None}, is_system_override={_sys2} (False=editable)")
|
print(f"[DLM step6] {ob.name} after: override={_ol2 is not None}, is_system_override={_sys2} (False=editable)")
|
||||||
if ob.data.shape_keys:
|
if ob.data.shape_keys:
|
||||||
|
# Ensure we can write shape key values: override the Key block if it is linked.
|
||||||
|
sk = ob.data.shape_keys
|
||||||
|
if getattr(sk, "library", None):
|
||||||
|
try:
|
||||||
|
sk.override_create(remap_local_usages=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[DLM step6] {ob.name} shape_keys.override_create: {e}")
|
||||||
|
# Copy shape key values from original base body to replacement (by matching key name).
|
||||||
|
if orig_base and orig_base.data.shape_keys:
|
||||||
|
rep_blocks = ob.data.shape_keys.key_blocks
|
||||||
|
orig_blocks = orig_base.data.shape_keys.key_blocks
|
||||||
|
n_copied = 0
|
||||||
|
for orig_key in orig_blocks:
|
||||||
|
rep_key = rep_blocks.get(orig_key.name)
|
||||||
|
if rep_key is not None:
|
||||||
|
rep_key.value = orig_key.value
|
||||||
|
n_copied += 1
|
||||||
|
print(f"[DLM step6] {ob.name} shapekey values: copied {n_copied}/{len(orig_blocks)} from {orig_base.name}")
|
||||||
|
else:
|
||||||
|
if not orig_base:
|
||||||
|
print(f"[DLM step6] {ob.name} no orig base body found for armature {orig.name}")
|
||||||
|
elif not orig_base.data.shape_keys:
|
||||||
|
print(f"[DLM step6] {ob.name} orig base body has no shape_keys")
|
||||||
if not ob.data.shape_keys.animation_data:
|
if not ob.data.shape_keys.animation_data:
|
||||||
ob.data.shape_keys.animation_data_create()
|
ob.data.shape_keys.animation_data_create()
|
||||||
body_name = ob.name
|
body_name = ob.name
|
||||||
|
|||||||
Reference in New Issue
Block a user