disable (currently unused) addons, update
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -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])
|
||||
|
||||
|
||||
@@ -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": {}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user