2025-12-09

This commit is contained in:
2026-03-17 15:03:35 -06:00
parent 4b82b57113
commit aae574f8dc
137 changed files with 17355 additions and 4067 deletions
@@ -8307,7 +8307,7 @@ def _cancel_corrective_driver(self):
if len(data_list) != 4:
# reset the data property
scn["arp_corrective_shapes_data"] = ""
scn.arp_corrective_shapes_data = ''
return
rotated_bone_name = data_list[0]
@@ -8330,7 +8330,7 @@ def _cancel_corrective_driver(self):
bpy.context.object.data.use_mirror_x = xmirror_state
# reset the data property
scn["arp_corrective_shapes_data"] = ""
scn.arp_corrective_shapes_data = ''
# Restore saved mode
restore_current_mode(current_mode)
@@ -8377,7 +8377,7 @@ def _add_corrective_driver(self):
new_var.targets[1].bone_target = source_bone
# reset the corrective shapes property data
scene["arp_corrective_shapes_data"] = ""
scene.arp_corrective_shapes_data = ''
print("Driver created")
@@ -18480,14 +18480,19 @@ def _dupli_limb(dupli_mirror=False):
mirror_par = get_edit_bone(mirror_par_name)
if mirror_par:
eb.parent = mirror_par
bpy.ops.object.mode_set(mode='POSE')
# warning, selection is lost after duplicating and switching to pose mode in Blender 5+
# operate on a list instead
sel_bones = [eb.name for eb in get_selected_edit_bones()]
bpy.ops.object.mode_set(mode='POSE')
# mirror colors.
if dupli_mirror and not symmetrical and not limb == 'kilt':# avoid kilt bones coloring for visual clarity
for pb in bpy.context.selected_pose_bones:
if bpy.app.version >= (4,0,0):
mirror_colors = bpy.context.scene.color_set_right if pb.name.endswith('.r') else bpy.context.scene.color_set_left
if dupli_mirror and not symmetrical and not limb == 'kilt':# avoid kilt bones coloring for visual clarity
for pbname in sel_bones:
pb = get_pose_bone(pbname)
if bpy.app.version >= (4,0,0):
mirror_colors = bpy.context.scene.color_set_right if pb.name.endswith('.r') else bpy.context.scene.color_set_left
set_bone_color_group(rig, pb.bone, None, custom_color=mirror_colors)
pb.color.palette = 'DEFAULT'# pose color same as data color
else:
@@ -18495,8 +18500,7 @@ def _dupli_limb(dupli_mirror=False):
mirrored_grp_name = pb.bone_group.name[:-2] + get_opposite_side(pb.bone_group.name[-2:])
mirrored_grp = rig.pose.bone_groups.get(mirrored_grp_name)
if mirrored_grp:
pb.bone_group = mirrored_grp
pb.bone_group = mirrored_grp
bpy.ops.object.mode_set(mode='EDIT')
@@ -23714,16 +23718,13 @@ def parent_retarget(ref_bone):
if ref_bone.parent == None:
return None
if ref_bone.parent.name[:-2][-4:] == "_ref":
is_a_ref_bone = True
if "_ref_dupli_" in ref_bone.parent.name:
if ref_bone.parent.name[:-2][-4:] == '_ref' or '_ref_dupli_' in ref_bone.parent.name:
is_a_ref_bone = True
if is_a_ref_bone:# parent is a ref bone, map it to controller or deforming bone
#print(ref_bone.name, "is parented to a ref bone")
# try to map to a controller bone
# first, try to map to a controller
par_side = get_bone_side(ref_bone.parent.name)
# add c_, remove _ref
control_parent_name = 'c_'+ref_bone.parent.name.replace('_ref'+par_side, par_side)
@@ -23791,11 +23792,10 @@ def parent_retarget(ref_bone):
n = parent_name
print(' '+n)
retargetted_parent = get_edit_bone(n)
retargetted_parent = get_edit_bone(n)
else:# controller bone not found, try to map to deforming bone
else:# controller not found, try to map to deforming bone
print(' parent to deforming bone...')
def_b_name = ''
par_side = get_bone_side(ref_bone.parent.name)
@@ -23807,6 +23807,8 @@ def parent_retarget(ref_bone):
def_b_name = ard.leg_bones_dict['thigh']['stretch'] + par_side
elif 'leg' in ref_bone.parent.name:
def_b_name = ard.leg_bones_dict['leg']['stretch'] + par_side
else:
def_b_name = ref_bone.parent.name.replace('_ref'+par_side, par_side)# may not always match an existing deforming bone name, to improve later
print(' deforming bone parent:', def_b_name)
retargetted_parent = get_edit_bone(def_b_name)
@@ -44883,8 +44885,11 @@ def set_facial(enable=True,
else:# remove facial module
if module_name == 'rig_mouth':
bones_list += ard.get_variable_lips(side, btype='ALL')
bones_list += ard.get_tongues(side=side, type='ALL', no_side=False)
elif module_name.startswith('rig_eye_'):
bones_list += ard.get_variable_eyelids(side, btype='ALL', eye_sides=['.'+module_name[-1:]])
bones_list += ard.get_variable_eyelids(side, btype='ALL', eye_sides=['.'+module_name[-1:]])
elif module_name.startswith('rig_eyebrow_'):
bones_list += ard.get_eyebrows(side=side, type='ALL', with_side=True)
for bname in bones_list:
final_bname = retarget_bone_side(bname, side, dupli_only=True)
@@ -46380,6 +46385,8 @@ def set_facial(enable=True,
def set_tongues_amount():
if not mouth_enabled:
return
bpy.ops.object.mode_set(mode='EDIT')
@@ -46821,14 +46828,23 @@ def set_facial(enable=True,
bpy.ops.object.mode_set(mode='EDIT')
# remove older masters
# remove older
for eyebi in range(1, 32):
if eyebi == eyeb_amount-1: continue
stri = '%02d' % eyebi
# masters
master_name = 'c_eyebrow_'+stri+'_master'+head_side+_side
master_eb = get_edit_bone(master_name)
if master_eb:
delete_edit_bone(master_eb)
# offsets
if eyebi >= eyeb_amount:
offset_name = 'eyebrow_'+stri+'_offset'+head_side+_side
offset_eb = get_edit_bone(offset_name)
if offset_eb:
delete_edit_bone(offset_eb)
bpy.ops.object.mode_set(mode='POSE')
@@ -46841,14 +46857,29 @@ def set_facial(enable=True,
first_m = get_edit_bone(first_m_name)
if first_m:
delete_edit_bone(first_m)
print("DELETED ", first_cname)
tip_cname = eyeb_list[len(eyeb_list)-1]#ard.eyebrow_bones_dict['eyebrow_03']['name']
tip_m_name = tip_cname+'_master'+head_side+_side
tip_m = get_edit_bone(tip_m_name)
if tip_m:
delete_edit_bone(tip_m)
print("DELETED ", tip_m_name)
# remove older
for eyebi in range(1, 32):
stri = '%02d' % eyebi
if eyebi >= eyeb_amount:
# masters
master_name = 'c_eyebrow_'+stri+'_master'+head_side+_side
master_eb = get_edit_bone(master_name)
if master_eb:
delete_edit_bone(master_eb)
# offsets
offset_name = 'eyebrow_'+stri+'_offset'+head_side+_side
offset_eb = get_edit_bone(offset_name)
if offset_eb:
delete_edit_bone(offset_eb)
# delete constraints
bpy.ops.object.mode_set(mode='POSE')
@@ -691,7 +691,7 @@ eyebrow_bones_left = [i+'.l' for i in eyebrow_bones] + [i+'.l' for i in eyebrow_
eyebrow_bones_right = [i+'.r' for i in eyebrow_bones] + [i+'.r' for i in eyebrow_ref]
def get_eyebrows(side='.l', type='ALL', include_full=True):
def get_eyebrows(side='.l', type='ALL', include_full=True, with_side=False):
list = []
main_ctrl = []
ref = []
@@ -699,15 +699,17 @@ def get_eyebrows(side='.l', type='ALL', include_full=True):
if side.endswith('.x'):
side = side[:-2]+'.l'# same count for left and right brows for now
side_suff = '' if with_side == False else side
for _i in range(0, 32):
stri = '%02d' % _i if _i > 0 else '01_end'
if bpy.context.active_object.data.bones.get('eyebrow_'+stri+'_ref'+side):
main_ctrl.append('c_eyebrow_'+stri)
ref.append('eyebrow_'+stri+'_ref')
main_ctrl.append('c_eyebrow_'+stri+side_suff)
ref.append('eyebrow_'+stri+'_ref'+side_suff)
master_ctrl = [eyebrow_bones_dict['eyebrow_full']['name']]
master_ref = [eyebrow_bones_ref_dict['eyebrow_full']]
master_ctrl = [eyebrow_bones_dict['eyebrow_full']['name']+side_suff]
master_ref = [eyebrow_bones_ref_dict['eyebrow_full']+side_suff]
if type == 'ALL':
list = main_ctrl + ref
@@ -4545,13 +4545,13 @@ def _add_marker(_name, enable_mirror):
def _auto_detect(self):
print("\nAuto-Detecting... \n")
scene = bpy.context.scene
scn = bpy.context.scene
set_selection_filters(['EMPTY', 'MESH', 'ARMATURE'], True)
show_extras(True)
# get character mesh name
body = get_object(scene.arp_body_name)
body = get_object(scn.arp_body_name)
# apply transforms
bpy.ops.object.select_all(action='DESELECT')
@@ -4600,9 +4600,9 @@ def _auto_detect(self):
bpy.ops.object.select_all(action='DESELECT')
# save current pivot mode
pivot_mod = scene.tool_settings.transform_pivot_point
pivot_mod = scn.tool_settings.transform_pivot_point
if scene.arp_smart_type == 'BODY':
if scn.arp_smart_type == 'BODY':
# Arms
# get the loc guides
hand_loc_l = get_object("hand_loc")
@@ -4617,7 +4617,7 @@ def _auto_detect(self):
hand_markers = [hand_loc_l]
if not scene.arp_smart_sym:
if not scn.arp_smart_sym:
hand_markers.append(hand_loc_r)
# iterate on left and right sides
@@ -4640,7 +4640,7 @@ def _auto_detect(self):
# HAND DETECTION ----------
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Find hands boundaries...\n")
print(" Find wrist...\n")
@@ -4699,7 +4699,7 @@ def _auto_detect(self):
shoulder_front = None
shoulder_back = None
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Find shoulders...\n")
ray_origin = shoulder_loc.location + vectorize3([0, -body_depth*2, 0])
@@ -4725,7 +4725,7 @@ def _auto_detect(self):
shoulder_depth = 0.0
if scene.arp_smart_depth:
if scn.arp_smart_depth:
shoulder_depth = shoulder_loc.location[1]
else:
shoulder_depth = shoulder_back + (shoulder_front-shoulder_back)*0.4
@@ -4735,7 +4735,7 @@ def _auto_detect(self):
# Shoulder_base
# Y position: best to bring it forward for best compatibility with humanoid rigs (UE) (Model Fit only)
base_depth = 0.0
if scene.arp_smart_depth:
if scn.arp_smart_depth:
base_depth = shoulder_empty_loc[1] + (shoulder_front-shoulder_empty_loc[1])*0.5
else:
@@ -4755,13 +4755,13 @@ def _auto_detect(self):
elbow_loc_obj = get_object('elbow_loc') if side_idx == 0 else get_object('elbow_loc_sym')
if elbow_loc_obj:
elbow_empty_loc[0], elbow_empty_loc[2] = elbow_loc_obj.location[0], elbow_loc_obj.location[2]
if scene.arp_smart_depth:
if scn.arp_smart_depth:
elbow_empty_loc[1] = elbow_loc_obj.location[1]
# Find the elbow boundaries
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Find elbow boundaries...\n")
# Get the arm X angle
@@ -4849,7 +4849,7 @@ def _auto_detect(self):
elbow_center = elbow_empty_loc.copy()
if not scene.arp_smart_depth:
if not scn.arp_smart_depth:
if elbow_angle > 3.6:
# get the resulting vector
vec = p-p_proj
@@ -4872,7 +4872,7 @@ def _auto_detect(self):
# FINGERS DETECTION ---------------------------------------------------------------------------------------------
print(" Find fingers...\n")
if scene.arp_smart_fingers_engine == 'LEGACY' and scene.arp_fingers_to_detect != 0:
if scn.arp_smart_fingers_engine == 'LEGACY' and scn.arp_fingers_to_detect != 0:
# Initialize the hand rotation by creating a new hand mesh horizontally aligned
# Z angle
@@ -4892,7 +4892,7 @@ def _auto_detect(self):
forearm_angle_z = forearm_vec.angle(global_x_vec)
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(' Arm Angle X:', degrees(arm_angle_x))
print(' Arm Angle Z:', degrees(forearm_angle_z))
@@ -4949,33 +4949,33 @@ def _auto_detect(self):
# delete other verts
bpy.ops.mesh.delete(type='VERT')
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Remesh...")
# Remesh
bpy.ops.object.mode_set(mode='OBJECT')
mod = bpy.context.active_object.modifiers.new('remesh', 'REMESH')
if scene.arp_smart_remesh_type == "type1":
if scn.arp_smart_remesh_type == "type1":
mod.mode = 'SMOOTH'
# it's best to set the remesh definition according to the mesh actual dimensions
if bpy.context.active_object.dimensions[0] < (body_width/3):# generally, t-pose
remesh_def = scene.arp_smart_remesh - 2
remesh_def = scn.arp_smart_remesh - 2
else:# a-pose
remesh_def = scene.arp_smart_remesh
remesh_def = scn.arp_smart_remesh
mod.octree_depth = remesh_def
mod.use_remove_disconnected = True
mod.threshold = 0.0015
elif scene.arp_smart_remesh_type == "type2":
elif scn.arp_smart_remesh_type == "type2":
mod.mode = 'VOXEL'
mod.voxel_size = 0.0016 * bpy.context.active_object.dimensions[0] * (1/(scene.arp_smart_remesh/9))
mod.voxel_size = 0.0016 * bpy.context.active_object.dimensions[0] * (1/(scn.arp_smart_remesh/9))
mod.adaptivity = 0.0
bpy.ops.object.convert(target='MESH')
# select the closest point to the wrist marker
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Select closest point to the wrist")
bpy.ops.object.mode_set(mode='EDIT')
obj = bpy.context.active_object
@@ -5001,8 +5001,8 @@ def _auto_detect(self):
bpy.ops.mesh.delete(type='VERT')
# change for cursor
scene.tool_settings.transform_pivot_point = 'CURSOR'
scene.cursor.location = shoulder_pos
scn.tool_settings.transform_pivot_point = 'CURSOR'
scn.cursor.location = shoulder_pos
bpy.ops.object.mode_set(mode='OBJECT')
@@ -5145,7 +5145,7 @@ def _auto_detect(self):
dist_fac = 1
# No centering engine for 1 finger detection. Only raycast detection.
if scene.arp_fingers_to_detect == 1:
if scn.arp_fingers_to_detect == 1:
centering_engine = -1
if centering_engine == 1:
@@ -5191,7 +5191,7 @@ def _auto_detect(self):
if y_hit and ny_hit:
y_magn = y_distance + ny_distance
dist_max = (dist_fac * (hand_obj.dimensions[1] * scene.arp_finger_thickness)) / 9.0
dist_max = (dist_fac * (hand_obj.dimensions[1] * scn.arp_finger_thickness)) / 9.0
if y_magn > dist_max:
vert_to_del.append(vert)
@@ -5212,7 +5212,7 @@ def _auto_detect(self):
y_magn = y_distance + ny_distance
x_magn = x_distance + nx_distance
dist_max = (dist_fac * (hand_obj.dimensions[1] * scene.arp_finger_thickness)) / 9.0
dist_max = (dist_fac * (hand_obj.dimensions[1] * scn.arp_finger_thickness)) / 9.0
if y_magn > dist_max and x_magn > dist_max:
vert_to_del.append(vert)
@@ -5249,7 +5249,7 @@ def _auto_detect(self):
return _i
# Separate the longer finger tip vertice as a new vert, if fingers to detect == 1 or 2
if scene.arp_fingers_to_detect == 1 or scene.arp_fingers_to_detect == 2:
if scn.arp_fingers_to_detect == 1 or scn.arp_fingers_to_detect == 2:
print("Separate longer finger tip...")
b_mesh = bmesh.from_edit_mesh(bpy.context.active_object.data)
b_mesh.verts.ensure_lookup_table()
@@ -5266,7 +5266,7 @@ def _auto_detect(self):
new_vert = b_mesh.verts.new(coords_sorted1[0])
new_vert.select = True
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print("\n Creating edges...")
hand_obj = get_object(bpy.context.active_object.name)
@@ -5304,7 +5304,7 @@ def _auto_detect(self):
b_mesh = bmesh.from_edit_mesh(bpy.context.active_object.data)
b_mesh.verts.ensure_lookup_table()
fingers_total = scene.arp_fingers_to_detect
fingers_total = scn.arp_fingers_to_detect
restrict_edgify_half_hand = False
if fingers_total <= 2:
restrict_edgify_half_hand = True
@@ -5324,7 +5324,7 @@ def _auto_detect(self):
# Get the index in the actual vert list
vert_tip = get_index(vert_coords, coords_sorted[0])
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" vert_tip", vert_tip, coords_sorted[0])
bpy.ops.mesh.select_all(action='DESELECT')
@@ -5332,7 +5332,7 @@ def _auto_detect(self):
first_finger_tip = vert_tip
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Found first finger vert", vert_tip)
# Create edges between verts
@@ -5566,7 +5566,7 @@ def _auto_detect(self):
last_vert = current_vert
cast_object = get_object("arp_hand_aligned")
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print('create verts and edges aligned toward the wrist')
# create verts and edges aligned toward the wrist
@@ -5603,7 +5603,7 @@ def _auto_detect(self):
if iter < 5000:# there's a hole in the mesh, offset the Y position
ori[1] -= bpy.context.active_object.dimensions[1]*0.0001
else:
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print("Success top")
have_hit_top = True
iter = 0
@@ -5614,7 +5614,7 @@ def _auto_detect(self):
hit_top[1] += bpy.context.active_object.dimensions[1]*0.0001*ray_dir_neg
else:
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print("Success bot")
vloc[2] = (hit_top[2] + hit_bot[2])*0.5
have_hit_bot = True
@@ -5622,7 +5622,7 @@ def _auto_detect(self):
iter += 1
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print("Terminated while")
# Create the vert
@@ -5632,7 +5632,7 @@ def _auto_detect(self):
b_mesh.edges.new((last_vert, new_vert))
last_vert = new_vert
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print("Final edge...")
# Final edge
@@ -5644,7 +5644,7 @@ def _auto_detect(self):
found_first_finger = True
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print("Found first finger", root_vert.index)
@@ -5655,7 +5655,7 @@ def _auto_detect(self):
edge_count, root_idx, tip_idx = edgify(b_mesh.verts[first_finger_tip])
if edge_count < 3:
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Could not edgify the first finger, try again...")
# Find another close vert
@@ -5696,7 +5696,7 @@ def _auto_detect(self):
else:
found_first_finger = True
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Found first finger", root_idx)
iterate += 1
@@ -5718,7 +5718,7 @@ def _auto_detect(self):
go_lower = False
# Find upper tips
if scene.arp_debug_mode:
if scn.arp_debug_mode:
if go_upper:
print("\n Going up")
@@ -5735,12 +5735,12 @@ def _auto_detect(self):
# Edgify
edge_count, root_idx, tip_idx = edgify(b_mesh.verts[idx])
if edge_count < 4:
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Finger", go_upper_count, "is invalid finger, not enough edges detected")
invalid_verts.append(idx)
invalid_verts.append(root_idx)
else:
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Found finger", go_upper_count, tip_idx)
fingers_list.append(("finger"+str(go_upper_count), tip_idx, root_idx, b_mesh.verts[tip_idx].co.copy(), b_mesh.verts[root_idx].co.copy()))
@@ -5757,7 +5757,7 @@ def _auto_detect(self):
# Go Lower
if scene.arp_debug_mode:
if scn.arp_debug_mode:
if go_lower:
print("\n Going down")
@@ -5780,11 +5780,11 @@ def _auto_detect(self):
bpy.ops.mesh.select_linked(delimit=set())
bpy.ops.mesh.delete(type='EDGE_FACE')
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Finger", go_lower_count, "is invalid finger, not enough edges detected")
else:
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Found finger", go_lower_count, tip_idx)
fingers_list.append(("finger"+str(go_lower_count), tip_idx, root_idx, b_mesh.verts[tip_idx].co.copy(), b_mesh.verts[root_idx].co.copy()))
@@ -5817,7 +5817,7 @@ def _auto_detect(self):
pos, idx, dist = kd.find(vert.co, filter=find_connected_verts)
if idx != None and not idx in invalid_verts:
invalid_verts.append(vert.index)
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" APPENDING INVALID", vert.index)
# If some fingers haven't been found yet, try again, it's probably the thumb wich is in a tricky place
@@ -5868,11 +5868,11 @@ def _auto_detect(self):
edge_count, root_idx, tip_idx = edgify(thumb_tip)
if edge_count < 3:
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Thumb is invalid finger, not enough edges detected")
invalid_verts.append(root_idx)
else:
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Found thumb", tip_idx)
fingers_list.append(("thumb", tip_idx, root_idx, b_mesh.verts[tip_idx].co.copy(), b_mesh.verts[root_idx].co.copy()))
@@ -5999,7 +5999,7 @@ def _auto_detect(self):
fingers_length.append(total_length)
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print("\n Fingers length:")
for fi in fingers_length:
print(" ", fi)
@@ -6133,11 +6133,11 @@ def _auto_detect(self):
create_empty_loc(0.02, phalanges_pos[fi+1][1], phalanges_pos[fi+1][0] + "_phal_2"+side)
# --End if scene.arp_fingers_to_detect != 0
# --End if scn.arp_fingers_to_detect != 0
bpy.ops.object.mode_set(mode='OBJECT')
# rotate the empties back to original coords
scene.cursor.location = shoulder_pos
scn.cursor.location = shoulder_pos
bpy.ops.object.select_all(action='DESELECT')
rot_angle_x = arm_angle_x * rot_fac
@@ -6165,7 +6165,7 @@ def _auto_detect(self):
else:
print("Too low poly, could not find the wrist vertices")
scene.arp_fingers_to_detect = 0
scn.arp_fingers_to_detect = 0
if bpy.context.active_object:
bpy.ops.object.mode_set(mode='OBJECT')
@@ -6179,7 +6179,7 @@ def _auto_detect(self):
foot_markers = [foot_loc_l]
if not scene.arp_smart_sym:
if not scn.arp_smart_sym:
foot_markers.append(foot_loc_r)
@@ -6286,7 +6286,7 @@ def _auto_detect(self):
if compare_x:
ray_origin = new_origin
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print("Iterating foot ray...")
if iterate > 60:
@@ -6299,7 +6299,7 @@ def _auto_detect(self):
last_hit = hit
else:
ray_origin = new_origin
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print("Iterating foot ray...")
if iterate > 60:
self.error_message = "Could not find the feet, are they on the ground?"
@@ -6309,7 +6309,7 @@ def _auto_detect(self):
iterate += 1
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(' ray foot origin', ray_origin)
print(' ray hit front', hit_front)
@@ -6330,7 +6330,7 @@ def _auto_detect(self):
hit_back = last_hit
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(' ray hit back', hit_back)
hit_center = (hit_back+hit_front)/2
@@ -6367,7 +6367,7 @@ def _auto_detect(self):
hit_back = last_hit
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(' ray hit back', hit_back)
hit_center_ankle = (hit_back+hit_front)/2
@@ -6376,7 +6376,7 @@ def _auto_detect(self):
ankle_endfoot_dist = (vectorize3([ankle_empty_loc[0], bound_front, ankle_empty_loc[2]]) - vectorize3(ankle_empty_loc)).magnitude
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Find bank bones...\n")
# Bank bones
@@ -6394,9 +6394,9 @@ def _auto_detect(self):
foot_dir = vectorize3([hit_center[0] - ankle_empty_loc[0], hit_center[1] - ankle_empty_loc[1], 0])
if side == ".l":
scene.arp_foot_dir_l = foot_dir
scn.arp_foot_dir_l = foot_dir
if side == ".r":
scene.arp_foot_dir_r = foot_dir
scn.arp_foot_dir_r = foot_dir
#find the bank bones in foot direction space
#create temp empty object for the coord space calculation
@@ -6638,12 +6638,12 @@ def _auto_detect(self):
print_progress_bar("Verts", vidx, len(vert_sel))
# Todo, skip the depth evaluation if arp_smart_depth is off
root_depth = root_marker.location[1] if scene.arp_smart_depth else (hips_back[1]+hips_front[1])/2
root_depth = root_marker.location[1] if scn.arp_smart_depth else (hips_back[1]+hips_front[1])/2
hips_right = Vector((hips_bound_right, (hips_back[1]+hips_front[1])/2, root_marker.location[2]))
hips_left = Vector((hips_bound_left, (hips_back[1]+hips_front[1])/2, root_marker.location[2]))
if scene.arp_smart_sym:
if scn.arp_smart_sym:
hips_left = Vector((-hips_bound_right, (hips_back[1]+hips_front[1])/2, root_marker.location[2]))
root_empty_loc = [root_marker.location[0], root_depth, root_marker.location[2]]
@@ -6671,14 +6671,14 @@ def _auto_detect(self):
thigh_loc_obj = get_object('thigh_loc') if side_idx == 0 else get_object('thigh_loc_sym')
if thigh_loc_obj:
leg_empty_loc[0], leg_empty_loc[2] = thigh_loc_obj.location[0], thigh_loc_obj.location[2]
if scene.arp_smart_depth:
if scn.arp_smart_depth:
leg_empty_loc[1] = thigh_loc_obj.location[1]
knee_empty_loc = [(leg_empty_loc[0] + ankle_empty_loc[0])/2, 0, (leg_empty_loc[2] + ankle_empty_loc[2])/2]
bot_empty_loc = [leg_empty_loc[0], -hips_front[1], leg_empty_loc[2]]
# find the knee boundaries
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Find knee boundaries...\n")
set_active_object(body.name)
@@ -6765,7 +6765,7 @@ def _auto_detect(self):
knee_loc_obj = get_object('knee_loc') if side_idx == 0 else get_object('knee_loc_sym')
knee_empty_loc[0], knee_empty_loc[2] = knee_loc_obj.location[0], knee_loc_obj.location[2]
if scene.arp_smart_depth:
if scn.arp_smart_depth:
knee_empty_loc[1] = knee_loc_obj.location[1]
create_empty_loc(0.04, root_empty_loc, "root_loc")
@@ -6784,59 +6784,46 @@ def _auto_detect(self):
mesh = bmesh.from_edit_mesh(bpy.context.active_object.data)
# select vertices in the overlapping neck sphere
neck_selection = []
clear_selection()
has_selected_neck = False
sel_dist = body_height / 25
while has_selected_neck == False:
for vb in mesh.verts:
if tolerance_check_2(vb.co, neck_loc.location, 0, 2, sel_dist, ".l"):
vb.select = True
neck_selection.append(vb.index)
has_selected_neck = True
sel_dist *= 2
# find the neck bounds
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Find neck boundaries...\n")
ray_origin = Vector((neck_loc.location[0],-body_depth*2, neck_loc.location[2]))
ray_dir = vectorize3([0,body_depth*4,0])
if not scn.arp_smart_depth:
# find the neck bounds
ray_origin = Vector((neck_loc.location[0],-body_depth*2, neck_loc.location[2]))
ray_dir = vectorize3([0, body_depth*4, 0])
hit, normal, index, distance = my_tree.ray_cast(ray_origin, ray_dir, ray_dir.magnitude)
neck_back = None
hit, normal, index, distance = my_tree.ray_cast(ray_origin, ray_dir, ray_dir.magnitude)
neck_back = None
if distance == None or distance < 0.001:
self.error_during_auto_detect = True
self.error_message = 'Could not find the neck, marker out of mesh?'
return
else:
neck_front = hit
have_hit = True
last_hit = hit
#iterate if multiples faces layers
while have_hit:
have_hit = False
hit, normal, index, distance = my_tree.ray_cast(last_hit + vectorize3([0,0.001,0]), ray_dir, ray_dir.magnitude)
if hit != None:
have_hit = True
last_hit = hit
neck_back = last_hit
if distance == None or distance < 0.001:
self.error_during_auto_detect = True
self.error_message = 'Could not find the neck, marker out of mesh?'
return
else:
neck_front = hit
have_hit = True
last_hit = hit
#iterate if multiples faces layers
while have_hit:
have_hit = False
hit, normal, index, distance = my_tree.ray_cast(last_hit+vectorize3([0,0.001,0]), ray_dir, ray_dir.magnitude)
if hit != None:
have_hit = True
last_hit = hit
neck_back = last_hit
neck_depth = neck_back[1] + (neck_front[1]-neck_back[1])*0.45
if scene.arp_smart_depth:
neck_depth = None
if scn.arp_smart_depth:
neck_depth = get_object('neck_loc').location[1]
else:
neck_depth = neck_back[1] + (neck_front[1]-neck_back[1])*0.45
neck_empty_loc = [neck_loc.location[0], neck_depth, neck_loc.location[2]]
# Spine 01
print("Find spine 01...\n")
@@ -6870,7 +6857,7 @@ def _auto_detect(self):
spine_01_back = last_hit
spine_01_empty_loc = spine_01_front + (spine_01_back-spine_01_front)*0.65
if scene.arp_smart_depth:
if scn.arp_smart_depth:
spine_01_empty_loc[1] = root_depth
@@ -6903,7 +6890,7 @@ def _auto_detect(self):
spine_02_back = last_hit
spine_02_empty_loc = spine_02_front + (spine_02_back-spine_02_front)*0.65
if scene.arp_smart_depth:
if scn.arp_smart_depth:
spine_02_empty_loc[1] = root_depth
# Breast
@@ -6929,7 +6916,7 @@ def _auto_detect(self):
spine_02_back = -1000
spine_02_front = 1000
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print(" Find breast boundaries...\n")
for vs in spine_02_selection:
@@ -6955,9 +6942,9 @@ def _auto_detect(self):
if chin_loc == None:# backward-compatibility, chin was not defined in earlier versions
head_height = neck_empty_loc[2] + (body_height - neck_empty_loc[2])*0.25
else:
if scene.arp_smart_type == 'BODY':
if scn.arp_smart_type == 'BODY':
head_height = chin_loc.location[2] + (chin_loc.location[2] - neck_loc.location[2])*0.2
elif scene.arp_smart_type == 'FACIAL':
elif scn.arp_smart_type == 'FACIAL':
head_height = chin_loc.location[2]
xpos = chin_loc.location[0]
@@ -7005,7 +6992,7 @@ def _auto_detect(self):
head_back = last_hit
mid_head_y = (head_front[1] + head_back[1]) * 0.5
head_loc_y = head_back[1] + (head_front[1] - head_back[1]) * 0.3 if scene.arp_smart_type == 'FACIAL' else (mid_head_y + neck_empty_loc[1])*0.5
head_loc_y = head_back[1] + (head_front[1] - head_back[1]) * 0.3 if scn.arp_smart_type == 'FACIAL' else (mid_head_y + neck_empty_loc[1])*0.5
head_empty_loc = [chin_loc.location[0], head_loc_y, head_height]
@@ -7014,7 +7001,7 @@ def _auto_detect(self):
body_top = None
head_top = None
if scene.arp_smart_type == 'FACIAL':# 'facial only' mode has no toes markers
if scn.arp_smart_type == 'FACIAL':# 'facial only' mode has no toes markers
body_top = body.bound_box[1][2]
else:
body_top = body_height + get_object('toes_end.l_auto').location[2]# add offset if feet above ground
@@ -7052,7 +7039,7 @@ def _auto_detect(self):
# create the empties
bpy.ops.object.mode_set(mode='OBJECT')
if scene.arp_smart_type == 'BODY':
if scn.arp_smart_type == 'BODY':
create_empty_loc(0.04, neck_empty_loc, "neck_loc")
create_empty_loc(0.04, spine_01_empty_loc, "spine_01_loc")
create_empty_loc(0.04, spine_02_empty_loc, "spine_02_loc")
@@ -7064,12 +7051,12 @@ def _auto_detect(self):
# restore pivot mode
scene.tool_settings.transform_pivot_point = pivot_mod
scn.tool_settings.transform_pivot_point = pivot_mod
# update hack
bpy.ops.transform.translate(value=(0, 0, 0))
if scene.arp_debug_mode:
if scn.arp_debug_mode:
print("End Auto-Detection.\n")
@@ -13,7 +13,6 @@ def sort_armature_collections(armature, only_collection=None, custom_collection=
# sort a specific custom collection with custom index
if custom_collection and to_index != None:
col = get_armature_collections(armature).get(custom_collection)
cur_idx = get_arm_col_idx(armature, custom_collection)
armature.data.collections.move(cur_idx, to_index)
return
@@ -24,9 +23,22 @@ def sort_armature_collections(armature, only_collection=None, custom_collection=
if only_collection != col_name:
continue
col = get_armature_collections(armature).get(col_name)
cur_idx = get_arm_col_idx(armature, col_name)
to_idx = order[col_name]
to_idx = order[col_name]
# check if collection is parented, if so, offset the index from the first sibling
col = get_armature_collections(armature).get(col_name)
if col.parent:
#print('Collection is parented:', col_name, 'get the first sibling index...')
first_idx = 1000000
for _c in get_armature_collections(armature):
if _c.parent == col.parent and _c.index < first_idx:
first_idx = _c.index
#print('First sibling is:', first_idx)
to_idx += first_idx
#print('Move from', cur_idx, 'to', to_idx)
armature.data.collections.move(cur_idx, to_idx)
@@ -339,12 +339,9 @@ def delete_fcurve(act, fc, slot_idx=0):
def get_action_fcurves(act, slot_idx=0, as_list=True):
if bpy.app.version >= (4,4,0):
if bpy.app.version >= (5,0,0):
cb = anim_utils.action_ensure_channelbag_for_slot(act, act.slots[slot_idx])
else:
cb = act.layers[0].strips[0].channelbag(act.slots[slot_idx])
if bpy.app.version >= (5,0,0):
cb = anim_utils.action_ensure_channelbag_for_slot(act, act.slots[slot_idx])
if cb:
if as_list:
return [_fc for _fc in cb.fcurves if _fc != None]# check for None curve, debug
@@ -7,6 +7,7 @@ from bpy.app.handlers import persistent
from . import auto_rig_datas as ard
from . import reset_all_controllers
from operator import itemgetter
from bpy_extras import anim_utils
# Global vars
@@ -25,6 +26,31 @@ toes_start = ["c_toes_thumb", "c_toes_index", "c_toes_middle", "c_toes_ring", "c
spines_ctrls = ['c_spine_', 'c_root', 'c_chest']
def delete_fcurve(act, fc, slot_idx=0):
if bpy.app.version >= (5,0,0):
cb = anim_utils.action_ensure_channelbag_for_slot(act, act.slots[slot_idx])
cb.fcurves.remove(fc)
else:
act.fcurves.remove(fc)
def create_fcurve(act, dp, slot_idx=0, fc_index=0, action_group=''):
if bpy.app.version >= (5,0,0):
cb = anim_utils.action_ensure_channelbag_for_slot(act, act.slots[slot_idx])
return cb.fcurves.new(dp, index=fc_index, group_name=action_group)
else:
return act.fcurves.new(dp, index=fc_index, action_group=action_group)
def find_fcurve(act, dp, slot_idx=0, fc_index=0):
if bpy.app.version >= (5,0,0):
cb = anim_utils.action_get_channelbag_for_slot(act, act.slots[slot_idx])
if cb == None: return None
return cb.fcurves.find(dp, index=fc_index)
else:
return act.fcurves.find(data_path=dp, index=fc_index)
def is_pbone_selected(pbone):
if bpy.app.version >= (5,0,0):
return pbone.select
@@ -239,12 +265,18 @@ def update_layer_set_exclusive(self, context):
eb.hide = False
elif bpy.context.mode == "POSE" or bpy.context.mode == "OBJECT":
for db in rig.data.bones:
for pb in rig.pose.bones:
if self.exclusive_toggle:
if not db.name in bones_list:
db.hide = True
if not pb.name in bones_list:
if bpy.app.version >= (5,0,0):
pb.hide = True
else:
pb.bone.hide = True
else:
db.hide = False
if bpy.app.version >= (5,0,0):
pb.hide = False
else:
pb.bone.hide = False
# for now, multiple exclusive layers is not possible, maybe todo later
@@ -2864,9 +2896,9 @@ def keyframe_pb_transforms(pb, loc=True, rot=True, scale=True, keyf_locked=False
dp = 'pose.bones["'+pb.name+'"].location'
for i in range(0,3):
fcurve = action.fcurves.find(dp, index=i)
fcurve = find_fcurve(action, dp, fc_index=i)#action.fcurves.find(dp, index=i)
if fcurve == None:
fcurve = action.fcurves.new(dp, index=i, action_group=pb.name)
fcurve = create_fcurve(action, dp, fc_index=i, action_group=pb.name)#action.fcurves.new(dp, index=i, action_group=pb.name)
fcurve.keyframe_points.insert(bpy.context.scene.frame_current, pb.location[i])
else:
@@ -2878,9 +2910,9 @@ def keyframe_pb_transforms(pb, loc=True, rot=True, scale=True, keyf_locked=False
dp = 'pose.bones["'+pb.name+'"].rotation_euler'
for i in range(0,3):
fcurve = action.fcurves.find(dp, index=i)
fcurve = find_fcurve(action, dp, fc_index=i)#action.fcurves.find(dp, index=i)
if fcurve == None:
fcurve = action.fcurves.new(dp, index=i, action_group=pb.name)
fcurve = create_fcurve(action, dp, fc_index=i, action_group=pb.name)#action.fcurves.new(dp, index=i, action_group=pb.name)
fcurve.keyframe_points.insert(bpy.context.scene.frame_current, pb.rotation_euler[i])
else:
@@ -2902,13 +2934,14 @@ def insert_keyframes(action, keyframes, start=0, end=10):
for bone_name in keyframes:
dico = keyframes[bone_name]
for fc_key, key_values in dico.items():
data_path, _index = fc_key
fcurve = action.fcurves.find(data_path=data_path, index=_index)
data_path, _index = fc_key
fcurve = find_fcurve(action, data_path, fc_index=_index)#action.fcurves.find(data_path=data_path, index=_index)
curr_fc_keyf_data = []
if fcurve:
curr_fc_keyf_data = [get_keyf_data(key) for key in fcurve.keyframe_points]
action.fcurves.remove(fcurve)
fcurve = action.fcurves.new(data_path, index=_index, action_group=bone_name)
delete_fcurve(action, fcurve)
#action.fcurves.remove(fcurve)
fcurve = create_fcurve(action, data_path, fc_index=_index, action_group=bone_name)#action.fcurves.new(data_path, index=_index, action_group=bone_name)
# set keyframes points
num_keys = len(key_values) // 2
@@ -3502,9 +3535,14 @@ def set_layer_vis(self, state):
b.hide = not state
elif bpy.context.mode == "POSE" or bpy.context.mode == "OBJECT":
b = get_data_bone(bname)
if b:
b.hide = not state
if bpy.app.version >= (5,0,0):
pb = get_pose_bone(bname)
if pb:
pb.hide = not state
else:
b = get_data_bone(bname)
if b:
b.hide = not state
# set object collection visibility
@@ -3793,11 +3831,11 @@ def _extract_root_motion(self):
rot = traj_rot
if self.rotation:
target_vec = None
if self.forward_axis == 'X':
if 'X' in self.forward_axis:
target_vec = c_root_pb.x_axis if self.root_type == 'ROOT_MASTER' else -c_root_pb.x_axis
elif self.forward_axis == 'Y':
elif 'Y' in self.forward_axis:
target_vec = c_root_pb.y_axis if self.root_type == 'ROOT_MASTER' else -c_root_pb.y_axis
elif self.forward_axis == 'Z':
elif 'Z' in self.forward_axis:
target_vec = c_root_pb.z_axis if self.root_type == 'ROOT_MASTER' else -c_root_pb.z_axis
if '-' in self.forward_axis:
@@ -6486,6 +6524,9 @@ def _snap_limb_lock(self, add_keyframe=False):
update_transform()
# ensure location remains zeroed out
c_limb_fk.location = [0,0,0]
#insert keyframe if autokey enable
if bpy.context.scene.tool_settings.use_keyframe_insert_auto or add_keyframe:
c_prop_bone.keyframe_insert(data_path='["'+prop_name+'"]')
@@ -6738,7 +6779,7 @@ def convert_rot_mode(self):
current_mode = pb.rotation_mode
pb_path = pb.path_from_id()
fc_data_path = pb_path+'.rotation_quaternion' if current_mode == 'QUATERNION' else pb_path+'.rotation_euler'
fc = armature.animation_data.action.fcurves.find(fc_data_path)
fc = find_fcurve(armature.animation_data.action, fc_data_path)#armature.animation_data.action.fcurves.find(fc_data_path)
if fc == None and self.selected_only == False:# only animated bones, otherwise could insert keyframes on unwanted bones (rig mechanics)
continue