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:
Diffstat (limited to 'rigify/rigs/face/skin_jaw.py')
-rw-r--r--rigify/rigs/face/skin_jaw.py862
1 files changed, 862 insertions, 0 deletions
diff --git a/rigify/rigs/face/skin_jaw.py b/rigify/rigs/face/skin_jaw.py
new file mode 100644
index 00000000..6829818c
--- /dev/null
+++ b/rigify/rigs/face/skin_jaw.py
@@ -0,0 +1,862 @@
+# ====================== 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
+import math
+
+from itertools import count, repeat
+from mathutils import Vector, Matrix
+from bl_math import clamp
+
+from ...utils.naming import make_derived_name, Side, SideZ, get_name_side_z
+from ...utils.bones import align_bone_z_axis, put_bone
+from ...utils.misc import map_list, matrix_from_axis_pair, LazyRef
+from ...utils.widgets_basic import create_circle_widget
+
+from ...base_rig import stage, RigComponent
+
+from ..skin.skin_nodes import ControlBoneNode
+from ..skin.skin_parents import ControlBoneParentOrg, ControlBoneParentArmature
+from ..skin.skin_rigs import BaseSkinRig
+
+from ..skin.basic_chain import Rig as BasicChainRig
+
+from ..widgets import create_jaw_widget
+
+
+class Rig(BaseSkinRig):
+ """
+ Jaw rig that manages loops of four mouth chains each. The chains
+ must connect together at their ends using L/R and T/B symmetry.
+ """
+
+ def find_org_bones(self, bone):
+ return bone.name
+
+ def initialize(self):
+ super().initialize()
+
+ self.mouth_orientation = self.get_mouth_orientation()
+ self.chain_to_layer = None
+
+ self.init_child_chains()
+
+ ####################################################
+ # UTILITIES
+
+ def get_mouth_orientation(self):
+ jaw_axis = self.get_bone(self.base_bone).y_axis.copy()
+ jaw_axis[2] = 0
+
+ return matrix_from_axis_pair(jaw_axis, (0, 0, 1), 'z').to_quaternion()
+
+ def is_corner_node(self, node):
+ # Corners are nodes where two T/B or L/R chains meet.
+ siblings = [n for n in node.get_merged_siblings() if n.rig in self.child_chains]
+
+ sides_x = set(n.name_split.side for n in siblings)
+ sides_z = set(n.name_split.side_z for n in siblings)
+
+ if {SideZ.BOTTOM, SideZ.TOP}.issubset(sides_z):
+ if Side.LEFT in sides_x:
+ return Side.LEFT
+ else:
+ return Side.RIGHT
+
+ if {Side.LEFT, Side.RIGHT}.issubset(sides_x):
+ if SideZ.TOP in sides_z:
+ return SideZ.TOP
+ else:
+ return SideZ.BOTTOM
+
+ return None
+
+ ####################################################
+ # BONES
+ #
+ # ctrl:
+ # master:
+ # Main jaw open control.
+ # mouth:
+ # Main control for adjusting mouth position and scale.
+ # mch:
+ # lock:
+ # Jaw master mirror for the locked mouth.
+ # top[]:
+ # Jaw master mirrors for the loop top.
+ # bottom[]:
+ # Jaw master mirrors for the loop bottom.
+ # middle[]:
+ # Middle position between top[] and bottom[].
+ # mouth_parent = middle[0]:
+ # Parent for ctrl.mouth, mouth_layers and *_in
+ # mouth_layers[]:
+ # Apply fade out of ctrl.mouth motion for outer loops.
+ # top_out[], bottom_out[], middle_out[]:
+ # Combine mouth and jaw motions via Copy Custom to Local.
+ # deform:
+ # master:
+ # Deform mirror of ctrl.master.
+ #
+ ####################################################
+
+ ####################################################
+ # CHILD CHAINS
+
+ def init_child_chains(self):
+ self.child_chains = [
+ rig
+ for rig in self.rigify_children
+ if isinstance(rig, BasicChainRig) and get_name_side_z(rig.base_bone) != SideZ.MIDDLE
+ ]
+
+ self.corners = {Side.LEFT: [], Side.RIGHT: [], SideZ.TOP: [], SideZ.BOTTOM: []}
+
+ def arrange_child_chains(self):
+ """Sort child chains into their corresponding mouth loops."""
+ if self.chain_to_layer is not None:
+ return
+
+ # Index child node corners
+ for child in self.child_chains:
+ for node in child.control_nodes:
+ corner = self.is_corner_node(node)
+ if corner:
+ if node.merged_master not in self.corners[corner]:
+ self.corners[corner].append(node.merged_master)
+
+ self.num_layers = len(self.corners[SideZ.TOP])
+
+ for k, v in self.corners.items():
+ if len(v) == 0:
+ self.raise_error("Could not find all mouth corners")
+ if len(v) != self.num_layers:
+ self.raise_error(
+ "Mouth corner counts differ: {} vs {}",
+ [n.name for n in v], [n.name for n in self.corners[SideZ.TOP]]
+ )
+
+ # Find inner top/bottom corners
+ anchor = self.corners[SideZ.BOTTOM][0].point
+ inner_top = min(self.corners[SideZ.TOP], key=lambda p: (p.point - anchor).length)
+
+ anchor = inner_top.point
+ inner_bottom = min(self.corners[SideZ.BOTTOM], key=lambda p: (p.point - anchor).length)
+
+ # Compute the mouth space
+ self.mouth_center = center = (inner_top.point + inner_bottom.point) / 2
+
+ matrix = self.mouth_orientation.to_matrix().to_4x4()
+ matrix.translation = center
+ self.mouth_space = matrix
+ self.to_mouth_space = matrix.inverted()
+
+ # Build a mapping of child chain to layer (i.e. sort multiple mouth loops)
+ self.chain_to_layer = {}
+ self.chains_by_side = {}
+
+ for k, v in list(self.corners.items()):
+ self.corners[k] = ordered = sorted(v, key=lambda p: (p.point - center).length)
+
+ chain_set = set()
+
+ for i, node in enumerate(ordered):
+ for sibling in node.get_merged_siblings():
+ if sibling.rig in self.child_chains:
+ cur_layer = self.chain_to_layer.get(sibling.rig)
+
+ if cur_layer is not None and cur_layer != i:
+ self.raise_error(
+ "Conflicting mouth chain layer on {}: {} and {}", sibling.rig.base_bone, i, cur_layer)
+
+ self.chain_to_layer[sibling.rig] = i
+ chain_set.add(sibling.rig)
+
+ self.chains_by_side[k] = chain_set
+
+ for child in self.child_chains:
+ if child not in self.chain_to_layer:
+ self.raise_error("Could not determine chain layer on {}", child.base_bone)
+
+ if not self.chains_by_side[Side.LEFT].isdisjoint(self.chains_by_side[Side.RIGHT]):
+ self.raise_error("Left/right conflict in mouth")
+ if not self.chains_by_side[SideZ.TOP].isdisjoint(self.chains_by_side[SideZ.BOTTOM]):
+ self.raise_error("Top/bottom conflict in mouth")
+
+ # Find left/right direction
+ pt = self.to_mouth_space @ self.corners[Side.LEFT][0].point
+
+ self.left_sign = 1 if pt.x > 0 else -1
+
+ for node in self.corners[Side.LEFT]:
+ if (self.to_mouth_space @ node.point).x * self.left_sign <= 0:
+ self.raise_error("Bad left corner location: {}", node.name)
+
+ for node in self.corners[Side.RIGHT]:
+ if (self.to_mouth_space @ node.point).x * self.left_sign >= 0:
+ self.raise_error("Bad right corner location: {}", node.name)
+
+ # Find layer loop widths
+ self.layer_width = [
+ (self.corners[Side.LEFT][i].point - self.corners[Side.RIGHT][i].point).length
+ for i in range(self.num_layers)
+ ]
+
+ def position_mouth_bone(self, name, scale):
+ self.arrange_child_chains()
+
+ bone = self.get_bone(name)
+ bone.matrix = self.mouth_space
+ bone.length = self.layer_width[0] * scale
+
+ ####################################################
+ # CONTROL NODES
+
+ def get_node_parent_bones(self, node):
+ """Get parent bones and their armature weights for the given control node."""
+ self.arrange_child_chains()
+
+ # Choose correct layer bones
+ layer = self.chain_to_layer[node.rig]
+
+ top_mch = LazyRef(self.bones.mch, 'top_out', layer)
+ bottom_mch = LazyRef(self.bones.mch, 'bottom_out', layer)
+ middle_mch = LazyRef(self.bones.mch, 'middle_out', layer)
+
+ # Corners have one input
+ corner = self.is_corner_node(node)
+ if corner:
+ if corner == SideZ.TOP:
+ return [top_mch]
+ elif corner == SideZ.BOTTOM:
+ return [bottom_mch]
+ else:
+ return [middle_mch]
+
+ # Otherwise blend two
+ if node.rig in self.chains_by_side[SideZ.TOP]:
+ side_mch = top_mch
+ else:
+ side_mch = bottom_mch
+
+ pt_x = (self.to_mouth_space @ node.point).x
+ side = Side.LEFT if pt_x * self.left_sign >= 0 else Side.RIGHT
+
+ corner_x = (self.to_mouth_space @ self.corners[side][layer].point).x
+ factor = math.sqrt(1 - clamp(pt_x / corner_x) ** 2)
+
+ return [(side_mch, factor), (middle_mch, 1-factor)]
+
+ def get_parent_for_name(self, name, parent_bone):
+ """Get single replacement parent for the given child bone."""
+ if parent_bone == self.base_bone:
+ side = get_name_side_z(name)
+ if side == SideZ.TOP:
+ return LazyRef(self.bones.mch, 'top', -1)
+ if side == SideZ.BOTTOM:
+ return LazyRef(self.bones.mch, 'bottom', -1)
+
+ return parent_bone
+
+ def get_child_chain_parent(self, rig, parent_bone):
+ return self.get_parent_for_name(rig.base_bone, parent_bone)
+
+ def build_control_node_parent(self, node, parent_bone):
+ if node.rig in self.child_chains:
+ return ControlBoneParentArmature(
+ self, node,
+ bones=self.get_node_parent_bones(node),
+ orientation=self.mouth_orientation,
+ copy_scale=LazyRef(self.bones.mch, 'mouth_parent'),
+ )
+
+ return ControlBoneParentOrg(self.get_parent_for_name(node.name, parent_bone))
+
+ ####################################################
+ # Master control
+
+ @stage.generate_bones
+ def make_master_control(self):
+ org = self.bones.org
+ name = self.copy_bone(org, make_derived_name(org, 'ctrl'), parent=True)
+ self.bones.ctrl.master = name
+
+ @stage.configure_bones
+ def configure_master_control(self):
+ self.copy_bone_properties(self.bones.org, self.bones.ctrl.master)
+
+ self.get_bone(self.bones.ctrl.master).lock_scale = (True, True, True)
+
+ @stage.generate_widgets
+ def make_master_control_widget(self):
+ ctrl = self.bones.ctrl.master
+ create_jaw_widget(self.obj, ctrl)
+
+ ####################################################
+ # Mouth control
+
+ @stage.generate_bones
+ def make_mouth_control(self):
+ org = self.bones.org
+ name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_mouth'))
+ self.position_mouth_bone(name, 1)
+ self.bones.ctrl.mouth = name
+
+ @stage.parent_bones
+ def parent_mouth_control(self):
+ self.set_bone_parent(self.bones.ctrl.mouth, self.bones.mch.mouth_parent)
+
+ @stage.configure_bones
+ def configure_mouth_control(self):
+ pass
+
+ @stage.generate_widgets
+ def make_mouth_control_widget(self):
+ ctrl = self.bones.ctrl.mouth
+
+ width = (self.corners[Side.LEFT][0].point - self.corners[Side.RIGHT][0].point).length
+ height = (self.corners[SideZ.TOP][0].point - self.corners[SideZ.BOTTOM][0].point).length
+ back = (self.corners[Side.LEFT][0].point + self.corners[Side.RIGHT][0].point) / 2
+ front = (self.corners[SideZ.TOP][0].point + self.corners[SideZ.BOTTOM][0].point) / 2
+ depth = (front - back).length
+
+ create_circle_widget(
+ self.obj, ctrl,
+ radius=0.2 + 0.5 * (height / width), radius_x=0.7,
+ head_tail=0.2, head_tail_x=0.2 - (depth / width)
+ )
+
+ ####################################################
+ # Jaw Motion MCH
+
+ @stage.generate_bones
+ def make_mch_lock_bones(self):
+ org = self.bones.org
+ mch = self.bones.mch
+
+ self.arrange_child_chains()
+
+ mch.lock = self.copy_bone(
+ org, make_derived_name(org, 'mch', '_lock'), scale=1/2, parent=True)
+
+ mch.top = map_list(self.make_mch_top_bone, range(self.num_layers), repeat(org))
+ mch.bottom = map_list(self.make_mch_bottom_bone, range(self.num_layers), repeat(org))
+ mch.middle = map_list(self.make_mch_middle_bone, range(self.num_layers), repeat(org))
+
+ mch.mouth_parent = mch.middle[0]
+
+ def make_mch_top_bone(self, i, org):
+ return self.copy_bone(org, make_derived_name(org, 'mch', '_top'), scale=1/4, parent=True)
+
+ def make_mch_bottom_bone(self, i, org):
+ return self.copy_bone(org, make_derived_name(org, 'mch', '_bottom'), scale=1/3, parent=True)
+
+ def make_mch_middle_bone(self, i, org):
+ return self.copy_bone(org, make_derived_name(org, 'mch', '_middle'), scale=2/3, parent=True)
+
+ @stage.parent_bones
+ def parent_mch_lock_bones(self):
+ mch = self.bones.mch
+ ctrl = self.bones.ctrl
+
+ for mid, top in zip(mch.middle, mch.top):
+ self.set_bone_parent(mid, top)
+
+ for bottom in mch.bottom[1:]:
+ self.set_bone_parent(bottom, ctrl.master)
+
+ @stage.configure_bones
+ def configure_mch_lock_bones(self):
+ ctrl = self.bones.ctrl
+
+ panel = self.script.panel_with_selected_check(self, [ctrl.master, ctrl.mouth])
+
+ self.make_property(ctrl.master, 'mouth_lock', 0.0, description='Mouth is locked closed')
+ panel.custom_prop(ctrl.master, 'mouth_lock', text='Mouth Lock', slider=True)
+
+ @stage.rig_bones
+ def rig_mch_track_bones(self):
+ mch = self.bones.mch
+ ctrl = self.bones.ctrl
+
+ # Lock position follows jaw master with configured influence
+ self.make_constraint(
+ mch.lock, 'COPY_TRANSFORMS', ctrl.master,
+ influence=self.params.jaw_locked_influence,
+ )
+
+ # Innermost top bone follows lock position according to slider
+ con = self.make_constraint(mch.top[0], 'COPY_TRANSFORMS', mch.lock)
+ self.make_driver(con, 'influence', variables=[(ctrl.master, 'mouth_lock')])
+
+ # Innermost bottom bone follows jaw master with configured influence, and then lock
+ self.make_constraint(
+ mch.bottom[0], 'COPY_TRANSFORMS', ctrl.master,
+ influence=self.params.jaw_mouth_influence,
+ )
+
+ con = self.make_constraint(mch.bottom[0], 'COPY_TRANSFORMS', mch.lock)
+ self.make_driver(con, 'influence', variables=[(ctrl.master, 'mouth_lock')])
+
+ # Outer layer bones interpolate toward innermost based on influence decay
+ coeff = self.params.jaw_secondary_influence
+
+ for i, name in enumerate(mch.top[1:]):
+ self.make_constraint(name, 'COPY_TRANSFORMS', mch.top[0], influence=coeff ** (1+i))
+
+ for i, name in enumerate(mch.bottom[1:]):
+ self.make_constraint(name, 'COPY_TRANSFORMS', mch.bottom[0], influence=coeff ** (1+i))
+
+ # Middle bones interpolate the middle between top and bottom
+ for mid, bottom in zip(mch.middle, mch.bottom):
+ self.make_constraint(mid, 'COPY_TRANSFORMS', bottom, influence=0.5)
+
+ ####################################################
+ # Mouth MCH
+
+ @stage.generate_bones
+ def make_mch_mouth_bones(self):
+ mch = self.bones.mch
+
+ mch.mouth_layers = map_list(self.make_mch_mouth_bone,
+ range(1, self.num_layers), repeat('_mouth_layer'), repeat(0.6))
+
+ mch.top_out = map_list(self.make_mch_mouth_inout_bone,
+ range(self.num_layers), repeat('_top_out'), repeat(0.4))
+ mch.bottom_out = map_list(self.make_mch_mouth_inout_bone,
+ range(self.num_layers), repeat('_bottom_out'), repeat(0.35))
+ mch.middle_out = map_list(self.make_mch_mouth_inout_bone,
+ range(self.num_layers), repeat('_middle_out'), repeat(0.3))
+
+ def make_mch_mouth_bone(self, i, suffix, size):
+ name = self.copy_bone(self.bones.org, make_derived_name(self.bones.org, 'mch', suffix))
+ self.position_mouth_bone(name, size)
+ return name
+
+ def make_mch_mouth_inout_bone(self, i, suffix, size):
+ return self.copy_bone(self.bones.org, make_derived_name(self.bones.org, 'mch', suffix), scale=size)
+
+ @stage.parent_bones
+ def parent_mch_mouth_bones(self):
+ mch = self.bones.mch
+ layers = [self.bones.ctrl.mouth, *mch.mouth_layers]
+
+ for name in mch.mouth_layers:
+ self.set_bone_parent(name, mch.mouth_parent)
+
+ for name_list in [mch.top_out, mch.bottom_out, mch.middle_out]:
+ for name, parent in zip(name_list, layers):
+ self.set_bone_parent(name, parent)
+
+ @stage.rig_bones
+ def rig_mch_mouth_bones(self):
+ mch = self.bones.mch
+ ctrl = self.bones.ctrl.mouth
+
+ # Mouth influence fade out
+ for i, name in enumerate(mch.mouth_layers):
+ self.rig_mch_mouth_layer_bone(i+1, name, ctrl)
+
+ # Transfer and combine jaw motion with mouth
+ all_jaw = mch.top + mch.bottom + mch.middle
+ all_out = mch.top_out + mch.bottom_out + mch.middle_out
+
+ for dest, src in zip(all_out, all_jaw):
+ self.make_constraint(
+ dest, 'COPY_TRANSFORMS', src,
+ owner_space='LOCAL', target_space='CUSTOM',
+ space_object=self.obj, space_subtarget=mch.mouth_parent,
+ )
+
+ def rig_mch_mouth_layer_bone(self, i, mch, ctrl):
+ # Fade location and rotation based on influence decay
+ inf = self.params.jaw_secondary_influence ** i
+
+ self.make_constraint(mch, 'COPY_LOCATION', ctrl, influence=inf)
+ self.make_constraint(mch, 'COPY_ROTATION', ctrl, influence=inf)
+
+ # For scale, additionally take radius into account
+ inf_scale = inf * self.layer_width[0] / self.layer_width[i]
+
+ self.make_constraint(mch, 'COPY_SCALE', ctrl, influence=inf_scale)
+
+ ####################################################
+ # ORG bone
+
+ @stage.parent_bones
+ def parent_org_chain(self):
+ self.set_bone_parent(self.bones.org, self.bones.ctrl.master, inherit_scale='FULL')
+
+ ####################################################
+ # Deform bones
+
+ @stage.generate_bones
+ def make_deform_bone(self):
+ org = self.bones.org
+ deform = self.bones.deform
+ self.bones.deform.master = self.copy_bone(org, make_derived_name(org, 'def'))
+
+ @stage.parent_bones
+ def parent_deform_chain(self):
+ deform = self.bones.deform
+ self.set_bone_parent(deform.master, self.bones.org)
+
+ ####################################################
+ # SETTINGS
+
+ @classmethod
+ def add_parameters(self, params):
+ params.jaw_mouth_influence = bpy.props.FloatProperty(
+ name="Bottom Lip Influence",
+ default=0.5, min=0, max=1,
+ description="Influence of the jaw on the bottom lip chains"
+ )
+
+ params.jaw_locked_influence = bpy.props.FloatProperty(
+ name="Locked Influence",
+ default=0.2, min=0, max=1,
+ description="Influence of the jaw on the locked mouth"
+ )
+
+ params.jaw_secondary_influence = bpy.props.FloatProperty(
+ name="Secondary Influence Falloff",
+ default=0.5, min=0, max=1,
+ description="Reduction factor for each level of secondary mouth loops"
+ )
+
+ @classmethod
+ def parameters_ui(self, layout, params):
+ layout.prop(params, "jaw_mouth_influence", slider=True)
+ layout.prop(params, "jaw_locked_influence", slider=True)
+ layout.prop(params, "jaw_secondary_influence", slider=True)
+
+
+def create_sample(obj):
+ # generated by rigify.utils.write_metarig
+ bpy.ops.object.mode_set(mode='EDIT')
+ arm = obj.data
+
+ bones = {}
+
+ bone = arm.edit_bones.new('jaw')
+ bone.head = 0.0000, 0.0000, 0.0000
+ bone.tail = 0.0000, -0.0585, -0.0489
+ bone.roll = 0.0000
+ bone.use_connect = False
+ bones['jaw'] = bone.name
+ bone = arm.edit_bones.new('teeth.T')
+ bone.head = 0.0000, -0.0589, 0.0080
+ bone.tail = 0.0000, -0.0283, 0.0080
+ bone.roll = 0.0000
+ bone.use_connect = False
+ bones['teeth.T'] = bone.name
+ bone = arm.edit_bones.new('lip.T.L')
+ bone.head = -0.0000, -0.0684, 0.0030
+ bone.tail = 0.0105, -0.0655, 0.0033
+ bone.roll = -0.0000
+ bone.use_connect = False
+ bone.parent = arm.edit_bones[bones['jaw']]
+ bones['lip.T.L'] = bone.name
+ bone = arm.edit_bones.new('lip.B.L')
+ bone.head = -0.0000, -0.0655, -0.0078
+ bone.tail = 0.0107, -0.0625, -0.0053
+ bone.roll = -0.0551
+ bone.use_connect = False
+ bone.parent = arm.edit_bones[bones['jaw']]
+ bones['lip.B.L'] = bone.name
+ bone = arm.edit_bones.new('lip.T.R')
+ bone.head = 0.0000, -0.0684, 0.0030
+ bone.tail = -0.0105, -0.0655, 0.0033
+ bone.roll = 0.0000
+ bone.use_connect = False
+ bone.parent = arm.edit_bones[bones['jaw']]
+ bones['lip.T.R'] = bone.name
+ bone = arm.edit_bones.new('lip.B.R')
+ bone.head = 0.0000, -0.0655, -0.0078
+ bone.tail = -0.0107, -0.0625, -0.0053
+ bone.roll = 0.0551
+ bone.use_connect = False
+ bone.parent = arm.edit_bones[bones['jaw']]
+ bones['lip.B.R'] = bone.name
+ bone = arm.edit_bones.new('teeth.B')
+ bone.head = 0.0000, -0.0543, -0.0136
+ bone.tail = 0.0000, -0.0237, -0.0136
+ bone.roll = 0.0000
+ bone.use_connect = False
+ bone.parent = arm.edit_bones[bones['jaw']]
+ bones['teeth.B'] = bone.name
+ bone = arm.edit_bones.new('lip1.T.L')
+ bone.head = 0.0105, -0.0655, 0.0033
+ bone.tail = 0.0193, -0.0586, 0.0007
+ bone.roll = -0.0257
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['lip.T.L']]
+ bones['lip1.T.L'] = bone.name
+ bone = arm.edit_bones.new('lip1.B.L')
+ bone.head = 0.0107, -0.0625, -0.0053
+ bone.tail = 0.0194, -0.0573, -0.0029
+ bone.roll = 0.0716
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['lip.B.L']]
+ bones['lip1.B.L'] = bone.name
+ bone = arm.edit_bones.new('lip1.T.R')
+ bone.head = -0.0105, -0.0655, 0.0033
+ bone.tail = -0.0193, -0.0586, 0.0007
+ bone.roll = 0.0257
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['lip.T.R']]
+ bones['lip1.T.R'] = bone.name
+ bone = arm.edit_bones.new('lip1.B.R')
+ bone.head = -0.0107, -0.0625, -0.0053
+ bone.tail = -0.0194, -0.0573, -0.0029
+ bone.roll = -0.0716
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['lip.B.R']]
+ bones['lip1.B.R'] = bone.name
+ bone = arm.edit_bones.new('lip2.T.L')
+ bone.head = 0.0193, -0.0586, 0.0007
+ bone.tail = 0.0236, -0.0539, -0.0014
+ bone.roll = 0.0324
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['lip1.T.L']]
+ bones['lip2.T.L'] = bone.name
+ bone = arm.edit_bones.new('lip2.B.L')
+ bone.head = 0.0194, -0.0573, -0.0029
+ bone.tail = 0.0236, -0.0539, -0.0014
+ bone.roll = 0.0467
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['lip1.B.L']]
+ bones['lip2.B.L'] = bone.name
+ bone = arm.edit_bones.new('lip2.T.R')
+ bone.head = -0.0193, -0.0586, 0.0007
+ bone.tail = -0.0236, -0.0539, -0.0014
+ bone.roll = -0.0324
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['lip1.T.R']]
+ bones['lip2.T.R'] = bone.name
+ bone = arm.edit_bones.new('lip2.B.R')
+ bone.head = -0.0194, -0.0573, -0.0029
+ bone.tail = -0.0236, -0.0539, -0.0014
+ bone.roll = -0.0467
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['lip1.B.R']]
+ bones['lip2.B.R'] = bone.name
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+ pbone = obj.pose.bones[bones['jaw']]
+ pbone.rigify_type = 'face.skin_jaw'
+ 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['teeth.T']]
+ pbone.rigify_type = 'basic.super_copy'
+ 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.make_deform = False
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.super_copy_widget_type = "teeth"
+ except AttributeError:
+ pass
+ pbone = obj.pose.bones[bones['lip.T.L']]
+ pbone.rigify_type = 'skin.stretchy_chain'
+ 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.bbones = 3
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_falloff_spherical = [True, False, True]
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_falloff = [0.5, 1.0, -0.5]
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_connect_mirror = [True, False]
+ except AttributeError:
+ pass
+ pbone = obj.pose.bones[bones['lip.B.L']]
+ pbone.rigify_type = 'skin.stretchy_chain'
+ 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.bbones = 3
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_falloff_spherical = [True, False, True]
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_falloff = [0.5, 1.0, -0.5]
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_connect_mirror = [True, False]
+ except AttributeError:
+ pass
+ pbone = obj.pose.bones[bones['lip.T.R']]
+ pbone.rigify_type = 'skin.stretchy_chain'
+ 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.bbones = 3
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_falloff_spherical = [True, False, True]
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_falloff = [0.5, 1.0, -0.5]
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_connect_mirror = [True, False]
+ except AttributeError:
+ pass
+ pbone = obj.pose.bones[bones['lip.B.R']]
+ pbone.rigify_type = 'skin.stretchy_chain'
+ 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.bbones = 3
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_falloff_spherical = [True, False, True]
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_falloff = [0.5, 1.0, -0.5]
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.skin_chain_connect_mirror = [True, False]
+ except AttributeError:
+ pass
+ pbone = obj.pose.bones[bones['teeth.B']]
+ pbone.rigify_type = 'basic.super_copy'
+ 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.super_copy_widget_type = "teeth"
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.make_deform = False
+ except AttributeError:
+ pass
+ pbone = obj.pose.bones[bones['lip1.T.L']]
+ 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['lip1.B.L']]
+ 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['lip1.T.R']]
+ 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['lip1.B.R']]
+ 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['lip2.T.L']]
+ 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['lip2.B.L']]
+ 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['lip2.T.R']]
+ 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['lip2.B.R']]
+ 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
+ bone.bbone_x = bone.bbone_z = bone.length * 0.05
+ arm.edit_bones.active = bone
+
+ return bones