2025-12-01

This commit is contained in:
2026-03-17 14:58:51 -06:00
parent 183e865f8b
commit 4b82b57113
6846 changed files with 954887 additions and 162606 deletions
@@ -1573,7 +1573,8 @@ class PasteMatrix(bpy.types.Operator):
if bone.id_data.name in objs_matrix:
if bone.name in objs_matrix[bone.id_data.name]:
matrix_copied = objs_matrix[bone.id_data.name][bone.name]
matrix_copied = obj.matrix_world.inverted() @ matrix_copied
#Store the matrices for each bone that will use it
matrix_copied = reverse_childof_constraint(bone, matrix_copied, constrained)
@@ -1662,11 +1663,11 @@ class CopyRelativeMatrix(bpy.types.Operator):
#create a dictionary for all the realtive distance of the bones and objects
objs_matrix_dist = dict()
#get the source bofne or object
#get the source bone or object
if context.active_pose_bone:
source_active = context.active_pose_bone
source_rig_name = source_active.id_data.name
source_matrix = source_active.matrix
source_matrix = source_active.matrix
else:
source_active = context.active_object
source_matrix = source_active.matrix_world
@@ -1681,8 +1682,14 @@ class CopyRelativeMatrix(bpy.types.Operator):
continue
if bone_relative == source_active:
continue
matrix_dist = source_matrix.inverted() @ obj.matrix_world @ bone_relative.matrix# @ obj.matrix_world
#Adding the offset from the armature transform both for the active and relative
rig_offset = obj.matrix_world
if source_active.id_data.type == 'ARMATURE':
rig_offset = source_active.id_data.matrix_world.inverted() @ rig_offset
matrix_dist = source_matrix.inverted() @ rig_offset @ bone_relative.matrix
#store each bone matrix distance in a dictionary
if obj.name in objs_matrix_dist:
objs_matrix_dist[obj.name].update({bone_relative.name : matrix_dist})
@@ -1735,41 +1742,59 @@ def reverse_childof_constraint(source, matrix_source, constrained = set()):
offsets_lerp = []
offset_inv = Matrix.Identity(4)
offset_inv_lerp = Matrix.Identity(4)
#If the source is a bone then get the Armature matrix to add to the calculation
if type(source) == bpy.types.PoseBone:
obj_offset = obj.matrix_world
else:
obj_offset = Matrix.Identity(4)
#iterate and store all the inverted offsets of all the child constraints
for con in source.constraints:
if con.mute or not con.influence:
continue
if hasattr(con, 'target') and con.target is None:
continue
if con.type != 'CHILD_OF':
constrained.add(source)
continue
parent_matrix = con.target.matrix_world
if con.subtarget != '':
if con.subtarget == '':
parent_matrix = obj_offset.inverted() @ con.target.matrix_world
#remove obj.matrix_world when connected to an object
offset = parent_matrix @ con.inverse_matrix - Matrix.Identity(4)
#offset for the scale with influence already included
offset_lerp = Matrix.Identity(4).lerp(parent_matrix @ con.inverse_matrix, con.influence)
else:
parent_matrix = con.target.pose.bones[con.subtarget].matrix
offsets.append(Matrix.Identity(4) + con.influence * (parent_matrix @ con.inverse_matrix - Matrix.Identity(4)))
offsets_lerp.append(Matrix.Identity(4).lerp(parent_matrix @ con.inverse_matrix, con.influence))
if con.target != obj:
parent_matrix = obj_offset.inverted() @ con.target.matrix_world @ parent_matrix
#Include armature object matrix
offset = parent_matrix @ con.inverse_matrix - Matrix.Identity(4)
offset_lerp = Matrix.Identity(4).lerp(parent_matrix @ con.inverse_matrix, con.influence)
#Adding the influence to the offset
offset = Matrix.Identity(4) + con.influence * offset
offset_inv = offset_inv @ offset.inverted()
offset_inv_lerp = offset_inv_lerp @ offset_lerp.inverted()
offsets.append(offset)
if not offsets:
return matrix_source #@ obj.matrix_world.inverted()
return matrix_source
#Multiply all the child constraint inverted offsets
for offset, offsets_lerp in zip(offsets, offsets_lerp):
#offset_inv = offset_inv @ parent_offset_inv
offset_inv = offset_inv @ offset.inverted()
offset_inv_lerp = offset_inv_lerp @ offsets_lerp.inverted()
# add object space if it's a bone
if source != obj:
offset_inv = offset_inv #@ obj.matrix_world.inverted()
#final Matrix values
matrix_basis = offset_inv @ matrix_source
matrix_lerp = offset_inv_lerp @ matrix_source
matrix_lerp = offset_inv_lerp @ matrix_source
loc, rot, scale = matrix_basis.decompose()
loc_lerp, rot_lerp, scale_lerp = matrix_lerp.decompose()
matrix_basis = Matrix.LocRotScale(loc, rot_lerp, scale_lerp)
return matrix_basis
return matrix_basis
def reorder_bones_matrices(bones_matrices, constrained):
#Reordering the bones, so that we apply first the matrix offset to the constrained bones
@@ -1837,9 +1862,11 @@ class PasteRelativeMatrix(bpy.types.Operator):
if 'source_rig_name' in globals():
if source_rig_name in bpy.data.objects:
source_rig = bpy.data.objects[source_rig_name]
source_obj = source_rig
source_bone = source_rig.pose.bones[source_active_name]
#Get the current matrix of the source bone
matrix_source = source_bone.matrix
elif 'source_active_name' in globals():
if source_active_name in bpy.data.objects:
source_obj = bpy.data.objects[source_active_name]
@@ -1854,10 +1881,14 @@ class PasteRelativeMatrix(bpy.types.Operator):
#if the source object was in object mode during copy and now it's pose mode then quit
frame_range, inbetweens = get_frame_range(context, obj)
fcu_inbetweens = dict()
for frame in sorted(frame_range+inbetweens):
scene.frame_set(int(frame))
if obj.mode == 'POSE':
for bone in context.selected_pose_bones:
if bone.id_data != obj:
continue
#check that the selected bone is not the source bone
if bone == source_bone:
continue
@@ -1868,14 +1899,18 @@ class PasteRelativeMatrix(bpy.types.Operator):
if bone.name in objs_matrix_dist[bone.id_data.name]:
bone_matrix_dist = objs_matrix_dist[bone.id_data.name][bone.name]
matrix_new = matrix_source @ bone_matrix_dist
#Adding the offset from the armature transform both for the active and relative
#If it's the same Armature it will cancel each other
rig_offset = obj.matrix_world.inverted()
if source_rig:
rig_offset = rig_offset @ source_rig.matrix_world
matrix_new = rig_offset @ matrix_source @ bone_matrix_dist
#Store the matrices for each bone that will use it
matrix_new = reverse_childof_constraint(bone, matrix_new, constrained)
bones_matrices.update({bone : matrix_new})
matrix_copied = reverse_childof_constraint(bone, matrix_new, constrained)
# if bone not in constrained:
# matrix_copied = filter_matrix_properties(context, bone.matrix, matrix_copied)
#Reordering the bones, so that we apply first the matrix offset to the constrained bones
bones_matrices = reorder_bones_matrices(bones_matrices, constrained)
@@ -1896,16 +1931,16 @@ class PasteRelativeMatrix(bpy.types.Operator):
else:
obj_matrix_dist = matrix_dist
matrix_new = matrix_source @ obj_matrix_dist
matrix_copied = reverse_childof_constraint(target, matrix_new)
matrix_new = matrix_source @ obj_matrix_dist
matrix_new = reverse_childof_constraint(target, matrix_new)
if target not in constrained:
matrix_copied = filter_matrix_properties(context, target.matrix_world, matrix_copied)
target.matrix_world = matrix_copied
matrix_new = filter_matrix_properties(context, target.matrix_world, matrix_new)
target.matrix_world = matrix_new
if target in constrained:
context.view_layer.update()
matrix_copied = reverse_constraint_offset(target.matrix_world, matrix_copied)
target.matrix_world = filter_matrix_properties(context, target.matrix_world, matrix_copied)
matrix_new = reverse_constraint_offset(target.matrix_world, matrix_new)
target.matrix_world = filter_matrix_properties(context, target.matrix_world, matrix_new)
paste_keyframes_get_inbetweens(scene, target, inbetweens, frame, frame_range, fcu_inbetweens)