disable (currently unused) addons, update

This commit is contained in:
Nathan
2026-07-16 12:41:53 -06:00
parent e3310263f3
commit 0f26db3345
76 changed files with 19896 additions and 6197 deletions
+156 -96
View File
@@ -71,7 +71,6 @@ def draw_wgt(scale, bone, shape = 'sphere'):
shape = shape.lower()
mesh.from_pydata(np.array(shapes[shape]['vertices'])*scale , shapes[shape]['edges'], shapes[shape]['faces'])
# print('draw shape scale ', scale)
shape_obj['WGT_TempCtrl'] = True
return shape_obj
@@ -205,27 +204,28 @@ def tempctrl_shape_type(self, context):
ctrl.custom_shape_translation = (0, 0, 0)
ctrl.custom_shape_rotation_euler = (0, 0, 0)
continue
if org_bone.custom_shape_transform is not None and ctrl.custom_shape_transform is None:
if org_bone.custom_shape_transform is not None:# and ctrl.custom_shape_transform is None:
#check if the transform bone shape already exists
transform_bonename = org_bone.custom_shape_transform.name
if transform_bonename in ctrl.id_data.pose.bones:
# If it already exists then find it
ctrl.custom_shape_transform = ctrl.id_data.pose.bones[transform_bonename]
continue
#add an extra transform bone, if it doesnt exist
else:
#add an extra transform bone, if it doesnt exist
bpy.ops.object.mode_set(mode = 'EDIT')
boneshape = add_ctrl_bone(rig, org_bone.custom_shape_transform, rig.data.edit_bones[ctrl.name].parent, '')
transform_bonename = boneshape.name
add_bone_to_collection(rig, boneshape)
bpy.ops.object.mode_set(mode = 'POSE')
rig = ctrl.id_data
bpy.ops.object.mode_set(mode = 'EDIT')
boneshape = add_ctrl_bone(rig, org_bone.custom_shape_transform, rig.data.edit_bones[ctrl.name].parent, '')
bone_name = boneshape.name
add_bone_to_collection(rig, boneshape)
bpy.ops.object.mode_set(mode = 'POSE')
posebone = rig.pose.bones[bone_name]
posebone = rig.pose.bones[transform_bonename]
constraint_add(posebone, org_bone.custom_shape_transform, 'COPY_TRANSFORMS')
ctrl.custom_shape_transform = posebone
else:
# scale = (length_avg / ctrl.length)*0.4 + 0.4
scale = 1
# print('drawing shape in scale of ', scale)
ctrl.custom_shape = draw_wgt(scale, ctrl, shape = self.shape_type)
ctrl.custom_shape_scale_xyz = tuple([self.shape_size]*3)
ctrl.custom_shape_transform = None
@@ -1098,8 +1098,13 @@ class smartfcu:
self.all_frames = self.frames
self.inbetweens = []
#give only linear interpolation to all the keyframes
self.interpolations = {frame : 'LINEAR' for frame in self.frames}
# Use defaults
interpolation = bpy.context.preferences.edit.keyframe_new_interpolation_type
handle_type = bpy.context.preferences.edit.keyframe_new_handle_type
self.interpolations = {frame : interpolation for frame in self.frames}
self.handle_left_types = self.handle_right_types = {frame : handle_type for frame in self.frames}
def copy(self, smartfcurve, copy_fcurves = True):
'''Copying the smartfcurve attribute from another one'''
self.posebone = smartfcurve.posebone
@@ -1385,12 +1390,8 @@ def find_smartfcus_to_copy(smartfcurve, smartfcus):
if smartfcurve.frames:
return
def get_bone_layers_actions(bone, actions):
def get_obj_layered_actions(obj, actions):
'''get the actions from all layers'''
if not bpy.context.scene.btc.bake_layers:
return actions
obj = bone.id_data
if not obj.animation_data:
return actions
if not obj.animation_data.use_nla:
@@ -1406,6 +1407,16 @@ def get_bone_layers_actions(bone, actions):
actions.add(strip.action)
return actions
def get_bone_layers_actions(bone, actions):
'''get the actions from all layers during bake'''
if not bpy.context.scene.btc.bake_layers:
return actions
obj = bone.id_data
actions = get_obj_layered_actions(obj, actions)
return actions
def smartbake_to_ik(context, posebones, chain, sb):
@@ -1466,6 +1477,11 @@ def smartbake_to_ik(context, posebones, chain, sb):
#create the fcurves and add them to smartfcurves
for ctrl in ctrls:
if ctrl == chain.ik_tip and ctrl != chain.ik_ctrl:
continue
# if chain.pole_bone and ctrl == chain.base_bone:
# continue
ctrl_action = ctrl.id_data.animation_data.action
path = ctrl.path_from_id()
rot = Tools.rot_mode_to_channel(ctrl.rotation_mode)
@@ -1523,40 +1539,57 @@ def deselect_all_fcurves(fcurves):
fcurves.foreach_set('hide', array_true)
fcurves.foreach_set('select', array_false)
def get_enabled_keyframes(ctrl_rig, action_frames_remove):
def get_enabled_keyframes(ctrl_rig, smartframes):
'''Get all the frames where Temp Ctrls are turned off'''
'''Need to iterate over all layers of the ctrl rig'''
if not ctrl_rig:
return
action = ctrl_rig.animation_data.action
if action in action_frames_remove:
return action_frames_remove[action]
fcurves = Tools.get_fcurves(ctrl_rig, action)
enable_fcu = fcurves.find('animtoolbox.ctrls_enabled')
# if action in action_frames_remove:
# return action_frames_remove[action]
actions = set()
enable_fcu = None
get_obj_layered_actions(ctrl_rig, actions)
# Check for the enabled fcu in all layers of the ctrl rig
for action in actions:
fcurves = Tools.get_fcurves(ctrl_rig, action)
enable_fcu = fcurves.find('animtoolbox.ctrls_enabled')
if enable_fcu:
break
if not enable_fcu:
return None
action_frame_range = action.frame_range
frames_remove = []
# action_frame_range = action.frame_range
frames_enabled = []
keyframes = np.zeros(len(enable_fcu.keyframe_points)*2)
enable_fcu.keyframe_points.foreach_get('co', keyframes)
frames = keyframes[::2]
values = keyframes[1::2]
if values[0] == 0:
frames_remove += list(range(round(action_frame_range[0]), round(frames[0])))
for i in range(1, len(frames)):
if values[i-1] == 0 and values[i] == 1:
frames_remove += list(range(round(frames[i-1]), round(frames[i])))
if values[-1] == 0:
frames_remove += list(range(round(frames[-1]), round(action_frame_range[1])))
# Getting all the frames where it's turned on and off
frames_on = frames[values == 1]
frames_off = frames[values == 0]
# Getting the ranges from when it's turned on until it's off
for frame in frames_on:
if frame in frames_enabled:
continue
if len(frames_off[frame < frames_off]):
next_off = min(frames_off[frame < frames_off])
if next_off:
frames_enabled += list(range(int(frame), int(next_off)))
# if the last keyframe is turned on then get the frames until the rest of the range
if max(smartframes) > max(frames_on) > max(frames_off):
frames_enabled += list(range(int(max(frames_on)), int(max(smartframes))))
action_frames_remove.update({action : frames_remove})
# action_frames_remove.update({action : frames_remove})
return frames_remove
return frames_enabled
def replace_rot_mode(origin_data_path, posebone):
@@ -1904,7 +1937,7 @@ def smartbake_write_keyframes(scene, smartframes, smartfcus, chain = None, bake_
#Store the influence and set them to 0 before calculating the matrix without the constraint (to get the offset)
con_influence = get_con_influence(constrained)
if chain:
if chain and chain.pole_bone is not None:
# Adding the pole bone to the end of the list
bones_matrices.update({chain.pole_bone : None})
bones_matrices[chain.pole_bone] = bones_matrices.pop(chain.pole_bone)
@@ -1924,11 +1957,22 @@ def smartbake_write_keyframes(scene, smartframes, smartfcus, chain = None, bake_
else:
# Get the rest of the bones to check if they are children and if we need viewlayer update
bones = set(bones_matrices.keys()).difference(pasted_bones)
# Calculating pole target matrix after other bones were calcluated
if chain and bone == chain.pole_bone:
bpy.context.view_layer.update()
matrix = find_pole_vector(chain.base_bone, chain.ik_tip, chain.pole_bone, chain.step)
base_bone = chain.base_bone
ik_tip = chain.ik_tip
angle = chain.base_bone.vector.angle(chain.ik_tip.vector)
if not round(angle):
# continue
# If the angle is flat then use the position of the pole relative to the rest position base bone
relative_matrix = base_bone.bone.matrix_local.inverted() @ chain.pole_bone.bone.matrix_local
matrix = base_bone.matrix @ relative_matrix
else:
bpy.context.view_layer.update()
matrix = find_pole_vector(base_bone, ik_tip, chain.pole_bone, chain.step)
Tools.paste_bone_matrix(bone, matrix, constrained, bones, x_filter = False)
pasted_bones.add(bone)
@@ -1937,10 +1981,11 @@ def smartbake_write_keyframes(scene, smartframes, smartfcus, chain = None, bake_
Tools.compatible_rotation(bone, bones_prevrot)
#Add keyframes to all the fcurves of the bone
for fcu in bone_fcus[bone]:
groupname = fcu.group.name if fcu.group else ""
obj.keyframe_insert(fcu.data_path, index = fcu.array_index , frame = frame, group = groupname)
#Turn the influence of the constraints back on
if con_influence:
for con, influence in con_influence.items():
@@ -1977,6 +2022,7 @@ def smartbake_write_keyframes(scene, smartframes, smartfcus, chain = None, bake_
key.interpolation = smartfcurve.interpolations[frame]
if key.interpolation != 'BEZIER':
continue
key.handle_left_type = smartfcurve.handle_left_types[frame]
key.handle_right_type = smartfcurve.handle_right_types[frame]
@@ -1985,6 +2031,7 @@ def smartbake_write_keyframes(scene, smartframes, smartfcus, chain = None, bake_
# print('writing keyframes time 0.7.7', time.time() - starttime)
def add_interpolations(smartfcus):
#turn inbetween keyframes values to handles
for smartfcurve in smartfcus.values():
fcu = smartfcurve.fcu
@@ -2187,7 +2234,8 @@ def smartbake(context, org_action, posebones, ids):
frame_current = scene.frame_current
smartfcus = dict()
smartframes = set()
action_frames_remove = dict()
ctrl_rig = None
#Use this to check if an fcurve exist also in the original action (and not just on a layer)
org_action_fcus = set()
transformations = ["rotation_quaternion","rotation_euler", "rotation_axis_angle", "location", "scale"]
@@ -2202,10 +2250,13 @@ def smartbake(context, org_action, posebones, ids):
# find_fcu = False
path = posebone.path_from_id()
# Find the Ctrl Rig
if 'EMPTY' in posebone.btc.setup:
ctrl_rig = find_empty_ctrl(context, posebone)
else:
ctrl_rig = posebone.id_data.animtoolbox.controller
if not ctrl_rig:
ctrl_rig = next((item.controller for item in scene.btc.ctrl_items if item.controlled == posebone.id_data), None)
actions = {org_action}
get_bone_layers_actions(posebone, actions)
@@ -2249,8 +2300,8 @@ def smartbake(context, org_action, posebones, ids):
if ctrl_rig is None:
continue
frames_remove = get_enabled_keyframes(ctrl_rig, action_frames_remove)
# frames_remove = get_enabled_keyframes(ctrl_rig, action_frames_remove)
#Getting the Fcurve container, either action or channelbag
channelbag = Tools.get_channelbag(posebone.id_data, org_action)
if not channelbag:
@@ -2311,6 +2362,7 @@ def smartbake(context, org_action, posebones, ids):
else:
#Add the fcurve if it's in the ctrl but not in the original action
fcu = smartbake_add_fcurve(channelbag, origin_data_path, ctrl_fcu.array_index, posebone.name)
smartfcurve = get_smartfcurve(ctrl_fcu, smartfcus, posebone, origin_data_path, ctrl_fcu.array_index, scene.btc.smartbake)
if smartfcurve : smartfcurve.fcu = fcu
@@ -2325,22 +2377,26 @@ def smartbake(context, org_action, posebones, ids):
for mod in ctrl_fcu.modifiers:
smartfcurve.modifiers.append(mod)
#Remove frames to not include in the bake, in case of custom frame range
if frames_remove and smartfcurve:
smartframes = {frame for frame in smartframes if round(frame) not in frames_remove}
smartfcurve.frames = [frame for frame in smartfcurve.frames if round(frame) not in frames_remove]
smartfcurve.interpolations = {frame : interpolation for frame, interpolation in smartfcurve.interpolations.items() if round(frame) not in frames_remove}
#need to add the fcurves
add_missing_fcurves(org_action, posebone, smartfcus)
# print('frames_remove ', frames_remove)
smartframes = get_smartframes(scene, smartfcus)
frames_enabled = get_enabled_keyframes(ctrl_rig, smartframes)
# smartframes = smartframes - set(frames_remove)
# print('smartframes', smartframes)
if frames_enabled:
# Iterating instead of sets in case of sub-frames
smartframes = {frame for frame in smartframes if round(frame) in frames_enabled}
smartframes = sorted(smartframes)
#write all the keyframes
smartbake_write_keyframes(scene, smartframes, smartfcus, posebones = posebones)
add_interpolations(smartfcus)
btc = scene.btc
if btc.bake_range_type == 'KEYFRAMES' and btc.smartbake:
add_interpolations(smartfcus)
scene.frame_set(frame_current)
@@ -3442,16 +3498,12 @@ def child_prop_edit(self):
child_names = remove_child_ctrls(rig, child_names)
return child_ctrls
# org_obj = rig.animtoolbox.controlled
# print('org obj ', org_obj)
#Add child ctrls
child_names = []
for ctrl_posebone in ctrls:
ctrl = rig.data.edit_bones[ctrl_posebone.name]
child_ctrl = add_ctrl_bone(rig, ctrl, ctrl, 'Child_', 0.5, orient_world = self.orientation)
# child_ctrl.matrix = ctrl.matrix
# child_ctrl.length = ctrl.length * 0.5
# bpy.context.view_layer.update()
child_ctrls.append(child_ctrl)
add_bone_to_collection(rig, child_ctrl, col_name = 'Child Ctrls', visible = True)
child_names.append(child_ctrl.name)
@@ -4134,7 +4186,7 @@ def assign_setup_ids(self, context, ctrls, selected, child_ctrls, setup, setup_i
#Assign group, color, matrix and setup ids in pose mode
for ctrl, bone in zip(ctrls, selected):
ctrl.matrix = get_relative_ws_matrix(bone, ctrl)
#assign the controller to a group
if bpy.app.version < (4, 0, 0):
ctrl.bone_group = ctrl_group
@@ -4176,6 +4228,7 @@ def assign_setup_ids(self, context, ctrls, selected, child_ctrls, setup, setup_i
#get custom shape and assign the matrix
if bone.custom_shape_transform and self.shape_type == 'ORIGINAL':
obj_mat = bone.id_data.matrix_world
ot_bone = bone.custom_shape_transform.name
#Get the original override transform bone
target = bone.id_data.pose.bones[ot_bone]
@@ -5310,14 +5363,16 @@ def pole_prop_edit(self, context):
else:
add_bone_to_collection(rig, rig.data.edit_bones[chain.base_bone.name], col_name = 'IK Ctrls', visible = True)
#remove the pole bone and switch to base bone
if not hasattr(chain, 'pole_bone'):
if chain.pole_bone is None:
continue
rig.data.edit_bones.remove(rig.data.edit_bones[chain.pole_bone_name])
#remove from ctrls and append base bone instead
if chain.pole_bone in ctrls:
ctrls.remove(chain.pole_bone)
ctrls.append(chain.base_bone)
del chain.pole_bone, chain.pole_bone_name
chain.pole_bone = chain.pole_bone_name = None
# del chain.pole_bone, chain.pole_bone_name
#Remove child ctrls
if btc.child:
@@ -5330,13 +5385,17 @@ def pole_prop_pose(self, context):
if not btc.pole_target:
chain.base_bone.btc.org = 'CTRL'
if not hasattr(chain, 'pole_bone'):
continue
del chain.pole_bone
if hasattr(chain,'pole_bone_name'):
chain.pole_bone_name
continue
# if not hasattr(chain, 'pole_bone'):
# continue
if not chain.pole_bone:
continue
if not chain.pole_bone_name:
continue
chain.pole_bone = chain.pole_bone_name = None
# del chain.pole_bone
# if hasattr(chain,'pole_bone_name'):
# chain.pole_bone_name
# continue
pole_posebone_update(chain, ctrls)
if chain.base_bone in ctrls:
@@ -5413,7 +5472,9 @@ def ik_ctrl_orientation(self, context):
def pole_posebone_update(chain, ctrls):
'''update pole bone properties in the pole prop and add ik prop'''
if not hasattr(chain, 'pole_bone_name'):
# if not hasattr(chain, 'pole_bone_name'):
# return
if not chain.pole_bone_name:
return
chain.pole_bone = rig.pose.bones[chain.pole_bone_name]
@@ -5447,6 +5508,8 @@ def update_axis_prop(self, context):
if not hasattr(chain, 'pole_bone_name'):
continue
if not chain.pole_bone_name:
continue
pole_matrix = find_pole_vector(base_bone, ik_tip, ik_tip, chain.step)
#pole matrix orientation to world by default
@@ -5551,15 +5614,6 @@ def add_pole_bone(self, context, rig, chain):
new_rot = mathutils.Euler((0, 0, 0), 'XYZ')
pole_matrix = Matrix.LocRotScale(loc, new_rot, scale)
#In case of a flat IK skip adding a pole bone and use base bone instead
# if pole_matrix.translation == chain.ik_tip.matrix.translation:
# print('no pole bone')
# self.report({'ERROR'}, "Can't add Pole Ctrl because of a flat IK chain")
# chain.pole_bone = None
# add_bone_to_collection(rig, chain.base_bone, col_name = 'IK Ctrls', visible = True)
# btc['pole_target'] = False
# return
pole_bone_name = chain.org_bones[-2].name + '_Pole' if len(chain.org_bones) > 1 else chain.org_bones[0].name + '_Pole'
chain.pole_bone = rig.data.edit_bones.new(pole_bone_name)
@@ -5582,7 +5636,9 @@ def pole_offset(self, context):
global ik_chains, ctrls, child_names
for chain in ik_chains:
if not hasattr(chain, 'pole_bone_name'):
# if not hasattr(chain, 'pole_bone_name'):
# continue
if not chain.pole_bone_name:
continue
chain.pole_bone = rig.pose.bones[chain.pole_bone_name]
@@ -5621,7 +5677,7 @@ def add_ik_prop_edit(self, context):
chain.ik_tip_name = chain.ik_tip.name
#remove the pole bone
if btc.pole_target and hasattr(chain, 'pole_bone_name'):
if btc.pole_target and chain.pole_bone_name:
#removing and adding the pole_target without calling the whole pole prop update
ctrls.remove(chain.pole_bone)
rig.data.edit_bones.remove(rig.data.edit_bones[chain.pole_bone_name])
@@ -5654,7 +5710,7 @@ def add_ik_prop_pose(self, context):
chain.ik_ctrl.btc.org = 'CTRL'
chain.ik_ctrl.color.palette = context.scene.btc.color_set
if btc.pole_target and hasattr(chain, 'pole_bone_name'):
if btc.pole_target and chain.pole_bone_name: #hasattr(chain, 'pole_bone_name'):
pole_posebone_update(chain, ctrls)
add_bone_to_collection(rig, chain.ik_ctrl, col_name = 'IK Ctrls', visible = True)
@@ -5782,7 +5838,7 @@ class TempIK(bpy.types.Operator):
# for ctrl in ctrls:
# add_bone_to_collection(rig, ctrl, col_name = 'ORG', visible = True)
chain = IK_Chain(hierarchy, ctrls, root_ctrl)
#if only one bone is selected in the chain then add an extra control automatically
if len(hierarchy) == 1:
add_ik_ctrl = True
@@ -5791,7 +5847,7 @@ class TempIK(bpy.types.Operator):
for i, ctrl in enumerate(ctrls[:-1]):
ctrls[i+1].tail = ctrl.head
context.view_layer.update()
# return {'FINISHED'}
switch_layers(rig, chain.ik_tip, [31])
add_bone_to_collection(rig, chain.ik_tip)
add_bone_to_collection(rig, chain.ik_ctrl, col_name = 'IK Ctrls', visible = True)
@@ -5800,7 +5856,7 @@ class TempIK(bpy.types.Operator):
# rig.data.collections['ORG'].is_visible = False
ik_chains.append(chain)
btc['add_ik_ctrl'] = add_ik_ctrl
if add_ik_ctrl:
add_ik_prop_edit(self, context)
@@ -5824,8 +5880,7 @@ class TempIK(bpy.types.Operator):
####################################################################
bpy.ops.object.mode_set(mode = 'POSE')
setup_ids = set()
if btc.root:
@@ -5858,20 +5913,22 @@ class TempIK(bpy.types.Operator):
# #assign the matrix
distance = (bone.id_data.matrix_world @ bone.bone.matrix_local).inverted() @ ctrl.bone.matrix_local.copy()
ctrl.matrix = bone.id_data.matrix_world @ bone.matrix @ distance
# context.view_layer.update()
ctrl.color.palette = btc.color_set
add_bone_setup_id(chain.ik_ctrl, False, setup, 'CTRL', setup_id, org_id = chain.ik_ctrl.btc.org_id)
if add_ik_ctrl:
add_ik_prop_pose(self, context)
context.view_layer.update()
pole_prop_pose(self, context)
# child_prop_pose(context)
if context.scene.btc.child:
child_prop(context.scene.btc, context)
# return {'FINISHED'}
self.ik_chains = ik_chains
tempctrl_shape_type(self, context)
@@ -5885,7 +5942,7 @@ class TempIK(bpy.types.Operator):
if 'ctrls' not in globals():
self.report({'INFO'},'Not available. Please update the Temp Ctrls from the addon panel')
return {'CANCELLED'}
btc = context.scene.btc
controlled_objs = {item.controlled for item in context.scene.btc.ctrl_items if item.controlled}
hidden_objs = {obj for obj in context.view_layer.objects if obj and obj.hide_get()}
@@ -5952,7 +6009,7 @@ class TempIK(bpy.types.Operator):
rig.data.edit_bones[ctrl.name].parent = rig.data.edit_bones[chain.ctrls[i+1].name]
#updating the polebone position with the offset
if btc.pole_target and hasattr(chain, 'pole_bone_name'):
if btc.pole_target and chain.pole_bone_name: #hasattr(chain, 'pole_bone_name'):
pole_bone = rig.data.edit_bones[chain.pole_bone_name]
base_bone = rig.data.edit_bones[chain.base_bone_name]
ik_tip = rig.data.edit_bones[chain.ik_tip_name]
@@ -6081,7 +6138,8 @@ class TempIK(bpy.types.Operator):
#add the ik constraint to the ctrls
ik_con = constraint_add(chain.ik_tip, chain.ik_ctrl if not btc.child else chain.ik_child_ctrl, 'IK')
chain.pole_angle = get_pole_angle(chain.base_bone, chain.ik_tip, chain.pole_bone.matrix.translation)
if chain.pole_bone:
chain.pole_angle = get_pole_angle(chain.base_bone, chain.ik_tip, chain.pole_bone.matrix.translation)
ik_con.chain_count = chain.length(btc.add_ik_ctrl)
#setup the ik constraint
@@ -6316,6 +6374,8 @@ class IK_Chain:
self.ik_ctrl_name = self.ik_ctrl.name
self.base_bone_name = self.base_bone.name
self.ik_tip_name = self.ik_tip.name
self.pole_bone = None
self.pole_bone_name = None
self.step = get_step(hierarchy[0].id_data)
@@ -6337,7 +6397,7 @@ class IK_Chain:
self.parent = rig.pose.bones[self.parent_name]
if hasattr(self, 'root_name'):
self.root_ctrl = rig.pose.bones[self.root_name]
if hasattr(self, 'pole_bone_name'):
if self.pole_bone_name:
self.pole_bone = rig.pose.bones[self.pole_bone_name]
# if hasattr(self, 'pole_bone_ref_name'):
# self.pole_bone_ref = rig.pose.bones[self.pole_bone_ref_name]
+45 -11
View File
@@ -574,7 +574,12 @@ def cursor_change_post(self, context):
new_matrices = [bone.matrix.copy() for bone in context.selected_pose_bones]
elif context.selected_objects:
new_matrices = [obj.matrix_world.copy() for obj in context.selected_objects]
else:
return
if 'last_matrices' not in globals():
last_matrices = []
#checking if the selection was moving and have different matrix
if last_matrices != new_matrices:
update_cursor_matrix(context)
@@ -606,7 +611,7 @@ def cursor_change_pre(self, context):
return
item = selected_items[0]
if 'relative_cursor' in item:
if 'relative_cursor' in item.animtoolbox:
update_cursor_matrix(context)
else:
assign_relative_cursor_prop(context)
@@ -639,7 +644,11 @@ def update_cursor_matrix(context):
else:
item = context.object
selected_items = context.selected_objects
# No Matrix All zeros
if not any (item.animtoolbox.relative_cursor):
return
# for bone in selected_bones:
if len(selected_items) > 1:
#multiple selection cursor is relative to the center of all the selections
@@ -651,11 +660,12 @@ def update_cursor_matrix(context):
item_matrix = item.matrix_world
if bpy.app.version < (5, 0, 0):
relative_matrix = Matrix(item['relative_cursor'])
matrix_4x4 = item.animtoolbox.relative_cursor
else:
# Since Blender 5 I need to reshape the array into a matrix using numpy
matrix_4x4 = np.array(item['relative_cursor']).reshape(4, 4).T
relative_matrix = Matrix(matrix_4x4)
matrix_4x4 = np.array(item.animtoolbox.relative_cursor).reshape(4, 4).T
relative_matrix = Matrix(matrix_4x4)
cursor.matrix = item_matrix @ relative_matrix.inverted()
cursor_matrix = cursor.matrix
@@ -681,8 +691,11 @@ def assign_relative_matrix(context, items, prop = 'relative_cursor'):
item_matrix = matrix_avg if len(items) > 1 else item_matrix
matrix_dist = cursor_matrix.inverted() @ item_matrix
item[prop] = matrix_dist
# item[prop] = matrix_dist
# Storing the matrix in a non animated float vector property instead of ID property
item.animtoolbox.relative_cursor = np.array(matrix_dist.transposed()).flatten() # [v for row in matrix_dist for v in row] #
return matrix_dist
def assign_relative_cursor_prop(context):
@@ -751,7 +764,7 @@ class RelativeCursor(bpy.types.Operator):
if items:
#if it's a single selection and already has a cursor assigned then don't re-assign
if len(items) != 1 or 'relative_cursor' not in items[0]:
if len(items) != 1 or not hasattr (items[0].animtoolbox, 'relative_cursor' ):
assign_relative_cursor_prop(context)
#appending all the handlers
@@ -1520,10 +1533,20 @@ def compatible_rotation(bone, bones_prevrot):
'''Make sure the bone is not flipping and is compatible with previous frame rotation'''
rotation_channel = rot_mode_to_channel(bone.rotation_mode)
if bone in bones_prevrot:
rot = getattr(bone, rotation_channel)
rot.make_compatible(bones_prevrot[bone])
bones_prevrot[bone] = getattr(bone, rotation_channel).copy()
# def compatible_matrix_rotation(prev_matrix, new_matrix):
# '''Make sure the bone is not flipping and is compatible with previous frame rotation'''
# prev_loc, prev_rot, prev_scale = prev_matrix.decompose()
# loc, rot, scale = new_matrix.decompose()
# rot.make_compatible(prev_rot)
# new_matrix = Matrix.LocRotScale(loc, rot, scale)
# return new_matrix
class CopyMatrix(bpy.types.Operator):
"""Copy the matrix of the selection and store it"""
bl_idname = "anim.copy_matrix"
@@ -1771,7 +1794,7 @@ class CopyRelativeMatrix(bpy.types.Operator):
def paste_keyframes_get_inbetweens(scene, target, inbetweens, frame, frame_range, fcu_inbetweens, locked_fcus, bones_prevrot):
#Make sure the rotation is compatible with the previous rotation
compatible_rotation(target, bones_prevrot)
# compatible_rotation(target, bones_prevrot)
#if autokey is turned on then add a keyframe
if (scene.tool_settings.use_keyframe_insert_auto or scene.animtoolbox.range_type != 'CURRENT') and 'target' in locals():
@@ -1885,6 +1908,7 @@ def paste_bone_matrix(bone, matrix_copied, constrained, bones = {}, x_filter = T
context = bpy.context
if x_filter : matrix_copied = filter_matrix_properties(context, getattr(bone, matrix_attr), matrix_copied)
# bone.matrix = bone.id_data.matrix_world.inverted() @ matrix_copied
# matrix_copied = compatible_matrix_rotation(getattr(bone, matrix_attr), matrix_copied)
setattr(bone, matrix_attr, matrix_copied) # bone.id_data.matrix_world.inverted() @
children = set(bone.children_recursive).intersection(bones)
@@ -1898,6 +1922,7 @@ def paste_bone_matrix(bone, matrix_copied, constrained, bones = {}, x_filter = T
matrix_copied = reverse_bone_constraints(context, bone, matrix_copied)
if x_filter : matrix_copied = filter_matrix_properties(context, bone.matrix, matrix_copied)
# bone.matrix = matrix_copied
setattr(bone, matrix_attr, matrix_copied)
#important to have the extra update
context.view_layer.update()
@@ -1907,8 +1932,16 @@ def paste_bones_matrices(bones_matrices, constrained, x_filter = True):
pasted_bones = set()
for bone, matrix_copied in bones_matrices.items():
#Get the rest of the bones to check if they are children of the current bone
old_rot = bone.rotation_quaternion.copy()
bones = set(bones_matrices.keys()).difference(pasted_bones)
paste_bone_matrix(bone, matrix_copied, constrained, bones, x_filter)
# Make sure rotation difference is compatible, no flipping
new_rot = bone.rotation_quaternion.copy()
new_rot.make_compatible(old_rot)
bone.rotation_quaternion = new_rot
pasted_bones.add(bone)
class PasteRelativeMatrix(bpy.types.Operator):
@@ -1986,6 +2019,8 @@ class PasteRelativeMatrix(bpy.types.Operator):
rig_offset = rig_offset @ source_rig.matrix_world
matrix_new = rig_offset @ matrix_source @ bone_matrix_dist
# matrix_new = compatible_matrix_rotation(matrix_source, matrix_new)
#Store the matrices for each bone that will use it
matrix_new = reverse_childof_constraint(bone, matrix_new, constrained)
@@ -2126,7 +2161,7 @@ def get_fcurves_frames(selection, fcurves, all_fcurves, frames, attr_index):
# transformations = ["rotation_quaternion","rotation_euler", "rotation_axis_angle", "location", "scale"]
for fcu in fcurves:
# print('fcu ', fcu)
if not bone_paths and not fcu.data_path.startswith('pose.bones'):
#in case it's just an object or data
all_fcurves.append(fcu)
@@ -2251,7 +2286,6 @@ class ShareKeys(bpy.types.Operator):
if obj.type in actions_data_types:
action_data = self.add_get_action(obj.data)
# print('udating objfcurves animation data')
obj_fcurves.update({obj.data: [fcu for fcu in all_fcurves if fcu.id_data == action_data]})
obj_fcurves[obj.data] = sharekeys_add_missing_fcurves(obj.data, attr_index_obj, obj_fcurves[obj.data])
+11 -4
View File
@@ -20,7 +20,7 @@
bl_info = {
"name": "AnimToolBox",
"author": "Tal Hershkovich",
"version" : (0, 2, 0),
"version" : (0, 2, 6),
"blender" : (3, 2, 0),
"location": "View3D - Properties - Animation Panel",
"description": "A set of animation tools",
@@ -204,7 +204,12 @@ class AnimToolBoxObjectSettings(bpy.types.PropertyGroup):
child: bpy.props.BoolProperty(name = "Child Empty", description = "Empty is marked as a child bone inside the setup", default = False, override = {'LIBRARY_OVERRIDABLE'})
keyframes_offset: bpy.props.FloatProperty(name = "Keyframes Offset", description = "Interactive slider to offset keyframes back and forth ", default = 0)
relative_cursor: bpy.props.FloatVectorProperty(name="Relative Cursor", size=16, options={'HIDDEN'})
class AnimToolBoxBoneSettings(bpy.types.PropertyGroup):
relative_cursor: bpy.props.FloatVectorProperty(name="Relative Cursor", size=16, options={'HIDDEN'})
class IsolatedRigs(bpy.types.PropertyGroup):
hidden: bpy.props.PointerProperty(name = "Hidden Rigs", description = "List of Rigs that are hidden during pose mode isolation", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
@@ -468,7 +473,7 @@ def loadanimtoolbox_post(self, context):
Tools.selection_order(self, context)
classes = (TempCtrlsItems, TempCtrlsOrgIds, TempCtrlsObjectSetups, TempCtrlsSceneSettings,TempCtrlsBoneSettings, MultikeyProperties,
IsolatedRigs, AnimToolBoxObjectSettings, AnimToolBoxUILayout, AnimToolBoxGlobalSettings) + ui.classes
IsolatedRigs, AnimToolBoxObjectSettings, AnimToolBoxBoneSettings, AnimToolBoxUILayout, AnimToolBoxGlobalSettings) + ui.classes
addon_keymaps = []
@@ -493,9 +498,10 @@ def register():
bpy.types.Scene.btc = bpy.props.PointerProperty(type = TempCtrlsSceneSettings, override = {'LIBRARY_OVERRIDABLE'})
bpy.types.PoseBone.btc = bpy.props.PointerProperty(type = TempCtrlsBoneSettings, override = {'LIBRARY_OVERRIDABLE'})
bpy.types.Object.animtoolbox = bpy.props.PointerProperty(type = AnimToolBoxObjectSettings, override = {'LIBRARY_OVERRIDABLE'})
bpy.types.PoseBone.animtoolbox = bpy.props.PointerProperty(type = AnimToolBoxBoneSettings, override = {'LIBRARY_OVERRIDABLE'})
bpy.types.Scene.animtoolbox = bpy.props.PointerProperty(type = AnimToolBoxGlobalSettings, override = {'LIBRARY_OVERRIDABLE'})
bpy.types.WindowManager.atb_ui = bpy.props.PointerProperty(type = AnimToolBoxUILayout, override = {'LIBRARY_OVERRIDABLE'})
ui.update_panel(None, bpy.context)
ui.add_multikey(None, bpy.context)
ui.add_riggertoolbox(None, bpy.context)
@@ -554,6 +560,7 @@ def unregister():
del bpy.types.Scene.btc
# del bpy.types.Bone.btc
del bpy.types.Object.animtoolbox
del bpy.types.PoseBone.animtoolbox
del bpy.types.Scene.animtoolbox
if hasattr(bpy.types.Object, 'keyframes_offset'):
del bpy.types.Object.keyframes_offset
@@ -1374,7 +1374,8 @@ def register(bl_info):
# **WARNING** Depending on the engine, this token can act like a password!!
# Only provide a token if the project is *non-public*, see readme for
# other considerations and suggestions from a security standpoint
updater.private_token = "glpat-js__ikigVSQ_tKWgjVn1" # "tokenstring"
# updater.private_token = "glpat-js__ikigVSQ_tKWgjVn1" # "tokenstring"
updater.private_token = "glpat-5rHfAdBG2Br3ww6H8U4vI286MQp1OjFpcXEK.01.100el42cj"
# choose your own username, must match website (not needed for GitLab)
updater.user = ""
@@ -1,9 +0,0 @@
{
"last_check": "",
"backup_date": "",
"update_ready": false,
"ignore": false,
"just_restored": false,
"just_updated": false,
"version_text": {}
}
+18 -6
View File
@@ -2007,7 +2007,7 @@ def remove_draw_handlers(self):
# Operator with modal and draw handler
class MotionPathOperator(bpy.types.Operator):
"""Creates a custom motion path"""
"""Creates an editable motion path, Ctrl click to refresh"""
bl_idname = "object.motion_path_operator"
bl_label = "Motion Path Operator"
bl_options = {'REGISTER', 'UNDO'}
@@ -2028,10 +2028,15 @@ class MotionPathOperator(bpy.types.Operator):
scene = context.scene
emp = scene.emp
emp.refresh = False
if emp.motion_path:
emp.motion_path = False
if event.ctrl:
# Refresh the motion path
emp.refresh = True
else:
emp.motion_path = False
return {'CANCELLED'}
if context.selected_pose_bones is None and context.selected_objects is None:
emp.motion_path = False
return {'CANCELLED'}
@@ -2237,9 +2242,6 @@ class MotionPathOperator(bpy.types.Operator):
#return negative frame range to what it was
if context.preferences.edit.use_negative_frames != nfr:
context.preferences.edit.use_negative_frames = nfr
#assign the draw handler
context.window_manager.modal_handler_add(self)
#If overlays are turned off then skip drawing
if self.mp_vis:
@@ -2255,6 +2257,9 @@ class MotionPathOperator(bpy.types.Operator):
self.area.tag_redraw()
# Tools.redraw_areas(['VIEW_3D'])
#assign the draw handler
context.window_manager.modal_handler_add(self)
bpy.ops.ed.undo_push(message = 'Initialize Motion Path')
return {'RUNNING_MODAL'}
@@ -2279,6 +2284,11 @@ class MotionPathOperator(bpy.types.Operator):
if not emp.motion_path:
quit_mp(self, context)
return {'FINISHED'}
if emp.refresh:
get_mp_points(self, context)
emp.refresh = False
return {'PASS_THROUGH'}
if not self.mp_vis:
check_mp_vis_on(self, context)
@@ -4864,6 +4874,8 @@ def disbale_non_smooth(self, context):
class EditableMotionPathSettings(bpy.types.PropertyGroup):
'''All the settings for Editable motion path'''
motion_path: bpy.props.BoolProperty(name = "Motion Path", description = "Flag when Motion Path is on", default = False, override = {'LIBRARY_OVERRIDABLE'})
refresh: bpy.props.BoolProperty(name = "Refresh Motion Path", description = "Refresh the motion paths with hotkey ctrl", default = False, override = {'LIBRARY_OVERRIDABLE'})
settings: bpy.props.BoolProperty(name = "Motion Path Settings", description = "Open the settings Menu", default = False, override = {'LIBRARY_OVERRIDABLE'})
# mp_keyframe_scale: bpy.props.FloatProperty(name = "Scale Selecgted Keyframes Bounding Box", description = "Change the scale of the bounding box around the selected keyframes ", default = 0.1, step = 0.1, precision = 3)
color_before: bpy.props.FloatVectorProperty(name="Motion Path Before Color", subtype='COLOR', default=(1.0, 0.0, 0.0), min=0.0, max=1.0, description="Motion path color before the current frame", update=update_prop_callback)