Welcome to mirror list, hosted at ThFree Co, Russian Federation.

skin_rigs.py « skin « rigs « rigify - git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: bc6b63503671b56d5b3ffd6dca418de191aac51c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# SPDX-License-Identifier: GPL-2.0-or-later

# <pep8 compliant>

import bpy

from ...utils.naming import make_derived_name
from ...utils.misc import force_lazy, LazyRef

from ...base_rig import BaseRig, stage

from .skin_parents import ControlBoneParentOrg


class BaseSkinRig(BaseRig):
    """
    Base type for all rigs involved in the skin system.
    This includes chain rigs and the parent provider rigs.
    """

    def initialize(self):
        self.rig_parent_bone = self.get_bone_parent(self.base_bone)

    ##########################
    # Utilities

    def get_parent_skin_rig(self):
        """Find the closest BaseSkinRig parent."""
        parent = self.rigify_parent

        while parent:
            if isinstance(parent, BaseSkinRig):
                return parent
            parent = parent.rigify_parent

        return None

    def get_all_parent_skin_rigs(self):
        """Get a list of all BaseSkinRig parents, starting with this rig."""
        items = []
        current = self
        while current:
            items.append(current)
            current = current.get_parent_skin_rig()
        return items

    def get_child_chain_parent_next(self, rig):
        """
        Retrieves the parent bone for the child chain rig
        as determined by the parent skin rig.
        """
        if isinstance(self.rigify_parent, BaseSkinRig):
            return self.rigify_parent.get_child_chain_parent(rig, self.rig_parent_bone)
        else:
            return self.rig_parent_bone

    def build_control_node_parent_next(self, node):
        """
        Retrieves the parent mechanism generator for the child control node
        as determined by the parent skin rig.
        """
        if isinstance(self.rigify_parent, BaseSkinRig):
            return self.rigify_parent.build_control_node_parent(node, self.rig_parent_bone)
        else:
            return ControlBoneParentOrg(self.rig_parent_bone)

    ##########################
    # Methods to override

    def get_child_chain_parent(self, rig, parent_bone):
        """
        Returns the (lazy) parent bone to use for the given child chain rig.
        The parent_bone argument specifies the actual parent bone from caller.
        """
        return parent_bone

    def build_control_node_parent(self, node, parent_bone):
        """
        Returns the parent mechanism generator for the child control node.
        The parent_bone argument specifies the actual parent bone from caller.
        Called during the initialize stage.
        """
        return ControlBoneParentOrg(self.get_child_chain_parent(node.rig, parent_bone))

    def build_own_control_node_parent(self, node):
        """
        Returns the parent mechanism generator for nodes directly owned by this rig.
        Called during the initialize stage.
        """
        return self.build_control_node_parent_next(node)

    def extend_control_node_parent(self, parent, node):
        """
        First callback pass of adjustments to the parent mechanism generator for the given node.
        Called for all BaseSkinRig parents in parent to child order during the initialize stage.
        """
        return parent

    def extend_control_node_parent_post(self, parent, node):
        """
        Second callback pass of adjustments to the parent mechanism generator for the given node.
        Called for all BaseSkinRig parents in child to parent order during the initialize stage.
        """
        return parent

    def extend_control_node_rig(self, node):
        """
        A callback pass for adding constraints directly to the generated control.
        Called for all BaseSkinRig parents in parent to child order during the rig stage.
        """
        pass


def get_bone_quaternion(obj, bone):
    return obj.pose.bones[bone].bone.matrix_local.to_quaternion()


class BaseSkinChainRig(BaseSkinRig):
    """
    Base type for all skin rigs that can own control nodes, rather than
    only modifying nodes of their children or other rigs.
    """

    chain_priority = 0

    def initialize(self):
        super().initialize()

        if type(self).chain_priority is None:
            self.chain_priority = self.params.skin_chain_priority

    def parent_bones(self):
        self.rig_parent_bone = force_lazy(self.get_child_chain_parent_next(self))

    def get_final_control_node_rotation(self, node):
        """Returns the orientation to use for the given control node owned by this rig."""
        return self.get_control_node_rotation(node)

    ##########################
    # Methods to override

    def get_control_node_rotation(self, node):
        """
        Returns the rig-specific orientation to use for the given control node of this rig,
        if not overridden by the Orientation Bone option.
        """
        return get_bone_quaternion(self.obj, self.base_bone)

    def get_control_node_layers(self, node):
        """Returns the armature layers to use for the given control node owned by this rig."""
        return self.get_bone(self.base_bone).bone.layers

    def make_control_node_widget(self, node):
        """Called to generate the widget for nodes with ControlNodeIcon.CUSTOM."""
        raise NotImplementedError()

    ##########################
    # UI

    @classmethod
    def add_parameters(self, params):
        params.skin_chain_priority = bpy.props.IntProperty(
            name='Chain Priority',
            min=-10, max=10, default=0,
            description='When merging controls, chains with higher priority always win'
        )

    @classmethod
    def parameters_ui(self, layout, params):
        if self.chain_priority is None:
            layout.prop(params, "skin_chain_priority")


class BaseSkinChainRigWithRotationOption(BaseSkinChainRig):
    """
    Skin chain rig with an option to override the orientation to use
    for controls via specifying an arbitrary template bone.
    """

    use_skin_control_orientation_bone = True

    def get_final_control_node_rotation(self, node):
        bone_name = self.params.skin_control_orientation_bone

        if bone_name and self.use_skin_control_orientation_bone:
            # Retrieve the orientation from the specified ORG bone
            try:
                org_name = make_derived_name(bone_name, 'org')

                if org_name not in self.obj.pose.bones:
                    org_name = bone_name

                return get_bone_quaternion(self.obj, org_name)

            except KeyError:
                self.raise_error('Could not find orientation bone {}', bone_name)

        else:
            # Use the rig-specific orientation
            return self.get_control_node_rotation(node)

    @classmethod
    def add_parameters(self, params):
        params.skin_control_orientation_bone = bpy.props.StringProperty(
            name="Orientation Bone",
            description="If set, control orientation is taken from the specified bone",
        )

        super().add_parameters(params)

    @classmethod
    def parameters_ui(self, layout, params):
        if self.use_skin_control_orientation_bone:
            from rigify.operators.copy_mirror_parameters import make_copy_parameter_button

            row = layout.row()
            row.prop_search(params, "skin_control_orientation_bone",
                            bpy.context.active_object.pose, "bones", text="Orientation")

            make_copy_parameter_button(
                row, "skin_control_orientation_bone", mirror_bone=True,
                base_class=BaseSkinChainRigWithRotationOption
            )

        super().parameters_ui(layout, params)