Imagine you would like to control pose morphs sequentially one by one. This python tag makes it easy to control your animation as it sequentially handles all pose strengths.
You need to add a percentage slider user-data to your root object. (Not on Python Tag).
Add this to your Python Tag:
Python
import c4d
def main():
# === Get the OBJECT that this Python tag is attached to ===
controller = op.GetObject()
if not controller:
print("Could not get the object this tag is attached to")
return
# === Read User Data ID 1 ===
raw_strength = None
try:
raw_strength = controller[c4d.ID_USERDATA, 1]
except Exception as e:
print("Failed to read User Data:", e)
return
if raw_strength is None:
return
# === Normalize strength intelligently ===
try:
rs = float(raw_strength)
except Exception as e:
return
if rs <= 1.0:
s = max(0.0, min(1.0, rs))
else:
s = max(0.0, min(1.0, rs / 100.0))
print(f"\n=== Strength: {s} ===")
# === Get Pose Morph Tag FROM CONTROLLER ===
pose_tag = None
for tag in controller.GetTags():
if tag.GetType() == c4d.Tposemorph:
pose_tag = tag
break
if not pose_tag:
return
# === Get all pose IDs dynamically ===
description = pose_tag.GetDescription(c4d.DESCFLAGS_DESC_0)
pose_ids = []
if description:
for bc, descid, groupid in description:
if len(descid) >= 2 and descid[0].id == 4000:
second_id = descid[1].id
if second_id >= 1101 and second_id % 100 == 1:
pose_ids.append((descid[0].id, descid[1].id))
name = bc.GetString(c4d.DESC_NAME)
print(f"Pose found: '{name}' ID: {(descid[0].id, descid[1].id)}")
num_poses = len(pose_ids)
if num_poses == 0:
print("No poses found!")
return
print(f"Total poses: {num_poses}")
# === Helper function ===
def map_range(val, start, end):
if val <= start: return 0.0
if val >= end: return 1.0
return (val - start) / (end - start)
# === Sequential (cascading/cumulative) blending ===
section = 1.0 / num_poses
pose_values = [0.0] * num_poses
print(f"Section size: {section}")
for i in range(num_poses):
start = i * section
end = (i + 1) * section
print(f"Pose {i}: range [{start:.3f} - {end:.3f}]", end="")
if s < start:
pose_values[i] = 0.0
print(f" -> 0.0 (not started)")
elif s >= end:
pose_values[i] = 1.0
print(f" -> 1.0 (complete)")
else:
pose_values[i] = map_range(s, start, end)
print(f" -> {pose_values[i]:.3f} (transitioning)")
# === Apply values ===
try:
pose_tag[c4d.ID_CA_POSE_TOTAL_STRENGTH] = 1.0
for i, pose_id in enumerate(pose_ids):
old_value = pose_tag[pose_id]
pose_tag[pose_id] = pose_values[i]
print(f"Set pose {i} from {old_value} to {pose_values[i]}")
pose_tag.Message(c4d.MSG_UPDATE)
c4d.EventAdd()
print("Successfully applied!\n")
except Exception as e:
print(f"Error: {e}")
import traceback
traceback.print_exc()