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/limbs/super_finger.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/limbs/super_finger.py')
-rw-r--r--rigify/rigs/limbs/super_finger.py538
1 files changed, 237 insertions, 301 deletions
diff --git a/rigify/rigs/limbs/super_finger.py b/rigify/rigs/limbs/super_finger.py
index 081dca7a..1a9171a7 100644
--- a/rigify/rigs/limbs/super_finger.py
+++ b/rigify/rigs/limbs/super_finger.py
@@ -1,298 +1,76 @@
+#====================== 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 ...utils import copy_bone, flip_bone
-from ...utils import strip_org, make_deformer_name, connected_children_names, make_mechanism_name
-from ...utils import create_circle_widget, create_widget
-from ...utils import MetarigError, align_bone_x_axis
-from ...utils.mechanism import make_property
+import re
-script = """
-controls = [%s]
-master_name = '%s'
-if is_selected(controls):
- layout.prop(pose_bones[master_name], '["%s"]', text="Curvature", slider=True)
-"""
+from itertools import count
+from ...utils.errors import MetarigError
+from ...utils.bones import flip_bone, align_chain_x_axis
+from ...utils.naming import make_derived_name
+from ...utils.widgets import create_widget
+from ...utils.widgets_basic import create_circle_widget
+from ...utils.misc import map_list
-class Rig:
+from ...base_rig import stage
- def __init__(self, obj, bone_name, params):
- self.obj = obj
- self.org_bones = [bone_name] + connected_children_names(obj, bone_name)
- self.params = params
+from ..chain_rigs import SimpleChainRig
- if len(self.org_bones) <= 1:
- raise MetarigError("RIGIFY ERROR: Bone '%s': listen bro, that finger rig jusaint put tugetha rite. A little hint, use more than one bone!!" % (strip_org(bone_name)))
- def orient_org_bones(self):
+class Rig(SimpleChainRig):
+ """A finger rig with master control."""
+ def initialize(self):
+ super().initialize()
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ self.bbone_segments = 8
+ self.first_parent = self.get_bone_parent(self.bones.org[0])
+ def prepare_bones(self):
if self.params.primary_rotation_axis == 'automatic':
+ align_chain_x_axis(self.obj, self.bones.org)
- first_bone = eb[self.org_bones[0]]
- last_bone = eb[self.org_bones[-1]]
-
- # Orient uarm farm bones
- chain_y_axis = last_bone.tail - first_bone.head
- chain_rot_axis = first_bone.y_axis.cross(chain_y_axis) # ik-plane normal axis (rotation)
- if chain_rot_axis.length < first_bone.length/100:
- chain_rot_axis = first_bone.x_axis.normalized()
- else:
- chain_rot_axis = chain_rot_axis.normalized()
-
- for bone in self.org_bones:
- align_bone_x_axis(self.obj, bone, chain_rot_axis)
+ ##############################
+ # Master Control
- def generate(self):
- org_bones = self.org_bones
+ @stage.generate_bones
+ def make_master_control(self):
+ orgs = self.bones.org
+ name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_master'), parent=True)
+ self.bones.ctrl.master = name
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ first_bone = self.get_bone(orgs[0])
+ last_bone = self.get_bone(orgs[-1])
+ self.get_bone(name).tail += (last_bone.tail - first_bone.head) * 1.25
- self.orient_org_bones()
+ @stage.configure_bones
+ def configure_master_control(self):
+ master = self.bones.ctrl.master
- # Bone name lists
- ctrl_chain = []
- def_chain = []
- mch_chain = []
- mch_drv_chain = []
+ bone = self.get_bone(master)
+ bone.lock_scale = True, False, True
- # Create ctrl master bone
- org_name = self.org_bones[0]
- temp_name = strip_org(self.org_bones[0])
+ @stage.generate_widgets
+ def make_master_control_widget(self):
+ master_name = self.bones.ctrl.master
- if temp_name[-2:] == '.L' or temp_name[-2:] == '.R':
- suffix = temp_name[-2:]
- master_name = temp_name[:-2] + "_master" + suffix
- else:
- master_name = temp_name + "_master"
- master_name = copy_bone(self.obj, org_name, master_name)
- ctrl_bone_master = eb[master_name]
-
- # Parenting bug fix ??
- ctrl_bone_master.use_connect = False
- ctrl_bone_master.parent = None
-
- ctrl_bone_master.tail += (eb[org_bones[-1]].tail - eb[org_name].head) * 1.25
-
- for bone in org_bones:
- eb[bone].use_connect = False
- if org_bones.index(bone) != 0:
- eb[bone].parent = None
-
- # Creating the bone chains
- for i in range(len(self.org_bones)):
-
- name = self.org_bones[i]
- ctrl_name = strip_org(name)
-
- # Create control bones
- ctrl_bone = copy_bone(self.obj, name, ctrl_name)
- ctrl_bone_e = eb[ctrl_name]
-
- # Create deformation bones
- def_name = make_deformer_name(ctrl_name)
- def_bone = copy_bone(self.obj, name, def_name)
-
- # Create mechanism bones
- mch_name = make_mechanism_name(ctrl_name)
- mch_bone = copy_bone(self.obj, name, mch_name)
-
- # Create mechanism driver bones
- drv_name = make_mechanism_name(ctrl_name) + "_drv"
- mch_bone_drv = copy_bone(self.obj, name, drv_name)
-
- # Adding to lists
- ctrl_chain += [ctrl_bone]
- def_chain += [def_bone]
- mch_chain += [mch_bone]
- mch_drv_chain += [mch_bone_drv]
-
- # Restoring org chain parenting
- for bone in org_bones[1:]:
- eb[bone].parent = eb[org_bones[org_bones.index(bone) - 1]]
-
- # Parenting the master bone to the first org
- ctrl_bone_master = eb[master_name]
- ctrl_bone_master.parent = eb[org_bones[0]]
-
- # Parenting chain bones
- for i in range(len(self.org_bones)):
- # Edit bone references
- def_bone_e = eb[def_chain[i]]
- ctrl_bone_e = eb[ctrl_chain[i]]
- mch_bone_e = eb[mch_chain[i]]
- mch_bone_drv_e = eb[mch_drv_chain[i]]
-
- if i == 0:
- # First ctl bone
- ctrl_bone_e.parent = mch_bone_drv_e
- ctrl_bone_e.use_connect = False
- # First def bone
- def_bone_e.parent = eb[self.org_bones[i]].parent
- def_bone_e.use_connect = False
- # First mch bone
- mch_bone_e.parent = eb[self.org_bones[i]].parent
- mch_bone_e.use_connect = False
- # First mch driver bone
- mch_bone_drv_e.parent = eb[self.org_bones[i]].parent
- mch_bone_drv_e.use_connect = False
- else:
- # The rest
- ctrl_bone_e.parent = mch_bone_drv_e
- ctrl_bone_e.use_connect = False
-
- def_bone_e.parent = eb[def_chain[i-1]]
- def_bone_e.use_connect = True
-
- mch_bone_drv_e.parent = eb[ctrl_chain[i-1]]
- mch_bone_drv_e.use_connect = False
-
- # Parenting mch bone
- mch_bone_e.parent = ctrl_bone_e
- mch_bone_e.use_connect = False
-
- # Creating tip control bone
- tip_name = copy_bone(self.obj, org_bones[-1], temp_name)
- ctrl_bone_tip = eb[tip_name]
- flip_bone(self.obj, tip_name)
- ctrl_bone_tip.length /= 2
-
- ctrl_bone_tip.parent = eb[ctrl_chain[-1]]
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- pb = self.obj.pose.bones
-
- # Setting pose bones locks
- pb_master = pb[master_name]
- pb_master.lock_scale = True, False, True
-
- pb[tip_name].lock_scale = True, True, True
- pb[tip_name].lock_rotation = True, True, True
- pb[tip_name].lock_rotation_w = True
-
- make_property(pb_master, 'finger_curve', 0.0, description="Rubber hose finger cartoon effect")
-
- # Pose settings
- for org, ctrl, deform, mch, mch_drv in zip(self.org_bones, ctrl_chain, def_chain, mch_chain, mch_drv_chain):
-
- # Constraining the deform bones
- con = pb[deform].constraints.new('COPY_TRANSFORMS')
- con.target = self.obj
- con.subtarget = mch
-
- # Constraining the mch bones
- if mch_chain.index(mch) == 0:
- con = pb[mch].constraints.new('COPY_LOCATION')
- con.target = self.obj
- con.subtarget = ctrl
-
- con = pb[mch].constraints.new('COPY_SCALE')
- con.target = self.obj
- con.subtarget = ctrl
-
- con = pb[mch].constraints.new('DAMPED_TRACK')
- con.target = self.obj
- con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]
-
- con = pb[mch].constraints.new('STRETCH_TO')
- con.target = self.obj
- con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]
- con.volume = 'NO_VOLUME'
-
- elif mch_chain.index(mch) == len(mch_chain) - 1:
- con = pb[mch].constraints.new('DAMPED_TRACK')
- con.target = self.obj
- con.subtarget = tip_name
-
- con = pb[mch].constraints.new('STRETCH_TO')
- con.target = self.obj
- con.subtarget = tip_name
- con.volume = 'NO_VOLUME'
- else:
- con = pb[mch].constraints.new('DAMPED_TRACK')
- con.target = self.obj
- con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]
-
- con = pb[mch].constraints.new('STRETCH_TO')
- con.target = self.obj
- con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]
- con.volume = 'NO_VOLUME'
-
- # Constraining and driving mch driver bones
- pb[mch_drv].rotation_mode = 'YZX'
-
- if mch_drv_chain.index(mch_drv) == 0:
- # Constraining to master bone
- con = pb[mch_drv].constraints.new('COPY_LOCATION')
- con.target = self.obj
- con.subtarget = master_name
-
- con = pb[mch_drv].constraints.new('COPY_ROTATION')
- con.target = self.obj
- con.subtarget = master_name
- con.target_space = 'LOCAL'
- con.owner_space = 'LOCAL'
-
- else:
- # Match axis to expression
- options = {
- "automatic": {"axis": 0,
- "expr": '(1-sy)*pi'},
- "X": {"axis": 0,
- "expr": '(1-sy)*pi'},
- "-X": {"axis": 0,
- "expr": '-((1-sy)*pi)'},
- "Y": {"axis": 1,
- "expr": '(1-sy)*pi'},
- "-Y": {"axis": 1,
- "expr": '-((1-sy)*pi)'},
- "Z": {"axis": 2,
- "expr": '(1-sy)*pi'},
- "-Z": {"axis": 2,
- "expr": '-((1-sy)*pi)'}
- }
-
- axis = self.params.primary_rotation_axis
-
- # Drivers
- drv = pb[mch_drv].driver_add("rotation_euler", options[axis]["axis"]).driver
- drv.type = 'SCRIPTED'
- drv.expression = options[axis]["expr"]
- drv_var = drv.variables.new()
- drv_var.name = 'sy'
- drv_var.type = "SINGLE_PROP"
- drv_var.targets[0].id = self.obj
- drv_var.targets[0].data_path = pb[master_name].path_from_id() + '.scale.y'
-
- # Setting bone curvature setting, custom property, and drivers
- def_bone = self.obj.data.bones[deform]
-
- def_bone.bbone_segments = 8
- drv = def_bone.driver_add("bbone_easein").driver # Ease in
-
- drv.type='SUM'
- drv_var = drv.variables.new()
- drv_var.name = "curvature"
- drv_var.type = "SINGLE_PROP"
- drv_var.targets[0].id = self.obj
- drv_var.targets[0].data_path = pb_master.path_from_id() + '["finger_curve"]'
-
- drv = def_bone.driver_add("bbone_easeout").driver # Ease out
-
- drv.type='SUM'
- drv_var = drv.variables.new()
- drv_var.name = "curvature"
- drv_var.type = "SINGLE_PROP"
- drv_var.targets[0].id = self.obj
- drv_var.targets[0].data_path = pb_master.path_from_id() + '["finger_curve"]'
-
- # Assigning shapes to control bones
- create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5)
-
- # Create ctrl master widget
w = create_widget(self.obj, master_name)
if w is not None:
mesh = w.data
@@ -307,31 +85,189 @@ class Rig:
mesh.from_pydata(verts, edges, [])
mesh.update()
- # Create tip control widget
- create_circle_widget(self.obj, tip_name, radius=0.3, head_tail=0.0)
+ ##############################
+ # Control chain
+
+ @stage.generate_bones
+ def make_control_chain(self):
+ orgs = self.bones.org
+ self.bones.ctrl.fk = map_list(self.make_control_bone, count(0), orgs)
+ self.bones.ctrl.fk += [self.make_tip_control_bone(orgs[-1], orgs[0])]
+
+ def make_control_bone(self, i, org):
+ return self.copy_bone(org, make_derived_name(org, 'ctrl'), parent=False)
+
+ def make_tip_control_bone(self, org, name_org):
+ name = self.copy_bone(org, make_derived_name(name_org, 'ctrl'), parent=False)
+
+ flip_bone(self.obj, name)
+ self.get_bone(name).length /= 2
+
+ return name
+
+ @stage.parent_bones
+ def parent_control_chain(self):
+ ctrls = self.bones.ctrl.fk
+ for args in zip(ctrls, self.bones.mch.bend + ctrls[-2:]):
+ self.set_bone_parent(*args)
+
+ @stage.configure_bones
+ def configure_control_chain(self):
+ for args in zip(count(0), self.bones.ctrl.fk, self.bones.org + [None]):
+ self.configure_control_bone(*args)
+
+ def configure_control_bone(self, i, ctrl, org):
+ if org:
+ self.copy_bone_properties(org, ctrl)
+ else:
+ bone = self.get_bone(ctrl)
+ bone.lock_rotation_w = True
+ bone.lock_rotation = (True, True, True)
+ bone.lock_scale = (True, True, True)
+
+ def make_control_widget(self, ctrl):
+ if ctrl == self.bones.ctrl.fk[-1]:
+ # Tip control
+ create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.0)
+ else:
+ create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5)
+
+ ##############################
+ # MCH bend chain
+
+ @stage.generate_bones
+ def make_mch_bend_chain(self):
+ self.bones.mch.bend = map_list(self.make_mch_bend_bone, self.bones.org)
+
+ def make_mch_bend_bone(self, org):
+ return self.copy_bone(org, make_derived_name(org, 'mch', '_drv'), parent=False)
+
+ @stage.parent_bones
+ def parent_mch_bend_chain(self):
+ ctrls = self.bones.ctrl.fk
+ for args in zip(self.bones.mch.bend, [self.first_parent] + ctrls):
+ self.set_bone_parent(*args)
+
+ # Match axis to expression
+ axis_options = {
+ "automatic": {"axis": 0,
+ "expr": '(1-sy)*pi'},
+ "X": {"axis": 0,
+ "expr": '(1-sy)*pi'},
+ "-X": {"axis": 0,
+ "expr": '-((1-sy)*pi)'},
+ "Y": {"axis": 1,
+ "expr": '(1-sy)*pi'},
+ "-Y": {"axis": 1,
+ "expr": '-((1-sy)*pi)'},
+ "Z": {"axis": 2,
+ "expr": '(1-sy)*pi'},
+ "-Z": {"axis": 2,
+ "expr": '-((1-sy)*pi)'}
+ }
+
+ @stage.rig_bones
+ def rig_mch_bend_chain(self):
+ for args in zip(count(0), self.bones.mch.bend):
+ self.rig_mch_bend_bone(*args)
+
+ def rig_mch_bend_bone(self, i, mch):
+ master = self.bones.ctrl.master
+ if i == 0:
+ self.make_constraint(mch, 'COPY_LOCATION', master)
+ self.make_constraint(mch, 'COPY_ROTATION', master, space='LOCAL')
+ else:
+ axis = self.params.primary_rotation_axis
+ options = self.axis_options[axis]
+
+ bone = self.get_bone(mch)
+ bone.rotation_mode = 'YZX'
+
+ self.make_driver(
+ bone, 'rotation_euler', index=options['axis'],
+ expression=options['expr'],
+ variables={'sy': (master, '.scale.y')}
+ )
+
+ ##############################
+ # MCH stretch chain
+
+ @stage.generate_bones
+ def make_mch_stretch_chain(self):
+ self.bones.mch.stretch = map_list(self.make_mch_stretch_bone, self.bones.org)
+
+ def make_mch_stretch_bone(self, org):
+ return self.copy_bone(org, make_derived_name(org, 'mch'), parent=False)
+
+ @stage.parent_bones
+ def parent_mch_stretch_chain(self):
+ ctrls = self.bones.ctrl.fk
+ for args in zip(self.bones.mch.stretch, [self.first_parent] + ctrls[1:]):
+ self.set_bone_parent(*args)
+
+ @stage.rig_bones
+ def rig_mch_stretch_chain(self):
+ ctrls = self.bones.ctrl.fk
+ for args in zip(count(0), self.bones.mch.stretch, ctrls, ctrls[1:]):
+ self.rig_mch_stretch_bone(*args)
+
+ def rig_mch_stretch_bone(self, i, mch, ctrl, ctrl_next):
+ if i == 0:
+ self.make_constraint(mch, 'COPY_LOCATION', ctrl)
+ self.make_constraint(mch, 'COPY_SCALE', ctrl)
+
+ self.make_constraint(mch, 'DAMPED_TRACK', ctrl_next)
+ self.make_constraint(mch, 'STRETCH_TO', ctrl_next, volume='NO_VOLUME')
+
+ ##############################
+ # ORG chain
+
+ @stage.rig_bones
+ def rig_org_chain(self):
+ for args in zip(count(0), self.bones.org, self.bones.mch.stretch):
+ self.rig_org_bone(*args)
+
+ ##############################
+ # Deform chain
+
+ @stage.configure_bones
+ def configure_master_properties(self):
+ master = self.bones.ctrl.master
+
+ self.make_property(master, 'finger_curve', 0.0, description="Rubber hose finger cartoon effect")
# Create UI
- controls_string = ", ".join(
- ["'" + x + "'" for x in ctrl_chain]
- ) + ", " + "'" + master_name + "'"
- return [script % (controls_string, master_name, 'finger_curve')]
-
-
-def add_parameters(params):
- """ Add the parameters of this rig type to the
- RigifyParameters PropertyGroup
- """
- items = [('automatic', 'Automatic', ''), ('X', 'X manual', ''), ('Y', 'Y manual', ''), ('Z', 'Z manual', ''),
- ('-X', '-X manual', ''), ('-Y', '-Y manual', ''), ('-Z', '-Z manual', '')]
- params.primary_rotation_axis = bpy.props.EnumProperty(items=items, name="Primary Rotation Axis", default='automatic')
-
-
-def parameters_ui(layout, params):
- """ Create the ui for the rig parameters.
- """
- r = layout.row()
- r.label(text="Bend rotation axis:")
- r.prop(params, "primary_rotation_axis", text="")
+ panel = self.script.panel_with_selected_check(self, self.bones.ctrl.flatten())
+ panel.custom_prop(master, 'finger_curve', text="Curvature", slider=True)
+
+ def rig_deform_bone(self, i, deform, org):
+ master = self.bones.ctrl.master
+ bone = self.get_bone(deform)
+
+ self.make_constraint(deform, 'COPY_TRANSFORMS', org)
+
+ self.make_driver(bone.bone, 'bbone_easein', variables=[(master, 'finger_curve')])
+ self.make_driver(bone.bone, 'bbone_easeout', variables=[(master, 'finger_curve')])
+
+ ###############
+ # OPTIONS
+
+ @classmethod
+ def add_parameters(self, params):
+ """ Add the parameters of this rig type to the
+ RigifyParameters PropertyGroup
+ """
+ items = [('automatic', 'Automatic', ''), ('X', 'X manual', ''), ('Y', 'Y manual', ''), ('Z', 'Z manual', ''),
+ ('-X', '-X manual', ''), ('-Y', '-Y manual', ''), ('-Z', '-Z manual', '')]
+ params.primary_rotation_axis = bpy.props.EnumProperty(items=items, name="Primary Rotation Axis", default='automatic')
+
+ @classmethod
+ def parameters_ui(self, layout, params):
+ """ Create the ui for the rig parameters.
+ """
+ r = layout.row()
+ r.label(text="Bend rotation axis:")
+ r.prop(params, "primary_rotation_axis", text="")
def create_sample(obj):