Changeset View
Changeset View
Standalone View
Standalone View
rigify/rigs/spines/basic_tail.py
- This file was added.
| #====================== BEGIN GPL LICENSE BLOCK ====================== | |||||
| # | |||||
| # This program is free software; you can redistribute it and/or | |||||
| # modify it under the terms of the GNU General Public License | |||||
| # as published by the Free Software Foundation; either version 2 | |||||
| # of the License, or (at your option) any later version. | |||||
| # | |||||
| # This program is distributed in the hope that it will be useful, | |||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # GNU General Public License for more details. | |||||
| # | |||||
| # You should have received a copy of the GNU General Public License | |||||
| # along with this program; if not, write to the Free Software Foundation, | |||||
| # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
| # | |||||
| #======================= END GPL LICENSE BLOCK ======================== | |||||
| # <pep8 compliant> | |||||
| import bpy | |||||
| from itertools import count | |||||
| from ...utils.naming import strip_org, make_derived_name | |||||
| from ...utils.bones import put_bone, flip_bone, is_same_position, connect_bbone_chain_handles, align_bone_orientation | |||||
| from ...utils.widgets_basic import create_circle_widget | |||||
| from ...utils.layers import ControlLayersOption | |||||
| from ...utils.misc import map_list | |||||
| from ...base_rig import stage | |||||
| from ..chain_rigs import TweakChainRig, SimpleChainRig | |||||
| from ..widgets import create_ballsocket_widget | |||||
| from .spine_rigs import BaseHeadTailRig | |||||
| class Rig(BaseHeadTailRig): | |||||
| def initialize(self): | |||||
| super().initialize() | |||||
| self.copy_rotation_axes = self.params.copy_rotation_axes | |||||
| def parent_bones(self): | |||||
| super().parent_bones() | |||||
| if self.connected_tweak and self.use_connect_reverse: | |||||
| self.rig_parent_bone = self.connected_tweak | |||||
| #################################################### | |||||
| # Master control | |||||
| @stage.generate_bones | |||||
| def make_master_control(self): | |||||
| org = self.bones.org[0] | |||||
| self.bones.ctrl.master = self.copy_bone(org, make_derived_name(org, 'ctrl', '_master')) | |||||
| self.default_prop_bone = self.bones.ctrl.master | |||||
| @stage.parent_bones | |||||
| def parent_master_control(self): | |||||
| self.set_bone_parent(self.bones.ctrl.master, self.rig_parent_bone) | |||||
| @stage.configure_bones | |||||
| def configure_master_control(self): | |||||
| bone = self.get_bone(self.bones.ctrl.master) | |||||
| bone.lock_location = True, True, True | |||||
| @stage.generate_widgets | |||||
| def make_master_control_widget(self): | |||||
| bone = self.bones.ctrl.master | |||||
| self.get_bone(bone).custom_shape_transform = self.get_bone(self.bones.ctrl.tweak[-1]) | |||||
| create_ballsocket_widget(self.obj, bone, size=0.7) | |||||
| #################################################### | |||||
| # Control bones | |||||
| @stage.parent_bones | |||||
| def parent_control_chain(self): | |||||
| self.set_bone_parent(self.bones.ctrl.fk[0], self.bones.mch.rot_tail) | |||||
| self.parent_bone_chain(self.bones.ctrl.fk, use_connect=False) | |||||
| @stage.rig_bones | |||||
| def rig_control_chain(self): | |||||
| ctrls = self.bones.ctrl.fk | |||||
| for args in zip(count(0), ctrls, [self.bones.ctrl.master] + ctrls): | |||||
| self.rig_control_bone(*args) | |||||
| def rig_control_bone(self, i, ctrl, prev_ctrl): | |||||
| self.make_constraint( | |||||
| ctrl, 'COPY_ROTATION', prev_ctrl, | |||||
| use_xyz=self.copy_rotation_axes, | |||||
| space='LOCAL', use_offset=True | |||||
| ) | |||||
| # Widgets | |||||
| def make_control_widget(self, ctrl): | |||||
| create_circle_widget(self.obj, ctrl, radius=0.5, head_tail=0.75) | |||||
| #################################################### | |||||
| # MCH bones associated with main controls | |||||
| @stage.generate_bones | |||||
| def make_mch_control_bones(self): | |||||
| self.bones.mch.rot_tail = self.make_mch_follow_bone(self.bones.org[0], 'tail', 0.0) | |||||
| @stage.parent_bones | |||||
| def parent_mch_control_bones(self): | |||||
| self.set_bone_parent(self.bones.mch.rot_tail, self.rig_parent_bone) | |||||
| #################################################### | |||||
| # Tweak bones | |||||
| @stage.generate_bones | |||||
| def make_tweak_chain(self): | |||||
| orgs = self.bones.org | |||||
| self.bones.ctrl.tweak = map_list(self.make_tweak_bone, count(0), orgs[0:1] + orgs) | |||||
| def make_tweak_bone(self, i, org): | |||||
| if i == 0: | |||||
| if self.check_connect_tweak(org): | |||||
| return self.connected_tweak | |||||
| else: | |||||
| name = self.copy_bone(org, 'tweak_base_' + strip_org(org), parent=False, scale=0.5) | |||||
| else: | |||||
| name = self.copy_bone(org, 'tweak_' + strip_org(org), parent=False, scale=0.5) | |||||
| put_bone(self.obj, name, self.get_bone(org).tail) | |||||
| return name | |||||
| #################################################### | |||||
| # Deform chain | |||||
| @stage.configure_bones | |||||
| def configure_deform_chain(self): | |||||
| if self.use_connect_chain and self.use_connect_reverse: | |||||
| self.get_bone(self.bones.deform[-1]).bone.bbone_easein = 0.0 | |||||
| self.get_bone(self.rigify_parent.bones.deform[0]).bone.bbone_easein = 1.0 | |||||
| else: | |||||
| self.get_bone(self.bones.deform[-1]).bone.bbone_easeout = 0.0 | |||||
| #################################################### | |||||
| # SETTINGS | |||||
| @classmethod | |||||
| def add_parameters(self, params): | |||||
| """ Add the parameters of this rig type to the | |||||
| RigifyParameters PropertyGroup | |||||
| """ | |||||
| super().add_parameters(params) | |||||
| params.copy_rotation_axes = bpy.props.BoolVectorProperty( | |||||
| size=3, | |||||
| description="Automation axes", | |||||
| default=tuple([i == 0 for i in range(0, 3)]) | |||||
| ) | |||||
| @classmethod | |||||
| def parameters_ui(self, layout, params): | |||||
| """ Create the ui for the rig parameters. | |||||
| """ | |||||
| row = layout.row(align=True) | |||||
| for i, axis in enumerate(['x', 'y', 'z']): | |||||
| row.prop(params, "copy_rotation_axes", index=i, toggle=True, text=axis) | |||||
| super().parameters_ui(layout, params) | |||||
| def create_sample(obj, *, parent=None): | |||||
| # generated by rigify.utils.write_metarig | |||||
| bpy.ops.object.mode_set(mode='EDIT') | |||||
| arm = obj.data | |||||
| bones = {} | |||||
| bone = arm.edit_bones.new('tail') | |||||
| bone.head[:] = 0.0000, 0.0552, 1.0099 | |||||
| bone.tail[:] = -0.0000, 0.0582, 0.8669 | |||||
| bone.roll = 0.0000 | |||||
| bone.use_connect = False | |||||
| if parent: | |||||
| bone.parent = arm.edit_bones[parent] | |||||
| bones['tail'] = bone.name | |||||
| bone = arm.edit_bones.new('tail.001') | |||||
| bone.head[:] = -0.0000, 0.0582, 0.8669 | |||||
| bone.tail[:] = -0.0000, 0.0365, 0.7674 | |||||
| bone.roll = 0.0000 | |||||
| bone.use_connect = True | |||||
| bone.parent = arm.edit_bones[bones['tail']] | |||||
| bones['tail.001'] = bone.name | |||||
| bone = arm.edit_bones.new('tail.002') | |||||
| bone.head[:] = -0.0000, 0.0365, 0.7674 | |||||
| bone.tail[:] = -0.0000, 0.0010, 0.6984 | |||||
| bone.roll = 0.0000 | |||||
| bone.use_connect = True | |||||
| bone.parent = arm.edit_bones[bones['tail.001']] | |||||
| bones['tail.002'] = bone.name | |||||
| bpy.ops.object.mode_set(mode='OBJECT') | |||||
| pbone = obj.pose.bones[bones['tail']] | |||||
| pbone.rigify_type = 'spines.basic_tail' | |||||
| pbone.lock_location = (False, False, False) | |||||
| pbone.lock_rotation = (False, False, False) | |||||
| pbone.lock_rotation_w = False | |||||
| pbone.lock_scale = (False, False, False) | |||||
| pbone.rotation_mode = 'QUATERNION' | |||||
| try: | |||||
| pbone.rigify_parameters.connect_chain = bool(parent) | |||||
| except AttributeError: | |||||
| pass | |||||
| try: | |||||
| pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] | |||||
| except AttributeError: | |||||
| pass | |||||
| pbone = obj.pose.bones[bones['tail.001']] | |||||
| pbone.rigify_type = '' | |||||
| pbone.lock_location = (False, False, False) | |||||
| pbone.lock_rotation = (False, False, False) | |||||
| pbone.lock_rotation_w = False | |||||
| pbone.lock_scale = (False, False, False) | |||||
| pbone.rotation_mode = 'QUATERNION' | |||||
| pbone = obj.pose.bones[bones['tail.002']] | |||||
| pbone.rigify_type = '' | |||||
| pbone.lock_location = (False, False, False) | |||||
| pbone.lock_rotation = (False, False, False) | |||||
| pbone.lock_rotation_w = False | |||||
| pbone.lock_scale = (False, False, False) | |||||
| pbone.rotation_mode = 'QUATERNION' | |||||
| bpy.ops.object.mode_set(mode='EDIT') | |||||
| for bone in arm.edit_bones: | |||||
| bone.select = False | |||||
| bone.select_head = False | |||||
| bone.select_tail = False | |||||
| for b in bones: | |||||
| bone = arm.edit_bones[bones[b]] | |||||
| bone.select = True | |||||
| bone.select_head = True | |||||
| bone.select_tail = True | |||||
| arm.edit_bones.active = bone | |||||