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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'release/scripts/modules/rigify/tongue.py')
-rw-r--r--release/scripts/modules/rigify/tongue.py361
1 files changed, 361 insertions, 0 deletions
diff --git a/release/scripts/modules/rigify/tongue.py b/release/scripts/modules/rigify/tongue.py
new file mode 100644
index 00000000000..b6dfe756b71
--- /dev/null
+++ b/release/scripts/modules/rigify/tongue.py
@@ -0,0 +1,361 @@
+# ##### 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 rigify import RigifyError
+from rigify_utils import bone_class_instance, copy_bone_simple
+from rna_prop_ui import rna_idprop_ui_prop_get
+
+# not used, defined for completeness
+METARIG_NAMES = ("body", "head")
+
+
+def metarig_template():
+ # TODO:
+ ## generated by rigify.write_meta_rig
+ #bpy.ops.object.mode_set(mode='EDIT')
+ #obj = bpy.context.active_object
+ #arm = obj.data
+ #bone = arm.edit_bones.new('body')
+ #bone.head[:] = 0.0000, -0.0276, -0.1328
+ #bone.tail[:] = 0.0000, -0.0170, -0.0197
+ #bone.roll = 0.0000
+ #bone.connected = False
+ #bone = arm.edit_bones.new('head')
+ #bone.head[:] = 0.0000, -0.0170, -0.0197
+ #bone.tail[:] = 0.0000, 0.0726, 0.1354
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['body']
+ #bone = arm.edit_bones.new('neck.01')
+ #bone.head[:] = 0.0000, -0.0170, -0.0197
+ #bone.tail[:] = 0.0000, -0.0099, 0.0146
+ #bone.roll = 0.0000
+ #bone.connected = False
+ #bone.parent = arm.edit_bones['head']
+ #bone = arm.edit_bones.new('neck.02')
+ #bone.head[:] = 0.0000, -0.0099, 0.0146
+ #bone.tail[:] = 0.0000, -0.0242, 0.0514
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.01']
+ #bone = arm.edit_bones.new('neck.03')
+ #bone.head[:] = 0.0000, -0.0242, 0.0514
+ #bone.tail[:] = 0.0000, -0.0417, 0.0868
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.02']
+ #bone = arm.edit_bones.new('neck.04')
+ #bone.head[:] = 0.0000, -0.0417, 0.0868
+ #bone.tail[:] = 0.0000, -0.0509, 0.1190
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.03']
+ #bone = arm.edit_bones.new('neck.05')
+ #bone.head[:] = 0.0000, -0.0509, 0.1190
+ #bone.tail[:] = 0.0000, -0.0537, 0.1600
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.04']
+ #
+ #bpy.ops.object.mode_set(mode='OBJECT')
+ #pbone = obj.pose.bones['head']
+ #pbone['type'] = 'neck_flex'
+ pass
+
+
+def metarig_definition(obj, orig_bone_name):
+ '''
+ The bone given is the tongue control, its parent is the body,
+ # its only child the first of a chain with matching basenames.
+ eg.
+ body -> tongue_control -> tongue_01 -> tongue_02 -> tongue_03.... etc
+ '''
+ arm = obj.data
+ tongue = arm.bones[orig_bone_name]
+ body = tongue.parent
+
+ children = tongue.children
+ if len(children) != 1:
+ raise RigifyError("expected the tongue bone '%s' to have only 1 child." % orig_bone_name)
+
+ child = children[0]
+ bone_definition = [body.name, tongue.name, child.name]
+ bone_definition.extend([child.name for child in child.children_recursive_basename])
+ return bone_definition
+
+
+def deform(obj, definitions, base_names, options):
+ for org_bone_name in definitions[2:]:
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ # Create deform bone.
+ bone = copy_bone_simple(obj.data, org_bone_name, "DEF-%s" % base_names[org_bone_name], parent=True)
+
+ # Store name before leaving edit mode
+ bone_name = bone.name
+
+ # Leave edit mode
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Get the pose bone
+ bone = obj.pose.bones[bone_name]
+
+ # Constrain to the original bone
+ # XXX. Todo, is this needed if the bone is connected to its parent?
+ con = bone.constraints.new('COPY_TRANSFORMS')
+ con.name = "copy_loc"
+ con.target = obj
+ con.subtarget = org_bone_name
+
+
+# TODO: rename all of the head/neck references to tongue
+def main(obj, bone_definition, base_names, options):
+ from mathutils import Vector
+
+ arm = obj.data
+
+ # Initialize container classes for convenience
+ mt = bone_class_instance(obj, ["body", "head"]) # meta
+ mt.body = bone_definition[0]
+ mt.head = bone_definition[1]
+ mt.update()
+
+ neck_chain = bone_definition[2:]
+
+ mt_chain = bone_class_instance(obj, [("neck_%.2d" % (i + 1)) for i in range(len(neck_chain))]) # 99 bones enough eh?
+ for i, attr in enumerate(mt_chain.attr_names):
+ setattr(mt_chain, attr, neck_chain[i])
+ mt_chain.update()
+
+ neck_chain_basename = base_names[mt_chain.neck_01_e.name].split(".")[0]
+ neck_chain_segment_length = mt_chain.neck_01_e.length
+
+ ex = bone_class_instance(obj, ["head", "head_hinge", "neck_socket", "head_ctrl"]) # hinge & extras
+
+ # Add the head hinge at the bodys location, becomes the parent of the original head
+
+ # apply everything to this copy of the chain
+ ex_chain = mt_chain.copy(base_names=base_names)
+ ex_chain.neck_01_e.parent = mt_chain.neck_01_e.parent
+
+
+ # Copy the head bone and offset
+ ex.head_e = copy_bone_simple(arm, mt.head, "MCH-%s" % base_names[mt.head], parent=True)
+ ex.head_e.connected = False
+ ex.head = ex.head_e.name
+ # offset
+ head_length = ex.head_e.length
+ ex.head_e.head.y += head_length / 2.0
+ ex.head_e.tail.y += head_length / 2.0
+
+ # Yes, use the body bone but call it a head hinge
+ ex.head_hinge_e = copy_bone_simple(arm, mt.body, "MCH-%s_hinge" % base_names[mt.head], parent=False)
+ ex.head_hinge_e.connected = False
+ ex.head_hinge = ex.head_hinge_e.name
+ ex.head_hinge_e.head.y += head_length / 4.0
+ ex.head_hinge_e.tail.y += head_length / 4.0
+
+ # Insert the neck socket, the head copys this loation
+ ex.neck_socket_e = arm.edit_bones.new("MCH-%s_socked" % neck_chain_basename)
+ ex.neck_socket = ex.neck_socket_e.name
+ ex.neck_socket_e.connected = False
+ ex.neck_socket_e.parent = mt.body_e
+ ex.neck_socket_e.head = mt.head_e.head
+ ex.neck_socket_e.tail = mt.head_e.head - Vector((0.0, neck_chain_segment_length / 2.0, 0.0))
+ ex.neck_socket_e.roll = 0.0
+
+
+ # copy of the head for controling
+ ex.head_ctrl_e = copy_bone_simple(arm, mt.head, base_names[mt.head])
+ ex.head_ctrl = ex.head_ctrl_e.name
+ ex.head_ctrl_e.parent = ex.head_hinge_e
+
+ for i, attr in enumerate(ex_chain.attr_names):
+ neck_e = getattr(ex_chain, attr + "_e")
+
+ # dont store parent names, re-reference as each chain bones parent.
+ neck_e_parent = arm.edit_bones.new("MCH-rot_%s" % base_names[getattr(mt_chain, attr)])
+ neck_e_parent.head = neck_e.head
+ neck_e_parent.tail = neck_e.head + (mt.head_e.vector.normalize() * neck_chain_segment_length / 2.0)
+ neck_e_parent.roll = mt.head_e.roll
+
+ orig_parent = neck_e.parent
+ neck_e.connected = False
+ neck_e.parent = neck_e_parent
+ neck_e_parent.connected = False
+
+ if i == 0:
+ neck_e_parent.parent = mt.body_e
+ else:
+ neck_e_parent.parent = orig_parent
+
+ deform(obj, bone_definition, base_names, options)
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ mt.update()
+ mt_chain.update()
+ ex_chain.update()
+ ex.update()
+
+ # Axis locks
+ ex.head_ctrl_p.lock_location = True, True, True
+ ex.head_ctrl_p.lock_scale = True, False, True
+
+ # Simple one off constraints, no drivers
+ con = ex.head_ctrl_p.constraints.new('COPY_LOCATION')
+ con.target = obj
+ con.subtarget = ex.neck_socket
+
+ con = ex.head_p.constraints.new('COPY_ROTATION')
+ con.target = obj
+ con.subtarget = ex.head_ctrl
+
+ # driven hinge
+ prop = rna_idprop_ui_prop_get(ex.head_ctrl_p, "hinge", create=True)
+ ex.head_ctrl_p["hinge"] = 0.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+
+ con = ex.head_hinge_p.constraints.new('COPY_ROTATION')
+ con.name = "hinge"
+ con.target = obj
+ con.subtarget = mt.body
+
+ # add driver
+ hinge_driver_path = ex.head_ctrl_p.path_to_id() + '["hinge"]'
+
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = hinge_driver_path
+
+ #mod = fcurve_driver.modifiers.new('GENERATOR')
+ mod = fcurve.modifiers[0]
+ mod.poly_order = 1
+ mod.coefficients[0] = 1.0
+ mod.coefficients[1] = -1.0
+
+ head_driver_path = ex.head_ctrl_p.path_to_id()
+
+ target_names = [("b%.2d" % (i + 1)) for i in range(len(neck_chain))]
+
+ ex.head_ctrl_p["bend_tot"] = 0.0
+ fcurve = ex.head_ctrl_p.driver_add('["bend_tot"]')
+ driver = fcurve.driver
+ driver.type = 'SUM'
+ fcurve.modifiers.remove(0) # grr dont need a modifier
+
+ for i in range(len(neck_chain)):
+ var = driver.variables.new()
+ var.name = target_names[i]
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = head_driver_path + ('["bend_%.2d"]' % (i + 1))
+
+
+ for i, attr in enumerate(ex_chain.attr_names):
+ neck_p = getattr(ex_chain, attr + "_p")
+ neck_p.lock_location = True, True, True
+ neck_p.lock_location = True, True, True
+ neck_p.lock_rotations_4d = True
+
+ # Add bend prop
+ prop_name = "bend_%.2d" % (i + 1)
+ prop = rna_idprop_ui_prop_get(ex.head_ctrl_p, prop_name, create=True)
+ ex.head_ctrl_p[prop_name] = 1.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+
+ # add parent constraint
+ neck_p_parent = neck_p.parent
+
+ # add constraints
+ if i == 0:
+ con = neck_p.constraints.new('COPY_SCALE')
+ con.name = "Copy Scale"
+ con.target = obj
+ con.subtarget = ex.head_ctrl
+ con.owner_space = 'LOCAL'
+ con.target_space = 'LOCAL'
+
+ con = neck_p_parent.constraints.new('COPY_ROTATION')
+ con.name = "Copy Rotation"
+ con.target = obj
+ con.subtarget = ex.head
+ con.owner_space = 'LOCAL'
+ con.target_space = 'LOCAL'
+
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ driver.type = 'SCRIPTED'
+ driver.expression = "bend/bend_tot"
+
+ fcurve.modifiers.remove(0) # grr dont need a modifier
+
+
+ # add target
+ var = driver.variables.new()
+ var.name = "bend_tot"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = head_driver_path + ('["bend_tot"]')
+
+ var = driver.variables.new()
+ var.name = "bend"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = head_driver_path + ('["%s"]' % prop_name)
+
+
+ # finally constrain the original bone to this one
+ orig_neck_p = getattr(mt_chain, attr + "_p")
+ con = orig_neck_p.constraints.new('COPY_TRANSFORMS')
+ con.target = obj
+ con.subtarget = neck_p.name
+
+
+ # Set the head control's custom shape to use the last
+ # org neck bone for its transform
+ ex.head_ctrl_p.custom_shape_transform = obj.pose.bones[bone_definition[len(bone_definition)-1]]
+
+
+ # last step setup layers
+ if "ex_layer" in options:
+ layer = [n==options["ex_layer"] for n in range(0,32)]
+ else:
+ layer = list(arm.bones[bone_definition[1]].layer)
+ for attr in ex_chain.attr_names:
+ getattr(ex_chain, attr + "_b").layer = layer
+ for attr in ex.attr_names:
+ getattr(ex, attr + "_b").layer = layer
+
+ layer = list(arm.bones[bone_definition[1]].layer)
+ ex.head_ctrl_b.layer = layer
+
+
+ # no blending the result of this
+ return None
+