File headers: use SPDX license identifiers
[blender-addons.git] / rigify / rigs / spines / super_spine.py
blob9d9e6d0f08c81c3e454b08b53e7c6d1a706c5e31
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # <pep8 compliant>
5 import bpy
7 from ...utils.rig import connected_children_names
8 from ...utils.layers import ControlLayersOption
9 from ...utils.bones import BoneUtilityMixin, flip_bone_chain
11 from ...base_generate import SubstitutionRig
13 from . import basic_spine, basic_tail, super_head
16 class Rig(SubstitutionRig, BoneUtilityMixin):
17 """Compatibility proxy for the monolithic super_spine rig that splits it into parts."""
19 def substitute(self):
20 params_copy = self.params_copy
21 orgs = [self.base_bone] + connected_children_names(self.obj, self.base_bone)
23 # Split the bone list according to the settings
24 spine_orgs = orgs
25 head_orgs = None
26 tail_orgs = None
28 pivot_pos = self.params.pivot_pos
30 if self.params.use_head:
31 neck_pos = self.params.neck_pos
32 if neck_pos <= pivot_pos:
33 self.raise_error("Neck cannot be below or the same as pivot.")
34 if neck_pos >= len(orgs):
35 self.raise_error("Neck is too short.")
37 spine_orgs = orgs[0 : neck_pos-1]
38 head_orgs = orgs[neck_pos-1 : ]
40 if self.params.use_tail:
41 tail_pos = self.params.tail_pos
42 if tail_pos < 2:
43 self.raise_error("Tail is too short.")
44 if tail_pos >= pivot_pos:
45 self.raise_error("Tail cannot be above or the same as pivot.")
47 tail_orgs = list(reversed(spine_orgs[0 : tail_pos]))
48 spine_orgs = spine_orgs[tail_pos : ]
49 pivot_pos -= tail_pos
51 # Split the bone chain and flip the tail
52 if head_orgs or tail_orgs:
53 bpy.ops.object.mode_set(mode='EDIT')
55 if spine_orgs[0] != orgs[0]:
56 self.set_bone_parent(spine_orgs[0], self.get_bone_parent(orgs[0]))
58 if head_orgs:
59 self.get_bone(head_orgs[0]).use_connect = False
61 if tail_orgs:
62 flip_bone_chain(self.obj, reversed(tail_orgs))
63 self.set_bone_parent(tail_orgs[0], spine_orgs[0])
65 bpy.ops.object.mode_set(mode='OBJECT')
67 # Create the parts
68 self.assign_params(spine_orgs[0], params_copy, pivot_pos=pivot_pos, make_fk_controls=False)
70 result = [ self.instantiate_rig(basic_spine.Rig, spine_orgs[0]) ]
72 if tail_orgs:
73 self.assign_params(tail_orgs[0], params_copy, connect_chain=True)
75 result += [ self.instantiate_rig(basic_tail.Rig, tail_orgs[0]) ]
77 if head_orgs:
78 self.assign_params(head_orgs[0], params_copy, connect_chain=True)
80 result += [ self.instantiate_rig(super_head.Rig, head_orgs[0]) ]
82 return result
85 def add_parameters(params):
86 basic_spine.Rig.add_parameters(params)
87 basic_tail.Rig.add_parameters(params)
88 super_head.Rig.add_parameters(params)
90 params.neck_pos = bpy.props.IntProperty(
91 name = 'neck_position',
92 default = 6,
93 min = 0,
94 description = 'Neck start position'
97 params.tail_pos = bpy.props.IntProperty(
98 name='tail_position',
99 default=2,
100 min=2,
101 description='Where the tail starts'
104 params.use_tail = bpy.props.BoolProperty(
105 name='use_tail',
106 default=False,
107 description='Create tail bones'
110 params.use_head = bpy.props.BoolProperty(
111 name='use_head',
112 default=True,
113 description='Create head and neck bones'
117 def parameters_ui(layout, params):
118 """ Create the ui for the rig parameters."""
120 layout.label(text="Note: this combined rig is deprecated.", icon='INFO')
122 r = layout.row(align=True)
123 r.prop(params, "use_head", toggle=True, text="Head")
124 r.prop(params, "use_tail", toggle=True, text="Tail")
126 r = layout.row()
127 r.prop(params, "neck_pos")
128 r.enabled = params.use_head
130 r = layout.row()
131 r.prop(params, "pivot_pos")
133 r = layout.row()
134 r.prop(params, "tail_pos")
135 r.enabled = params.use_tail
137 r = layout.row()
138 col = r.column(align=True)
139 row = col.row(align=True)
140 for i, axis in enumerate(['x', 'y', 'z']):
141 row.prop(params, "copy_rotation_axes", index=i, toggle=True, text=axis)
142 r.enabled = params.use_tail
144 ControlLayersOption.TWEAK.parameters_ui(layout, params)
147 def create_sample(obj):
148 bones = basic_spine.create_sample(obj)
149 basic_tail.create_sample(obj, parent=bones['spine'])
150 super_head.create_sample(obj, parent=bones['spine.003'])