1 # SPDX-License-Identifier: GPL-2.0-or-later
4 from bpy
.props
import (
11 from typing
import TYPE_CHECKING
, Callable
12 from mathutils
import Color
14 from .utils
.errors
import MetarigError
15 from .utils
.rig
import write_metarig
, get_rigify_type
, get_rigify_target_rig
, get_rigify_layers
, \
16 get_rigify_colors
, get_rigify_params
17 from .utils
.widgets
import write_widget
18 from .utils
.naming
import unique_name
19 from .utils
.rig
import upgrade_metarig_types
, outdated_types
20 from .utils
.misc
import verify_armature_obj
, ArmatureObject
, IdPropSequence
22 from .rigs
.utils
import get_limb_generated_names
24 from .utils
.animation
import get_keyed_frames_in_range
, bones_in_frame
, overwrite_prop_animation
25 from .utils
.animation
import RIGIFY_OT_get_frame_range
27 from .utils
.animation
import register
as animation_register
28 from .utils
.animation
import unregister
as animation_unregister
30 from . import base_rig
31 from . import rig_lists
32 from . import generate
33 from . import rot_mode
34 from . import feature_set_list
37 from . import RigifyName
, RigifySelectionColors
40 def get_rigify_types(id_store
: bpy
.types
.WindowManager
) -> IdPropSequence
['RigifyName']:
41 return id_store
.rigify_types
# noqa
44 def get_transfer_only_selected(id_store
: bpy
.types
.WindowManager
) -> bool:
45 return id_store
.rigify_transfer_only_selected
# noqa
48 def get_selection_colors(armature
: bpy
.types
.Armature
) -> 'RigifySelectionColors':
49 return armature
.rigify_selection_colors
# noqa
52 def get_colors_lock(armature
: bpy
.types
.Armature
) -> bool:
53 return armature
.rigify_colors_lock
# noqa
56 def get_colors_index(armature
: bpy
.types
.Armature
) -> int:
57 return armature
.rigify_colors_index
# noqa
60 def get_theme_to_add(armature
: bpy
.types
.Armature
) -> str:
61 return armature
.rigify_theme_to_add
# noqa
64 def build_type_list(context
, rigify_types
: IdPropSequence
['RigifyName']):
67 for r
in sorted(rig_lists
.rigs
):
68 if (context
.object.data
.active_feature_set
in ('all', rig_lists
.rigs
[r
]['feature_set'])
69 or len(feature_set_list
.get_enabled_modules_names()) == 0):
70 a
= rigify_types
.add()
74 # noinspection PyPep8Naming
75 class DATA_PT_rigify(bpy
.types
.Panel
):
77 bl_space_type
= 'PROPERTIES'
78 bl_region_type
= 'WINDOW'
82 def poll(cls
, context
):
84 if not context
.object:
86 return obj
.type == 'ARMATURE' \
87 and obj
.data
.get("rig_id") is None
89 def draw(self
, context
):
92 obj
= verify_armature_obj(C
.object)
94 WARNING
= "Warning: Some features may change after generation"
96 show_update_metarig
= False
97 show_not_updatable
= False
98 show_upgrade_face
= False
100 check_props
= ['IK_follow', 'root/parent', 'FK_limb_follow', 'IK_Stretch']
102 for pose_bone
in obj
.pose
.bones
:
103 bone
= pose_bone
.bone
105 # If we are in edit mode and the bone was just created,
106 # a pose bone won't exist yet.
108 if bone
.layers
[30] and (list(set(pose_bone
.keys()) & set(check_props
))):
115 for b
in obj
.pose
.bones
:
116 old_rig
= get_rigify_type(b
)
117 if old_rig
in outdated_types
:
119 if outdated_types
[old_rig
]:
120 show_update_metarig
= True
122 show_update_metarig
= False
123 show_not_updatable
= True
125 elif old_rig
== 'faces.super_face':
126 show_upgrade_face
= True
129 layout
.label(text
=WARNING
, icon
='ERROR')
131 enable_generate
= not (show_not_updatable
or show_update_metarig
)
133 if show_not_updatable
:
134 layout
.label(text
="WARNING: This metarig contains deprecated rigify rig-types and "
135 "cannot be upgraded automatically.", icon
='ERROR')
136 layout
.label(text
="(" + old_rig
+ " on bone " + old_bone
+ ")")
137 elif show_update_metarig
:
138 layout
.label(text
="This metarig contains old rig-types that can be automatically "
139 "upgraded to benefit from new rigify features.", icon
='ERROR')
140 layout
.label(text
="(" + old_rig
+ " on bone " + old_bone
+ ")")
141 layout
.operator("pose.rigify_upgrade_types", text
="Upgrade Metarig")
142 elif show_upgrade_face
:
143 layout
.label(text
="This metarig uses the old face rig.", icon
='INFO')
144 layout
.operator("pose.rigify_upgrade_face")
148 col
= layout
.column(align
=True)
149 col
.active
= ('rig_id' not in C
.object.data
)
153 text
= "Re-Generate Rig" if get_rigify_target_rig(obj
.data
) else "Generate Rig"
154 row
.operator("pose.rigify_generate", text
=text
, icon
='POSE_HLT')
155 row
.enabled
= enable_generate
158 # noinspection PyPep8Naming
159 class DATA_PT_rigify_advanced(bpy
.types
.Panel
):
160 bl_space_type
= 'PROPERTIES'
161 bl_region_type
= 'WINDOW'
163 bl_label
= "Advanced"
164 bl_parent_id
= 'DATA_PT_rigify'
165 bl_options
= {'DEFAULT_CLOSED'}
167 def draw(self
, context
):
169 layout
.use_property_split
= True
170 layout
.use_property_decorate
= False
172 armature_id_store
= verify_armature_obj(context
.object).data
174 col
= layout
.column()
177 row
.active
= not get_rigify_target_rig(armature_id_store
)
178 row
.prop(armature_id_store
, "rigify_rig_basename", text
="Rig Name")
182 col2
= col
.box().column()
183 col2
.label(text
="Overwrite Existing:")
184 col2
.row().prop(armature_id_store
, "rigify_target_rig", text
="Target Rig")
185 col2
.row().prop(armature_id_store
, "rigify_rig_ui", text
="Rig UI Script")
186 col2
.row().prop(armature_id_store
, "rigify_widgets_collection")
189 col
.row().prop(armature_id_store
, "rigify_force_widget_update")
190 col
.row().prop(armature_id_store
, "rigify_mirror_widgets")
192 col
.row().prop(armature_id_store
, "rigify_finalize_script", text
="Run Script")
195 # noinspection PyPep8Naming
196 class DATA_PT_rigify_samples(bpy
.types
.Panel
):
198 bl_space_type
= 'PROPERTIES'
199 bl_region_type
= 'WINDOW'
201 bl_parent_id
= "DATA_PT_rigify"
202 bl_options
= {'DEFAULT_CLOSED'}
205 def poll(cls
, context
):
209 return obj
.type == 'ARMATURE' \
210 and obj
.data
.get("rig_id") is None \
211 and obj
.mode
== 'EDIT'
213 def draw(self
, context
):
215 layout
.use_property_split
= True
216 layout
.use_property_decorate
= False
217 id_store
= context
.window_manager
220 rigify_types
= get_rigify_types(id_store
)
221 build_type_list(context
, rigify_types
)
223 if id_store
.rigify_active_type
> len(rigify_types
):
224 id_store
.rigify_active_type
= 0
227 if len(feature_set_list
.get_enabled_modules_names()) > 0:
229 row
.prop(context
.object.data
, "active_feature_set")
231 row
.template_list("UI_UL_list", "rigify_types", id_store
, "rigify_types", id_store
, 'rigify_active_type')
233 props
= layout
.operator("armature.metarig_sample_add", text
="Add sample")
234 props
.metarig_type
= rigify_types
[id_store
.rigify_active_type
].name
237 # noinspection PyPep8Naming
238 class DATA_PT_rigify_layer_names(bpy
.types
.Panel
):
239 bl_label
= "Layer Names"
240 bl_space_type
= 'PROPERTIES'
241 bl_region_type
= 'WINDOW'
243 bl_options
= {'DEFAULT_CLOSED'}
244 bl_parent_id
= "DATA_PT_rigify"
247 def poll(cls
, context
):
248 if not context
.object:
250 return context
.object.type == 'ARMATURE' and context
.active_object
.data
.get("rig_id") is None
252 def draw(self
, context
):
254 obj
= verify_armature_obj(context
.object)
257 rigify_layers
= get_rigify_layers(arm
)
258 rigify_colors
= get_rigify_colors(arm
)
260 # Ensure that the layers exist
261 if len(rigify_layers
) < 29:
262 layout
.operator("pose.rigify_layer_init")
266 main_row
= layout
.row(align
=True).split(factor
=0.05)
267 col1
= main_row
.column()
268 col2
= main_row
.column()
271 if i
== 16 or i
== 29:
273 col1
.label(text
=str(i
))
275 col
: bpy
.types
.UILayout
= col2
277 for i
, rigify_layer
in enumerate(rigify_layers
):
278 # note: rigify_layer == arm.rigify_layers[i]
282 col
.label(text
="Top Row:")
284 col
.label(text
="Bottom Row:")
288 row
= col
.row(align
=True)
289 icon
= 'RESTRICT_VIEW_OFF' if arm
.layers
[i
] else 'RESTRICT_VIEW_ON'
290 row
.prop(arm
, "layers", index
=i
, text
="", toggle
=True, icon
=icon
)
291 # row.prop(arm, "layers", index=i, text="Layer %d" % (i + 1), toggle=True, icon=icon)
292 row
.prop(rigify_layer
, "name", text
="")
293 row
.prop(rigify_layer
, "row", text
="UI Row")
294 icon
= 'RADIOBUT_ON' if rigify_layer
.selset
else 'RADIOBUT_OFF'
295 row
.prop(rigify_layer
, "selset", text
="", toggle
=True, icon
=icon
)
296 row
.prop(rigify_layer
, "group", text
="Bone Group")
298 row
= col
.row(align
=True)
300 icon
= 'RESTRICT_VIEW_OFF' if arm
.layers
[i
] else 'RESTRICT_VIEW_ON'
301 row
.prop(arm
, "layers", index
=i
, text
="", toggle
=True, icon
=icon
)
302 # row.prop(arm, "layers", index=i, text="Layer %d" % (i + 1), toggle=True, icon=icon)
303 row1
= row
.split(align
=True).row(align
=True)
304 row1
.prop(rigify_layer
, "name", text
="")
305 row1
.prop(rigify_layer
, "row", text
="UI Row")
307 icon
= 'RADIOBUT_ON' if rigify_layer
.selset
else 'RADIOBUT_OFF'
308 row
.prop(rigify_layer
, "selset", text
="", toggle
=True, icon
=icon
)
309 row
.prop(rigify_layer
, "group", text
="Bone Group")
310 if rigify_layer
.group
== 0:
311 row
.label(text
='None')
313 row
.label(text
=rigify_colors
[rigify_layer
.group
-1].name
)
316 col
.label(text
="Reserved:")
317 # reserved_names = {28: 'Root', 29: 'DEF', 30: 'MCH', 31: 'ORG'}
318 reserved_names
= {29: 'DEF', 30: 'MCH', 31: 'ORG'}
319 # for i in range(28, 32):
320 for i
in range(29, 32):
321 row
= col
.row(align
=True)
322 icon
= 'RESTRICT_VIEW_OFF' if arm
.layers
[i
] else 'RESTRICT_VIEW_ON'
323 row
.prop(arm
, "layers", index
=i
, text
="", toggle
=True, icon
=icon
)
324 row
.label(text
=reserved_names
[i
])
327 # noinspection PyPep8Naming
328 class DATA_OT_rigify_add_bone_groups(bpy
.types
.Operator
):
329 bl_idname
= "armature.rigify_add_bone_groups"
330 bl_label
= "Rigify Add Standard Bone Groups"
333 def poll(cls
, context
):
334 return context
.object and context
.object.type == 'ARMATURE'
336 def execute(self
, context
):
337 obj
= verify_armature_obj(context
.object)
340 if not hasattr(armature
, 'rigify_colors'):
343 rigify_colors
= get_rigify_colors(armature
)
344 groups
= ['Root', 'IK', 'Special', 'Tweak', 'FK', 'Extra']
347 if g
in rigify_colors
:
350 color
= rigify_colors
.add()
353 color
.select
= Color((0.3140000104904175, 0.7839999794960022, 1.0))
354 color
.active
= Color((0.5490000247955322, 1.0, 1.0))
355 color
.standard_colors_lock
= True
358 color
.normal
= Color((0.43529415130615234, 0.18431372940540314, 0.41568630933761597))
360 color
.normal
= Color((0.6039215922355652, 0.0, 0.0))
362 color
.normal
= Color((0.9568628072738647, 0.7882353663444519, 0.0470588281750679))
364 color
.normal
= Color((0.03921568766236305, 0.21176472306251526, 0.5803921818733215))
366 color
.normal
= Color((0.11764706671237946, 0.5686274766921997, 0.03529411926865578))
368 color
.normal
= Color((0.9686275124549866, 0.250980406999588, 0.0941176563501358))
373 # noinspection PyPep8Naming
374 class DATA_OT_rigify_use_standard_colors(bpy
.types
.Operator
):
375 bl_idname
= "armature.rigify_use_standard_colors"
376 bl_label
= "Rigify Get active/select colors from current theme"
379 def poll(cls
, context
):
380 return context
.object and context
.object.type == 'ARMATURE'
382 def execute(self
, context
):
383 obj
= verify_armature_obj(context
.object)
385 if not hasattr(armature
, 'rigify_colors'):
388 current_theme
= bpy
.context
.preferences
.themes
.items()[0][0]
389 theme
= bpy
.context
.preferences
.themes
[current_theme
]
391 selection_colors
= get_selection_colors(armature
)
392 selection_colors
.select
= theme
.view_3d
.bone_pose
393 selection_colors
.active
= theme
.view_3d
.bone_pose_active
395 # for col in armature.rigify_colors:
396 # col.select = theme.view_3d.bone_pose
397 # col.active = theme.view_3d.bone_pose_active
402 # noinspection PyPep8Naming
403 class DATA_OT_rigify_apply_selection_colors(bpy
.types
.Operator
):
404 bl_idname
= "armature.rigify_apply_selection_colors"
405 bl_label
= "Rigify Apply user defined active/select colors"
408 def poll(cls
, context
):
409 return context
.object and context
.object.type == 'ARMATURE'
411 def execute(self
, context
):
412 obj
= verify_armature_obj(context
.object)
415 if not hasattr(armature
, 'rigify_colors'):
418 # current_theme = bpy.context.preferences.themes.items()[0][0]
419 # theme = bpy.context.preferences.themes[current_theme]
421 rigify_colors
= get_rigify_colors(armature
)
422 selection_colors
= get_selection_colors(armature
)
424 for col
in rigify_colors
:
425 col
.select
= selection_colors
.select
426 col
.active
= selection_colors
.active
431 # noinspection PyPep8Naming
432 class DATA_OT_rigify_bone_group_add(bpy
.types
.Operator
):
433 bl_idname
= "armature.rigify_bone_group_add"
434 bl_label
= "Rigify Add Bone Group color set"
437 def poll(cls
, context
):
438 return context
.object and context
.object.type == 'ARMATURE'
440 def execute(self
, context
):
444 if hasattr(armature
, 'rigify_colors'):
445 armature
.rigify_colors
.add()
446 armature
.rigify_colors
[-1].name
= unique_name(armature
.rigify_colors
, 'Group')
448 current_theme
= bpy
.context
.preferences
.themes
.items()[0][0]
449 theme
= bpy
.context
.preferences
.themes
[current_theme
]
451 armature
.rigify_colors
[-1].normal
= theme
.view_3d
.wire
452 armature
.rigify_colors
[-1].normal
.hsv
= theme
.view_3d
.wire
.hsv
453 armature
.rigify_colors
[-1].select
= theme
.view_3d
.bone_pose
454 armature
.rigify_colors
[-1].select
.hsv
= theme
.view_3d
.bone_pose
.hsv
455 armature
.rigify_colors
[-1].active
= theme
.view_3d
.bone_pose_active
456 armature
.rigify_colors
[-1].active
.hsv
= theme
.view_3d
.bone_pose_active
.hsv
461 # noinspection PyPep8Naming
462 class DATA_OT_rigify_bone_group_add_theme(bpy
.types
.Operator
):
463 bl_idname
= "armature.rigify_bone_group_add_theme"
464 bl_label
= "Rigify Add Bone Group color set from Theme"
465 bl_options
= {"REGISTER", "UNDO"}
467 theme
: EnumProperty(items
=(
468 ('THEME01', 'THEME01', ''),
469 ('THEME02', 'THEME02', ''),
470 ('THEME03', 'THEME03', ''),
471 ('THEME04', 'THEME04', ''),
472 ('THEME05', 'THEME05', ''),
473 ('THEME06', 'THEME06', ''),
474 ('THEME07', 'THEME07', ''),
475 ('THEME08', 'THEME08', ''),
476 ('THEME09', 'THEME09', ''),
477 ('THEME10', 'THEME10', ''),
478 ('THEME11', 'THEME11', ''),
479 ('THEME12', 'THEME12', ''),
480 ('THEME13', 'THEME13', ''),
481 ('THEME14', 'THEME14', ''),
482 ('THEME15', 'THEME15', ''),
483 ('THEME16', 'THEME16', ''),
484 ('THEME17', 'THEME17', ''),
485 ('THEME18', 'THEME18', ''),
486 ('THEME19', 'THEME19', ''),
487 ('THEME20', 'THEME20', '')
492 def poll(cls
, context
):
493 return context
.object and context
.object.type == 'ARMATURE'
495 def execute(self
, context
):
496 obj
= verify_armature_obj(context
.object)
499 if hasattr(armature
, 'rigify_colors'):
500 rigify_colors
= get_rigify_colors(armature
)
502 if self
.theme
in rigify_colors
.keys():
506 rigify_colors
[-1].name
= self
.theme
508 color_id
= int(self
.theme
[-2:]) - 1
510 theme_color_set
= bpy
.context
.preferences
.themes
[0].bone_color_sets
[color_id
]
512 rigify_colors
[-1].normal
= theme_color_set
.normal
513 rigify_colors
[-1].select
= theme_color_set
.select
514 rigify_colors
[-1].active
= theme_color_set
.active
519 # noinspection PyPep8Naming
520 class DATA_OT_rigify_bone_group_remove(bpy
.types
.Operator
):
521 bl_idname
= "armature.rigify_bone_group_remove"
522 bl_label
= "Rigify Remove Bone Group color set"
527 def poll(cls
, context
):
528 return context
.object and context
.object.type == 'ARMATURE'
530 def execute(self
, context
):
531 obj
= verify_armature_obj(context
.object)
533 rigify_colors
= get_rigify_colors(obj
.data
)
534 rigify_colors
.remove(self
.idx
)
536 # set layers references to 0
537 rigify_layers
= get_rigify_layers(obj
.data
)
539 for layer
in rigify_layers
:
540 if layer
.group
== self
.idx
+ 1:
542 elif layer
.group
> self
.idx
+ 1:
548 # noinspection PyPep8Naming
549 class DATA_OT_rigify_bone_group_remove_all(bpy
.types
.Operator
):
550 bl_idname
= "armature.rigify_bone_group_remove_all"
551 bl_label
= "Rigify Remove All Bone Groups"
554 def poll(cls
, context
):
555 return context
.object and context
.object.type == 'ARMATURE'
557 def execute(self
, context
):
558 obj
= verify_armature_obj(context
.object)
560 rigify_colors
= get_rigify_colors(obj
.data
)
561 while len(rigify_colors
) > 0:
562 rigify_colors
.remove(0)
564 # set layers references to 0
565 for layer
in get_rigify_layers(obj
.data
):
571 # noinspection PyPep8Naming
572 class DATA_UL_rigify_bone_groups(bpy
.types
.UIList
):
573 def draw_item(self
, context
, layout
, data
, item
, icon
, active_data
, active_propname
, index
=0, flt_flag
=0):
574 row
= layout
.row(align
=True)
575 row
= row
.split(factor
=0.1)
576 row
.label(text
=str(index
+1))
577 row
= row
.split(factor
=0.7)
578 row
.prop(item
, "name", text
='', emboss
=False)
579 row
= row
.row(align
=True)
580 # icon = 'LOCKED' if item.standard_colors_lock else 'UNLOCKED'
581 # row.prop(item, "standard_colors_lock", text='', icon=icon)
582 row
.prop(item
, "normal", text
='')
583 row2
= row
.row(align
=True)
584 row2
.prop(item
, "select", text
='')
585 row2
.prop(item
, "active", text
='')
586 # row2.enabled = not item.standard_colors_lock
587 arm
= verify_armature_obj(context
.object).data
588 row2
.enabled
= not get_colors_lock(arm
)
591 # noinspection PyPep8Naming
592 class DATA_MT_rigify_bone_groups_context_menu(bpy
.types
.Menu
):
593 bl_label
= 'Rigify Bone Groups Specials'
595 def draw(self
, context
):
598 layout
.operator('armature.rigify_bone_group_remove_all')
601 # noinspection PyPep8Naming
602 class DATA_PT_rigify_bone_groups(bpy
.types
.Panel
):
603 bl_label
= "Bone Groups"
604 bl_space_type
= 'PROPERTIES'
605 bl_region_type
= 'WINDOW'
607 bl_options
= {'DEFAULT_CLOSED'}
608 bl_parent_id
= "DATA_PT_rigify"
611 def poll(cls
, context
):
612 if not context
.object:
614 return context
.object.type == 'ARMATURE' and context
.active_object
.data
.get("rig_id") is None
616 def draw(self
, context
):
617 obj
= verify_armature_obj(context
.object)
619 idx
= get_colors_index(armature
)
620 selection_colors
= get_selection_colors(armature
)
621 is_locked
= get_colors_lock(armature
)
622 theme
= get_theme_to_add(armature
)
626 row
.operator("armature.rigify_use_standard_colors", icon
='FILE_REFRESH', text
='')
627 row
= row
.row(align
=True)
628 row
.prop(selection_colors
, 'select', text
='')
629 row
.prop(selection_colors
, 'active', text
='')
630 row
= layout
.row(align
=True)
631 icon
= 'LOCKED' if is_locked
else 'UNLOCKED'
632 row
.prop(armature
, 'rigify_colors_lock', text
='Unified select/active colors', icon
=icon
)
633 row
.operator("armature.rigify_apply_selection_colors", icon
='FILE_REFRESH', text
='Apply')
635 row
.template_list("DATA_UL_rigify_bone_groups", "", obj
.data
, "rigify_colors", obj
.data
, "rigify_colors_index")
637 col
= row
.column(align
=True)
638 col
.operator("armature.rigify_bone_group_add", icon
='ADD', text
="")
639 col
.operator("armature.rigify_bone_group_remove", icon
='REMOVE', text
="").idx
= idx
640 col
.menu("DATA_MT_rigify_bone_groups_context_menu", icon
='DOWNARROW_HLT', text
="")
642 row
.prop(armature
, 'rigify_theme_to_add', text
='Theme')
643 op
= row
.operator("armature.rigify_bone_group_add_theme", text
="Add From Theme")
646 row
.operator("armature.rigify_add_bone_groups", text
="Add Standard")
649 # noinspection PyPep8Naming
650 class BONE_PT_rigify_buttons(bpy
.types
.Panel
):
651 bl_label
= "Rigify Type"
652 bl_space_type
= 'PROPERTIES'
653 bl_region_type
= 'WINDOW'
655 # bl_options = {'DEFAULT_OPEN'}
658 def poll(cls
, context
):
659 if not context
.object:
661 return (context
.object.type == 'ARMATURE' and context
.active_pose_bone
and
662 context
.active_object
.data
.get("rig_id") is None)
664 def draw(self
, context
):
666 id_store
= C
.window_manager
667 bone
= context
.active_pose_bone
668 rig_name
= get_rigify_type(bone
)
671 rig_types
= get_rigify_types(id_store
)
674 build_type_list(context
, rig_types
)
677 if len(feature_set_list
.get_enabled_modules_names()) > 0:
679 row
.prop(context
.object.data
, "active_feature_set")
681 row
.prop_search(bone
, "rigify_type", id_store
, "rigify_types", text
="Rig type")
683 # Rig type parameters / Rig type non-exist alert
686 rig
= rig_lists
.rigs
[rig_name
]['module']
687 except (ImportError, AttributeError, KeyError):
690 box
.label(text
="ERROR: type \"%s\" does not exist!" % rig_name
, icon
='ERROR')
692 if hasattr(rig
.Rig
, 'parameters_ui'):
696 param_cb
= rig
.parameters_ui
698 # Ignore the known empty base method
699 if getattr(param_cb
, '__func__', None) == \
700 getattr(base_rig
.BaseRig
.parameters_ui
, '__func__'):
702 except AttributeError:
706 col
= layout
.column()
707 col
.label(text
="No options")
709 col
= layout
.column()
710 col
.label(text
="Options:")
712 param_cb(box
, get_rigify_params(bone
))
715 # noinspection PyPep8Naming
716 class VIEW3D_PT_tools_rigify_dev(bpy
.types
.Panel
):
717 bl_label
= "Rigify Dev Tools"
718 bl_space_type
= 'VIEW_3D'
719 bl_region_type
= 'UI'
720 bl_category
= "Rigify"
723 def poll(cls
, context
):
724 return context
.mode
in ['EDIT_ARMATURE', 'EDIT_MESH']
726 def draw(self
, context
):
727 obj
= context
.active_object
729 if context
.mode
== 'EDIT_ARMATURE':
730 r
= self
.layout
.row()
731 r
.operator("armature.rigify_encode_metarig", text
="Encode Metarig to Python")
732 r
= self
.layout
.row()
733 r
.operator("armature.rigify_encode_metarig_sample", text
="Encode Sample to Python")
735 if context
.mode
== 'EDIT_MESH':
736 r
= self
.layout
.row()
737 r
.operator("mesh.rigify_encode_mesh_widget", text
="Encode Mesh Widget to Python")
740 # noinspection PyPep8Naming
741 class VIEW3D_PT_rigify_animation_tools(bpy
.types
.Panel
):
742 bl_label
= "Rigify Animation Tools"
743 bl_context
= "posemode" # noqa
744 bl_space_type
= 'VIEW_3D'
745 bl_region_type
= 'UI'
746 bl_category
= "Rigify"
749 def poll(cls
, context
):
750 obj
= context
.active_object
751 if obj
and obj
.type == 'ARMATURE':
752 rig_id
= obj
.data
.get("rig_id")
753 if rig_id
is not None:
754 has_arm
= hasattr(bpy
.types
, 'POSE_OT_rigify_arm_ik2fk_' + rig_id
)
755 has_leg
= hasattr(bpy
.types
, 'POSE_OT_rigify_leg_ik2fk_' + rig_id
)
756 return has_arm
or has_leg
760 def draw(self
, context
):
761 obj
= context
.active_object
762 id_store
= context
.window_manager
764 row
= self
.layout
.row()
766 only_selected
= get_transfer_only_selected(id_store
)
769 icon
= 'OUTLINER_DATA_ARMATURE'
771 icon
= 'ARMATURE_DATA'
773 row
.prop(id_store
, 'rigify_transfer_only_selected', toggle
=True, icon
=icon
)
775 row
= self
.layout
.row(align
=True)
776 row
.operator("rigify.ik2fk", text
='IK2FK Pose', icon
='SNAP_ON')
777 row
.operator("rigify.fk2ik", text
='FK2IK Pose', icon
='SNAP_ON')
779 row
= self
.layout
.row(align
=True)
780 row
.operator("rigify.transfer_fk_to_ik", text
='IK2FK Action', icon
='ACTION_TWEAK')
781 row
.operator("rigify.transfer_ik_to_fk", text
='FK2IK Action', icon
='ACTION_TWEAK')
783 row
= self
.layout
.row(align
=True)
784 row
.operator("rigify.clear_animation", text
="Clear IK Action", icon
='CANCEL').anim_type
= "IK"
785 row
.operator("rigify.clear_animation", text
="Clear FK Action", icon
='CANCEL').anim_type
= "FK"
787 row
= self
.layout
.row(align
=True)
788 op
= row
.operator("rigify.rotation_pole", icon
='FORCE_HARMONIC', text
='Switch to pole')
792 op
= row
.operator("rigify.rotation_pole", icon
='FORCE_MAGNETIC', text
='Switch to rotation')
796 RIGIFY_OT_get_frame_range
.draw_range_ui(context
, self
.layout
)
799 def rigify_report_exception(operator
, exception
):
803 # find the non-utils module name where the error happened
804 # hint, this is the metarig type!
805 _exception_type
, _exception_value
, exception_traceback
= sys
.exc_info()
806 fns
= [item
.filename
for item
in traceback
.extract_tb(exception_traceback
)]
807 fns_rig
= [fn
for fn
in fns
if os
.path
.basename(os
.path
.dirname(fn
)) != 'utils']
809 fn
= os
.path
.basename(fn
)
810 fn
= os
.path
.splitext(fn
)[0]
812 if fn
.startswith("__"):
813 message
.append("Incorrect armature...")
815 message
.append("Incorrect armature for type '%s'" % fn
)
816 message
.append(exception
.message
)
818 message
.reverse() # XXX - stupid! menu's are upside down!
820 operator
.report({'ERROR'}, '\n'.join(message
))
823 class LayerInit(bpy
.types
.Operator
):
824 """Initialize armature rigify layers"""
826 bl_idname
= "pose.rigify_layer_init"
827 bl_label
= "Add Rigify Layers"
828 bl_options
= {'UNDO', 'INTERNAL'}
830 def execute(self
, context
):
831 obj
= verify_armature_obj(context
.object)
833 rigify_layers
= get_rigify_layers(arm
)
834 for i
in range(1 + len(rigify_layers
), 30):
836 rigify_layers
[28].name
= 'Root'
837 rigify_layers
[28].row
= 14
842 if not (obj
and obj
.data
and obj
.type == 'ARMATURE'):
844 if 'rig_id' in obj
.data
:
846 for b
in obj
.pose
.bones
:
847 if b
.rigify_type
!= "":
852 class Generate(bpy
.types
.Operator
):
853 """Generates a rig from the active metarig armature"""
855 bl_idname
= "pose.rigify_generate"
856 bl_label
= "Rigify Generate Rig"
857 bl_options
= {'UNDO'}
858 bl_description
= 'Generates a rig from the active metarig armature'
861 def poll(cls
, context
):
862 return is_metarig(context
.object)
864 def execute(self
, context
):
865 metarig
= verify_armature_obj(context
.object)
867 generate
.generate_rig(context
, metarig
)
868 except MetarigError
as rig_exception
:
870 traceback
.print_exc()
872 rigify_report_exception(self
, rig_exception
)
873 except Exception as rig_exception
:
875 traceback
.print_exc()
877 self
.report({'ERROR'}, 'Generation has thrown an exception: ' + str(rig_exception
))
879 target_rig
= get_rigify_target_rig(metarig
.data
)
880 self
.report({'INFO'}, f
'Successfully generated: "{target_rig.name}"')
882 bpy
.ops
.object.mode_set(mode
='OBJECT')
887 class UpgradeMetarigTypes(bpy
.types
.Operator
):
888 """Upgrades metarig bones rigify_types"""
890 bl_idname
= "pose.rigify_upgrade_types"
891 bl_label
= "Rigify Upgrade Metarig Types"
892 bl_description
= 'Upgrades the rigify types on the active metarig armature'
893 bl_options
= {'UNDO'}
895 def execute(self
, context
):
896 for obj
in bpy
.data
.objects
:
897 if type(obj
.data
) == bpy
.types
.Armature
:
898 upgrade_metarig_types(obj
)
902 class Sample(bpy
.types
.Operator
):
903 """Create a sample metarig to be modified before generating the final rig"""
905 bl_idname
= "armature.metarig_sample_add"
906 bl_label
= "Add Metarig Sample"
907 bl_options
= {'UNDO'}
909 metarig_type
: StringProperty(
911 description
="Name of the rig type to generate a sample of",
913 options
={'SKIP_SAVE'}
917 def poll(cls
, context
):
918 return context
.mode
== 'EDIT_ARMATURE'
920 def draw(self
, context
):
922 layout
.use_property_split
= True
923 layout
.use_property_decorate
= False
924 col
= layout
.column()
925 build_type_list(context
, get_rigify_types(context
.window_manager
))
926 col
.prop(context
.object.data
, "active_feature_set")
927 col
.prop_search(self
, "metarig_type", context
.window_manager
, "rigify_types")
929 def invoke(self
, context
, event
):
930 if self
.metarig_type
== "":
931 return context
.window_manager
.invoke_props_dialog(self
)
932 return self
.execute(context
)
934 def execute(self
, context
):
935 if self
.metarig_type
== "":
936 self
.report({'ERROR'}, "You must select a rig type to create a sample of.")
939 rig
= rig_lists
.rigs
[self
.metarig_type
]["module"]
940 create_sample
= rig
.create_sample
941 except (ImportError, AttributeError, KeyError):
942 raise Exception("rig type '" + self
.metarig_type
+ "' has no sample.")
944 create_sample(context
.active_object
)
946 bpy
.ops
.object.mode_set(mode
='EDIT')
951 class EncodeMetarig(bpy
.types
.Operator
):
952 """Creates Python code that will generate the selected metarig"""
953 bl_idname
= "armature.rigify_encode_metarig"
954 bl_label
= "Rigify Encode Metarig"
955 bl_options
= {'UNDO'}
958 def poll(cls
, context
):
959 return context
.mode
== 'EDIT_ARMATURE' and is_metarig(context
.object)
961 def execute(self
, context
):
964 if name
in bpy
.data
.texts
:
965 text_block
= bpy
.data
.texts
[name
]
968 text_block
= bpy
.data
.texts
.new(name
)
970 obj
= verify_armature_obj(context
.active_object
)
971 text
= write_metarig(obj
, layers
=True, func_name
="create", groups
=True, widgets
=True)
972 text_block
.write(text
)
973 bpy
.ops
.object.mode_set(mode
='EDIT')
974 self
.report({'INFO'}, f
"Metarig written to text datablock: {text_block.name}")
978 class EncodeMetarigSample(bpy
.types
.Operator
):
979 """Creates Python code that will generate the selected metarig as a sample"""
980 bl_idname
= "armature.rigify_encode_metarig_sample"
981 bl_label
= "Rigify Encode Metarig Sample"
982 bl_options
= {'UNDO'}
985 def poll(cls
, context
):
986 return context
.mode
== 'EDIT_ARMATURE' and is_metarig(context
.object)
988 def execute(self
, context
):
989 name
= "metarig_sample.py"
991 if name
in bpy
.data
.texts
:
992 text_block
= bpy
.data
.texts
[name
]
995 text_block
= bpy
.data
.texts
.new(name
)
997 obj
= verify_armature_obj(context
.active_object
)
998 text
= write_metarig(obj
, layers
=False, func_name
="create_sample")
999 text_block
.write(text
)
1000 bpy
.ops
.object.mode_set(mode
='EDIT')
1002 self
.report({'INFO'}, f
"Metarig Sample written to text datablock: {text_block.name}")
1006 # noinspection PyPep8Naming
1007 class VIEW3D_MT_rigify(bpy
.types
.Menu
):
1009 bl_idname
= "VIEW3D_MT_rigify"
1014 def draw(self
, context
):
1015 layout
= self
.layout
1016 obj
= verify_armature_obj(context
.object)
1017 target_rig
= get_rigify_target_rig(obj
.data
)
1019 text
= "Re-Generate Rig" if target_rig
else "Generate Rig"
1020 layout
.operator(Generate
.bl_idname
, text
=text
)
1022 if context
.mode
== 'EDIT_ARMATURE':
1024 layout
.operator(Sample
.bl_idname
)
1026 layout
.operator(EncodeMetarig
.bl_idname
, text
="Encode Metarig")
1027 layout
.operator(EncodeMetarigSample
.bl_idname
, text
="Encode Metarig Sample")
1030 def draw_rigify_menu(self
, context
):
1031 if is_metarig(context
.object):
1032 self
.layout
.menu(VIEW3D_MT_rigify
.bl_idname
)
1035 class EncodeWidget(bpy
.types
.Operator
):
1036 """ Creates Python code that will generate the selected metarig.
1038 bl_idname
= "mesh.rigify_encode_mesh_widget"
1039 bl_label
= "Rigify Encode Widget"
1040 bl_options
= {'UNDO'}
1043 def poll(cls
, context
):
1044 return context
.mode
== 'EDIT_MESH'
1046 def execute(self
, context
):
1049 if name
in bpy
.data
.texts
:
1050 text_block
= bpy
.data
.texts
[name
]
1053 text_block
= bpy
.data
.texts
.new(name
)
1055 text
= write_widget(context
.active_object
)
1056 text_block
.write(text
)
1057 bpy
.ops
.object.mode_set(mode
='EDIT')
1062 def draw_mesh_edit_menu(self
, _context
: bpy
.types
.Context
):
1063 self
.layout
.operator(EncodeWidget
.bl_idname
)
1064 self
.layout
.separator()
1067 def fk_to_ik(rig
: ArmatureObject
, window
='ALL'):
1068 scn
= bpy
.context
.scene
1069 id_store
= bpy
.context
.window_manager
1071 rig_id
= rig
.data
['rig_id']
1072 leg_ik2fk
= eval('bpy.ops.pose.rigify_leg_ik2fk_' + rig_id
)
1073 arm_ik2fk
= eval('bpy.ops.pose.rigify_arm_ik2fk_' + rig_id
)
1074 limb_generated_names
= get_limb_generated_names(rig
)
1077 frames
= get_keyed_frames_in_range(bpy
.context
, rig
)
1078 elif window
== 'CURRENT':
1079 frames
= [scn
.frame_current
]
1081 frames
= [scn
.frame_current
]
1083 only_selected
= get_transfer_only_selected(id_store
)
1085 if not only_selected
:
1086 pose_bones
= rig
.pose
.bones
1087 bpy
.ops
.pose
.select_all(action
='DESELECT')
1089 pose_bones
= bpy
.context
.selected_pose_bones
1090 bpy
.ops
.pose
.select_all(action
='DESELECT')
1092 for b
in pose_bones
:
1093 for group
in limb_generated_names
:
1094 if b
.name
in limb_generated_names
[group
].values() or b
.name
in limb_generated_names
[group
]['controls']\
1095 or b
.name
in limb_generated_names
[group
]['ik_ctrl']:
1096 names
= limb_generated_names
[group
]
1097 if names
['limb_type'] == 'arm':
1099 controls
= names
['controls']
1100 ik_ctrl
= names
['ik_ctrl']
1101 # fk_ctrl = names['fk_ctrl']
1102 parent
= names
['parent']
1103 pole
= names
['pole']
1104 rig
.pose
.bones
[controls
[0]].bone
.select
= True
1105 rig
.pose
.bones
[controls
[4]].bone
.select
= True
1106 rig
.pose
.bones
[pole
].bone
.select
= True
1107 rig
.pose
.bones
[parent
].bone
.select
= True
1108 kwargs
= {'uarm_fk': controls
[1], 'farm_fk': controls
[2], 'hand_fk': controls
[3],
1109 'uarm_ik': controls
[0], 'farm_ik': ik_ctrl
[1], 'hand_ik': controls
[4],
1110 'pole': pole
, 'main_parent': parent
}
1111 args
= (controls
[0], controls
[1], controls
[2], controls
[3],
1112 controls
[4], pole
, parent
)
1115 controls
= names
['controls']
1116 ik_ctrl
= names
['ik_ctrl']
1117 # fk_ctrl = names['fk_ctrl']
1118 parent
= names
['parent']
1119 pole
= names
['pole']
1120 rig
.pose
.bones
[controls
[0]].bone
.select
= True
1121 rig
.pose
.bones
[controls
[6]].bone
.select
= True
1122 rig
.pose
.bones
[controls
[5]].bone
.select
= True
1123 rig
.pose
.bones
[pole
].bone
.select
= True
1124 rig
.pose
.bones
[parent
].bone
.select
= True
1125 # noinspection SpellCheckingInspection
1126 kwargs
= {'thigh_fk': controls
[1], 'shin_fk': controls
[2], 'foot_fk': controls
[3],
1127 'mfoot_fk': controls
[7], 'thigh_ik': controls
[0], 'shin_ik': ik_ctrl
[1],
1128 'foot_ik': controls
[6], 'pole': pole
, 'footroll': controls
[5], 'mfoot_ik': ik_ctrl
[2],
1129 'main_parent': parent
}
1130 args
= (controls
[0], controls
[1], controls
[2], controls
[3],
1131 controls
[6], controls
[5], pole
, parent
)
1134 if not bones_in_frame(f
, rig
, *args
):
1138 bpy
.ops
.anim
.keyframe_insert_menu(type='BUILTIN_KSI_VisualLocRot')
1139 bpy
.ops
.anim
.keyframe_insert_menu(type='Scaling')
1141 bpy
.ops
.pose
.select_all(action
='DESELECT')
1142 limb_generated_names
.pop(group
)
1146 def ik_to_fk(rig
: ArmatureObject
, window
='ALL'):
1147 scn
= bpy
.context
.scene
1148 id_store
= bpy
.context
.window_manager
1150 rig_id
= rig
.data
['rig_id']
1151 leg_fk2ik
= eval('bpy.ops.pose.rigify_leg_fk2ik_' + rig_id
)
1152 arm_fk2ik
= eval('bpy.ops.pose.rigify_arm_fk2ik_' + rig_id
)
1153 limb_generated_names
= get_limb_generated_names(rig
)
1156 frames
= get_keyed_frames_in_range(bpy
.context
, rig
)
1157 elif window
== 'CURRENT':
1158 frames
= [scn
.frame_current
]
1160 frames
= [scn
.frame_current
]
1162 only_selected
= get_transfer_only_selected(id_store
)
1164 if not only_selected
:
1165 bpy
.ops
.pose
.select_all(action
='DESELECT')
1166 pose_bones
= rig
.pose
.bones
1168 pose_bones
= bpy
.context
.selected_pose_bones
1169 bpy
.ops
.pose
.select_all(action
='DESELECT')
1171 for b
in pose_bones
:
1172 for group
in limb_generated_names
:
1173 if b
.name
in limb_generated_names
[group
].values() or b
.name
in limb_generated_names
[group
]['controls']\
1174 or b
.name
in limb_generated_names
[group
]['ik_ctrl']:
1175 names
= limb_generated_names
[group
]
1176 if names
['limb_type'] == 'arm':
1178 controls
= names
['controls']
1179 ik_ctrl
= names
['ik_ctrl']
1180 # fk_ctrl = names['fk_ctrl']
1181 parent
= names
['parent']
1182 pole
= names
['pole']
1183 rig
.pose
.bones
[controls
[1]].bone
.select
= True
1184 rig
.pose
.bones
[controls
[2]].bone
.select
= True
1185 rig
.pose
.bones
[controls
[3]].bone
.select
= True
1186 kwargs
= {'uarm_fk': controls
[1], 'farm_fk': controls
[2], 'hand_fk': controls
[3],
1187 'uarm_ik': controls
[0], 'farm_ik': ik_ctrl
[1],
1188 'hand_ik': controls
[4]}
1189 args
= (controls
[0], controls
[1], controls
[2], controls
[3],
1190 controls
[4], pole
, parent
)
1193 controls
= names
['controls']
1194 ik_ctrl
= names
['ik_ctrl']
1195 # fk_ctrl = names['fk_ctrl']
1196 parent
= names
['parent']
1197 pole
= names
['pole']
1198 rig
.pose
.bones
[controls
[1]].bone
.select
= True
1199 rig
.pose
.bones
[controls
[2]].bone
.select
= True
1200 rig
.pose
.bones
[controls
[3]].bone
.select
= True
1201 # noinspection SpellCheckingInspection
1202 kwargs
= {'thigh_fk': controls
[1], 'shin_fk': controls
[2], 'foot_fk': controls
[3],
1203 'mfoot_fk': controls
[7], 'thigh_ik': controls
[0], 'shin_ik': ik_ctrl
[1],
1204 'foot_ik': ik_ctrl
[2], 'mfoot_ik': ik_ctrl
[2]}
1205 args
= (controls
[0], controls
[1], controls
[2], controls
[3],
1206 controls
[6], controls
[5], pole
, parent
)
1209 if not bones_in_frame(f
, rig
, *args
):
1213 bpy
.ops
.anim
.keyframe_insert_menu(type='BUILTIN_KSI_VisualLocRot')
1214 bpy
.ops
.anim
.keyframe_insert_menu(type='Scaling')
1216 bpy
.ops
.pose
.select_all(action
='DESELECT')
1217 limb_generated_names
.pop(group
)
1221 def clear_animation(act
, anim_type
, names
):
1224 if names
[group
]['limb_type'] == 'arm':
1225 if anim_type
== 'IK':
1226 bones
.extend([names
[group
]['controls'][0], names
[group
]['controls'][4]])
1227 elif anim_type
== 'FK':
1228 bones
.extend([names
[group
]['controls'][1], names
[group
]['controls'][2], names
[group
]['controls'][3]])
1230 if anim_type
== 'IK':
1231 bones
.extend([names
[group
]['controls'][0], names
[group
]['controls'][6], names
[group
]['controls'][5],
1232 names
[group
]['controls'][4]])
1233 elif anim_type
== 'FK':
1234 bones
.extend([names
[group
]['controls'][1], names
[group
]['controls'][2], names
[group
]['controls'][3],
1235 names
[group
]['controls'][4]])
1237 for fcu
in act
.fcurves
:
1238 words
= fcu
.data_path
.split('"')
1239 if words
[0] == "pose.bones[" and words
[1] in bones
:
1240 f_curves
.append(fcu
)
1245 for fcu
in f_curves
:
1246 act
.fcurves
.remove(fcu
)
1248 # Put cleared bones back to rest pose
1249 bpy
.ops
.pose
.loc_clear()
1250 bpy
.ops
.pose
.rot_clear()
1251 bpy
.ops
.pose
.scale_clear()
1256 def rot_pole_toggle(rig
: ArmatureObject
, window
='ALL', value
=False, toggle
=False, bake
=False):
1257 scn
= bpy
.context
.scene
1258 id_store
= bpy
.context
.window_manager
1260 rig_id
= rig
.data
['rig_id']
1261 leg_fk2ik
= eval('bpy.ops.pose.rigify_leg_fk2ik_' + rig_id
)
1262 arm_fk2ik
= eval('bpy.ops.pose.rigify_arm_fk2ik_' + rig_id
)
1263 leg_ik2fk
= eval('bpy.ops.pose.rigify_leg_ik2fk_' + rig_id
)
1264 arm_ik2fk
= eval('bpy.ops.pose.rigify_arm_ik2fk_' + rig_id
)
1265 limb_generated_names
= get_limb_generated_names(rig
)
1268 frames
= get_keyed_frames_in_range(bpy
.context
, rig
)
1269 elif window
== 'CURRENT':
1270 frames
= [scn
.frame_current
]
1272 frames
= [scn
.frame_current
]
1274 only_selected
= get_transfer_only_selected(id_store
)
1276 if not only_selected
:
1277 bpy
.ops
.pose
.select_all(action
='DESELECT')
1278 pose_bones
= rig
.pose
.bones
1280 pose_bones
= bpy
.context
.selected_pose_bones
1281 bpy
.ops
.pose
.select_all(action
='DESELECT')
1283 for b
in pose_bones
:
1284 for group
in limb_generated_names
:
1285 names
= limb_generated_names
[group
]
1288 new_pole_vector_value
= not rig
.pose
.bones
[names
['parent']]['pole_vector']
1290 new_pole_vector_value
= value
1292 if b
.name
in names
.values() or b
.name
in names
['controls'] or b
.name
in names
['ik_ctrl']:
1293 if names
['limb_type'] == 'arm':
1296 controls
= names
['controls']
1297 ik_ctrl
= names
['ik_ctrl']
1298 # fk_ctrl = names['fk_ctrl']
1299 parent
= names
['parent']
1300 pole
= names
['pole']
1301 rig
.pose
.bones
[controls
[0]].bone
.select
= not new_pole_vector_value
1302 rig
.pose
.bones
[controls
[4]].bone
.select
= not new_pole_vector_value
1303 rig
.pose
.bones
[parent
].bone
.select
= not new_pole_vector_value
1304 rig
.pose
.bones
[pole
].bone
.select
= new_pole_vector_value
1306 kwargs1
= {'uarm_fk': controls
[1], 'farm_fk': controls
[2], 'hand_fk': controls
[3],
1307 'uarm_ik': controls
[0], 'farm_ik': ik_ctrl
[1],
1308 'hand_ik': controls
[4]}
1309 kwargs2
= {'uarm_fk': controls
[1], 'farm_fk': controls
[2], 'hand_fk': controls
[3],
1310 'uarm_ik': controls
[0], 'farm_ik': ik_ctrl
[1], 'hand_ik': controls
[4],
1311 'pole': pole
, 'main_parent': parent
}
1312 args
= (controls
[0], controls
[4], pole
, parent
)
1316 controls
= names
['controls']
1317 ik_ctrl
= names
['ik_ctrl']
1318 # fk_ctrl = names['fk_ctrl']
1319 parent
= names
['parent']
1320 pole
= names
['pole']
1321 rig
.pose
.bones
[controls
[0]].bone
.select
= not new_pole_vector_value
1322 rig
.pose
.bones
[controls
[6]].bone
.select
= not new_pole_vector_value
1323 rig
.pose
.bones
[controls
[5]].bone
.select
= not new_pole_vector_value
1324 rig
.pose
.bones
[parent
].bone
.select
= not new_pole_vector_value
1325 rig
.pose
.bones
[pole
].bone
.select
= new_pole_vector_value
1327 # noinspection SpellCheckingInspection
1328 kwargs1
= {'thigh_fk': controls
[1], 'shin_fk': controls
[2], 'foot_fk': controls
[3],
1329 'mfoot_fk': controls
[7], 'thigh_ik': controls
[0], 'shin_ik': ik_ctrl
[1],
1330 'foot_ik': ik_ctrl
[2], 'mfoot_ik': ik_ctrl
[2]}
1331 # noinspection SpellCheckingInspection
1332 kwargs2
= {'thigh_fk': controls
[1], 'shin_fk': controls
[2], 'foot_fk': controls
[3],
1333 'mfoot_fk': controls
[7], 'thigh_ik': controls
[0], 'shin_ik': ik_ctrl
[1],
1334 'foot_ik': controls
[6], 'pole': pole
, 'footroll': controls
[5], 'mfoot_ik': ik_ctrl
[2],
1335 'main_parent': parent
}
1336 args
= (controls
[0], controls
[6], controls
[5], pole
, parent
)
1339 if bake
and not bones_in_frame(f
, rig
, *args
):
1343 rig
.pose
.bones
[names
['parent']]['pole_vector'] = new_pole_vector_value
1346 bpy
.ops
.anim
.keyframe_insert_menu(type='BUILTIN_KSI_VisualLocRot')
1347 bpy
.ops
.anim
.keyframe_insert_menu(type='Scaling')
1348 overwrite_prop_animation(rig
, rig
.pose
.bones
[parent
], 'pole_vector', new_pole_vector_value
, [f
])
1350 bpy
.ops
.pose
.select_all(action
='DESELECT')
1351 limb_generated_names
.pop(group
)
1356 # noinspection PyPep8Naming
1357 class OBJECT_OT_IK2FK(bpy
.types
.Operator
):
1358 """ Snaps IK limb on FK limb at current frame"""
1359 bl_idname
= "rigify.ik2fk"
1361 bl_description
= "Snaps IK limb on FK"
1362 bl_options
= {'INTERNAL'}
1364 def execute(self
, context
):
1365 rig
= verify_armature_obj(context
.object)
1367 fk_to_ik(rig
, window
='CURRENT')
1372 # noinspection PyPep8Naming
1373 class OBJECT_OT_FK2IK(bpy
.types
.Operator
):
1374 """ Snaps FK limb on IK limb at current frame"""
1375 bl_idname
= "rigify.fk2ik"
1377 bl_description
= "Snaps FK limb on IK"
1378 bl_options
= {'INTERNAL'}
1380 def execute(self
, context
):
1381 rig
= verify_armature_obj(context
.object)
1383 ik_to_fk(rig
, window
='CURRENT')
1388 # noinspection PyPep8Naming
1389 class OBJECT_OT_TransferFKtoIK(bpy
.types
.Operator
):
1390 """Transfers FK animation to IK"""
1391 bl_idname
= "rigify.transfer_fk_to_ik"
1392 bl_label
= "Transfer FK anim to IK"
1393 bl_description
= "Transfer FK animation to IK bones"
1394 bl_options
= {'INTERNAL'}
1396 def execute(self
, context
):
1397 rig
= verify_armature_obj(context
.object)
1404 # noinspection PyPep8Naming
1405 class OBJECT_OT_TransferIKtoFK(bpy
.types
.Operator
):
1406 """Transfers FK animation to IK"""
1407 bl_idname
= "rigify.transfer_ik_to_fk"
1408 bl_label
= "Transfer IK anim to FK"
1409 bl_description
= "Transfer IK animation to FK bones"
1410 bl_options
= {'INTERNAL'}
1412 def execute(self
, context
):
1413 rig
= verify_armature_obj(context
.object)
1420 # noinspection PyPep8Naming
1421 class OBJECT_OT_ClearAnimation(bpy
.types
.Operator
):
1422 bl_idname
= "rigify.clear_animation"
1423 bl_label
= "Clear Animation"
1424 bl_description
= "Clear Animation For FK or IK Bones"
1425 bl_options
= {'INTERNAL'}
1427 anim_type
: StringProperty()
1429 def execute(self
, context
):
1430 rig
= verify_armature_obj(context
.object)
1432 if not rig
.animation_data
:
1435 act
= rig
.animation_data
.action
1439 clear_animation(act
, self
.anim_type
, names
=get_limb_generated_names(rig
))
1443 # noinspection PyPep8Naming
1444 class OBJECT_OT_Rot2Pole(bpy
.types
.Operator
):
1445 bl_idname
= "rigify.rotation_pole"
1446 bl_label
= "Rotation - Pole toggle"
1447 bl_description
= "Toggles IK chain between rotation and pole target"
1448 bl_options
= {'INTERNAL'}
1450 bone_name
: StringProperty(default
='')
1451 window
: StringProperty(default
='ALL')
1452 toggle
: BoolProperty(default
=True)
1453 value
: BoolProperty(default
=True)
1454 bake
: BoolProperty(default
=True)
1456 def execute(self
, context
):
1457 rig
= verify_armature_obj(context
.object)
1460 bpy
.ops
.pose
.select_all(action
='DESELECT')
1461 rig
.pose
.bones
[self
.bone_name
].bone
.select
= True
1463 rot_pole_toggle(rig
, window
=self
.window
, toggle
=self
.toggle
, value
=self
.value
, bake
=self
.bake
)
1471 DATA_OT_rigify_add_bone_groups
,
1472 DATA_OT_rigify_use_standard_colors
,
1473 DATA_OT_rigify_apply_selection_colors
,
1474 DATA_OT_rigify_bone_group_add
,
1475 DATA_OT_rigify_bone_group_add_theme
,
1476 DATA_OT_rigify_bone_group_remove
,
1477 DATA_OT_rigify_bone_group_remove_all
,
1478 DATA_UL_rigify_bone_groups
,
1479 DATA_MT_rigify_bone_groups_context_menu
,
1481 DATA_PT_rigify_advanced
,
1482 DATA_PT_rigify_bone_groups
,
1483 DATA_PT_rigify_layer_names
,
1484 DATA_PT_rigify_samples
,
1485 BONE_PT_rigify_buttons
,
1486 VIEW3D_PT_rigify_animation_tools
,
1487 VIEW3D_PT_tools_rigify_dev
,
1490 UpgradeMetarigTypes
,
1494 EncodeMetarigSample
,
1498 OBJECT_OT_TransferFKtoIK
,
1499 OBJECT_OT_TransferIKtoFK
,
1500 OBJECT_OT_ClearAnimation
,
1506 from bpy
.utils
import register_class
1508 animation_register()
1514 bpy
.types
.VIEW3D_MT_editor_menus
.append(draw_rigify_menu
)
1515 bpy
.types
.VIEW3D_MT_edit_mesh
.prepend(draw_mesh_edit_menu
)
1522 from bpy
.utils
import unregister_class
1525 rot_mode
.unregister()
1529 unregister_class(cls
)
1531 bpy
.types
.VIEW3D_MT_editor_menus
.remove(draw_rigify_menu
)
1532 bpy
.types
.VIEW3D_MT_edit_mesh
.remove(draw_mesh_edit_menu
)
1534 animation_unregister()