#====================== 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 ======================== import bpy from math import acos from rigify.utils import MetarigError from rigify.utils import copy_bone from rigify.utils import org_name, make_mechanism_name class Rig: """ A delta rig. Creates a setup that will place its child at its position in pose mode, but will not modifying its child's position in edit mode. This is a mechanism-only rig (no control or deformation bones). """ def __init__(self, obj, bone, params): """ Gather and validate data about the rig. Store any data or references to data that will be needed later on. In particular, store references to bones that will be needed. Do NOT change any data in the scene. This is a gathering phase only. """ bb = obj.data.bones if bb[bone].children is None: raise MetarigError("RIGIFY ERROR: bone '%s': rig type requires one child." % org_name(bone.name)) if bb[bone].use_connect == True: raise MetarigError("RIGIFY ERROR: bone '%s': rig type cannot be connected to parent." % org_name(bone.name)) self.obj = obj self.org_bones = {"delta": bone, "child": bb[bone].children[0].name} self.org_names = [org_name(bone), org_name(bb[bone].children[0].name)] def generate(self): """ Generate the rig. Do NOT modify any of the original bones, except for adding constraints. The main armature should be selected and active before this is called. """ bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones org_delta = self.org_bones["delta"] org_delta_e = eb[self.org_bones["delta"]] org_child = self.org_bones["child"] org_child_e = eb[self.org_bones["child"]] # Calculate the matrix for achieving the delta child_mat = org_delta_e.matrix.invert() * org_child_e.matrix mat = org_delta_e.matrix * child_mat.invert() # Create the delta bones. delta_e = eb[copy_bone(self.obj, self.org_bones["delta"])] delta_e.name = make_mechanism_name(self.org_names[0]) delta = delta_e.name # Set the delta to the matrix's transforms set_mat(self.obj, delta, mat) bpy.ops.object.mode_set(mode='OBJECT') # Constrain org_delta to delta con = self.obj.pose.bones[org_delta].constraints.new('COPY_TRANSFORMS') con.name = "delta" con.target = self.obj con.subtarget = delta @classmethod def create_sample(self, obj): # generated by rigify.utils.write_metarig bpy.ops.object.mode_set(mode='EDIT') arm = obj.data bones = {} bone = arm.edit_bones.new('delta') bone.head[:] = 0.0000, -0.1198, 0.1253 bone.tail[:] = -0.0000, -0.2483, 0.2785 bone.roll = -0.0000 bone.use_connect = False bones['delta'] = bone.name bone = arm.edit_bones.new('Bone') bone.head[:] = -0.0000, 0.0000, 0.0000 bone.tail[:] = -0.0000, 0.0000, 0.2000 bone.roll = 0.0000 bone.use_connect = False bone.parent = arm.edit_bones[bones['delta']] bones['Bone'] = bone.name bpy.ops.object.mode_set(mode='OBJECT') pbone = obj.pose.bones[bones['delta']] pbone.rigify_type = 'misc.delta' 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.rigify_parameters.add() pbone = obj.pose.bones[bones['Bone']] 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 def set_mat(obj, bone_name, matrix): """ Sets the bone to have the given transform matrix. """ a = obj.data.edit_bones[bone_name] a.head = (0, 0, 0) a.tail = (0, 1, 0) a.transform(matrix) d = acos(a.matrix.to_quaternion().dot(matrix.to_quaternion())) * 2.0 roll_1 = a.roll + d roll_2 = a.roll - d a.roll = roll_1 d1 = a.matrix.to_quaternion().dot(matrix.to_quaternion()) a.roll = roll_2 d2 = a.matrix.to_quaternion().dot(matrix.to_quaternion()) if d1 > d2: a.roll = roll_1 else: a.roll = roll_2