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

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2019-09-14 09:17:30 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2019-09-14 09:30:00 +0300
commit8b1df843703fdb51ffa5758625c117c4f10bc6dd (patch)
tree949e84f80116132eab3ad5f3bac46e745c3a9195 /rigify/rigs/spines/super_head.py
parent9b693a6be0aa2b0b4825d30ac5034655dce9c0dd (diff)
Rigify: replace rigs with new implementations using the new base rig.
Spine is split into parts. Limbs and tentacles simply converted. Differential Revision: https://developer.blender.org/D4624
Diffstat (limited to 'rigify/rigs/spines/super_head.py')
-rw-r--r--rigify/rigs/spines/super_head.py406
1 files changed, 406 insertions, 0 deletions
diff --git a/rigify/rigs/spines/super_head.py b/rigify/rigs/spines/super_head.py
new file mode 100644
index 00000000..79ec2396
--- /dev/null
+++ b/rigify/rigs/spines/super_head.py
@@ -0,0 +1,406 @@
+#====================== 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 make_derived_name
+from ...utils.bones import align_bone_orientation
+from ...utils.widgets_basic import create_circle_widget, create_cube_widget
+from ...utils.widgets_special import create_neck_bend_widget, create_neck_tweak_widget
+from ...utils.misc import map_list
+
+from ...base_rig import stage
+
+from .spine_rigs import BaseHeadTailRig
+
+
+class Rig(BaseHeadTailRig):
+ """
+ Head rig with long neck support and connect option.
+ """
+
+ use_connect_reverse = False
+
+ def initialize(self):
+ super().initialize()
+
+ self.long_neck = len(self.bones.org) > 3
+
+ ####################################################
+ # BONES
+ #
+ # org[]:
+ # ORG bones
+ # ctrl:
+ # neck, head, neck_bend:
+ # Main controls.
+ # tweak[]:
+ # Tweak control chain.
+ # mch:
+ # rot_neck, rot_head:
+ # Main control parents, implement FK follow.
+ # stretch
+ # Long neck stretch behavior.
+ # ik[]
+ # Long neck IK behavior.
+ # chain[]
+ # Tweak parents.
+ # deform[]:
+ # DEF bones
+ #
+ ####################################################
+
+ ####################################################
+ # Main control bones
+
+ @stage.generate_bones
+ def make_control_chain(self):
+ orgs = self.bones.org
+ ctrl = self.bones.ctrl
+
+ ctrl.neck = self.make_neck_control_bone(orgs[0], 'neck', orgs[-1])
+ ctrl.head = self.make_head_control_bone(orgs[-1], 'head')
+ if self.long_neck:
+ ctrl.neck_bend = self.make_neck_bend_control_bone(orgs[0], 'neck_bend', ctrl.neck)
+
+ self.default_prop_bone = ctrl.head
+
+ def make_neck_control_bone(self, org, name, org_head):
+ name = self.copy_bone(org, name, parent=False)
+
+ # Neck spans all neck bones (except head)
+ self.get_bone(name).tail = self.get_bone(org_head).head
+
+ return name
+
+ def make_neck_bend_control_bone(self, org, name, neck):
+ name = self.copy_bone(org, name, parent=False)
+ neck_bend_eb = self.get_bone(name)
+
+ # Neck pivot position
+ neck_bones = self.bones.org
+ if (len(neck_bones)-1) % 2: # odd num of neck bones (head excluded)
+ center_bone = self.get_bone(neck_bones[int((len(neck_bones))/2) - 1])
+ neck_bend_eb.head = (center_bone.head + center_bone.tail)/2
+ else:
+ center_bone = self.get_bone(neck_bones[int((len(neck_bones)-1)/2) - 1])
+ neck_bend_eb.head = center_bone.tail
+
+ align_bone_orientation(self.obj, name, neck)
+ neck_bend_eb.length = self.get_bone(neck).length / 2
+
+ return name
+
+ def make_head_control_bone(self, org, name):
+ return self.copy_bone(org, name, parent=False)
+
+ @stage.parent_bones
+ def parent_control_chain(self):
+ ctrl = self.bones.ctrl
+ mch = self.bones.mch
+ self.set_bone_parent(ctrl.neck, mch.rot_neck)
+ self.set_bone_parent(ctrl.head, mch.rot_head)
+ if self.long_neck:
+ self.set_bone_parent(ctrl.neck_bend, mch.stretch)
+
+ @stage.configure_bones
+ def configure_control_chain(self):
+ self.configure_control_bone(0, self.bones.ctrl.neck, self.bones.org[0])
+ self.configure_control_bone(2, self.bones.ctrl.head, self.bones.org[-1])
+ if self.long_neck:
+ self.configure_control_bone(1, self.bones.ctrl.neck_bend, self.bones.org[0])
+
+ @stage.generate_widgets
+ def make_control_widgets(self):
+ ctrl = self.bones.ctrl
+ self.make_neck_widget(ctrl.neck)
+ self.make_head_widget(ctrl.head)
+ if self.long_neck:
+ self.make_neck_bend_widget(ctrl.neck_bend)
+
+ def make_neck_widget(self, ctrl):
+ radius = 1/max(1, len(self.bones.mch.chain))
+
+ create_circle_widget(
+ self.obj, ctrl,
+ radius=radius,
+ head_tail=0.5,
+ bone_transform_name=None
+ )
+
+ def make_neck_bend_widget(self, ctrl):
+ radius = 1/max(1, len(self.bones.mch.chain))
+
+ create_neck_bend_widget(
+ self.obj, ctrl,
+ radius=radius/2,
+ head_tail=0.0,
+ bone_transform_name=None
+ )
+
+ def make_head_widget(self, ctrl):
+ # place wgt @ middle of head bone for long necks
+ if self.long_neck:
+ head_tail = 0.5
+ else:
+ head_tail = 1.0
+
+ create_circle_widget(
+ self.obj, ctrl,
+ radius = 0.5,
+ head_tail = head_tail,
+ with_line = False,
+ bone_transform_name = None
+ )
+
+ ####################################################
+ # MCH bones associated with main controls
+
+ @stage.generate_bones
+ def make_mch_control_bones(self):
+ orgs = self.bones.org
+ mch = self.bones.mch
+
+ mch.rot_neck = self.make_mch_follow_bone(orgs[0], 'neck', 0.5, copy_scale=True)
+ mch.rot_head = self.make_mch_follow_bone(orgs[-1], 'head', 0.0, copy_scale=True)
+ mch.stretch = self.make_mch_stretch_bone(orgs[0], 'STR-neck', orgs[-1])
+
+ def make_mch_stretch_bone(self, org, name, org_head):
+ name = self.copy_bone(org, make_derived_name(name, 'mch'), parent=False)
+ self.get_bone(name).tail = self.get_bone(org_head).head
+ return name
+
+ @stage.parent_bones
+ def parent_mch_control_bones(self):
+ self.set_bone_parent(self.bones.mch.rot_neck, self.rig_parent_bone)
+ self.set_bone_parent(self.bones.mch.rot_head, self.bones.ctrl.neck)
+ self.set_bone_parent(self.bones.mch.stretch, self.bones.ctrl.neck)
+
+ @stage.rig_bones
+ def rig_mch_control_bones(self):
+ self.rig_mch_stretch_bone(self.bones.mch.stretch, self.bones.ctrl.head)
+
+ def rig_mch_stretch_bone(self, mch, head):
+ self.make_constraint(mch, 'DAMPED_TRACK', head)
+ self.make_constraint(mch, 'STRETCH_TO', head)
+
+ ####################################################
+ # MCH IK chain for the long neck
+
+ @stage.generate_bones
+ def make_mch_ik_chain(self):
+ orgs = self.bones.org
+ if self.long_neck:
+ self.bones.mch.ik = map_list(self.make_mch_ik_bone, orgs[0:-1])
+
+ def make_mch_ik_bone(self, org):
+ return self.copy_bone(org, make_derived_name(org, 'mch', '_ik'), parent=False)
+
+ @stage.parent_bones
+ def parent_mch_ik_chain(self):
+ if self.long_neck:
+ ik = self.bones.mch.ik
+ self.set_bone_parent(ik[0], self.bones.ctrl.tweak[0])
+ self.parent_bone_chain(ik, use_connect=True)
+
+ @stage.rig_bones
+ def rig_mch_ik_chain(self):
+ if self.long_neck:
+ ik = self.bones.mch.ik
+ head = self.bones.ctrl.head
+ for args in zip(count(0), ik):
+ self.rig_mch_ik_bone(*args, len(ik), head)
+
+ def rig_mch_ik_bone(self, i, mch, ik_len, head):
+ if i == ik_len - 1:
+ self.make_constraint(mch, 'IK', head, chain_count=ik_len)
+
+ self.get_bone(mch).ik_stretch = 0.1
+
+ ####################################################
+ # MCH chain for the middle of the neck
+
+ @stage.generate_bones
+ def make_mch_chain(self):
+ orgs = self.bones.org
+ self.bones.mch.chain = map_list(self.make_mch_bone, orgs[1:-1])
+
+ def make_mch_bone(self, org):
+ return self.copy_bone(org, make_derived_name(org, 'mch'), parent=False, scale=1/4)
+
+ @stage.parent_bones
+ def align_mch_chain(self):
+ for mch in self.bones.mch.chain:
+ align_bone_orientation(self.obj, mch, self.bones.ctrl.neck)
+
+ @stage.parent_bones
+ def parent_mch_chain(self):
+ mch = self.bones.mch
+ for bone in mch.chain:
+ self.set_bone_parent(bone, mch.stretch)
+ self.get_bone(bone).use_inherit_scale = False
+
+ @stage.rig_bones
+ def rig_mch_chain(self):
+ chain = self.bones.mch.chain
+ if self.long_neck:
+ ik = self.bones.mch.ik
+ for args in zip(count(0), chain, ik[1:]):
+ self.rig_mch_bone_long(*args, len(chain))
+ else:
+ for args in zip(count(0), chain):
+ self.rig_mch_bone(*args, len(chain))
+
+ def rig_mch_bone_long(self, i, mch, ik, len_mch):
+ ctrl = self.bones.ctrl
+
+ self.make_constraint(mch, 'COPY_LOCATION', ik)
+
+ step = 2/(len_mch+1)
+ xval = (i+1)*step
+ influence = 2*xval - xval**2 #parabolic influence of pivot
+
+ self.make_constraint(
+ mch, 'COPY_LOCATION', ctrl.neck_bend,
+ influence=influence, use_offset=True, space='LOCAL'
+ )
+
+ self.make_constraint(mch, 'COPY_SCALE', ctrl.neck)
+
+ def rig_mch_bone(self, i, mch, len_mch):
+ ctrl = self.bones.ctrl
+
+ nfactor = float((i + 1) / (len_mch + 1))
+ self.make_constraint(
+ mch, 'COPY_ROTATION', ctrl.head,
+ influence=nfactor, space='LOCAL'
+ )
+
+ ####################################################
+ # 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])
+
+ @stage.parent_bones
+ def parent_tweak_chain(self):
+ ctrl = self.bones.ctrl
+ mch = self.bones.mch
+
+ for args in zip(ctrl.tweak, [ctrl.neck, *mch.chain]):
+ self.set_bone_parent(*args)
+
+ @stage.rig_bones
+ def generate_neck_tweak_widget(self):
+ # Generate the widget early to override connected parent
+ if self.long_neck:
+ bone = self.bones.ctrl.tweak[0]
+ create_neck_tweak_widget(self.obj, bone, size=1.0)
+
+ ####################################################
+ # ORG and DEF bones
+
+ @stage.configure_bones
+ def configure_bbone_chain(self):
+ self.get_bone(self.bones.deform[-1]).bone.bbone_segments = 1
+
+ @stage.rig_bones
+ def rig_org_chain(self):
+ tweaks = self.bones.ctrl.tweak + [self.bones.ctrl.head]
+ for args in zip(count(0), self.bones.org, tweaks, tweaks[1:] + [None]):
+ self.rig_org_bone(*args)
+
+
+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('neck')
+ bone.head[:] = 0.0000, 0.0114, 1.6582
+ bone.tail[:] = 0.0000, -0.0130, 1.7197
+ bone.roll = 0.0000
+ bone.use_connect = False
+ if parent:
+ bone.parent = arm.edit_bones[parent]
+ bones['neck'] = bone.name
+ bone = arm.edit_bones.new('neck.001')
+ bone.head[:] = 0.0000, -0.0130, 1.7197
+ bone.tail[:] = 0.0000, -0.0247, 1.7813
+ bone.roll = 0.0000
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['neck']]
+ bones['neck.001'] = bone.name
+ bone = arm.edit_bones.new('head')
+ bone.head[:] = 0.0000, -0.0247, 1.7813
+ bone.tail[:] = 0.0000, -0.0247, 1.9796
+ bone.roll = 0.0000
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['neck.001']]
+ bones['head'] = bone.name
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+ pbone = obj.pose.bones[bones['neck']]
+ pbone.rigify_type = 'spines.super_head'
+ 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['neck.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['head']]
+ 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