Removed old rigify code, as it is starting to interfere with the newer Rigify addon.
The newer addon currently resides here: bzr://bzr.cessen.com/rigify But will eventually be included in svn.
This commit is contained in:
parent
05abc0d3eb
commit
30b4fa2aa8
@ -1,564 +0,0 @@
|
||||
# ##### 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 mathutils import Vector
|
||||
|
||||
# TODO, have these in a more general module
|
||||
from rna_prop_ui import rna_idprop_ui_prop_get
|
||||
SPECIAL_TYPES = "root",
|
||||
LAYER_TYPES = "main", "extra", "ik", "fk"
|
||||
|
||||
ORG_LAYERS = [n == 31 for n in range(0, 32)]
|
||||
MCH_LAYERS = [n == 30 for n in range(0, 32)]
|
||||
DEF_LAYERS = [n == 29 for n in range(0, 32)]
|
||||
ROOT_LAYERS = [n == 28 for n in range(0, 32)]
|
||||
|
||||
ORG_PREFIX = "ORG-"
|
||||
MCH_PREFIX = "MCH-"
|
||||
DEF_PREFIX = "DEF-"
|
||||
|
||||
WGT_PREFIX = "WGT-"
|
||||
|
||||
|
||||
class RigifyError(Exception):
|
||||
"""Exception raised for errors in the metarig.
|
||||
"""
|
||||
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.message)
|
||||
|
||||
|
||||
def submodule_func_from_type(bone_type):
|
||||
type_pair = bone_type.split(".")
|
||||
|
||||
# 'leg.ik' will look for an ik function in the leg module
|
||||
# 'leg' will look up leg.main
|
||||
if len(type_pair) == 1:
|
||||
type_pair = type_pair[0], "main"
|
||||
|
||||
type_name, func_name = type_pair
|
||||
|
||||
# from rigify import leg
|
||||
try:
|
||||
submod = __import__(name="%s.%s" % (__package__, type_name), fromlist=[type_name])
|
||||
except ImportError:
|
||||
raise RigifyError("python module for type '%s' not found" % type_name)
|
||||
|
||||
reload(submod)
|
||||
return type_name, submod, getattr(submod, func_name)
|
||||
|
||||
|
||||
def get_submodule_types():
|
||||
import os
|
||||
submodules = []
|
||||
files = os.listdir(os.path.dirname(__file__))
|
||||
for f in files:
|
||||
if not f.startswith("_") and f.endswith(".py"):
|
||||
submodules.append(f[:-3])
|
||||
|
||||
return sorted(submodules)
|
||||
|
||||
|
||||
def get_bone_type_options(pbone, type_name):
|
||||
options = {}
|
||||
bone_name = pbone.name
|
||||
for key, value in pbone.items():
|
||||
key_pair = key.rsplit(".")
|
||||
# get all bone properties
|
||||
""""
|
||||
if key_pair[0] == type_name:
|
||||
if len(key_pair) != 2:
|
||||
raise RigifyError("option error for bone '%s', property name was not a pair '%s'" % (bone_name, key_pair))
|
||||
options[key_pair[1]] = value
|
||||
"""
|
||||
options[key] = value
|
||||
|
||||
return options
|
||||
|
||||
|
||||
def get_layer_dict(options):
|
||||
'''
|
||||
Extracts layer info from a bone options dict
|
||||
defaulting to the layer index if not set.
|
||||
'''
|
||||
layer_default = [False] * 32
|
||||
result = {}
|
||||
for i, layer_type in enumerate(LAYER_TYPES):
|
||||
# no matter if its not defined
|
||||
layer_index = options.get("layer_" + layer_type, i + 2)
|
||||
layer = layer_default[:]
|
||||
layer[layer_index-1] = True
|
||||
result[layer_type] = layer
|
||||
return result
|
||||
|
||||
|
||||
def validate_rig(context, obj):
|
||||
'''
|
||||
Makes no changes
|
||||
only runs the metarig definitions and reports errors
|
||||
'''
|
||||
type_found = False
|
||||
|
||||
for pbone in obj.pose.bones:
|
||||
bone_name = pbone.name
|
||||
bone_type = pbone.get("type", "")
|
||||
|
||||
if bone_type:
|
||||
bone_type_list = [bt for bt in bone_type.replace(",", " ").split()]
|
||||
else:
|
||||
bone_type_list = []
|
||||
|
||||
for bone_type in bone_type_list:
|
||||
if bone_type.split(".")[0] in SPECIAL_TYPES:
|
||||
continue
|
||||
|
||||
type_name, submod, type_func = submodule_func_from_type(bone_type)
|
||||
reload(submod)
|
||||
submod.metarig_definition(obj, bone_name)
|
||||
type_found = True
|
||||
|
||||
get_bone_type_options(pbone, bone_type)
|
||||
|
||||
# missing, - check for duplicate root bone.
|
||||
|
||||
if not type_found:
|
||||
raise RigifyError("This rig has no 'type' properties defined on any pose bones, nothing to do")
|
||||
|
||||
|
||||
def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True):
|
||||
'''
|
||||
Main function for generating
|
||||
'''
|
||||
from collections import OrderedDict
|
||||
import rigify_utils
|
||||
reload(rigify_utils)
|
||||
|
||||
print("Begin...")
|
||||
|
||||
# Not needed but catches any errors before duplicating
|
||||
validate_rig(context, obj_orig)
|
||||
|
||||
use_global_undo = context.user_preferences.edit.use_global_undo
|
||||
context.user_preferences.edit.use_global_undo = False
|
||||
mode_orig = context.mode
|
||||
rest_backup = obj_orig.data.pose_position
|
||||
obj_orig.data.pose_position = 'REST'
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
scene = context.scene
|
||||
|
||||
# Check if the generated rig already exists, so we can
|
||||
# regenerate in the same object. If not, create a new
|
||||
# object to generate the rig in.
|
||||
print("Fetch rig.")
|
||||
try:
|
||||
name = obj_orig["rig_object_name"]
|
||||
except KeyError:
|
||||
name = "rig"
|
||||
|
||||
try:
|
||||
obj = scene.objects[name]
|
||||
except KeyError:
|
||||
obj = bpy.data.objects.new(name, bpy.data.armatures.new(name))
|
||||
scene.objects.link(obj)
|
||||
|
||||
obj.data.pose_position = 'POSE'
|
||||
|
||||
# Get rid of anim data in case the rig already existed
|
||||
print("Clear rig animation data.")
|
||||
obj.animation_data_clear()
|
||||
|
||||
# Select generated rig object
|
||||
obj_orig.select = False
|
||||
obj.select = True
|
||||
scene.objects.active = obj
|
||||
|
||||
# Remove all bones from the generated rig armature.
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
for bone in obj.data.edit_bones:
|
||||
obj.data.edit_bones.remove(bone)
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Create temporary duplicates for merging
|
||||
temp_rig_1 = obj_orig.copy()
|
||||
temp_rig_1.data = obj_orig.data.copy()
|
||||
scene.objects.link(temp_rig_1)
|
||||
|
||||
temp_rig_2 = obj_orig.copy()
|
||||
temp_rig_2.data = obj.data
|
||||
scene.objects.link(temp_rig_2)
|
||||
|
||||
# Select the temp rigs for merging
|
||||
for objt in scene.objects:
|
||||
objt.select = False # deselect all objects
|
||||
temp_rig_1.select = True
|
||||
temp_rig_2.select = True
|
||||
scene.objects.active = temp_rig_2
|
||||
|
||||
# Merge the temporary rigs
|
||||
bpy.ops.object.join(context)
|
||||
|
||||
# Delete the second temp rig
|
||||
bpy.ops.object.delete()
|
||||
|
||||
# Select the generated rig
|
||||
for objt in scene.objects:
|
||||
objt.select = False # deselect all objects
|
||||
obj.select = True
|
||||
scene.objects.active = obj
|
||||
|
||||
# Copy over the pose_bone properties
|
||||
for bone in obj_orig.pose.bones:
|
||||
bone_gen = obj.pose.bones[bone.name]
|
||||
|
||||
# Rotation mode and transform locks
|
||||
bone_gen.rotation_mode = bone.rotation_mode
|
||||
bone_gen.lock_rotation = tuple(bone.lock_rotation)
|
||||
bone_gen.lock_rotation_w = bone.lock_rotation_w
|
||||
bone_gen.lock_rotations_4d = bone.lock_rotations_4d
|
||||
bone_gen.lock_location = tuple(bone.lock_location)
|
||||
bone_gen.lock_scale = tuple(bone.lock_scale)
|
||||
|
||||
# Custom properties
|
||||
for prop in bone.keys():
|
||||
bone_gen[prop] = bone[prop]
|
||||
|
||||
# Copy over bone properties
|
||||
for bone in obj_orig.data.bones:
|
||||
bone_gen = obj.data.bones[bone.name]
|
||||
|
||||
# B-bone stuff
|
||||
bone_gen.bbone_segments = bone.bbone_segments
|
||||
bone_gen.bbone_in = bone.bbone_in
|
||||
bone_gen.bbone_out = bone.bbone_out
|
||||
|
||||
|
||||
# Create proxy deformation rig
|
||||
# TODO: remove this
|
||||
if META_DEF:
|
||||
obj_def = obj_orig.copy()
|
||||
obj_def.data = obj_orig.data.copy()
|
||||
scene.objects.link(obj_def)
|
||||
|
||||
scene.update()
|
||||
print("On to the real work.")
|
||||
|
||||
arm = obj.data
|
||||
|
||||
# prepend the ORG prefix to the bones, and create the base_names mapping
|
||||
base_names = {}
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
for bone in arm.edit_bones:
|
||||
bone_name = bone.name
|
||||
bone.name = ORG_PREFIX + bone_name
|
||||
base_names[bone.name] = bone_name
|
||||
|
||||
# create root_bone
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
edit_bone = obj.data.edit_bones.new("root")
|
||||
root_bone = edit_bone.name
|
||||
edit_bone.head = (0.0, 0.0, 0.0)
|
||||
edit_bone.tail = (0.0, 1.0, 0.0)
|
||||
edit_bone.roll = 0.0
|
||||
edit_bone.layers = ROOT_LAYERS
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# key: bone name
|
||||
# value: {type:definition, ...}
|
||||
# where type is the submodule name - leg, arm etc
|
||||
# and definition is a list of bone names
|
||||
bone_definitions = {}
|
||||
|
||||
# key: bone name
|
||||
# value: [functions, ...]
|
||||
# each function is from the module. eg leg.ik, arm.main
|
||||
bone_typeinfos = {}
|
||||
|
||||
# key: bone name
|
||||
# value: [new_bone_name, ...]
|
||||
# where each bone with a 'type' stores a list of bones that it created
|
||||
# ...needed so we can override the root parent
|
||||
bone_genesis = {}
|
||||
|
||||
|
||||
# inspect all bones and assign their definitions before modifying
|
||||
for pbone in obj.pose.bones:
|
||||
bone_name = pbone.name
|
||||
bone_type = pbone.get("type", "")
|
||||
if bone_type:
|
||||
bone_type_list = [bt for bt in bone_type.replace(",", " ").split()]
|
||||
|
||||
# not essential but means running autorig again wont do anything
|
||||
del pbone["type"]
|
||||
else:
|
||||
bone_type_list = []
|
||||
|
||||
for bone_type in bone_type_list:
|
||||
type_name, submod, type_func = submodule_func_from_type(bone_type)
|
||||
reload(submod)
|
||||
|
||||
bone_def_dict = bone_definitions.setdefault(bone_name, {})
|
||||
|
||||
# Only calculate bone definitions once
|
||||
if type_name not in bone_def_dict:
|
||||
bone_def_dict[type_name] = submod.metarig_definition(obj, bone_name)
|
||||
|
||||
bone_typeinfo = bone_typeinfos.setdefault(bone_name, [])
|
||||
bone_typeinfo.append((type_name, type_func))
|
||||
|
||||
|
||||
# sort bones, not needed but gives more pradictable execution which may be useful in rare cases
|
||||
bones_sorted = obj.pose.bones.values()
|
||||
bones_sorted.sort(key=lambda pbone: pbone.name) # first sort by names
|
||||
bones_sorted.sort(key=lambda pbone: len(pbone.parent_recursive)) # parents before children
|
||||
|
||||
# now we have all the info about bones we can start operating on them
|
||||
# for pbone in obj.pose.bones:
|
||||
for pbone in bones_sorted:
|
||||
bone_name = pbone.name
|
||||
print(bone_name)
|
||||
if bone_name not in bone_typeinfos:
|
||||
continue
|
||||
|
||||
bone_def_dict = bone_definitions[bone_name]
|
||||
|
||||
# Only blend results from the same submodule, eg.
|
||||
# leg.ik and arm.fk could not be blended.
|
||||
results = OrderedDict()
|
||||
|
||||
bone_names_pre = {bone.name for bone in arm.bones}
|
||||
|
||||
for type_name, type_func in bone_typeinfos[bone_name]:
|
||||
print(" " + type_name)
|
||||
# this bones definition of the current typeinfo
|
||||
definition = bone_def_dict[type_name]
|
||||
options = get_bone_type_options(pbone, type_name)
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
ret = type_func(obj, definition, base_names, options)
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
if ret:
|
||||
result_submod = results.setdefault(type_name, [])
|
||||
|
||||
if result_submod and len(result_submod[-1]) != len(ret):
|
||||
raise RigifyError("bone lists not compatible: %s, %s" % (result_submod[-1], ret))
|
||||
|
||||
result_submod.append(ret)
|
||||
|
||||
for result_submod in results.values():
|
||||
# blend 2 chains
|
||||
definition = bone_def_dict[type_name]
|
||||
|
||||
if len(result_submod) == 2:
|
||||
blend_bone_list(obj, definition, result_submod[0], result_submod[1], target_bone=bone_name)
|
||||
|
||||
|
||||
bone_names_post = {bone.name for bone in arm.bones}
|
||||
|
||||
# Store which bones were created from this one
|
||||
bone_genesis[bone_name] = list(bone_names_post - bone_names_pre)
|
||||
|
||||
# need a reverse lookup on bone_genesis so as to know immediately
|
||||
# where a bone comes from
|
||||
bone_genesis_reverse = {}
|
||||
'''
|
||||
for bone_name, bone_children in bone_genesis.items():
|
||||
for bone_child_name in bone_children:
|
||||
bone_genesis_reverse[bone_child_name] = bone_name
|
||||
'''
|
||||
|
||||
|
||||
if root_bone:
|
||||
# assign all new parentless bones to this
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
root_ebone = arm.edit_bones[root_bone]
|
||||
for ebone in arm.edit_bones:
|
||||
bone_name = ebone.name
|
||||
if ebone.parent is None:
|
||||
ebone.parent = root_ebone
|
||||
'''
|
||||
if ebone.parent is None and bone_name not in base_names:
|
||||
# check for override
|
||||
bone_creator = bone_genesis_reverse[bone_name]
|
||||
pbone_creator = obj.pose.bones[bone_creator]
|
||||
root_bone_override = pbone_creator.get("root", "")
|
||||
|
||||
if root_bone_override:
|
||||
root_ebone_tmp = arm.edit_bones[root_bone_override]
|
||||
else:
|
||||
root_ebone_tmp = root_ebone
|
||||
|
||||
ebone.use_connect = False
|
||||
ebone.parent = root_ebone_tmp
|
||||
'''
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
|
||||
if META_DEF:
|
||||
# for pbone in obj_def.pose.bones:
|
||||
for bone_name, bone_name_new in base_names.items():
|
||||
#pbone_from = bone_name
|
||||
pbone = obj_def.pose.bones[bone_name_new]
|
||||
|
||||
con = pbone.constraints.new('COPY_ROTATION')
|
||||
con.target = obj
|
||||
con.subtarget = bone_name
|
||||
|
||||
if not pbone.bone.use_connect:
|
||||
con = pbone.constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = bone_name
|
||||
|
||||
# would be 'REST' from when copied
|
||||
obj_def.data.pose_position = 'POSE'
|
||||
|
||||
# todo - make a more generic system?
|
||||
layer_tot = [False] * 32
|
||||
layer_last = layer_tot[:]
|
||||
layer_last[31] = True
|
||||
layer_second_last = layer_tot[:]
|
||||
layer_second_last[30] = True
|
||||
|
||||
for bone_name, bone in arm.bones.items():
|
||||
bone.use_deform = False # Non DEF bones shouldn't deform
|
||||
if bone_name.startswith(ORG_PREFIX):
|
||||
bone.layers = ORG_LAYERS
|
||||
elif bone_name.startswith(MCH_PREFIX): # XXX fixme
|
||||
bone.layers = MCH_LAYERS
|
||||
elif bone_name.startswith(DEF_PREFIX): # XXX fixme
|
||||
bone.layers = DEF_LAYERS
|
||||
bone.use_deform = True
|
||||
else:
|
||||
# Assign bone appearance if there is a widget for it
|
||||
obj.pose.bones[bone_name].custom_shape = context.scene.objects.get(WGT_PREFIX + bone_name)
|
||||
|
||||
layer_tot[:] = [max(lay) for lay in zip(layer_tot, bone.layers)]
|
||||
|
||||
# Only for demo'ing
|
||||
layer_show = [a and not (b or c or d) for a, b, c, d in zip(layer_tot, ORG_LAYERS, MCH_LAYERS, DEF_LAYERS)]
|
||||
arm.layers = layer_show
|
||||
|
||||
|
||||
# obj.hide = True
|
||||
obj.data.show_axes = False
|
||||
|
||||
bpy.ops.object.mode_set(mode=mode_orig)
|
||||
obj_orig.data.pose_position = rest_backup
|
||||
obj.data.pose_position = 'POSE'
|
||||
obj_orig.data.pose_position = 'POSE'
|
||||
context.user_preferences.edit.use_global_undo = use_global_undo
|
||||
|
||||
print("Done.\n")
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
def generate_test(context, metarig_type="", GENERATE_FINAL=True):
|
||||
import os
|
||||
new_objects = []
|
||||
|
||||
scene = context.scene
|
||||
|
||||
def create_empty_armature(name):
|
||||
armature = bpy.data.armatures.new(name)
|
||||
obj_new = bpy.data.objects.new(name, armature)
|
||||
scene.objects.link(obj_new)
|
||||
scene.objects.active = obj_new
|
||||
for obj in scene.objects:
|
||||
obj.select = False
|
||||
obj_new.select = True
|
||||
|
||||
for module_name in get_submodule_types():
|
||||
if (metarig_type and module_name != metarig_type):
|
||||
continue
|
||||
|
||||
# XXX workaround!, problem with updating the pose matrix.
|
||||
if module_name == "delta":
|
||||
continue
|
||||
|
||||
type_name, submodule, func = submodule_func_from_type(module_name)
|
||||
|
||||
metarig_template = getattr(submodule, "metarig_template", None)
|
||||
|
||||
if metarig_template:
|
||||
create_empty_armature("meta_" + module_name) # sets active
|
||||
metarig_template()
|
||||
obj = context.active_object
|
||||
obj.location = scene.cursor_location
|
||||
|
||||
if GENERATE_FINAL:
|
||||
obj_new = generate_rig(context, obj)
|
||||
new_objects.append((obj, obj_new))
|
||||
else:
|
||||
new_objects.append((obj, None))
|
||||
else:
|
||||
print("note: rig type '%s' has no metarig_template(), can't test this" % module_name)
|
||||
|
||||
return new_objects
|
||||
|
||||
|
||||
def generate_test_all(context, GRAPH=False):
|
||||
import rigify
|
||||
import rigify_utils
|
||||
import graphviz_export
|
||||
import os
|
||||
reload(rigify)
|
||||
reload(rigify_utils)
|
||||
reload(graphviz_export)
|
||||
|
||||
new_objects = rigify.generate_test(context)
|
||||
|
||||
if GRAPH:
|
||||
if(bpy.data.filepath):
|
||||
base_name = os.path.splitext(bpy.data.filepath)[0]
|
||||
else:
|
||||
import tempfile
|
||||
base_name = tempfile.mktemp(prefix=bpy.app.tempdir)
|
||||
for obj, obj_new in new_objects:
|
||||
for obj in (obj, obj_new):
|
||||
fn = base_name + "-" + bpy.path.clean_name(obj.name)
|
||||
|
||||
path_dot = fn + ".dot"
|
||||
path_png = fn + ".png"
|
||||
saved = graphviz_export.graph_armature(obj, path_dot, CONSTRAINTS=True, DRIVERS=True)
|
||||
|
||||
#if saved:
|
||||
# os.system("dot -Tpng %s > %s; eog %s" % (path_dot, path_png, path_png))
|
||||
|
||||
i = 0
|
||||
for obj, obj_new in new_objects:
|
||||
obj.data.draw_type = 'STICK'
|
||||
obj.location[1] += i
|
||||
obj_new.location[1] += i
|
||||
obj_new.select = False
|
||||
obj.select = True
|
||||
i += 4
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
generate_rig(bpy.context, bpy.context.active_object)
|
@ -1,396 +0,0 @@
|
||||
# ##### 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 math import radians, pi
|
||||
from rigify import RigifyError, ORG_PREFIX
|
||||
from rigify_utils import bone_class_instance, copy_bone_simple, add_pole_target_bone, add_stretch_to, blend_bone_list, get_side_name, get_base_name
|
||||
from rna_prop_ui import rna_idprop_ui_prop_get
|
||||
from mathutils import Vector
|
||||
|
||||
METARIG_NAMES = "shoulder", "arm", "forearm", "hand"
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('shoulder')
|
||||
bone.head[:] = 0.0000, -0.0425, 0.0000
|
||||
bone.tail[:] = 0.0942, -0.0075, 0.0333
|
||||
bone.roll = -0.2227
|
||||
bone.use_connect = False
|
||||
bone = arm.edit_bones.new('upper_arm')
|
||||
bone.head[:] = 0.1066, -0.0076, -0.0010
|
||||
bone.tail[:] = 0.2855, 0.0206, -0.0104
|
||||
bone.roll = 1.6152
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['shoulder']
|
||||
bone = arm.edit_bones.new('forearm')
|
||||
bone.head[:] = 0.2855, 0.0206, -0.0104
|
||||
bone.tail[:] = 0.4550, -0.0076, -0.0023
|
||||
bone.roll = 1.5153
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['upper_arm']
|
||||
bone = arm.edit_bones.new('hand')
|
||||
bone.head[:] = 0.4550, -0.0076, -0.0023
|
||||
bone.tail[:] = 0.5423, -0.0146, -0.0131
|
||||
bone.roll = -3.0083
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['forearm']
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['upper_arm']
|
||||
pbone['type'] = 'arm_biped'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
mt = bone_class_instance(obj, METARIG_NAMES) # meta
|
||||
mt.arm = orig_bone_name
|
||||
mt.update()
|
||||
|
||||
mt.shoulder_p = mt.arm_p.parent
|
||||
|
||||
if not mt.shoulder_p:
|
||||
raise RigifyError("could not find '%s' parent, skipping:" % orig_bone_name)
|
||||
|
||||
mt.shoulder = mt.shoulder_p.name
|
||||
|
||||
# We could have some bones attached, find the bone that has this as its 2nd parent
|
||||
hands = []
|
||||
for pbone in obj.pose.bones:
|
||||
index = pbone.parent_index(mt.arm_p)
|
||||
if index == 2 and pbone.bone.use_connect and pbone.bone.parent.use_connect:
|
||||
hands.append(pbone)
|
||||
|
||||
if len(hands) != 1:
|
||||
raise RigifyError("Found %s possible hands attached to this arm, expected 1 from bone: %s" % ([pbone.name for pbone in hands], orig_bone_name))
|
||||
|
||||
# first add the 2 new bones
|
||||
mt.hand_p = hands[0]
|
||||
mt.hand = mt.hand_p.name
|
||||
|
||||
mt.forearm_p = mt.hand_p.parent
|
||||
mt.forearm = mt.forearm_p.name
|
||||
|
||||
return mt.names()
|
||||
|
||||
|
||||
def ik(obj, definitions, base_names, options):
|
||||
|
||||
arm = obj.data
|
||||
|
||||
mt = bone_class_instance(obj, METARIG_NAMES)
|
||||
mt.shoulder, mt.arm, mt.forearm, mt.hand = definitions
|
||||
mt.update()
|
||||
|
||||
ik = bone_class_instance(obj, ["pole", "pole_vis", "hand_vis"])
|
||||
ik_chain = mt.copy(to_fmt="MCH-%s_ik", base_names=base_names, exclude_attrs=["shoulder"])
|
||||
|
||||
# IK needs no parent_index
|
||||
ik_chain.hand_e.use_connect = False
|
||||
ik_chain.hand_e.parent = None
|
||||
ik_chain.hand_e.use_local_location = False
|
||||
ik_chain.rename("hand", get_base_name(base_names[mt.hand]) + "_ik" + get_side_name(mt.hand))
|
||||
|
||||
ik_chain.arm_e.use_connect = False
|
||||
ik_chain.arm_e.parent = mt.shoulder_e
|
||||
|
||||
# Add the bone used for the arms poll target
|
||||
#ik.pole = add_pole_target_bone(obj, mt.forearm, get_base_name(base_names[mt.forearm]) + "_target" + get_side_name(mt.forearm), mode='ZAVERAGE')
|
||||
ik.pole = add_pole_target_bone(obj, mt.forearm, "elbow_target" + get_side_name(mt.forearm), mode='ZAVERAGE')
|
||||
|
||||
ik.update()
|
||||
ik.pole_e.use_local_location = False
|
||||
|
||||
# option: elbow_parent
|
||||
elbow_parent_name = options.get("elbow_parent", "")
|
||||
|
||||
if elbow_parent_name:
|
||||
try:
|
||||
elbow_parent_e = arm.edit_bones[ORG_PREFIX + elbow_parent_name]
|
||||
except:
|
||||
# TODO, old/new parent mapping
|
||||
raise RigifyError("parent bone from property 'arm_biped_generic.elbow_parent' not found '%s'" % elbow_parent_name)
|
||||
ik.pole_e.parent = elbow_parent_e
|
||||
|
||||
# update bones after this!
|
||||
ik.hand_vis = add_stretch_to(obj, mt.hand, ik_chain.hand, "VIS-%s_ik" % base_names[mt.hand])
|
||||
ik.pole_vis = add_stretch_to(obj, mt.forearm, ik.pole, "VIS-%s_ik" % base_names[mt.forearm])
|
||||
|
||||
ik.update()
|
||||
ik.hand_vis_e.hide_select = True
|
||||
ik.pole_vis_e.hide_select = True
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
mt.update()
|
||||
ik.update()
|
||||
ik_chain.update()
|
||||
|
||||
# Set IK dof
|
||||
ik_chain.forearm_p.lock_ik_x = False
|
||||
ik_chain.forearm_p.lock_ik_y = True
|
||||
ik_chain.forearm_p.lock_ik_z = True
|
||||
|
||||
con = ik_chain.forearm_p.constraints.new('IK')
|
||||
con.target = obj
|
||||
con.subtarget = ik_chain.hand
|
||||
con.pole_target = obj
|
||||
con.pole_subtarget = ik.pole
|
||||
|
||||
con.use_tail = True
|
||||
con.use_stretch = True
|
||||
con.use_target = True
|
||||
con.use_rotation = False
|
||||
con.chain_count = 2
|
||||
con.pole_angle = -pi/2
|
||||
|
||||
# last step setup layers
|
||||
if "ik_layer" in options:
|
||||
layer = [n==options["ik_layer"] for n in range(0,32)]
|
||||
else:
|
||||
layer = list(mt.arm_b.layers)
|
||||
ik_chain.hand_b.layers = layer
|
||||
ik.hand_vis_b.layers = layer
|
||||
ik.pole_b.layers = layer
|
||||
ik.pole_vis_b.layers = layer
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
# don't blend the shoulder
|
||||
return [None] + ik_chain.names()
|
||||
|
||||
|
||||
def fk(obj, definitions, base_names, options):
|
||||
|
||||
arm = obj.data
|
||||
|
||||
mt = bone_class_instance(obj, METARIG_NAMES)
|
||||
mt.shoulder, mt.arm, mt.forearm, mt.hand = definitions
|
||||
mt.update()
|
||||
|
||||
ex = bone_class_instance(obj, ["socket", "hand_delta"])
|
||||
fk_chain = mt.copy(base_names=base_names)
|
||||
|
||||
# shoulder is used as a hinge
|
||||
fk_chain.rename("shoulder", "MCH-%s_hinge" % base_names[mt.arm])
|
||||
fk_chain.shoulder_e.translate(Vector((0.0, fk_chain.shoulder_e.length / 2, 0.0)))
|
||||
|
||||
# upper arm constrains to this.
|
||||
ex.socket_e = copy_bone_simple(arm, mt.arm, "MCH-%s_socket" % base_names[mt.arm])
|
||||
ex.socket = ex.socket_e.name
|
||||
ex.socket_e.use_connect = False
|
||||
ex.socket_e.parent = mt.shoulder_e
|
||||
ex.socket_e.length *= 0.5
|
||||
|
||||
# insert the 'MCH-delta_hand', between the forearm and the hand
|
||||
# copies forarm rotation
|
||||
ex.hand_delta_e = copy_bone_simple(arm, fk_chain.hand, "MCH-delta_%s" % base_names[mt.hand], parent=True)
|
||||
ex.hand_delta = ex.hand_delta_e.name
|
||||
ex.hand_delta_e.length *= 0.5
|
||||
ex.hand_delta_e.use_connect = False
|
||||
if "hand_roll" in options:
|
||||
ex.hand_delta_e.roll += radians(options["hand_roll"])
|
||||
|
||||
fk_chain.hand_e.use_connect = False
|
||||
fk_chain.hand_e.parent = ex.hand_delta_e
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
mt.update()
|
||||
ex.update()
|
||||
fk_chain.update()
|
||||
|
||||
# Set rotation modes and axis locks
|
||||
fk_chain.forearm_p.rotation_mode = 'XYZ'
|
||||
fk_chain.forearm_p.lock_rotation = (False, True, True)
|
||||
fk_chain.hand_p.rotation_mode = 'ZXY'
|
||||
fk_chain.arm_p.lock_location = True, True, True
|
||||
|
||||
con = fk_chain.arm_p.constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = ex.socket
|
||||
|
||||
fk_chain.hand_p.lock_location = True, True, True
|
||||
con = ex.hand_delta_p.constraints.new('COPY_ROTATION')
|
||||
con.target = obj
|
||||
con.subtarget = fk_chain.forearm
|
||||
|
||||
def hinge_setup():
|
||||
# Hinge constraint & driver
|
||||
con = fk_chain.shoulder_p.constraints.new('COPY_ROTATION')
|
||||
con.name = "hinge"
|
||||
con.target = obj
|
||||
con.subtarget = mt.shoulder
|
||||
driver_fcurve = con.driver_add("influence")
|
||||
driver = driver_fcurve.driver
|
||||
|
||||
|
||||
controller_path = fk_chain.arm_p.path_from_id()
|
||||
# add custom prop
|
||||
fk_chain.arm_p["hinge"] = 0.0
|
||||
prop = rna_idprop_ui_prop_get(fk_chain.arm_p, "hinge", create=True)
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
|
||||
|
||||
# *****
|
||||
driver = driver_fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
|
||||
var = driver.variables.new()
|
||||
var.name = "hinge"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = controller_path + '["hinge"]'
|
||||
|
||||
mod = driver_fcurve.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = 1.0
|
||||
mod.coefficients[1] = -1.0
|
||||
|
||||
hinge_setup()
|
||||
|
||||
# last step setup layers
|
||||
if "fk_layer" in options:
|
||||
layer = [n==options["fk_layer"] for n in range(0,32)]
|
||||
else:
|
||||
layer = list(mt.arm_b.layers)
|
||||
fk_chain.arm_b.layers = layer
|
||||
fk_chain.forearm_b.layers = layer
|
||||
fk_chain.hand_b.layers = layer
|
||||
|
||||
# Forearm was getting wrong roll somehow. Hack to fix that.
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
fk_chain.update()
|
||||
mt.update()
|
||||
fk_chain.forearm_e.roll = mt.forearm_e.roll
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
return None, fk_chain.arm, fk_chain.forearm, fk_chain.hand
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
# Create upper arm bones: two bones, each half of the upper arm.
|
||||
uarm1 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.01" % base_names[definitions[1]], parent=True)
|
||||
uarm2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.02" % base_names[definitions[1]], parent=True)
|
||||
uarm1.use_connect = False
|
||||
uarm2.use_connect = False
|
||||
uarm2.parent = uarm1
|
||||
center = uarm1.center
|
||||
uarm1.tail = center
|
||||
uarm2.head = center
|
||||
|
||||
# Create forearm bones: two bones, each half of the forearm.
|
||||
farm1 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.01" % base_names[definitions[2]], parent=True)
|
||||
farm2 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.02" % base_names[definitions[2]], parent=True)
|
||||
farm1.use_connect = False
|
||||
farm2.use_connect = False
|
||||
farm2.parent = farm1
|
||||
center = farm1.center
|
||||
farm1.tail = center
|
||||
farm2.head = center
|
||||
|
||||
# Create twist bone
|
||||
twist = copy_bone_simple(obj.data, definitions[2], "MCH-arm_twist")
|
||||
twist.use_connect = False
|
||||
twist.parent = obj.data.edit_bones[definitions[3]]
|
||||
twist.length /= 2
|
||||
|
||||
# Create hand bone
|
||||
hand = copy_bone_simple(obj.data, definitions[3], "DEF-%s" % base_names[definitions[3]], parent=True)
|
||||
|
||||
# Store names before leaving edit mode
|
||||
uarm1_name = uarm1.name
|
||||
uarm2_name = uarm2.name
|
||||
farm1_name = farm1.name
|
||||
farm2_name = farm2.name
|
||||
twist_name = twist.name
|
||||
hand_name = hand.name
|
||||
|
||||
# Leave edit mode
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Get the pose bones
|
||||
uarm1 = obj.pose.bones[uarm1_name]
|
||||
uarm2 = obj.pose.bones[uarm2_name]
|
||||
farm1 = obj.pose.bones[farm1_name]
|
||||
farm2 = obj.pose.bones[farm2_name]
|
||||
twist = obj.pose.bones[twist_name]
|
||||
hand = obj.pose.bones[hand_name]
|
||||
|
||||
# Upper arm constraints
|
||||
con = uarm1.constraints.new('DAMPED_TRACK')
|
||||
con.name = "trackto"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[2]
|
||||
|
||||
con = uarm1.constraints.new('COPY_SCALE')
|
||||
con.name = "trackto"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[1]
|
||||
|
||||
con = uarm2.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[1]
|
||||
|
||||
# Forearm constraints
|
||||
con = farm1.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[2]
|
||||
|
||||
con = farm1.constraints.new('COPY_SCALE')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[2]
|
||||
|
||||
con = farm2.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = twist.name
|
||||
|
||||
con = farm2.constraints.new('DAMPED_TRACK')
|
||||
con.name = "trackto"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[3]
|
||||
|
||||
# Hand constraint
|
||||
con = hand.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[3]
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
return (uarm1_name, uarm2_name, farm1_name, farm2_name, hand_name)
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
bones_fk = fk(obj, bone_definition, base_names, options)
|
||||
bones_ik = ik(obj, bone_definition, base_names, options)
|
||||
bones_deform = deform(obj, bone_definition, base_names, options)
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
blend_bone_list(obj, bone_definition, bones_fk, bones_ik, target_bone=bones_ik[3], target_prop="ik", blend_default=0.0)
|
@ -1,112 +0,0 @@
|
||||
# ##### 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_utils import bone_class_instance, copy_bone_simple
|
||||
|
||||
METARIG_NAMES = ("cpy",)
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('Bone')
|
||||
bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
bone.tail[:] = 0.0000, 0.0000, 1.0000
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['Bone']
|
||||
pbone['type'] = 'copy'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
return (orig_bone_name,)
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
# Create deform bone.
|
||||
bone = copy_bone_simple(obj.data, definitions[0], "DEF-%s" % base_names[definitions[0]], 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
|
||||
con = bone.constraints.new('COPY_TRANSFORMS')
|
||||
con.name = "copy_loc"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[0]
|
||||
|
||||
return (bone_name,)
|
||||
|
||||
|
||||
def control(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
arm = obj.data
|
||||
mt = bone_class_instance(obj, METARIG_NAMES)
|
||||
mt.cpy = definitions[0]
|
||||
mt.update()
|
||||
cp = bone_class_instance(obj, ["cpy"])
|
||||
cp.cpy_e = copy_bone_simple(arm, mt.cpy, base_names[mt.cpy], parent=True)
|
||||
cp.cpy = cp.cpy_e.name
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
cp.update()
|
||||
mt.update()
|
||||
|
||||
con = mt.cpy_p.constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = cp.cpy
|
||||
|
||||
|
||||
# Rotation mode and axis locks
|
||||
cp.cpy_p.rotation_mode = mt.cpy_p.rotation_mode
|
||||
cp.cpy_p.lock_location = tuple(mt.cpy_p.lock_location)
|
||||
cp.cpy_p.lock_rotations_4d = mt.cpy_p.lock_rotations_4d
|
||||
cp.cpy_p.lock_rotation = tuple(mt.cpy_p.lock_rotation)
|
||||
cp.cpy_p.lock_rotation_w = mt.cpy_p.lock_rotation_w
|
||||
cp.cpy_p.lock_scale = tuple(mt.cpy_p.lock_scale)
|
||||
|
||||
# Layers
|
||||
cp.cpy_b.layers = list(mt.cpy_b.layers)
|
||||
|
||||
return (mt.cpy,)
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
# Create control bone
|
||||
cpy = control(obj, bone_definition, base_names, options)[0]
|
||||
# Create deform bone
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
|
||||
return (cpy,)
|
@ -1,162 +0,0 @@
|
||||
# ##### 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
|
||||
|
||||
# not used, defined for completeness
|
||||
METARIG_NAMES = tuple()
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('bonesker')
|
||||
bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
bone.tail[:] = -0.0000, 0.7382, 0.1895
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = False
|
||||
bone = arm.edit_bones.new('delta')
|
||||
bone.head[:] = -0.0497, 0.8414, 0.3530
|
||||
bone.tail[:] = -0.2511, 1.1588, 0.9653
|
||||
bone.roll = 2.6044
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['bonesker']
|
||||
bone = arm.edit_bones.new('boney')
|
||||
bone.head[:] = 0.7940, 2.5592, 0.4134
|
||||
bone.tail[:] = 0.7940, 3.3975, 0.4890
|
||||
bone.roll = 3.1416
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['delta']
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['delta']
|
||||
pbone['type'] = 'delta'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
'''
|
||||
The bone given is the head, its parent is the body,
|
||||
# its only child the first of a chain with matching basenames.
|
||||
eg.
|
||||
body -> head -> neck_01 -> neck_02 -> neck_03.... etc
|
||||
'''
|
||||
arm = obj.data
|
||||
delta = arm.bones[orig_bone_name]
|
||||
children = delta.children
|
||||
|
||||
if len(children) != 1:
|
||||
raise RigifyError("only 1 child supported for delta on bone '%s'" % delta.name)
|
||||
|
||||
if delta.use_connect:
|
||||
raise RigifyError("bone cannot be connected to its parent '%s'" % delta.name)
|
||||
|
||||
bone_definition = [delta.name, children[0].name]
|
||||
|
||||
return bone_definition
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
'''
|
||||
Use this bone to define a delta thats applied to its child in pose mode.
|
||||
'''
|
||||
mode_orig = obj.mode
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
delta_name, child_name = bone_definition
|
||||
|
||||
delta_pbone = obj.pose.bones[delta_name]
|
||||
|
||||
arm = obj.data
|
||||
child_pbone = obj.pose.bones[child_name]
|
||||
|
||||
delta_phead = delta_pbone.head.copy()
|
||||
delta_ptail = delta_pbone.tail.copy()
|
||||
delta_pmatrix = delta_pbone.matrix.copy()
|
||||
|
||||
child_phead = child_pbone.head.copy()
|
||||
child_ptail = child_pbone.tail.copy()
|
||||
child_pmatrix = child_pbone.matrix.copy()
|
||||
|
||||
|
||||
children = delta_pbone.children
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
delta_ebone = arm.edit_bones[delta_name]
|
||||
child_ebone = arm.edit_bones[child_name]
|
||||
|
||||
delta_head = delta_ebone.head.copy()
|
||||
delta_tail = delta_ebone.tail.copy()
|
||||
|
||||
child_head = child_ebone.head.copy()
|
||||
child_tail = child_ebone.tail.copy()
|
||||
|
||||
#arm.edit_bones.remove(delta_ebone)
|
||||
#del delta_ebone # cant use this
|
||||
del child_pbone
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
|
||||
# Move the child bone to the deltas location
|
||||
obj.animation_data_create()
|
||||
delta_pbone = obj.pose.bones[delta_name]
|
||||
# child_pbone = obj.pose.bones[child_name]
|
||||
|
||||
# ------------------- drivers
|
||||
|
||||
delta_pbone.rotation_mode = 'XYZ'
|
||||
|
||||
rot = delta_pmatrix.invert().rotation_part() * child_pmatrix.rotation_part()
|
||||
rot = rot.invert().to_euler()
|
||||
|
||||
fcurve_drivers = delta_pbone.driver_add("rotation_euler", -1)
|
||||
for i, fcurve_driver in enumerate(fcurve_drivers):
|
||||
driver = fcurve_driver.driver
|
||||
driver.type = 'AVERAGE'
|
||||
#mod = fcurve_driver.modifiers.new('GENERATOR')
|
||||
mod = fcurve_driver.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = rot[i]
|
||||
mod.coefficients[1] = 0.0
|
||||
|
||||
# tricky, find the transform to drive the bone to this location.
|
||||
delta_head_offset = child_pmatrix.rotation_part() * (delta_phead - child_phead)
|
||||
|
||||
fcurve_drivers = delta_pbone.driver_add("location", -1)
|
||||
for i, fcurve_driver in enumerate(fcurve_drivers):
|
||||
driver = fcurve_driver.driver
|
||||
driver.type = 'AVERAGE'
|
||||
#mod = fcurve_driver.modifiers.new('GENERATOR')
|
||||
mod = fcurve_driver.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = delta_head_offset[i]
|
||||
mod.coefficients[1] = 0.0
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
bpy.ops.object.mode_set(mode=mode_orig)
|
||||
|
||||
# no blendeing
|
||||
return None
|
@ -1,405 +0,0 @@
|
||||
# ##### 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 rna_prop_ui import rna_idprop_ui_prop_get
|
||||
from mathutils import Vector
|
||||
from rigify import RigifyError
|
||||
from rigify_utils import copy_bone_simple
|
||||
|
||||
#METARIG_NAMES = ("cpy",)
|
||||
RIG_TYPE = "eye_balls"
|
||||
|
||||
def addget_shape_key(obj, name="Key"):
|
||||
""" Fetches a shape key, or creates it if it doesn't exist
|
||||
"""
|
||||
# Create a shapekey set if it doesn't already exist
|
||||
if obj.data.shape_keys is None:
|
||||
shape = obj.add_shape_key(name="Basis", from_mix=False)
|
||||
obj.active_shape_key_index = 0
|
||||
|
||||
# Get the shapekey, or create it if it doesn't already exist
|
||||
if name in obj.data.shape_keys.keys:
|
||||
shape_key = obj.data.shape_keys.keys[name]
|
||||
else:
|
||||
shape_key = obj.add_shape_key(name=name, from_mix=False)
|
||||
|
||||
return shape_key
|
||||
|
||||
|
||||
def addget_shape_key_driver(obj, name="Key"):
|
||||
""" Fetches the driver for the shape key, or creates it if it doesn't
|
||||
already exist.
|
||||
"""
|
||||
driver_path = 'keys["' + name + '"].value'
|
||||
fcurve = None
|
||||
driver = None
|
||||
new = False
|
||||
if obj.data.shape_keys.animation_data is not None:
|
||||
for driver_s in obj.data.shape_keys.animation_data.drivers:
|
||||
if driver_s.data_path == driver_path:
|
||||
fcurve = driver_s
|
||||
if fcurve is None:
|
||||
fcurve = obj.data.shape_keys.keys[name].driver_add("value")
|
||||
fcurve.driver.type = 'AVERAGE'
|
||||
new = True
|
||||
|
||||
return fcurve, new
|
||||
|
||||
|
||||
def create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, expression):
|
||||
""" Creates/gets a shape key and sets up a driver for it.
|
||||
|
||||
obj = armature object
|
||||
bone = driving bone name
|
||||
meshes = list of meshes to create the shapekey/driver on
|
||||
shape_name = name of the shape key
|
||||
var_name = name of the driving variable
|
||||
var_path = path to the property on the bone to drive with
|
||||
expression = python expression for the driver
|
||||
"""
|
||||
pb = obj.pose.bones
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
for mesh_name in meshes:
|
||||
mesh_obj = bpy.data.objects[mesh_name]
|
||||
|
||||
# Add/get the shape key
|
||||
shape = addget_shape_key(mesh_obj, name=shape_name)
|
||||
|
||||
# Add/get the shape key driver
|
||||
fcurve, a = addget_shape_key_driver(mesh_obj, name=shape_name)
|
||||
|
||||
# Set up the driver
|
||||
driver = fcurve.driver
|
||||
driver.type = 'SCRIPTED'
|
||||
driver.expression = expression
|
||||
|
||||
# Get the variable, or create it if it doesn't already exist
|
||||
if var_name in driver.variables:
|
||||
var = driver.variables[var_name]
|
||||
else:
|
||||
var = driver.variables.new()
|
||||
var.name = var_name
|
||||
|
||||
# Set up the variable
|
||||
var.type = "SINGLE_PROP"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = 'pose.bones["' + bone + '"]' + var_path
|
||||
|
||||
|
||||
def mark_actions():
|
||||
for action in bpy.data.actions:
|
||||
action.tag = True
|
||||
|
||||
def get_unmarked_action():
|
||||
for action in bpy.data.actions:
|
||||
if action.tag != True:
|
||||
return action
|
||||
return None
|
||||
|
||||
def add_action(name=None):
|
||||
mark_actions()
|
||||
bpy.ops.action.new()
|
||||
action = get_unmarked_action()
|
||||
if name is not None:
|
||||
action.name = name
|
||||
return action
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('Bone')
|
||||
bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
bone.tail[:] = 0.0000, 0.0000, 1.0000
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['Bone']
|
||||
pbone['type'] = 'copy'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
bone = obj.data.bones[orig_bone_name]
|
||||
chain = []
|
||||
|
||||
try:
|
||||
chain += [bone.parent.name, bone.name]
|
||||
except AttributeError:
|
||||
raise RigifyError("'%s' rig type requires a parent (bone: %s)" % (RIG_TYPE, orig_bone_name))
|
||||
|
||||
return chain
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
eb = obj.data.edit_bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
# Get list of eyes
|
||||
if "eyes" in options:
|
||||
eye_base_names = options["eyes"].replace(" ", "").split(",")
|
||||
else:
|
||||
eye_base_names = []
|
||||
|
||||
# Get their ORG- names
|
||||
eyes = []
|
||||
for name in eye_base_names:
|
||||
eyes += ["ORG-"+name]
|
||||
|
||||
# Duplicate the eyes to make deformation bones
|
||||
def_eyes = [] # def/org pairs
|
||||
for eye in eyes:
|
||||
def_eyes += [(copy_bone_simple(obj.data, eye, "DEF-"+base_names[eye], parent=True).name, eye)]
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Constraints
|
||||
for eye in def_eyes:
|
||||
con = pb[eye[0]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = eye[1]
|
||||
|
||||
return (None,)
|
||||
|
||||
|
||||
|
||||
|
||||
def control(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
eb = obj.data.edit_bones
|
||||
bb = obj.data.bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
head = definitions[0]
|
||||
eye_target = definitions[1]
|
||||
|
||||
# Get list of pupil mesh objects
|
||||
if "mesh" in options:
|
||||
pupil_meshes = options["mesh"].replace(" ", "").split(",")
|
||||
else:
|
||||
pupil_meshes = []
|
||||
|
||||
# Get list of eyes
|
||||
if "eyes" in options:
|
||||
eye_base_names = options["eyes"].replace(" ", "").split(",")
|
||||
else:
|
||||
eye_base_names = []
|
||||
|
||||
# Get their ORG- names
|
||||
eyes = []
|
||||
for name in eye_base_names:
|
||||
eyes += ["ORG-"+name]
|
||||
|
||||
# Get the average position of the eyes
|
||||
center = Vector((0, 0, 0))
|
||||
for eye in eyes:
|
||||
center += eb[eye].head
|
||||
if len(eyes) != 0:
|
||||
center /= len(eyes)
|
||||
|
||||
# Get the average length of the eyes
|
||||
length = 0.0
|
||||
for eye in eyes:
|
||||
length += eb[eye].length
|
||||
if len(eyes) == 0:
|
||||
length = 1.0
|
||||
else:
|
||||
length /= len(eyes)
|
||||
|
||||
|
||||
# Make the mind's eye
|
||||
minds_eye = copy_bone_simple(obj.data, eye_target, "MCH-"+base_names[eye_target]+".mind", parent=True).name
|
||||
eb[minds_eye].head = center
|
||||
eb[minds_eye].tail = eb[eye_target].head
|
||||
eb[minds_eye].roll = 0.0
|
||||
eb[minds_eye].length = length
|
||||
|
||||
# Create org/copy/control eye sets
|
||||
eye_sets = []
|
||||
for eye in eyes:
|
||||
copy = copy_bone_simple(obj.data, minds_eye, "MCH-"+base_names[eye]+".cpy", parent=True).name
|
||||
eb[copy].translate(eb[eye].head - eb[copy].head)
|
||||
eb[copy].parent = eb[eye].parent
|
||||
|
||||
control = copy_bone_simple(obj.data, eye, base_names[eye], parent=True).name
|
||||
eb[control].parent = eb[copy]
|
||||
|
||||
eye_sets += [(eye, copy, control)]
|
||||
|
||||
# Bones for parent/free switch for eye target
|
||||
target_ctrl = copy_bone_simple(obj.data, eye_target, base_names[eye_target], parent=True).name
|
||||
parent = copy_bone_simple(obj.data, head, "MCH-eye_target_parent", parent=False).name
|
||||
|
||||
eb[target_ctrl].parent = eb[parent]
|
||||
|
||||
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Axis locks
|
||||
pb[target_ctrl].lock_scale = False, True, True
|
||||
|
||||
# Add eye_spread action if it doesn't already exist
|
||||
action_name = "eye_spread"
|
||||
if action_name in bpy.data.actions:
|
||||
spread_action = bpy.data.actions[action_name]
|
||||
else:
|
||||
spread_action = add_action(name=action_name)
|
||||
|
||||
# Add free property
|
||||
prop_name = "free"
|
||||
prop = rna_idprop_ui_prop_get(pb[target_ctrl], prop_name, create=True)
|
||||
pb[target_ctrl][prop_name] = 0.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
prop["min"] = 0.0
|
||||
prop["max"] = 1.0
|
||||
|
||||
free_driver_path = pb[target_ctrl].path_from_id() + '["free"]'
|
||||
|
||||
# Constraints
|
||||
# Mind's eye tracks eye target control
|
||||
con = pb[minds_eye].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = target_ctrl
|
||||
|
||||
# Parent copies transforms of head
|
||||
con = pb[parent].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = head
|
||||
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
mod = fcurve.modifiers[0]
|
||||
mod.coefficients[0] = 1.0
|
||||
mod.coefficients[1] = -1.0
|
||||
|
||||
var = driver.variables.new()
|
||||
var.name = "free"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = free_driver_path
|
||||
|
||||
# Eye set's constraints
|
||||
for eye in eye_sets:
|
||||
# Org copies transforms of control
|
||||
con = pb[eye[0]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = eye[2]
|
||||
|
||||
# Copy copies rotation of mind's eye
|
||||
con = pb[eye[1]].constraints.new('COPY_ROTATION')
|
||||
con.target = obj
|
||||
con.subtarget = minds_eye
|
||||
|
||||
# Control gets action constraint for eye spread
|
||||
con = pb[eye[2]].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = target_ctrl
|
||||
con.action = spread_action
|
||||
con.transform_channel = 'SCALE_X'
|
||||
con.frame_start = -20
|
||||
con.frame_end = 20
|
||||
con.min = 0.0
|
||||
con.max = 2.0
|
||||
con.target_space = 'LOCAL'
|
||||
|
||||
|
||||
# Get/create the shape keys and drivers for pupil dilation
|
||||
shape_names = ["PUPILS-dilate_wide", "PUPILS-dilate_narrow"]
|
||||
slider_name = "pupil_dilate"
|
||||
|
||||
# Set up the custom property on the bone
|
||||
prop = rna_idprop_ui_prop_get(pb[target_ctrl], slider_name, create=True)
|
||||
pb[target_ctrl][slider_name] = 0.0
|
||||
prop["min"] = 0.0
|
||||
prop["max"] = 1.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
if len(shape_names) > 1:
|
||||
prop["min"] = -1.0
|
||||
prop["soft_min"] = -1.0
|
||||
|
||||
# Add the shape drivers
|
||||
# Positive
|
||||
if shape_names[0] != "":
|
||||
# Set up the variables for creating the shape key driver
|
||||
shape_name = shape_names[0]
|
||||
var_name = slider_name.replace(".", "_").replace("-", "_")
|
||||
var_path = '["' + slider_name + '"]'
|
||||
if slider_name + "_fac" in options:
|
||||
fac = options[slider_name + "_fac"]
|
||||
else:
|
||||
fac = 1.0
|
||||
expression = var_name + " * " + str(fac)
|
||||
# Create the shape key driver
|
||||
create_shape_and_driver(obj, target_ctrl, pupil_meshes, shape_name, var_name, var_path, expression)
|
||||
# Negative
|
||||
if shape_names[0] != "" and len(shape_names) > 1:
|
||||
# Set up the variables for creating the shape key driver
|
||||
shape_name = shape_names[1]
|
||||
var_name = slider_name.replace(".", "_").replace("-", "_")
|
||||
var_path = '["' + slider_name + '"]'
|
||||
if slider_name + "_fac" in options:
|
||||
fac = options[slider_name + "_fac"]
|
||||
else:
|
||||
fac = 1.0
|
||||
expression = var_name + " * " + str(fac) + " * -1"
|
||||
# Create the shape key driver
|
||||
create_shape_and_driver(obj, target_ctrl, pupil_meshes, shape_name, var_name, var_path, expression)
|
||||
|
||||
|
||||
|
||||
# Set layers
|
||||
#layer = list(bb[definitions[2]].layers)
|
||||
#bb[lid1].layers = layer
|
||||
#bb[lid2].layers = layer
|
||||
#bb[lid3].layers = layer
|
||||
#bb[lid4].layers = layer
|
||||
#bb[lid5].layers = layer
|
||||
#bb[lid6].layers = layer
|
||||
#bb[lid7].layers = layer
|
||||
#bb[lid8].layers = layer
|
||||
|
||||
|
||||
return (None,)
|
||||
|
||||
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
# Create control rig
|
||||
control(obj, bone_definition, base_names, options)
|
||||
# Create deform rig
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
|
||||
return (None,)
|
||||
|
@ -1,687 +0,0 @@
|
||||
# ##### 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 rna_prop_ui import rna_idprop_ui_prop_get
|
||||
from math import acos
|
||||
from mathutils import Vector
|
||||
from rigify import RigifyError
|
||||
from rigify_utils import copy_bone_simple
|
||||
|
||||
#METARIG_NAMES = ("cpy",)
|
||||
RIG_TYPE = "eye_lid"
|
||||
|
||||
def mark_actions():
|
||||
for action in bpy.data.actions:
|
||||
action.tag = True
|
||||
|
||||
def get_unmarked_action():
|
||||
for action in bpy.data.actions:
|
||||
if action.tag != True:
|
||||
return action
|
||||
return None
|
||||
|
||||
def add_action(name=None):
|
||||
mark_actions()
|
||||
bpy.ops.action.new()
|
||||
action = get_unmarked_action()
|
||||
if name is not None:
|
||||
action.name = name
|
||||
return action
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('Bone')
|
||||
bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
bone.tail[:] = 0.0000, 0.0000, 1.0000
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['Bone']
|
||||
pbone['type'] = 'copy'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
bb = obj.data.bones
|
||||
bone = bb[orig_bone_name]
|
||||
chain = []
|
||||
|
||||
try:
|
||||
chain += [bone.parent.parent.name, bone.parent.name, bone.name]
|
||||
except AttributeError:
|
||||
raise RigifyError("'%s' rig type requires a chain of two parents (bone: %s)" % (RIG_TYPE, orig_bone_name))
|
||||
|
||||
chain += [child.name for child in bone.children_recursive_basename]
|
||||
|
||||
if len(chain) < 10:
|
||||
raise RigifyError("'%s' rig type requires a chain of 10 bones (bone: %s)" % (RIG_TYPE, orig_bone_name))
|
||||
|
||||
chain = chain[:10]
|
||||
|
||||
try:
|
||||
chain += [bb[chain[9]].children[0].name]
|
||||
chain += [bb[chain[10]].children[0].name]
|
||||
except IndexError:
|
||||
raise RigifyError("'%s' rig type requires a chain of 10 bones (bone: %s)" % (RIG_TYPE, orig_bone_name))
|
||||
|
||||
return chain
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
eb = obj.data.edit_bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
|
||||
# Upper lid MCH
|
||||
lid1 = make_lid_stretch_bone(obj, "MCH-lid", definitions[2], definitions[3], 1.0)
|
||||
lid2 = make_lid_stretch_bone(obj, "MCH-lid", definitions[3], definitions[4], 1.0)
|
||||
lid22 = make_lid_stretch_bone(obj, "MCH-lid", definitions[4], definitions[5], 1.0)
|
||||
lid33 = make_lid_stretch_bone(obj, "MCH-lid", definitions[4], definitions[3], 1.0)
|
||||
lid3 = make_lid_stretch_bone(obj, "MCH-lid", definitions[5], definitions[4], 1.0)
|
||||
lid4 = make_lid_stretch_bone(obj, "MCH-lid", definitions[6], definitions[5], 1.0)
|
||||
|
||||
dlid22 = copy_bone_simple(obj.data, lid22, "MCH-lid", parent=True).name
|
||||
dlid33 = copy_bone_simple(obj.data, lid33, "MCH-lid", parent=True).name
|
||||
eb[dlid22].bbone_segments = 8
|
||||
eb[dlid33].bbone_segments = 8
|
||||
|
||||
eb[lid1].parent = eb[definitions[2]]
|
||||
eb[lid2].parent = eb[definitions[3]]
|
||||
eb[lid22].parent = eb[definitions[4]]
|
||||
eb[lid33].parent = eb[definitions[4]]
|
||||
eb[lid3].parent = eb[definitions[5]]
|
||||
eb[lid4].parent = eb[definitions[6]]
|
||||
|
||||
# Lower lid MCH
|
||||
lid5 = make_lid_stretch_bone(obj, "MCH-lid", definitions[6], definitions[7], 1.0)
|
||||
lid6 = make_lid_stretch_bone(obj, "MCH-lid", definitions[7], definitions[8], 1.0)
|
||||
lid66 = make_lid_stretch_bone(obj, "MCH-lid", definitions[8], definitions[9], 1.0)
|
||||
lid77 = make_lid_stretch_bone(obj, "MCH-lid", definitions[8], definitions[7], 1.0)
|
||||
lid7 = make_lid_stretch_bone(obj, "MCH-lid", definitions[9], definitions[8], 1.0)
|
||||
lid8 = make_lid_stretch_bone(obj, "MCH-lid", definitions[2], definitions[9], 1.0)
|
||||
|
||||
dlid66 = copy_bone_simple(obj.data, lid66, "MCH-lid", parent=True).name
|
||||
dlid77 = copy_bone_simple(obj.data, lid77, "MCH-lid", parent=True).name
|
||||
eb[dlid66].bbone_segments = 8
|
||||
eb[dlid77].bbone_segments = 8
|
||||
|
||||
eb[lid5].parent = eb[definitions[6]]
|
||||
eb[lid6].parent = eb[definitions[7]]
|
||||
eb[lid66].parent = eb[definitions[8]]
|
||||
eb[lid77].parent = eb[definitions[8]]
|
||||
eb[lid7].parent = eb[definitions[9]]
|
||||
eb[lid8].parent = eb[definitions[2]]
|
||||
|
||||
# Upper lid DEF
|
||||
dlid1 = copy_bone_simple(obj.data, lid1, "DEF-" + base_names[definitions[2]], parent=True).name
|
||||
dlid2 = copy_bone_simple(obj.data, lid2, "DEF-" + base_names[definitions[3]], parent=True).name
|
||||
dlid3 = copy_bone_simple(obj.data, lid3, "DEF-" + base_names[definitions[4]], parent=True).name
|
||||
dlid4 = copy_bone_simple(obj.data, lid4, "DEF-" + base_names[definitions[5]], parent=True).name
|
||||
|
||||
eb[dlid2].parent = eb[dlid1]
|
||||
eb[dlid22].parent = eb[dlid2]
|
||||
|
||||
eb[dlid3].parent = eb[dlid4]
|
||||
eb[dlid33].parent = eb[dlid3]
|
||||
|
||||
eb[dlid2].use_connect = True
|
||||
eb[dlid22].use_connect = True
|
||||
eb[dlid3].use_connect = True
|
||||
eb[dlid33].use_connect = True
|
||||
|
||||
eb[dlid1].bbone_segments = 8
|
||||
eb[dlid2].bbone_segments = 8
|
||||
eb[dlid3].bbone_segments = 8
|
||||
eb[dlid4].bbone_segments = 8
|
||||
|
||||
# Lower lid DEF
|
||||
dlid5 = copy_bone_simple(obj.data, lid5, "DEF-" + base_names[definitions[6]], parent=True).name
|
||||
dlid6 = copy_bone_simple(obj.data, lid6, "DEF-" + base_names[definitions[7]], parent=True).name
|
||||
dlid7 = copy_bone_simple(obj.data, lid7, "DEF-" + base_names[definitions[8]], parent=True).name
|
||||
dlid8 = copy_bone_simple(obj.data, lid8, "DEF-" + base_names[definitions[9]], parent=True).name
|
||||
|
||||
eb[dlid6].parent = eb[dlid5]
|
||||
eb[dlid66].parent = eb[dlid6]
|
||||
|
||||
eb[dlid7].parent = eb[dlid8]
|
||||
eb[dlid77].parent = eb[dlid7]
|
||||
|
||||
eb[dlid6].use_connect = True
|
||||
eb[dlid66].use_connect = True
|
||||
eb[dlid7].use_connect = True
|
||||
eb[dlid77].use_connect = True
|
||||
|
||||
eb[dlid5].bbone_segments = 8
|
||||
eb[dlid6].bbone_segments = 8
|
||||
eb[dlid7].bbone_segments = 8
|
||||
eb[dlid8].bbone_segments = 8
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Constraints
|
||||
con = pb[dlid1].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid1
|
||||
|
||||
con = pb[dlid22].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid22
|
||||
|
||||
con = pb[dlid33].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid33
|
||||
|
||||
con = pb[dlid2].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid2
|
||||
|
||||
con = pb[dlid3].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid3
|
||||
|
||||
con = pb[dlid4].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid4
|
||||
|
||||
con = pb[dlid5].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid5
|
||||
|
||||
con = pb[dlid6].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid6
|
||||
|
||||
con = pb[dlid66].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid66
|
||||
|
||||
con = pb[dlid77].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid77
|
||||
|
||||
con = pb[dlid7].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid7
|
||||
|
||||
con = pb[dlid8].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lid8
|
||||
|
||||
return (None,)
|
||||
|
||||
|
||||
|
||||
|
||||
def control(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
eb = obj.data.edit_bones
|
||||
bb = obj.data.bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
head_e = eb[definitions[0]]
|
||||
eye_e = eb[definitions[1]]
|
||||
|
||||
|
||||
# Make eye "flower"
|
||||
flo1 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[2]]+".flower", parent=True).name
|
||||
flo2 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[3]]+".flower", parent=True).name
|
||||
flo3 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[4]]+".flower", parent=True).name
|
||||
flo4 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[5]]+".flower", parent=True).name
|
||||
flo5 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[6]]+".flower", parent=True).name
|
||||
flo6 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[7]]+".flower", parent=True).name
|
||||
flo7 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[8]]+".flower", parent=True).name
|
||||
flo8 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[9]]+".flower", parent=True).name
|
||||
|
||||
eb[flo1].tail = eb[definitions[2]].head
|
||||
eb[flo2].tail = eb[definitions[3]].head
|
||||
eb[flo3].tail = eb[definitions[4]].head
|
||||
eb[flo4].tail = eb[definitions[5]].head
|
||||
eb[flo5].tail = eb[definitions[6]].head
|
||||
eb[flo6].tail = eb[definitions[7]].head
|
||||
eb[flo7].tail = eb[definitions[8]].head
|
||||
eb[flo8].tail = eb[definitions[9]].head
|
||||
|
||||
|
||||
# Make eye lids on tips of flowers
|
||||
flid1 = copy_bone_simple(obj.data, definitions[2], "MCH-"+base_names[definitions[2]]).name
|
||||
flid2 = copy_bone_simple(obj.data, definitions[3], "MCH-"+base_names[definitions[3]]).name
|
||||
flid3 = copy_bone_simple(obj.data, definitions[4], "MCH-"+base_names[definitions[4]]).name
|
||||
flid4 = copy_bone_simple(obj.data, definitions[5], "MCH-"+base_names[definitions[5]]).name
|
||||
flid5 = copy_bone_simple(obj.data, definitions[6], "MCH-"+base_names[definitions[6]]).name
|
||||
flid6 = copy_bone_simple(obj.data, definitions[7], "MCH-"+base_names[definitions[7]]).name
|
||||
flid7 = copy_bone_simple(obj.data, definitions[8], "MCH-"+base_names[definitions[8]]).name
|
||||
flid8 = copy_bone_simple(obj.data, definitions[9], "MCH-"+base_names[definitions[9]]).name
|
||||
|
||||
eb[flid1].parent = eb[flo1]
|
||||
eb[flid2].parent = eb[flo2]
|
||||
eb[flid3].parent = eb[flo3]
|
||||
eb[flid4].parent = eb[flo4]
|
||||
eb[flid5].parent = eb[flo5]
|
||||
eb[flid6].parent = eb[flo6]
|
||||
eb[flid7].parent = eb[flo7]
|
||||
eb[flid8].parent = eb[flo8]
|
||||
|
||||
|
||||
# Make eye lid controls
|
||||
lid1 = copy_bone_simple(obj.data, definitions[2], base_names[definitions[2]]).name
|
||||
lid2 = copy_bone_simple(obj.data, definitions[3], base_names[definitions[3]]).name
|
||||
lid3 = copy_bone_simple(obj.data, definitions[4], base_names[definitions[4]]).name
|
||||
lid4 = copy_bone_simple(obj.data, definitions[5], base_names[definitions[5]]).name
|
||||
lid5 = copy_bone_simple(obj.data, definitions[6], base_names[definitions[6]]).name
|
||||
lid6 = copy_bone_simple(obj.data, definitions[7], base_names[definitions[7]]).name
|
||||
lid7 = copy_bone_simple(obj.data, definitions[8], base_names[definitions[8]]).name
|
||||
lid8 = copy_bone_simple(obj.data, definitions[9], base_names[definitions[9]]).name
|
||||
|
||||
size = eb[lid1].length
|
||||
size_y = Vector(0.0, size, 0.0)
|
||||
eb[lid1].tail = eb[lid1].head + size_y
|
||||
eb[lid2].tail = eb[lid2].head + size_y
|
||||
eb[lid3].tail = eb[lid3].head + size_y
|
||||
eb[lid4].tail = eb[lid4].head + size_y
|
||||
eb[lid5].tail = eb[lid5].head + size_y
|
||||
eb[lid6].tail = eb[lid6].head + size_y
|
||||
eb[lid7].tail = eb[lid7].head + size_y
|
||||
eb[lid8].tail = eb[lid8].head + size_y
|
||||
|
||||
eb[lid1].roll = 0
|
||||
eb[lid2].roll = 0
|
||||
eb[lid3].roll = 0
|
||||
eb[lid4].roll = 0
|
||||
eb[lid5].roll = 0
|
||||
eb[lid6].roll = 0
|
||||
eb[lid7].roll = 0
|
||||
eb[lid8].roll = 0
|
||||
|
||||
eb[lid1].parent = head_e
|
||||
eb[lid2].parent = head_e
|
||||
eb[lid3].parent = head_e
|
||||
eb[lid4].parent = head_e
|
||||
eb[lid5].parent = head_e
|
||||
eb[lid6].parent = head_e
|
||||
eb[lid7].parent = head_e
|
||||
eb[lid8].parent = head_e
|
||||
|
||||
lower_lid_ctrl = copy_bone_simple(obj.data, definitions[10], base_names[definitions[10]]).name
|
||||
upper_lid_ctrl = copy_bone_simple(obj.data, definitions[11], base_names[definitions[11]]).name
|
||||
eb[lower_lid_ctrl].parent = head_e
|
||||
eb[upper_lid_ctrl].parent = head_e
|
||||
distance = (eb[lower_lid_ctrl].head - eb[upper_lid_ctrl].head).length
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Axis locks
|
||||
pb[lower_lid_ctrl].lock_location = True, False, True
|
||||
pb[upper_lid_ctrl].lock_location = True, False, True
|
||||
|
||||
# Add eye close action if it doesn't already exist
|
||||
action_name = "eye_close"
|
||||
if action_name in bpy.data.actions:
|
||||
close_action = bpy.data.actions[action_name]
|
||||
else:
|
||||
close_action = add_action(name=action_name)
|
||||
|
||||
# Add close property (useful when making the animation in the action)
|
||||
prop_name = "close_action"
|
||||
prop = rna_idprop_ui_prop_get(pb[upper_lid_ctrl], prop_name, create=True)
|
||||
pb[upper_lid_ctrl][prop_name] = 1.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
prop["min"] = 0.0
|
||||
prop["max"] = 1.0
|
||||
|
||||
close_driver_path = pb[upper_lid_ctrl].path_from_id() + '["close_action"]'
|
||||
|
||||
# Constraints
|
||||
|
||||
# Flowers track lid controls
|
||||
con = pb[flo1].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lid1
|
||||
|
||||
con = pb[flo2].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lid2
|
||||
|
||||
con = pb[flo3].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lid3
|
||||
|
||||
con = pb[flo4].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lid4
|
||||
|
||||
con = pb[flo5].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lid5
|
||||
|
||||
con = pb[flo6].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lid6
|
||||
|
||||
con = pb[flo7].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lid7
|
||||
|
||||
con = pb[flo8].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lid8
|
||||
|
||||
|
||||
# ORG bones to flower lids
|
||||
con = pb[definitions[2]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = flid1
|
||||
|
||||
con = pb[definitions[3]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = flid2
|
||||
|
||||
con = pb[definitions[4]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = flid3
|
||||
|
||||
con = pb[definitions[5]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = flid4
|
||||
|
||||
con = pb[definitions[6]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = flid5
|
||||
|
||||
con = pb[definitions[7]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = flid6
|
||||
|
||||
con = pb[definitions[8]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = flid7
|
||||
|
||||
con = pb[definitions[9]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = flid8
|
||||
|
||||
|
||||
# Action constraints, upper lid
|
||||
con = pb[lid1].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = upper_lid_ctrl
|
||||
con.action = close_action
|
||||
con.transform_channel = 'LOCATION_Y'
|
||||
con.frame_start = -30
|
||||
con.frame_end = 30
|
||||
con.min = -distance*2
|
||||
con.max = distance
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = close_driver_path
|
||||
|
||||
|
||||
con = pb[lid2].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = upper_lid_ctrl
|
||||
con.action = close_action
|
||||
con.transform_channel = 'LOCATION_Y'
|
||||
con.frame_start = -30
|
||||
con.frame_end = 30
|
||||
con.min = -distance*2
|
||||
con.max = distance
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = close_driver_path
|
||||
|
||||
con = pb[lid3].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = upper_lid_ctrl
|
||||
con.action = close_action
|
||||
con.transform_channel = 'LOCATION_Y'
|
||||
con.frame_start = -30
|
||||
con.frame_end = 30
|
||||
con.min = -distance*2
|
||||
con.max = distance
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = close_driver_path
|
||||
|
||||
con = pb[lid4].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = upper_lid_ctrl
|
||||
con.action = close_action
|
||||
con.transform_channel = 'LOCATION_Y'
|
||||
con.frame_start = -30
|
||||
con.frame_end = 30
|
||||
con.min = -distance*2
|
||||
con.max = distance
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = close_driver_path
|
||||
|
||||
con = pb[lid5].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = upper_lid_ctrl
|
||||
con.action = close_action
|
||||
con.transform_channel = 'LOCATION_Y'
|
||||
con.frame_start = -30
|
||||
con.frame_end = 30
|
||||
con.min = -distance*2
|
||||
con.max = distance
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = close_driver_path
|
||||
|
||||
# Action constraints, lower lid
|
||||
con = pb[lid5].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = lower_lid_ctrl
|
||||
con.action = close_action
|
||||
con.transform_channel = 'LOCATION_Y'
|
||||
con.frame_start = -30
|
||||
con.frame_end = 30
|
||||
con.min = -distance
|
||||
con.max = distance*2
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = close_driver_path
|
||||
|
||||
con = pb[lid6].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = lower_lid_ctrl
|
||||
con.action = close_action
|
||||
con.transform_channel = 'LOCATION_Y'
|
||||
con.frame_start = -30
|
||||
con.frame_end = 30
|
||||
con.min = -distance
|
||||
con.max = distance*2
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = close_driver_path
|
||||
|
||||
con = pb[lid7].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = lower_lid_ctrl
|
||||
con.action = close_action
|
||||
con.transform_channel = 'LOCATION_Y'
|
||||
con.frame_start = -30
|
||||
con.frame_end = 30
|
||||
con.min = -distance
|
||||
con.max = distance*2
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = close_driver_path
|
||||
|
||||
con = pb[lid8].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = lower_lid_ctrl
|
||||
con.action = close_action
|
||||
con.transform_channel = 'LOCATION_Y'
|
||||
con.frame_start = -30
|
||||
con.frame_end = 30
|
||||
con.min = -distance
|
||||
con.max = distance*2
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = close_driver_path
|
||||
|
||||
con = pb[lid1].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = lower_lid_ctrl
|
||||
con.action = close_action
|
||||
con.transform_channel = 'LOCATION_Y'
|
||||
con.frame_start = -30
|
||||
con.frame_end = 30
|
||||
con.min = -distance
|
||||
con.max = distance*2
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = close_driver_path
|
||||
|
||||
|
||||
|
||||
|
||||
# Set layers
|
||||
layer = list(bb[definitions[2]].layers)
|
||||
bb[lid1].layers = layer
|
||||
bb[lid2].layers = layer
|
||||
bb[lid3].layers = layer
|
||||
bb[lid4].layers = layer
|
||||
bb[lid5].layers = layer
|
||||
bb[lid6].layers = layer
|
||||
bb[lid7].layers = layer
|
||||
bb[lid8].layers = layer
|
||||
|
||||
|
||||
return (None,)
|
||||
|
||||
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
# Create control rig
|
||||
control(obj, bone_definition, base_names, options)
|
||||
# Create deform rig
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
|
||||
return (None,)
|
||||
|
||||
|
||||
|
||||
|
||||
def make_lid_stretch_bone(obj, name, bone1, bone2, roll_alpha):
|
||||
eb = obj.data.edit_bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
# Create the bone, pointing from bone1 to bone2
|
||||
bone_e = copy_bone_simple(obj.data, bone1, name, parent=True)
|
||||
bone_e.use_connect = False
|
||||
bone_e.tail = eb[bone2].head
|
||||
bone = bone_e.name
|
||||
|
||||
# Align the bone roll with the average direction of bone1 and bone2
|
||||
vec = bone_e.y_axis.cross(((1.0-roll_alpha)*eb[bone1].y_axis) + (roll_alpha*eb[bone2].y_axis)).normalize()
|
||||
|
||||
ang = acos(vec * bone_e.x_axis)
|
||||
|
||||
bone_e.roll += ang
|
||||
c1 = vec * bone_e.x_axis
|
||||
bone_e.roll -= (ang*2)
|
||||
c2 = vec * bone_e.x_axis
|
||||
|
||||
if c1 > c2:
|
||||
bone_e.roll += (ang*2)
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
bone_p = pb[bone]
|
||||
|
||||
# Constrains
|
||||
con = bone_p.constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = bone1
|
||||
|
||||
con = bone_p.constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = bone2
|
||||
|
||||
con = bone_p.constraints.new('STRETCH_TO')
|
||||
con.target = obj
|
||||
con.subtarget = bone2
|
||||
con.volume = 'NO_VOLUME'
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
return bone
|
@ -1,378 +0,0 @@
|
||||
# ##### 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 copy_bone_simple, get_side_name
|
||||
from rna_prop_ui import rna_idprop_ui_prop_get
|
||||
|
||||
METARIG_NAMES = "finger_01", "finger_02", "finger_03"
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('finger.01')
|
||||
bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
bone.tail[:] = 0.0353, -0.0184, -0.0053
|
||||
bone.roll = -2.8722
|
||||
bone.use_connect = False
|
||||
bone = arm.edit_bones.new('finger.02')
|
||||
bone.head[:] = 0.0353, -0.0184, -0.0053
|
||||
bone.tail[:] = 0.0702, -0.0364, -0.0146
|
||||
bone.roll = -2.7099
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger.01']
|
||||
bone = arm.edit_bones.new('finger.03')
|
||||
bone.head[:] = 0.0702, -0.0364, -0.0146
|
||||
bone.tail[:] = 0.0903, -0.0461, -0.0298
|
||||
bone.roll = -2.1709
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger.02']
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['finger.01']
|
||||
pbone['type'] = 'finger_curl'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
'''
|
||||
The bone given is the first in a chain
|
||||
Expects a chain with at least 1 child of the same base name.
|
||||
eg.
|
||||
finger_01 -> finger_02
|
||||
'''
|
||||
|
||||
orig_bone = obj.data.bones[orig_bone_name]
|
||||
|
||||
bone_definition = [orig_bone.name]
|
||||
|
||||
bone_definition.extend([child.name for child in orig_bone.children_recursive_basename])
|
||||
|
||||
if len(bone_definition) < 2:
|
||||
raise RigifyError("expected the chain to have at least 1 child from bone '%s' without the same base name" % orig_bone_name)
|
||||
|
||||
return bone_definition
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
""" Creates the deform rig.
|
||||
"""
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
three_digits = True if len(definitions) > 2 else False
|
||||
|
||||
# Create base digit bones: two bones, each half of the base digit.
|
||||
f1a = copy_bone_simple(obj.data, definitions[0], "DEF-%s.01" % base_names[definitions[0]], parent=True)
|
||||
f1b = copy_bone_simple(obj.data, definitions[0], "DEF-%s.02" % base_names[definitions[0]], parent=True)
|
||||
f1a.use_connect = False
|
||||
f1b.use_connect = False
|
||||
f1b.parent = f1a
|
||||
center = f1a.center
|
||||
f1a.tail = center
|
||||
f1b.head = center
|
||||
|
||||
# Create the other deform bones.
|
||||
f2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s" % base_names[definitions[1]], parent=True)
|
||||
if three_digits:
|
||||
f3 = copy_bone_simple(obj.data, definitions[2], "DEF-%s" % base_names[definitions[2]], parent=True)
|
||||
|
||||
# Store names before leaving edit mode
|
||||
f1a_name = f1a.name
|
||||
f1b_name = f1b.name
|
||||
f2_name = f2.name
|
||||
if three_digits:
|
||||
f3_name = f3.name
|
||||
|
||||
# Leave edit mode
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Get the pose bones
|
||||
f1a = obj.pose.bones[f1a_name]
|
||||
f1b = obj.pose.bones[f1b_name]
|
||||
f2 = obj.pose.bones[f2_name]
|
||||
if three_digits:
|
||||
f3 = obj.pose.bones[f3_name]
|
||||
|
||||
# Constrain the base digit's bones
|
||||
con = f1a.constraints.new('DAMPED_TRACK')
|
||||
con.name = "trackto"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[1]
|
||||
|
||||
con = f1a.constraints.new('COPY_SCALE')
|
||||
con.name = "copy_scale"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[0]
|
||||
|
||||
con = f1b.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[0]
|
||||
|
||||
# Constrain the other digit's bones
|
||||
con = f2.constraints.new('COPY_TRANSFORMS')
|
||||
con.name = "copy_transforms"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[1]
|
||||
|
||||
if three_digits:
|
||||
con = f3.constraints.new('COPY_TRANSFORMS')
|
||||
con.name = "copy_transforms"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[2]
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
# *** EDITMODE
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
three_digits = True if len(bone_definition) > 2 else False
|
||||
|
||||
# get assosiated data
|
||||
arm = obj.data
|
||||
bb = obj.data.bones
|
||||
eb = obj.data.edit_bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
org_f1 = bone_definition[0] # Original finger bone 01
|
||||
org_f2 = bone_definition[1] # Original finger bone 02
|
||||
if three_digits:
|
||||
org_f3 = bone_definition[2] # Original finger bone 03
|
||||
|
||||
# Check options
|
||||
if "bend_ratio" in options:
|
||||
bend_ratio = options["bend_ratio"]
|
||||
else:
|
||||
bend_ratio = 0.4
|
||||
|
||||
yes = [1, 1.0, True, "True", "true", "Yes", "yes"]
|
||||
make_hinge = False
|
||||
if ("hinge" in options) and (eb[org_f1].parent is not None):
|
||||
if options["hinge"] in yes:
|
||||
make_hinge = True
|
||||
|
||||
|
||||
# Needed if its a new armature with no keys
|
||||
obj.animation_data_create()
|
||||
|
||||
# Create the control bone
|
||||
base_name = base_names[bone_definition[0]].split(".", 1)[0]
|
||||
if three_digits:
|
||||
tot_len = eb[org_f1].length + eb[org_f2].length + eb[org_f3].length
|
||||
else:
|
||||
tot_len = eb[org_f1].length + eb[org_f2].length
|
||||
control = copy_bone_simple(arm, bone_definition[0], base_name + get_side_name(base_names[bone_definition[0]]), parent=True).name
|
||||
eb[control].use_connect = eb[org_f1].use_connect
|
||||
eb[control].parent = eb[org_f1].parent
|
||||
eb[control].length = tot_len
|
||||
|
||||
# Create secondary control bones
|
||||
f1 = copy_bone_simple(arm, bone_definition[0], base_names[bone_definition[0]]).name
|
||||
f2 = copy_bone_simple(arm, bone_definition[1], base_names[bone_definition[1]]).name
|
||||
if three_digits:
|
||||
f3 = copy_bone_simple(arm, bone_definition[2], base_names[bone_definition[2]]).name
|
||||
|
||||
# Create driver bones
|
||||
df1 = copy_bone_simple(arm, bone_definition[0], "MCH-" + base_names[bone_definition[0]]).name
|
||||
eb[df1].length /= 2
|
||||
df2 = copy_bone_simple(arm, bone_definition[1], "MCH-" + base_names[bone_definition[1]]).name
|
||||
eb[df2].length /= 2
|
||||
if three_digits:
|
||||
df3 = copy_bone_simple(arm, bone_definition[2], "MCH-" + base_names[bone_definition[2]]).name
|
||||
eb[df3].length /= 2
|
||||
|
||||
# Set parents of the bones, interleaving the driver bones with the secondary control bones
|
||||
if three_digits:
|
||||
eb[f3].use_connect = False
|
||||
eb[df3].use_connect = False
|
||||
eb[f2].use_connect = False
|
||||
eb[df2].use_connect = False
|
||||
eb[f1].use_connect = False
|
||||
eb[df1].use_connect = eb[org_f1].use_connect
|
||||
|
||||
if three_digits:
|
||||
eb[f3].parent = eb[df3]
|
||||
eb[df3].parent = eb[f2]
|
||||
eb[f2].parent = eb[df2]
|
||||
eb[df2].parent = eb[f1]
|
||||
eb[f1].parent = eb[df1]
|
||||
eb[df1].parent = eb[org_f1].parent
|
||||
|
||||
# Set up bones for hinge
|
||||
if make_hinge:
|
||||
socket = copy_bone_simple(arm, org_f1, "MCH-socket_"+control, parent=True).name
|
||||
hinge = copy_bone_simple(arm, eb[org_f1].parent.name, "MCH-hinge_"+control).name
|
||||
|
||||
eb[control].use_connect = False
|
||||
eb[control].parent = eb[hinge]
|
||||
|
||||
# Create the deform rig while we're still in edit mode
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
|
||||
|
||||
# *** POSEMODE
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Set rotation modes and axis locks
|
||||
pb[control].rotation_mode = obj.pose.bones[bone_definition[0]].rotation_mode
|
||||
pb[control].lock_location = True, True, True
|
||||
pb[control].lock_scale = True, False, True
|
||||
pb[f1].rotation_mode = 'YZX'
|
||||
pb[f2].rotation_mode = 'YZX'
|
||||
if three_digits:
|
||||
pb[f3].rotation_mode = 'YZX'
|
||||
pb[f1].lock_location = True, True, True
|
||||
pb[f2].lock_location = True, True, True
|
||||
if three_digits:
|
||||
pb[f3].lock_location = True, True, True
|
||||
pb[df2].rotation_mode = 'YZX'
|
||||
if three_digits:
|
||||
pb[df3].rotation_mode = 'YZX'
|
||||
|
||||
# Add the bend_ratio property to the control bone
|
||||
pb[control]["bend_ratio"] = bend_ratio
|
||||
prop = rna_idprop_ui_prop_get(pb[control], "bend_ratio", create=True)
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
|
||||
# Add hinge property to the control bone
|
||||
if make_hinge:
|
||||
pb[control]["hinge"] = 0.0
|
||||
prop = rna_idprop_ui_prop_get(pb[control], "hinge", create=True)
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
|
||||
# Constraints
|
||||
con = pb[df1].constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = control
|
||||
|
||||
con = pb[df1].constraints.new('COPY_ROTATION')
|
||||
con.target = obj
|
||||
con.subtarget = control
|
||||
|
||||
con = pb[org_f1].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = f1
|
||||
|
||||
con = pb[org_f2].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = f2
|
||||
|
||||
if three_digits:
|
||||
con = pb[org_f3].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = f3
|
||||
|
||||
if make_hinge:
|
||||
con = pb[hinge].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = bb[org_f1].parent.name
|
||||
|
||||
hinge_driver_path = pb[control].path_from_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.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = 1.0
|
||||
mod.coefficients[1] = -1.0
|
||||
|
||||
con = pb[control].constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = socket
|
||||
|
||||
# Create the drivers for the driver bones (control bone scale rotates driver bones)
|
||||
controller_path = pb[control].path_from_id() # 'pose.bones["%s"]' % control_bone_name
|
||||
|
||||
if three_digits:
|
||||
finger_digits = [df2, df3]
|
||||
else:
|
||||
finger_digits = [df2]
|
||||
|
||||
i = 0
|
||||
for bone in finger_digits:
|
||||
|
||||
# XXX - todo, any number
|
||||
if i == 2:
|
||||
break
|
||||
|
||||
pbone = pb[bone]
|
||||
|
||||
pbone.rotation_mode = 'YZX'
|
||||
fcurve_driver = pbone.driver_add("rotation_euler", 0)
|
||||
|
||||
#obj.driver_add('pose.bones["%s"].scale', 1)
|
||||
#obj.animation_data.drivers[-1] # XXX, WATCH THIS
|
||||
driver = fcurve_driver.driver
|
||||
|
||||
# scale target
|
||||
var = driver.variables.new()
|
||||
var.name = "scale"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = controller_path + '.scale[1]'
|
||||
|
||||
# bend target
|
||||
var = driver.variables.new()
|
||||
var.name = "br"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = controller_path + '["bend_ratio"]'
|
||||
|
||||
# XXX - todo, any number
|
||||
if three_digits:
|
||||
if i == 0:
|
||||
driver.expression = '(-scale+1.0)*pi*2.0*(1.0-br)'
|
||||
elif i == 1:
|
||||
driver.expression = '(-scale+1.0)*pi*2.0*br'
|
||||
else:
|
||||
driver.expression = driver.expression = '(-scale+1.0)*pi*2.0'
|
||||
|
||||
i += 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[0]].layers)
|
||||
#for bone_name in [f1, f2, f3]:
|
||||
# arm.bones[bone_name].layers = layer
|
||||
arm.bones[f1].layers = layer
|
||||
arm.bones[f2].layers = layer
|
||||
if three_digits:
|
||||
arm.bones[f3].layers = layer
|
||||
|
||||
layer = list(arm.bones[bone_definition[0]].layers)
|
||||
bb[control].layers = layer
|
||||
|
||||
# no blending the result of this
|
||||
return None
|
||||
|
@ -1,501 +0,0 @@
|
||||
# ##### 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 math import pi
|
||||
from rigify import RigifyError
|
||||
from rigify_utils import bone_class_instance, copy_bone_simple, blend_bone_list, get_side_name, get_base_name
|
||||
from rna_prop_ui import rna_idprop_ui_prop_get
|
||||
|
||||
METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe", "heel"
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('hips')
|
||||
bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
bone.tail[:] = 0.0000, 0.0000, 0.2506
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
bone = arm.edit_bones.new('thigh')
|
||||
bone.head[:] = 0.1253, 0.0000, -0.0000
|
||||
bone.tail[:] = 0.0752, -0.0251, -0.4260
|
||||
bone.roll = 0.1171
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hips']
|
||||
bone = arm.edit_bones.new('shin')
|
||||
bone.head[:] = 0.0752, -0.0251, -0.4260
|
||||
bone.tail[:] = 0.0752, 0.0000, -0.8771
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['thigh']
|
||||
bone = arm.edit_bones.new('foot')
|
||||
bone.head[:] = 0.0752, 0.0000, -0.8771
|
||||
bone.tail[:] = 0.1013, -0.1481, -0.9773
|
||||
bone.roll = -0.4662
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['shin']
|
||||
bone = arm.edit_bones.new('toe')
|
||||
bone.head[:] = 0.1013, -0.1481, -0.9773
|
||||
bone.tail[:] = 0.1100, -0.2479, -0.9773
|
||||
bone.roll = 3.1416
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['foot']
|
||||
bone = arm.edit_bones.new('heel')
|
||||
bone.head[:] = 0.0652, 0.0501, -1.0024
|
||||
bone.tail[:] = 0.0927, -0.1002, -1.0024
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['foot']
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['thigh']
|
||||
pbone['type'] = 'leg_biped'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
'''
|
||||
The bone given is the first in a chain
|
||||
Expects a chain of at least 3 children.
|
||||
eg.
|
||||
thigh -> shin -> foot -> [toe, heel]
|
||||
'''
|
||||
|
||||
bone_definition = []
|
||||
|
||||
orig_bone = obj.data.bones[orig_bone_name]
|
||||
orig_bone_parent = orig_bone.parent
|
||||
|
||||
if orig_bone_parent is None:
|
||||
raise RigifyError("expected the thigh bone to have a parent hip bone")
|
||||
|
||||
bone_definition.append(orig_bone_parent.name)
|
||||
bone_definition.append(orig_bone.name)
|
||||
|
||||
|
||||
bone = orig_bone
|
||||
chain = 0
|
||||
while chain < 2: # first 2 bones only have 1 child
|
||||
children = bone.children
|
||||
|
||||
if len(children) != 1:
|
||||
raise RigifyError("expected the thigh bone to have 3 children without a fork")
|
||||
bone = children[0]
|
||||
bone_definition.append(bone.name) # shin, foot
|
||||
chain += 1
|
||||
|
||||
children = bone.children
|
||||
# Now there must be 2 children, only one connected
|
||||
if len(children) != 2:
|
||||
raise RigifyError("expected the foot bone:'%s' to have 2 children" % bone.name)
|
||||
|
||||
if children[0].use_connect == children[1].use_connect:
|
||||
raise RigifyError("expected one bone to be connected")
|
||||
|
||||
toe, heel = children
|
||||
if heel.use_connect:
|
||||
toe, heel = heel, toe
|
||||
|
||||
|
||||
bone_definition.append(toe.name)
|
||||
bone_definition.append(heel.name)
|
||||
|
||||
if len(bone_definition) != len(METARIG_NAMES):
|
||||
raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES))
|
||||
|
||||
return bone_definition
|
||||
|
||||
|
||||
def ik(obj, bone_definition, base_names, options):
|
||||
arm = obj.data
|
||||
|
||||
# setup the existing bones, use names from METARIG_NAMES
|
||||
mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
|
||||
mt = bone_class_instance(obj, ["hips", "heel"])
|
||||
|
||||
mt.attr_initialize(METARIG_NAMES, bone_definition)
|
||||
mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
|
||||
|
||||
# children of ik_foot
|
||||
ik = bone_class_instance(obj, ["foot", "foot_roll", "foot_roll_01", "foot_roll_02", "knee_target"])
|
||||
|
||||
# Make a new chain
|
||||
ik_chain = mt_chain.copy(to_fmt="MCH-%s", base_names=base_names)
|
||||
|
||||
# simple rename
|
||||
ik_chain.rename("thigh", ik_chain.thigh + "_ik")
|
||||
ik_chain.rename("shin", ik_chain.shin + "_ik")
|
||||
|
||||
# make sure leg is child of hips
|
||||
ik_chain.thigh_e.parent = mt.hips_e
|
||||
|
||||
# ik foot: no parents
|
||||
base_foot_name = get_base_name(base_names[mt_chain.foot])
|
||||
ik.foot_e = copy_bone_simple(arm, mt.heel, base_foot_name + "_ik" + get_side_name(base_names[mt_chain.foot]))
|
||||
ik.foot = ik.foot_e.name
|
||||
ik.foot_e.translate(mt_chain.foot_e.head - ik.foot_e.head)
|
||||
ik.foot_e.use_local_location = False
|
||||
|
||||
# foot roll: heel pointing backwards, half length
|
||||
ik.foot_roll_e = copy_bone_simple(arm, mt.heel, base_foot_name + "_roll" + get_side_name(base_names[mt_chain.foot]))
|
||||
ik.foot_roll = ik.foot_roll_e.name
|
||||
ik.foot_roll_e.tail = ik.foot_roll_e.head - ik.foot_roll_e.vector / 2.0
|
||||
ik.foot_roll_e.parent = ik.foot_e # heel is disconnected
|
||||
|
||||
# heel pointing forwards to the toe base, parent of the following 2 bones
|
||||
ik.foot_roll_01_e = copy_bone_simple(arm, mt.heel, "MCH-%s_roll.01" % base_foot_name)
|
||||
ik.foot_roll_01 = ik.foot_roll_01_e.name
|
||||
ik.foot_roll_01_e.tail = mt_chain.foot_e.tail
|
||||
ik.foot_roll_01_e.parent = ik.foot_e # heel is disconnected
|
||||
|
||||
# same as above but reverse direction
|
||||
ik.foot_roll_02_e = copy_bone_simple(arm, mt.heel, "MCH-%s_roll.02" % base_foot_name)
|
||||
ik.foot_roll_02 = ik.foot_roll_02_e.name
|
||||
ik.foot_roll_02_e.parent = ik.foot_roll_01_e # heel is disconnected
|
||||
ik.foot_roll_02_e.head = mt_chain.foot_e.tail
|
||||
ik.foot_roll_02_e.tail = mt.heel_e.head
|
||||
|
||||
del base_foot_name
|
||||
|
||||
# rename 'MCH-toe' --> to 'toe_ik' and make the child of ik.foot_roll_01
|
||||
# ------------------ FK or IK?
|
||||
ik_chain.rename("toe", get_base_name(base_names[mt_chain.toe]) + "_ik" + get_side_name(base_names[mt_chain.toe]))
|
||||
ik_chain.toe_e.use_connect = False
|
||||
ik_chain.toe_e.parent = ik.foot_roll_01_e
|
||||
|
||||
# re-parent ik_chain.foot to the
|
||||
ik_chain.foot_e.use_connect = False
|
||||
ik_chain.foot_e.parent = ik.foot_roll_02_e
|
||||
|
||||
|
||||
# knee target is the heel moved up and forward on its local axis
|
||||
ik.knee_target_e = copy_bone_simple(arm, mt.heel, "knee_target" + get_side_name(mt.heel))
|
||||
ik.knee_target = ik.knee_target_e.name
|
||||
offset = ik.knee_target_e.tail - ik.knee_target_e.head
|
||||
offset.z = 0
|
||||
offset.length = mt_chain.shin_e.head.z - mt.heel_e.head.z
|
||||
offset.z += offset.length
|
||||
ik.knee_target_e.translate(offset)
|
||||
ik.knee_target_e.length *= 0.5
|
||||
ik.knee_target_e.parent = ik.foot_e
|
||||
ik.knee_target_e.use_local_location = False
|
||||
|
||||
# roll the bone to point up... could also point in the same direction as ik.foot_roll
|
||||
# ik.foot_roll_02_e.matrix * Vector((0.0, 0.0, 1.0)) # ACK!, no rest matrix in editmode
|
||||
ik.foot_roll_01_e.align_roll((0.0, 0.0, -1.0))
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
ik.update()
|
||||
mt_chain.update()
|
||||
ik_chain.update()
|
||||
|
||||
# Set IK dof
|
||||
ik_chain.shin_p.lock_ik_x = False
|
||||
ik_chain.shin_p.lock_ik_y = True
|
||||
ik_chain.shin_p.lock_ik_z = True
|
||||
|
||||
# Set rotation modes and axis locks
|
||||
ik.foot_roll_p.rotation_mode = 'XYZ'
|
||||
ik.foot_roll_p.lock_rotation = False, True, True
|
||||
ik_chain.toe_p.rotation_mode = 'YXZ'
|
||||
ik_chain.toe_p.lock_rotation = False, True, True
|
||||
ik_chain.toe_p.lock_location = True, True, True
|
||||
ik.foot_roll_p.lock_location = True, True, True
|
||||
|
||||
# IK
|
||||
con = ik_chain.shin_p.constraints.new('IK')
|
||||
con.chain_count = 2
|
||||
con.iterations = 500
|
||||
con.pole_angle = -pi / 2.0
|
||||
con.use_tail = True
|
||||
con.use_stretch = True
|
||||
con.use_target = True
|
||||
con.use_rotation = False
|
||||
con.weight = 1.0
|
||||
|
||||
con.target = obj
|
||||
con.subtarget = ik_chain.foot
|
||||
|
||||
con.pole_target = obj
|
||||
con.pole_subtarget = ik.knee_target
|
||||
|
||||
# foot roll
|
||||
cons = [ \
|
||||
(ik.foot_roll_01_p.constraints.new('COPY_ROTATION'), ik.foot_roll_01_p.constraints.new('LIMIT_ROTATION')), \
|
||||
(ik.foot_roll_02_p.constraints.new('COPY_ROTATION'), ik.foot_roll_02_p.constraints.new('LIMIT_ROTATION'))]
|
||||
|
||||
for con, con_l in cons:
|
||||
con.target = obj
|
||||
con.subtarget = ik.foot_roll
|
||||
con.use_x, con.use_y, con.use_z = True, False, False
|
||||
con.target_space = con.owner_space = 'LOCAL'
|
||||
|
||||
con = con_l
|
||||
con.use_limit_x, con.use_limit_y, con.use_limit_z = True, False, False
|
||||
con.owner_space = 'LOCAL'
|
||||
|
||||
if con_l is cons[-1][-1]:
|
||||
con.min_x = 0.0
|
||||
con.max_x = 180.0 # XXX -deg
|
||||
else:
|
||||
con.min_x = -180.0 # XXX -deg
|
||||
con.max_x = 0.0
|
||||
|
||||
|
||||
# last step setup layers
|
||||
if "ik_layer" in options:
|
||||
layer = [n == options["ik_layer"] for n in range(0, 32)]
|
||||
else:
|
||||
layer = list(mt_chain.thigh_b.layers)
|
||||
for attr in ik_chain.attr_names:
|
||||
getattr(ik_chain, attr + "_b").layers = layer
|
||||
for attr in ik.attr_names:
|
||||
getattr(ik, attr + "_b").layers = layer
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
return (None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe, None, ik.foot)
|
||||
|
||||
|
||||
def fk(obj, bone_definition, base_names, options):
|
||||
from mathutils import Vector
|
||||
arm = obj.data
|
||||
|
||||
# these account for all bones in METARIG_NAMES
|
||||
mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
|
||||
mt = bone_class_instance(obj, ["hips", "heel"])
|
||||
|
||||
# new bones
|
||||
ex = bone_class_instance(obj, ["thigh_socket", "thigh_hinge"])
|
||||
|
||||
for bone_class in (mt, mt_chain):
|
||||
for attr in bone_class.attr_names:
|
||||
i = METARIG_NAMES.index(attr)
|
||||
ebone = arm.edit_bones[bone_definition[i]]
|
||||
setattr(bone_class, attr, ebone.name)
|
||||
bone_class.update()
|
||||
|
||||
ex.thigh_socket_e = copy_bone_simple(arm, mt_chain.thigh, "MCH-%s_socket" % base_names[mt_chain.thigh], parent=True)
|
||||
ex.thigh_socket = ex.thigh_socket_e.name
|
||||
ex.thigh_socket_e.tail = ex.thigh_socket_e.head + Vector((0.0, 0.0, ex.thigh_socket_e.length / 4.0))
|
||||
|
||||
ex.thigh_hinge_e = copy_bone_simple(arm, mt.hips, "MCH-%s_hinge" % base_names[mt_chain.thigh], parent=False)
|
||||
ex.thigh_hinge = ex.thigh_hinge_e.name
|
||||
|
||||
fk_chain = mt_chain.copy(base_names=base_names) # fk has no prefix!
|
||||
fk_chain.foot_e.name = "MCH-" + fk_chain.foot
|
||||
fk_chain.foot = fk_chain.foot_e.name
|
||||
|
||||
# Set up fk foot control
|
||||
foot_e = copy_bone_simple(arm, mt.heel, base_names[mt_chain.foot])
|
||||
foot = foot_e.name
|
||||
foot_e.translate(mt_chain.foot_e.head - foot_e.head)
|
||||
foot_e.parent = fk_chain.shin_e
|
||||
foot_e.use_connect = fk_chain.foot_e.use_connect
|
||||
fk_chain.foot_e.use_connect = False
|
||||
fk_chain.foot_e.parent = foot_e
|
||||
|
||||
fk_chain.thigh_e.use_connect = False
|
||||
fk_chain.thigh_e.parent = ex.thigh_hinge_e
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
ex.update()
|
||||
mt_chain.update()
|
||||
fk_chain.update()
|
||||
foot_p = obj.pose.bones[foot]
|
||||
|
||||
# Set rotation modes and axis locks
|
||||
fk_chain.shin_p.rotation_mode = 'XYZ'
|
||||
fk_chain.shin_p.lock_rotation = False, True, True
|
||||
foot_p.rotation_mode = 'YXZ'
|
||||
fk_chain.toe_p.rotation_mode = 'YXZ'
|
||||
fk_chain.toe_p.lock_rotation = False, True, True
|
||||
fk_chain.thigh_p.lock_location = True, True, True
|
||||
|
||||
con = fk_chain.thigh_p.constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = ex.thigh_socket
|
||||
|
||||
# hinge
|
||||
prop = rna_idprop_ui_prop_get(fk_chain.thigh_p, "hinge", create=True)
|
||||
fk_chain.thigh_p["hinge"] = 0.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
|
||||
con = ex.thigh_hinge_p.constraints.new('COPY_ROTATION')
|
||||
con.target = obj
|
||||
con.subtarget = mt.hips
|
||||
|
||||
# add driver
|
||||
hinge_driver_path = fk_chain.thigh_p.path_from_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.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = 1.0
|
||||
mod.coefficients[1] = -1.0
|
||||
|
||||
|
||||
# last step setup layers
|
||||
if "fk_layer" in options:
|
||||
layer = [n == options["fk_layer"] for n in range(0, 32)]
|
||||
else:
|
||||
layer = list(mt_chain.thigh_b.layers)
|
||||
for attr in fk_chain.attr_names:
|
||||
getattr(fk_chain, attr + "_b").layers = layer
|
||||
for attr in ex.attr_names:
|
||||
getattr(ex, attr + "_b").layers = layer
|
||||
arm.bones[foot].layers = layer
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
# dont blend the hips or heel
|
||||
return (None, fk_chain.thigh, fk_chain.shin, fk_chain.foot, fk_chain.toe, None, None)
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
# Create upper leg bones: two bones, each half of the upper leg.
|
||||
uleg1 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.01" % base_names[definitions[1]], parent=True)
|
||||
uleg2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.02" % base_names[definitions[1]], parent=True)
|
||||
uleg1.use_connect = False
|
||||
uleg2.use_connect = False
|
||||
uleg2.parent = uleg1
|
||||
center = uleg1.center
|
||||
uleg1.tail = center
|
||||
uleg2.head = center
|
||||
|
||||
# Create lower leg bones: two bones, each half of the lower leg.
|
||||
lleg1 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.01" % base_names[definitions[2]], parent=True)
|
||||
lleg2 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.02" % base_names[definitions[2]], parent=True)
|
||||
lleg1.use_connect = False
|
||||
lleg2.use_connect = False
|
||||
lleg2.parent = lleg1
|
||||
center = lleg1.center
|
||||
lleg1.tail = center
|
||||
lleg2.head = center
|
||||
|
||||
# Create a bone for the second lower leg deform bone to twist with
|
||||
twist = copy_bone_simple(obj.data, lleg2.name, "MCH-leg_twist")
|
||||
twist.length /= 4
|
||||
twist.use_connect = False
|
||||
twist.parent = obj.data.edit_bones[definitions[3]]
|
||||
|
||||
# Create foot bone
|
||||
foot = copy_bone_simple(obj.data, definitions[3], "DEF-%s" % base_names[definitions[3]], parent=True)
|
||||
|
||||
# Create toe bone
|
||||
toe = copy_bone_simple(obj.data, definitions[4], "DEF-%s" % base_names[definitions[4]], parent=True)
|
||||
|
||||
# Store names before leaving edit mode
|
||||
uleg1_name = uleg1.name
|
||||
uleg2_name = uleg2.name
|
||||
lleg1_name = lleg1.name
|
||||
lleg2_name = lleg2.name
|
||||
twist_name = twist.name
|
||||
foot_name = foot.name
|
||||
toe_name = toe.name
|
||||
|
||||
# Leave edit mode
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Get the pose bones
|
||||
uleg1 = obj.pose.bones[uleg1_name]
|
||||
uleg2 = obj.pose.bones[uleg2_name]
|
||||
lleg1 = obj.pose.bones[lleg1_name]
|
||||
lleg2 = obj.pose.bones[lleg2_name]
|
||||
foot = obj.pose.bones[foot_name]
|
||||
toe = obj.pose.bones[toe_name]
|
||||
|
||||
# Upper leg constraints
|
||||
con = uleg1.constraints.new('DAMPED_TRACK')
|
||||
con.name = "trackto"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[2]
|
||||
|
||||
con = uleg1.constraints.new('COPY_SCALE')
|
||||
con.name = "scale"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[1]
|
||||
|
||||
con = uleg2.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[1]
|
||||
|
||||
# Lower leg constraints
|
||||
con = lleg1.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[2]
|
||||
|
||||
con = lleg1.constraints.new('COPY_SCALE')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[2]
|
||||
|
||||
con = lleg2.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = twist_name
|
||||
|
||||
con = lleg2.constraints.new('DAMPED_TRACK')
|
||||
con.name = "trackto"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[3]
|
||||
|
||||
# Foot constraint
|
||||
con = foot.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[3]
|
||||
|
||||
# Toe constraint
|
||||
con = toe.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[4]
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
return (uleg1_name, uleg2_name, lleg1_name, lleg2_name, foot_name, toe_name, None)
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
bones_fk = fk(obj, bone_definition, base_names, options)
|
||||
bones_ik = ik(obj, bone_definition, base_names, options)
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
blend_bone_list(obj, bone_definition + [None], bones_fk, bones_ik, target_bone=bones_ik[6], target_prop="ik", blend_default=1.0)
|
@ -1,497 +0,0 @@
|
||||
# ##### 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 rna_prop_ui import rna_idprop_ui_prop_get
|
||||
from math import pi
|
||||
from rigify import RigifyError
|
||||
from rigify_utils import bone_class_instance, copy_bone_simple, get_side_name, get_base_name
|
||||
from mathutils import Vector
|
||||
|
||||
METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe"
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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.0728, -0.2427, 0.0000
|
||||
bone.tail[:] = -0.0728, -0.2427, 0.2427
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
bone = arm.edit_bones.new('thigh')
|
||||
bone.head[:] = 0.0000, 0.0000, -0.0000
|
||||
bone.tail[:] = 0.0813, -0.2109, -0.3374
|
||||
bone.roll = -0.4656
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['body']
|
||||
bone = arm.edit_bones.new('shin')
|
||||
bone.head[:] = 0.0813, -0.2109, -0.3374
|
||||
bone.tail[:] = 0.0714, -0.0043, -0.5830
|
||||
bone.roll = -0.2024
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['thigh']
|
||||
bone = arm.edit_bones.new('foot')
|
||||
bone.head[:] = 0.0714, -0.0043, -0.5830
|
||||
bone.tail[:] = 0.0929, -0.0484, -0.7652
|
||||
bone.roll = -0.3766
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['shin']
|
||||
bone = arm.edit_bones.new('toe')
|
||||
bone.head[:] = 0.0929, -0.0484, -0.7652
|
||||
bone.tail[:] = 0.1146, -0.1244, -0.7652
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['foot']
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['thigh']
|
||||
pbone['type'] = 'leg_quadruped'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
'''
|
||||
The bone given is the first in a chain
|
||||
Expects a chain of at least 3 children.
|
||||
eg.
|
||||
thigh -> shin -> foot -> [toe, heel]
|
||||
'''
|
||||
|
||||
bone_definition = []
|
||||
|
||||
orig_bone = obj.data.bones[orig_bone_name]
|
||||
orig_bone_parent = orig_bone.parent
|
||||
|
||||
if orig_bone_parent is None:
|
||||
raise RigifyError("expected the thigh bone to have a parent hip bone")
|
||||
|
||||
bone_definition.append(orig_bone_parent.name)
|
||||
bone_definition.append(orig_bone.name)
|
||||
|
||||
|
||||
bone = orig_bone
|
||||
chain = 0
|
||||
while chain < 3: # first 2 bones only have 1 child
|
||||
children = bone.children
|
||||
|
||||
if len(children) != 1:
|
||||
raise RigifyError("expected the thigh bone to have 3 children without a fork")
|
||||
bone = children[0]
|
||||
bone_definition.append(bone.name) # shin, foot
|
||||
chain += 1
|
||||
|
||||
if len(bone_definition) != len(METARIG_NAMES):
|
||||
raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES))
|
||||
|
||||
return bone_definition
|
||||
|
||||
|
||||
def ik(obj, bone_definition, base_names, options):
|
||||
eb = obj.data.edit_bones
|
||||
pb = obj.pose.bones
|
||||
arm = obj.data
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
# setup the existing bones, use names from METARIG_NAMES
|
||||
mt = bone_class_instance(obj, ["hips"])
|
||||
mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
|
||||
|
||||
mt.attr_initialize(METARIG_NAMES, bone_definition)
|
||||
mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
|
||||
|
||||
ik_chain = mt_chain.copy(to_fmt="MCH-%s.ik", base_names=base_names)
|
||||
|
||||
ik_chain.thigh_e.use_connect = False
|
||||
ik_chain.thigh_e.parent = mt.hips_e
|
||||
|
||||
ik_chain.foot_e.parent = None
|
||||
ik_chain.rename("foot", get_base_name(base_names[bone_definition[3]]) + "_ik" + get_side_name(base_names[bone_definition[3]]))
|
||||
ik_chain.rename("toe", get_base_name(base_names[bone_definition[4]]) + "_ik" + get_side_name(base_names[bone_definition[4]]))
|
||||
|
||||
# keep the foot_ik as the parent
|
||||
ik_chain.toe_e.use_connect = False
|
||||
|
||||
# Foot uses pose space, not local space, for translation
|
||||
ik_chain.foot_e.use_local_location = False
|
||||
|
||||
# must be after disconnecting the toe
|
||||
ik_chain.foot_e.align_orientation(mt_chain.toe_e)
|
||||
|
||||
# children of ik_foot
|
||||
ik = bone_class_instance(obj, ["foot_roll", "foot_roll_01", "foot_roll_02", "foot_target"])
|
||||
|
||||
# knee rotator
|
||||
knee_rotator = copy_bone_simple(arm, mt_chain.toe, "knee_rotator" + get_side_name(base_names[mt_chain.foot]), parent=True).name
|
||||
eb[knee_rotator].use_connect = False
|
||||
eb[knee_rotator].parent = eb[mt.hips]
|
||||
eb[knee_rotator].head = eb[ik_chain.thigh].head
|
||||
eb[knee_rotator].tail = eb[knee_rotator].head + eb[mt_chain.toe].vector
|
||||
eb[knee_rotator].length = eb[ik_chain.thigh].length / 2
|
||||
eb[knee_rotator].roll += pi/2
|
||||
|
||||
# parent ik leg to the knee rotator
|
||||
eb[ik_chain.thigh].parent = eb[knee_rotator]
|
||||
|
||||
# foot roll is an interesting one!
|
||||
# plot a vector from the toe bones head, bactwards to the length of the foot
|
||||
# then align it with the foot but reverse direction.
|
||||
ik.foot_roll_e = copy_bone_simple(arm, mt_chain.toe, get_base_name(base_names[mt_chain.foot]) + "_roll" + get_side_name(base_names[mt_chain.foot]))
|
||||
ik.foot_roll = ik.foot_roll_e.name
|
||||
ik.foot_roll_e.use_connect = False
|
||||
ik.foot_roll_e.parent = ik_chain.foot_e
|
||||
ik.foot_roll_e.head -= mt_chain.toe_e.vector.normalize() * mt_chain.foot_e.length
|
||||
ik.foot_roll_e.tail = ik.foot_roll_e.head - (mt_chain.foot_e.vector.normalize() * mt_chain.toe_e.length)
|
||||
ik.foot_roll_e.align_roll(mt_chain.foot_e.matrix.rotation_part() * Vector((0.0, 0.0, -1.0)))
|
||||
|
||||
# MCH-foot
|
||||
ik.foot_roll_01_e = copy_bone_simple(arm, mt_chain.foot, "MCH-" + base_names[mt_chain.foot])
|
||||
ik.foot_roll_01 = ik.foot_roll_01_e.name
|
||||
ik.foot_roll_01_e.parent = ik_chain.foot_e
|
||||
ik.foot_roll_01_e.head, ik.foot_roll_01_e.tail = mt_chain.foot_e.tail, mt_chain.foot_e.head
|
||||
ik.foot_roll_01_e.roll = ik.foot_roll_e.roll
|
||||
|
||||
# ik_target, child of MCH-foot
|
||||
ik.foot_target_e = copy_bone_simple(arm, mt_chain.foot, "MCH-" + base_names[mt_chain.foot] + "_ik_target")
|
||||
ik.foot_target = ik.foot_target_e.name
|
||||
ik.foot_target_e.parent = ik.foot_roll_01_e
|
||||
ik.foot_target_e.align_orientation(ik_chain.foot_e)
|
||||
ik.foot_target_e.length = ik_chain.foot_e.length / 2.0
|
||||
ik.foot_target_e.use_connect = True
|
||||
|
||||
# MCH-foot.02 child of MCH-foot
|
||||
ik.foot_roll_02_e = copy_bone_simple(arm, mt_chain.foot, "MCH-%s_02" % base_names[mt_chain.foot])
|
||||
ik.foot_roll_02 = ik.foot_roll_02_e.name
|
||||
ik.foot_roll_02_e.parent = ik.foot_roll_01_e
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
mt.update()
|
||||
mt_chain.update()
|
||||
ik.update()
|
||||
ik_chain.update()
|
||||
|
||||
# Set rotation modes and axis locks
|
||||
#pb[knee_rotator].rotation_mode = 'YXZ'
|
||||
#pb[knee_rotator].lock_rotation = False, True, False
|
||||
pb[knee_rotator].lock_location = True, True, True
|
||||
pb[ik.foot_roll].rotation_mode = 'XYZ'
|
||||
pb[ik.foot_roll].lock_rotation = False, True, True
|
||||
pb[ik_chain.toe].rotation_mode = 'XYZ'
|
||||
pb[ik_chain.toe].lock_rotation = False, True, True
|
||||
|
||||
# IK switch property
|
||||
prop = rna_idprop_ui_prop_get(pb[ik_chain.foot], "ik", create=True)
|
||||
pb[ik_chain.foot]["ik"] = 1.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
prop["min"] = 0.0
|
||||
prop["max"] = 1.0
|
||||
|
||||
ik_driver_path = pb[ik_chain.foot].path_from_id() + '["ik"]'
|
||||
|
||||
# simple constraining of orig bones
|
||||
con = mt_chain.thigh_p.constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = ik_chain.thigh
|
||||
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 = ik_driver_path
|
||||
|
||||
con = mt_chain.shin_p.constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = ik_chain.shin
|
||||
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 = ik_driver_path
|
||||
|
||||
con = mt_chain.foot_p.constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = ik.foot_roll_02
|
||||
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 = ik_driver_path
|
||||
|
||||
con = mt_chain.toe_p.constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = ik_chain.toe
|
||||
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 = ik_driver_path
|
||||
|
||||
# others...
|
||||
con = ik.foot_roll_01_p.constraints.new('COPY_ROTATION')
|
||||
con.target = obj
|
||||
con.subtarget = ik.foot_roll
|
||||
con.target_space = 'LOCAL'
|
||||
con.owner_space = 'LOCAL'
|
||||
|
||||
|
||||
# IK
|
||||
con = ik_chain.shin_p.constraints.new('IK')
|
||||
con.chain_count = 2
|
||||
con.iterations = 500
|
||||
con.pole_angle = -90.0 # XXX - in deg!
|
||||
con.use_tail = True
|
||||
con.use_stretch = True
|
||||
con.use_target = True
|
||||
con.use_rotation = False
|
||||
con.weight = 1.0
|
||||
|
||||
con.target = obj
|
||||
con.subtarget = ik.foot_target
|
||||
|
||||
con.pole_target = None
|
||||
|
||||
ik.update()
|
||||
ik_chain.update()
|
||||
|
||||
# Set layers of the bones.
|
||||
if "ik_layer" in options:
|
||||
layer = [n==options["ik_layer"] for n in range(0,32)]
|
||||
else:
|
||||
layer = list(mt_chain.thigh_b.layers)
|
||||
for attr in ik_chain.attr_names:
|
||||
obj.data.bones[getattr(ik_chain, attr)].layers = layer
|
||||
for attr in ik.attr_names:
|
||||
obj.data.bones[getattr(ik, attr)].layers = layer
|
||||
obj.data.bones[knee_rotator].layers = layer
|
||||
|
||||
return None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe
|
||||
|
||||
|
||||
|
||||
def fk(obj, bone_definition, base_names, options):
|
||||
eb = obj.data.edit_bones
|
||||
pb = obj.pose.bones
|
||||
arm = obj.data
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
# setup the existing bones, use names from METARIG_NAMES
|
||||
mt = bone_class_instance(obj, ["hips"])
|
||||
mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
|
||||
|
||||
mt.attr_initialize(METARIG_NAMES, bone_definition)
|
||||
mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
|
||||
|
||||
fk_chain = mt_chain.copy(to_fmt="%s", base_names=base_names)
|
||||
|
||||
# Create the socket
|
||||
socket = copy_bone_simple(arm, mt_chain.thigh, "MCH-leg_socket").name
|
||||
eb[socket].parent = eb[mt.hips]
|
||||
eb[socket].length = eb[mt_chain.thigh].length / 4
|
||||
|
||||
# Create the hinge
|
||||
hinge = copy_bone_simple(arm, mt.hips, "MCH-leg_hinge").name
|
||||
eb[hinge].length = eb[mt.hips].length / 2
|
||||
|
||||
# Make leg child of hinge
|
||||
eb[fk_chain.thigh].use_connect = False
|
||||
eb[fk_chain.thigh].parent = eb[hinge]
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Set rotation modes and axis locks
|
||||
pb[fk_chain.shin].rotation_mode = 'XYZ'
|
||||
pb[fk_chain.shin].lock_rotation = False, True, True
|
||||
|
||||
# Constrain original bones to control bones
|
||||
con = mt_chain.thigh_p.constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = fk_chain.thigh
|
||||
|
||||
con = mt_chain.shin_p.constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = fk_chain.shin
|
||||
|
||||
con = mt_chain.foot_p.constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = fk_chain.foot
|
||||
|
||||
con = mt_chain.toe_p.constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = fk_chain.toe
|
||||
|
||||
# Socket constraint
|
||||
con = pb[fk_chain.thigh].constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = socket
|
||||
|
||||
# Hinge constraint
|
||||
con = pb[hinge].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = mt.hips
|
||||
|
||||
prop = rna_idprop_ui_prop_get(pb[fk_chain.thigh], "hinge", create=True)
|
||||
pb[fk_chain.thigh]["hinge"] = 0.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
prop["min"] = 0.0
|
||||
prop["max"] = 1.0
|
||||
|
||||
hinge_driver_path = pb[fk_chain.thigh].path_from_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.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = 1.0
|
||||
mod.coefficients[1] = -1.0
|
||||
|
||||
return None, fk_chain.thigh, fk_chain.shin, fk_chain.foot, fk_chain.toe
|
||||
|
||||
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
# Create upper leg bones: two bones, each half of the upper leg.
|
||||
uleg1 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.01" % base_names[definitions[1]], parent=True)
|
||||
uleg2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.02" % base_names[definitions[1]], parent=True)
|
||||
uleg1.use_connect = False
|
||||
uleg2.use_connect = False
|
||||
uleg2.parent = uleg1
|
||||
center = uleg1.center
|
||||
uleg1.tail = center
|
||||
uleg2.head = center
|
||||
|
||||
# Create lower leg bones: two bones, each half of the lower leg.
|
||||
lleg1 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.01" % base_names[definitions[2]], parent=True)
|
||||
lleg2 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.02" % base_names[definitions[2]], parent=True)
|
||||
lleg1.use_connect = False
|
||||
lleg2.use_connect = False
|
||||
lleg2.parent = lleg1
|
||||
center = lleg1.center
|
||||
lleg1.tail = center
|
||||
lleg2.head = center
|
||||
|
||||
# Create a bone for the second lower leg deform bone to twist with
|
||||
twist = copy_bone_simple(obj.data, lleg2.name, "MCH-leg_twist")
|
||||
twist.length /= 4
|
||||
twist.use_connect = False
|
||||
twist.parent = obj.data.edit_bones[definitions[3]]
|
||||
|
||||
# Create foot bone
|
||||
foot = copy_bone_simple(obj.data, definitions[3], "DEF-%s" % base_names[definitions[3]], parent=True)
|
||||
|
||||
# Create toe bone
|
||||
toe = copy_bone_simple(obj.data, definitions[4], "DEF-%s" % base_names[definitions[4]], parent=True)
|
||||
|
||||
# Store names before leaving edit mode
|
||||
uleg1_name = uleg1.name
|
||||
uleg2_name = uleg2.name
|
||||
lleg1_name = lleg1.name
|
||||
lleg2_name = lleg2.name
|
||||
twist_name = twist.name
|
||||
foot_name = foot.name
|
||||
toe_name = toe.name
|
||||
|
||||
# Leave edit mode
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Get the pose bones
|
||||
uleg1 = obj.pose.bones[uleg1_name]
|
||||
uleg2 = obj.pose.bones[uleg2_name]
|
||||
lleg1 = obj.pose.bones[lleg1_name]
|
||||
lleg2 = obj.pose.bones[lleg2_name]
|
||||
foot = obj.pose.bones[foot_name]
|
||||
toe = obj.pose.bones[toe_name]
|
||||
|
||||
# Upper leg constraints
|
||||
con = uleg1.constraints.new('DAMPED_TRACK')
|
||||
con.name = "trackto"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[2]
|
||||
|
||||
con = uleg2.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[1]
|
||||
|
||||
# Lower leg constraints
|
||||
con = lleg1.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[2]
|
||||
|
||||
con = lleg2.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = twist_name
|
||||
|
||||
con = lleg2.constraints.new('DAMPED_TRACK')
|
||||
con.name = "trackto"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[3]
|
||||
|
||||
# Foot constraint
|
||||
con = foot.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[3]
|
||||
|
||||
# Toe constraint
|
||||
con = toe.constraints.new('COPY_ROTATION')
|
||||
con.name = "copy_rot"
|
||||
con.target = obj
|
||||
con.subtarget = definitions[4]
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
return (uleg1_name, uleg2_name, lleg1_name, lleg2_name, foot_name, toe_name, None)
|
||||
|
||||
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
bones_fk = fk(obj, bone_definition, base_names, options)
|
||||
bones_ik = ik(obj, bone_definition, base_names, options)
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
return bones_ik
|
@ -1,756 +0,0 @@
|
||||
# ##### 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 rna_prop_ui import rna_idprop_ui_prop_get
|
||||
from math import acos, pi
|
||||
from mathutils import Vector
|
||||
from rigify import RigifyError
|
||||
from rigify_utils import copy_bone_simple
|
||||
|
||||
#METARIG_NAMES = ("cpy",)
|
||||
RIG_TYPE = "mouth"
|
||||
|
||||
|
||||
def mark_actions():
|
||||
for action in bpy.data.actions:
|
||||
action.tag = True
|
||||
|
||||
def get_unmarked_action():
|
||||
for action in bpy.data.actions:
|
||||
if action.tag != True:
|
||||
return action
|
||||
return None
|
||||
|
||||
def add_action(name=None):
|
||||
mark_actions()
|
||||
bpy.ops.action.new()
|
||||
action = get_unmarked_action()
|
||||
if name is not None:
|
||||
action.name = name
|
||||
return action
|
||||
|
||||
def addget_shape_key(obj, name="Key"):
|
||||
""" Fetches a shape key, or creates it if it doesn't exist
|
||||
"""
|
||||
# Create a shapekey set if it doesn't already exist
|
||||
if obj.data.shape_keys is None:
|
||||
shape = obj.add_shape_key(name="Basis", from_mix=False)
|
||||
obj.active_shape_key_index = 0
|
||||
|
||||
# Get the shapekey, or create it if it doesn't already exist
|
||||
if name in obj.data.shape_keys.keys:
|
||||
shape_key = obj.data.shape_keys.keys[name]
|
||||
else:
|
||||
shape_key = obj.add_shape_key(name=name, from_mix=False)
|
||||
|
||||
return shape_key
|
||||
|
||||
|
||||
def addget_shape_key_driver(obj, name="Key"):
|
||||
""" Fetches the driver for the shape key, or creates it if it doesn't
|
||||
already exist.
|
||||
"""
|
||||
driver_path = 'keys["' + name + '"].value'
|
||||
fcurve = None
|
||||
driver = None
|
||||
new = False
|
||||
if obj.data.shape_keys.animation_data is not None:
|
||||
for driver_s in obj.data.shape_keys.animation_data.drivers:
|
||||
if driver_s.data_path == driver_path:
|
||||
fcurve = driver_s
|
||||
if fcurve is None:
|
||||
fcurve = obj.data.shape_keys.keys[name].driver_add("value")
|
||||
fcurve.driver.type = 'AVERAGE'
|
||||
new = True
|
||||
|
||||
return fcurve, new
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('Bone')
|
||||
bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
bone.tail[:] = 0.0000, 0.0000, 1.0000
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['Bone']
|
||||
pbone['type'] = 'copy'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
bone = obj.data.bones[orig_bone_name]
|
||||
chain = []
|
||||
|
||||
try:
|
||||
chain += [bone.parent.parent.name, bone.parent.name, bone.name]
|
||||
except AttributeError:
|
||||
raise RigifyError("'%s' rig type requires a chain of two parents (bone: %s)" % (RIG_TYPE, orig_bone_name))
|
||||
|
||||
chain += [child.name for child in bone.children_recursive_basename]
|
||||
|
||||
if len(chain) < 10:
|
||||
raise RigifyError("'%s' rig type requires a chain of 8 bones (bone: %s)" % (RIG_TYPE, orig_bone_name))
|
||||
|
||||
return chain[:10]
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
eb = obj.data.edit_bones
|
||||
bb = obj.data.bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
jaw = definitions[1]
|
||||
|
||||
# Options
|
||||
req_options = ["mesh"]
|
||||
for option in req_options:
|
||||
if option not in options:
|
||||
raise RigifyError("'%s' rig type requires a '%s' option (bone: %s)" % (RIG_TYPE, option, base_names[definitions[0]]))
|
||||
|
||||
meshes = options["mesh"].replace(" ", "").split(",")
|
||||
|
||||
# Lip DEF
|
||||
lip1 = copy_bone_simple(obj.data, definitions[2], "DEF-" + base_names[definitions[2]]).name
|
||||
lip2 = copy_bone_simple(obj.data, definitions[3], "DEF-" + base_names[definitions[3]]).name
|
||||
lip3 = copy_bone_simple(obj.data, definitions[4], "DEF-" + base_names[definitions[4]]).name
|
||||
lip4 = copy_bone_simple(obj.data, definitions[5], "DEF-" + base_names[definitions[5]]).name
|
||||
lip5 = copy_bone_simple(obj.data, definitions[6], "DEF-" + base_names[definitions[6]]).name
|
||||
lip6 = copy_bone_simple(obj.data, definitions[7], "DEF-" + base_names[definitions[7]]).name
|
||||
lip7 = copy_bone_simple(obj.data, definitions[8], "DEF-" + base_names[definitions[8]]).name
|
||||
lip8 = copy_bone_simple(obj.data, definitions[9], "DEF-" + base_names[definitions[9]]).name
|
||||
|
||||
# Mouth corner spread bones (for driving corrective shape keys)
|
||||
spread_l_1 = copy_bone_simple(obj.data, definitions[6], "MCH-" + base_names[definitions[6]] + ".spread_1").name
|
||||
spread_l_2 = copy_bone_simple(obj.data, definitions[6], "MCH-" + base_names[definitions[6]] + ".spread_2").name
|
||||
eb[spread_l_1].tail = eb[definitions[5]].head
|
||||
eb[spread_l_2].tail = eb[definitions[5]].head
|
||||
eb[spread_l_1].roll = 0
|
||||
eb[spread_l_2].roll = 0
|
||||
eb[spread_l_1].use_connect = False
|
||||
eb[spread_l_2].use_connect = False
|
||||
eb[spread_l_1].parent = eb[definitions[6]]
|
||||
eb[spread_l_2].parent = eb[definitions[6]]
|
||||
|
||||
spread_r_1 = copy_bone_simple(obj.data, definitions[2], "MCH-" + base_names[definitions[2]] + ".spread_1").name
|
||||
spread_r_2 = copy_bone_simple(obj.data, definitions[2], "MCH-" + base_names[definitions[2]] + ".spread_2").name
|
||||
eb[spread_r_1].tail = eb[definitions[3]].head
|
||||
eb[spread_r_2].tail = eb[definitions[3]].head
|
||||
eb[spread_r_1].roll = 0
|
||||
eb[spread_r_2].roll = 0
|
||||
eb[spread_r_1].use_connect = False
|
||||
eb[spread_r_2].use_connect = False
|
||||
eb[spread_r_1].parent = eb[definitions[2]]
|
||||
eb[spread_r_2].parent = eb[definitions[2]]
|
||||
|
||||
|
||||
|
||||
# Jaw open bones (for driving corrective shape keys)
|
||||
jopen1 = copy_bone_simple(obj.data, jaw, "MCH-"+base_names[jaw]+".track1", parent=True).name
|
||||
eb[jopen1].use_connect = False
|
||||
eb[jopen1].head = eb[jaw].tail
|
||||
eb[jopen1].tail = eb[jopen1].head + Vector((0, 0, eb[jaw].length/4))
|
||||
|
||||
jopen2 = copy_bone_simple(obj.data, jopen1, "MCH-"+base_names[jaw]+".track2").name
|
||||
eb[jopen2].parent = eb[jaw]
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Constrain DEF bones to ORG bones
|
||||
con = pb[lip1].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = definitions[2]
|
||||
|
||||
con = pb[lip2].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = definitions[3]
|
||||
|
||||
con = pb[lip3].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = definitions[4]
|
||||
|
||||
con = pb[lip4].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = definitions[5]
|
||||
|
||||
con = pb[lip5].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = definitions[6]
|
||||
|
||||
con = pb[lip6].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = definitions[7]
|
||||
|
||||
con = pb[lip7].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = definitions[8]
|
||||
|
||||
con = pb[lip8].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = definitions[9]
|
||||
|
||||
# Constraint mouth corner spread bones
|
||||
con = pb[spread_l_1].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lip4
|
||||
|
||||
con = pb[spread_l_2].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = spread_l_1
|
||||
|
||||
con = pb[spread_l_2].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lip6
|
||||
|
||||
con = pb[spread_r_1].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lip2
|
||||
|
||||
con = pb[spread_r_2].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = spread_r_1
|
||||
|
||||
con = pb[spread_r_2].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = lip8
|
||||
|
||||
|
||||
# Corrective shape keys for the corners of the mouth.
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
# Calculate the rotation difference between the bones
|
||||
rotdiff_l = acos((eb[lip5].head - eb[lip4].head).normalize().dot((eb[lip5].head - eb[lip6].head).normalize()))
|
||||
rotdiff_r = acos((eb[lip1].head - eb[lip2].head).normalize().dot((eb[lip1].head - eb[lip8].head).normalize()))
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
|
||||
# Left side shape key
|
||||
for mesh_name in meshes:
|
||||
mesh_obj = bpy.data.objects[mesh_name]
|
||||
shape_key_name = "COR-" + base_names[definitions[6]] + ".spread"
|
||||
|
||||
# Add/get the shape key
|
||||
shape_key = addget_shape_key(mesh_obj, name=shape_key_name)
|
||||
|
||||
# Add/get the shape key driver
|
||||
fcurve, is_new_driver = addget_shape_key_driver(mesh_obj, name=shape_key_name)
|
||||
driver = fcurve.driver
|
||||
|
||||
# Get the variable, or create it if it doesn't already exist
|
||||
var_name = base_names[definitions[6]]
|
||||
if var_name in driver.variables:
|
||||
var = driver.variables[var_name]
|
||||
else:
|
||||
var = driver.variables.new()
|
||||
var.name = var_name
|
||||
|
||||
# Set up the variable
|
||||
var.type = "ROTATION_DIFF"
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].bone_target = spread_l_1
|
||||
var.targets[1].id = obj
|
||||
var.targets[1].bone_target = spread_l_2
|
||||
|
||||
# Set fcurve offset
|
||||
if is_new_driver:
|
||||
mod = fcurve.modifiers[0]
|
||||
if rotdiff_l != pi:
|
||||
mod.coefficients[0] = -rotdiff_l / (pi-rotdiff_l)
|
||||
mod.coefficients[1] = 1 / (pi-rotdiff_l)
|
||||
|
||||
# Right side shape key
|
||||
for mesh_name in meshes:
|
||||
mesh_obj = bpy.data.objects[mesh_name]
|
||||
shape_key_name = "COR-" + base_names[definitions[2]] + ".spread"
|
||||
|
||||
# Add/get the shape key
|
||||
shape_key = addget_shape_key(mesh_obj, name=shape_key_name)
|
||||
|
||||
# Add/get the shape key driver
|
||||
fcurve, is_new_driver = addget_shape_key_driver(mesh_obj, name=shape_key_name)
|
||||
driver = fcurve.driver
|
||||
|
||||
# Get the variable, or create it if it doesn't already exist
|
||||
var_name = base_names[definitions[2]]
|
||||
if var_name in driver.variables:
|
||||
var = driver.variables[var_name]
|
||||
else:
|
||||
var = driver.variables.new()
|
||||
var.name = var_name
|
||||
|
||||
# Set up the variable
|
||||
var.type = "ROTATION_DIFF"
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].bone_target = spread_r_1
|
||||
var.targets[1].id = obj
|
||||
var.targets[1].bone_target = spread_r_2
|
||||
|
||||
# Set fcurve offset
|
||||
if is_new_driver:
|
||||
mod = fcurve.modifiers[0]
|
||||
if rotdiff_r != pi:
|
||||
mod.coefficients[0] = -rotdiff_r / (pi-rotdiff_r)
|
||||
mod.coefficients[1] = 1 / (pi-rotdiff_r)
|
||||
|
||||
# Jaw open corrective shape key
|
||||
for mesh_name in meshes:
|
||||
mesh_obj = bpy.data.objects[mesh_name]
|
||||
shape_key_name = "COR-" + base_names[definitions[4]] + ".jaw_open"
|
||||
|
||||
# Add/get the shape key
|
||||
shape_key = addget_shape_key(mesh_obj, name=shape_key_name)
|
||||
|
||||
# Add/get the shape key driver
|
||||
fcurve, is_new_driver = addget_shape_key_driver(mesh_obj, name=shape_key_name)
|
||||
driver = fcurve.driver
|
||||
|
||||
# Get the variable, or create it if it doesn't already exist
|
||||
var_name = base_names[definitions[4]]
|
||||
if var_name in driver.variables:
|
||||
var = driver.variables[var_name]
|
||||
else:
|
||||
var = driver.variables.new()
|
||||
var.name = var_name
|
||||
|
||||
# Set up the variable
|
||||
var.type = "LOC_DIFF"
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].bone_target = jopen1
|
||||
var.targets[1].id = obj
|
||||
var.targets[1].bone_target = jopen2
|
||||
|
||||
# Set fcurve offset
|
||||
if is_new_driver:
|
||||
mod = fcurve.modifiers[0]
|
||||
mod.coefficients[0] = 0.0
|
||||
mod.coefficients[1] = 1.0 / bb[jaw].length
|
||||
|
||||
return (None,)
|
||||
|
||||
|
||||
|
||||
|
||||
def control(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
eb = obj.data.edit_bones
|
||||
bb = obj.data.bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
head_e = eb[definitions[0]]
|
||||
jaw_e = eb[definitions[1]]
|
||||
jaw = definitions[1]
|
||||
|
||||
# Head lips
|
||||
hlip1 = copy_bone_simple(obj.data, definitions[2], "MCH-"+base_names[definitions[2]]+".head").name
|
||||
hlip2 = copy_bone_simple(obj.data, definitions[3], "MCH-"+base_names[definitions[3]]+".head").name
|
||||
hlip3 = copy_bone_simple(obj.data, definitions[4], "MCH-"+base_names[definitions[4]]+".head").name
|
||||
hlip4 = copy_bone_simple(obj.data, definitions[5], "MCH-"+base_names[definitions[5]]+".head").name
|
||||
hlip5 = copy_bone_simple(obj.data, definitions[6], "MCH-"+base_names[definitions[6]]+".head").name
|
||||
hlip6 = copy_bone_simple(obj.data, definitions[7], "MCH-"+base_names[definitions[7]]+".head").name
|
||||
hlip7 = copy_bone_simple(obj.data, definitions[8], "MCH-"+base_names[definitions[8]]+".head").name
|
||||
hlip8 = copy_bone_simple(obj.data, definitions[9], "MCH-"+base_names[definitions[9]]+".head").name
|
||||
|
||||
eb[hlip1].parent = head_e
|
||||
eb[hlip2].parent = head_e
|
||||
eb[hlip3].parent = head_e
|
||||
eb[hlip4].parent = head_e
|
||||
eb[hlip5].parent = head_e
|
||||
eb[hlip6].parent = head_e
|
||||
eb[hlip7].parent = head_e
|
||||
eb[hlip8].parent = head_e
|
||||
|
||||
# Jaw lips
|
||||
jlip1 = copy_bone_simple(obj.data, definitions[2], "MCH-"+base_names[definitions[2]]+".jaw").name
|
||||
jlip2 = copy_bone_simple(obj.data, definitions[3], "MCH-"+base_names[definitions[3]]+".jaw").name
|
||||
jlip3 = copy_bone_simple(obj.data, definitions[4], "MCH-"+base_names[definitions[4]]+".jaw").name
|
||||
jlip4 = copy_bone_simple(obj.data, definitions[5], "MCH-"+base_names[definitions[5]]+".jaw").name
|
||||
jlip5 = copy_bone_simple(obj.data, definitions[6], "MCH-"+base_names[definitions[6]]+".jaw").name
|
||||
jlip6 = copy_bone_simple(obj.data, definitions[7], "MCH-"+base_names[definitions[7]]+".jaw").name
|
||||
jlip7 = copy_bone_simple(obj.data, definitions[8], "MCH-"+base_names[definitions[8]]+".jaw").name
|
||||
jlip8 = copy_bone_simple(obj.data, definitions[9], "MCH-"+base_names[definitions[9]]+".jaw").name
|
||||
|
||||
eb[jlip1].parent = jaw_e
|
||||
eb[jlip2].parent = jaw_e
|
||||
eb[jlip3].parent = jaw_e
|
||||
eb[jlip4].parent = jaw_e
|
||||
eb[jlip5].parent = jaw_e
|
||||
eb[jlip6].parent = jaw_e
|
||||
eb[jlip7].parent = jaw_e
|
||||
eb[jlip8].parent = jaw_e
|
||||
|
||||
# Control lips
|
||||
lip1 = copy_bone_simple(obj.data, definitions[2], base_names[definitions[2]]).name
|
||||
lip2 = copy_bone_simple(obj.data, definitions[3], base_names[definitions[3]]).name
|
||||
lip3 = copy_bone_simple(obj.data, definitions[4], base_names[definitions[4]]).name
|
||||
lip4 = copy_bone_simple(obj.data, definitions[5], base_names[definitions[5]]).name
|
||||
lip5 = copy_bone_simple(obj.data, definitions[6], base_names[definitions[6]]).name
|
||||
lip6 = copy_bone_simple(obj.data, definitions[7], base_names[definitions[7]]).name
|
||||
lip7 = copy_bone_simple(obj.data, definitions[8], base_names[definitions[8]]).name
|
||||
lip8 = copy_bone_simple(obj.data, definitions[9], base_names[definitions[9]]).name
|
||||
|
||||
eb[lip1].parent = eb[hlip1]
|
||||
eb[lip2].parent = eb[hlip2]
|
||||
eb[lip3].parent = eb[hlip3]
|
||||
eb[lip4].parent = eb[hlip4]
|
||||
eb[lip5].parent = eb[hlip5]
|
||||
eb[lip6].parent = eb[hlip6]
|
||||
eb[lip7].parent = eb[hlip7]
|
||||
eb[lip8].parent = eb[hlip8]
|
||||
|
||||
# Jaw open tracker
|
||||
jopent = copy_bone_simple(obj.data, jaw_e.name, "MCH-"+base_names[jaw_e.name]+".track", parent=True).name
|
||||
eb[jopent].use_connect = False
|
||||
eb[jopent].tail = jaw_e.tail + Vector((0.0, 0.0, jaw_e.length))
|
||||
eb[jopent].head = jaw_e.tail
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Add mouth open action if it doesn't already exist
|
||||
action_name = "mouth_open"
|
||||
if action_name in bpy.data.actions:
|
||||
open_action = bpy.data.actions[action_name]
|
||||
else:
|
||||
open_action = add_action(name=action_name)
|
||||
|
||||
# Add close property (useful when making the animation in the action)
|
||||
prop_name = "open_action"
|
||||
prop = rna_idprop_ui_prop_get(pb[lip1], prop_name, create=True)
|
||||
pb[lip1][prop_name] = 1.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
prop["min"] = 0.0
|
||||
prop["max"] = 1.0
|
||||
|
||||
open_driver_path = pb[lip1].path_from_id() + '["open_action"]'
|
||||
|
||||
|
||||
# Constraints
|
||||
|
||||
# Jaw open tracker stretches to jaw tip
|
||||
con = pb[jopent].constraints.new('STRETCH_TO')
|
||||
con.target = obj
|
||||
con.subtarget = jaw
|
||||
con.head_tail = 1.0
|
||||
con.rest_length = bb[jopent].length
|
||||
con.volume = 'NO_VOLUME'
|
||||
|
||||
# Head lips to jaw lips
|
||||
influence = [0.02, 0.1, 0.35, 0.25, 0.0]
|
||||
|
||||
con = pb[hlip1].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = jlip1
|
||||
con.influence = influence[2]
|
||||
|
||||
con = pb[hlip2].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = jlip2
|
||||
con.influence = influence[1]
|
||||
|
||||
con = pb[hlip3].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = jlip3
|
||||
con.influence = influence[0]
|
||||
|
||||
con = pb[hlip4].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = jlip4
|
||||
con.influence = influence[1]
|
||||
|
||||
con = pb[hlip5].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = jlip5
|
||||
con.influence = influence[2]
|
||||
|
||||
con = pb[hlip6].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = jlip6
|
||||
con.influence = 1.0 - influence[3]
|
||||
|
||||
con = pb[hlip7].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = jlip7
|
||||
con.influence = 1.0 - influence[4]
|
||||
|
||||
con = pb[hlip8].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = jlip8
|
||||
con.influence = 1.0 - influence[3]
|
||||
|
||||
# ORG bones to lips
|
||||
con = pb[definitions[2]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lip1
|
||||
|
||||
con = pb[definitions[3]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lip2
|
||||
|
||||
con = pb[definitions[4]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lip3
|
||||
|
||||
con = pb[definitions[5]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lip4
|
||||
|
||||
con = pb[definitions[6]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lip5
|
||||
|
||||
con = pb[definitions[7]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lip6
|
||||
|
||||
con = pb[definitions[8]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lip7
|
||||
|
||||
con = pb[definitions[9]].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = lip8
|
||||
|
||||
# Action constraints for open mouth
|
||||
con = pb[lip1].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = jopent
|
||||
con.action = open_action
|
||||
con.transform_channel = 'SCALE_Y'
|
||||
con.frame_start = 0
|
||||
con.frame_end = 60
|
||||
con.min = 0.0
|
||||
con.max = 1.0
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = open_driver_path
|
||||
|
||||
con = pb[lip2].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = jopent
|
||||
con.action = open_action
|
||||
con.transform_channel = 'SCALE_Y'
|
||||
con.frame_start = 0
|
||||
con.frame_end = 60
|
||||
con.min = 0.0
|
||||
con.max = 1.0
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = open_driver_path
|
||||
|
||||
con = pb[lip3].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = jopent
|
||||
con.action = open_action
|
||||
con.transform_channel = 'SCALE_Y'
|
||||
con.frame_start = 0
|
||||
con.frame_end = 60
|
||||
con.min = 0.0
|
||||
con.max = 1.0
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = open_driver_path
|
||||
|
||||
con = pb[lip4].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = jopent
|
||||
con.action = open_action
|
||||
con.transform_channel = 'SCALE_Y'
|
||||
con.frame_start = 0
|
||||
con.frame_end = 60
|
||||
con.min = 0.0
|
||||
con.max = 1.0
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = open_driver_path
|
||||
|
||||
con = pb[lip5].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = jopent
|
||||
con.action = open_action
|
||||
con.transform_channel = 'SCALE_Y'
|
||||
con.frame_start = 0
|
||||
con.frame_end = 60
|
||||
con.min = 0.0
|
||||
con.max = 1.0
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = open_driver_path
|
||||
|
||||
con = pb[lip6].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = jopent
|
||||
con.action = open_action
|
||||
con.transform_channel = 'SCALE_Y'
|
||||
con.frame_start = 0
|
||||
con.frame_end = 60
|
||||
con.min = 0.0
|
||||
con.max = 1.0
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = open_driver_path
|
||||
|
||||
con = pb[lip7].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = jopent
|
||||
con.action = open_action
|
||||
con.transform_channel = 'SCALE_Y'
|
||||
con.frame_start = 0
|
||||
con.frame_end = 60
|
||||
con.min = 0.0
|
||||
con.max = 1.0
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = open_driver_path
|
||||
|
||||
con = pb[lip8].constraints.new('ACTION')
|
||||
con.target = obj
|
||||
con.subtarget = jopent
|
||||
con.action = open_action
|
||||
con.transform_channel = 'SCALE_Y'
|
||||
con.frame_start = 0
|
||||
con.frame_end = 60
|
||||
con.min = 0.0
|
||||
con.max = 1.0
|
||||
con.target_space = 'LOCAL'
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = open_driver_path
|
||||
|
||||
|
||||
# Set layers
|
||||
layer = list(bb[definitions[2]].layers)
|
||||
bb[lip1].layers = layer
|
||||
bb[lip2].layers = layer
|
||||
bb[lip3].layers = layer
|
||||
bb[lip4].layers = layer
|
||||
bb[lip5].layers = layer
|
||||
bb[lip6].layers = layer
|
||||
bb[lip7].layers = layer
|
||||
bb[lip8].layers = layer
|
||||
|
||||
|
||||
return (None,)
|
||||
|
||||
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
# Create control rig
|
||||
control(obj, bone_definition, base_names, options)
|
||||
# Create deform rig
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
|
||||
return (None,)
|
||||
|
||||
|
||||
|
||||
|
||||
def make_lip_stretch_bone(obj, name, bone1, bone2, roll_alpha):
|
||||
eb = obj.data.edit_bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
# Create the bone, pointing from bone1 to bone2
|
||||
bone_e = copy_bone_simple(obj.data, bone1, name, parent=True)
|
||||
bone_e.use_connect = False
|
||||
bone_e.tail = eb[bone2].head
|
||||
bone = bone_e.name
|
||||
|
||||
# Align the bone roll with the average direction of bone1 and bone2
|
||||
vec = bone_e.y_axis.cross(((1.0-roll_alpha)*eb[bone1].y_axis) + (roll_alpha*eb[bone2].y_axis)).normalize()
|
||||
|
||||
ang = acos(vec * bone_e.x_axis)
|
||||
|
||||
bone_e.roll += ang
|
||||
c1 = vec * bone_e.x_axis
|
||||
bone_e.roll -= (ang*2)
|
||||
c2 = vec * bone_e.x_axis
|
||||
|
||||
if c1 > c2:
|
||||
bone_e.roll += (ang*2)
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
bone_p = pb[bone]
|
||||
|
||||
# Constrains
|
||||
con = bone_p.constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = bone1
|
||||
|
||||
con = bone_p.constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = bone2
|
||||
|
||||
con = bone_p.constraints.new('STRETCH_TO')
|
||||
con.target = obj
|
||||
con.subtarget = bone2
|
||||
con.volume = 'NO_VOLUME'
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
return bone
|
@ -1,344 +0,0 @@
|
||||
# ##### 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
|
||||
|
||||
|
||||
|
||||
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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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 neck_01, its parent is the body
|
||||
eg.
|
||||
body -> neck_01 -> neck_02 -> neck_03.... etc
|
||||
'''
|
||||
arm = obj.data
|
||||
neck = arm.bones[orig_bone_name]
|
||||
body = neck.parent
|
||||
|
||||
bone_definition = [body.name, neck.name]
|
||||
bone_definition.extend([child.name for child in neck.children_recursive_basename])
|
||||
return bone_definition
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
for org_bone_name in definitions[1:]:
|
||||
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
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
from mathutils import Vector
|
||||
|
||||
arm = obj.data
|
||||
eb = obj.data.edit_bones
|
||||
bb = obj.data.bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
body = bone_definition[0]
|
||||
|
||||
# Create the neck and head control bones
|
||||
if "head_name" in options:
|
||||
head_name = options["head_name"]
|
||||
else:
|
||||
head_name = "head"
|
||||
|
||||
neck_name = base_names[bone_definition[1]].split(".")[0]
|
||||
|
||||
neck_ctrl = copy_bone_simple(arm, bone_definition[1], neck_name).name
|
||||
head_ctrl = copy_bone_simple(arm, bone_definition[len(bone_definition)-1], head_name).name
|
||||
eb[head_ctrl].tail += eb[neck_ctrl].head - eb[head_ctrl].head
|
||||
eb[head_ctrl].head = eb[neck_ctrl].head
|
||||
|
||||
# Create hinge and socket bones
|
||||
neck_hinge = copy_bone_simple(arm, bone_definition[0], "MCH-" + neck_name + "_hinge").name
|
||||
head_hinge = copy_bone_simple(arm, neck_ctrl, "MCH-" + head_name + "_hinge").name
|
||||
eb[neck_hinge].tail += eb[neck_ctrl].head - eb[neck_hinge].head
|
||||
eb[neck_hinge].head = eb[neck_ctrl].head
|
||||
eb[head_hinge].tail += eb[neck_ctrl].head - eb[head_hinge].head
|
||||
eb[head_hinge].head = eb[neck_ctrl].head
|
||||
|
||||
neck_socket = copy_bone_simple(arm, bone_definition[1], "MCH-" + neck_name + "_socket").name
|
||||
head_socket = copy_bone_simple(arm, bone_definition[1], "MCH-" + head_name + "_socket").name
|
||||
|
||||
# Parent-child relationships between the body, hinges, controls, and sockets
|
||||
eb[neck_ctrl].parent = eb[neck_hinge]
|
||||
eb[head_ctrl].parent = eb[head_hinge]
|
||||
|
||||
eb[neck_socket].parent = eb[body]
|
||||
eb[head_socket].parent = eb[body]
|
||||
|
||||
# Create neck bones
|
||||
neck = [] # neck bones
|
||||
neck_neck = [] # bones constrained to neck control
|
||||
neck_head = [] # bones constrained to head control
|
||||
for i in range(1, len(bone_definition)):
|
||||
# Create bones
|
||||
neck_bone = copy_bone_simple(arm, bone_definition[i], base_names[bone_definition[i]]).name
|
||||
neck_neck_bone = copy_bone_simple(arm, neck_ctrl, "MCH-" + base_names[bone_definition[i]] + ".neck").name
|
||||
neck_head_bone = copy_bone_simple(arm, head_ctrl, "MCH-" + base_names[bone_definition[i]] + ".head").name
|
||||
|
||||
# Move them all to the same place
|
||||
eb[neck_neck_bone].tail += eb[neck_bone].head - eb[neck_neck_bone].head
|
||||
eb[neck_head_bone].tail += eb[neck_bone].head - eb[neck_neck_bone].head
|
||||
eb[neck_neck_bone].head = eb[neck_bone].head
|
||||
eb[neck_head_bone].head = eb[neck_bone].head
|
||||
|
||||
# Parent/child relationships
|
||||
eb[neck_bone].parent = eb[neck_head_bone]
|
||||
eb[neck_head_bone].parent = eb[neck_neck_bone]
|
||||
|
||||
if i > 1:
|
||||
eb[neck_neck_bone].parent = eb[neck[i-2]]
|
||||
else:
|
||||
eb[neck_neck_bone].parent = eb[body]
|
||||
|
||||
# Add them to the lists
|
||||
neck += [neck_bone]
|
||||
neck_neck += [neck_neck_bone]
|
||||
neck_head += [neck_head_bone]
|
||||
|
||||
# Create deformation rig
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Axis locks
|
||||
pb[neck_ctrl].lock_location = True, True, True
|
||||
pb[head_ctrl].lock_location = True, True, True
|
||||
|
||||
for bone in neck:
|
||||
pb[bone].lock_location = True, True, True
|
||||
|
||||
# Neck hinge
|
||||
prop = rna_idprop_ui_prop_get(pb[neck_ctrl], "hinge", create=True)
|
||||
pb[neck_ctrl]["hinge"] = 0.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
prop["hard_min"] = 0.0
|
||||
prop["hard_max"] = 1.0
|
||||
|
||||
con = pb[neck_hinge].constraints.new('COPY_LOCATION')
|
||||
con.name = "socket"
|
||||
con.target = obj
|
||||
con.subtarget = neck_socket
|
||||
|
||||
con = pb[neck_hinge].constraints.new('COPY_ROTATION')
|
||||
con.name = "hinge"
|
||||
con.target = obj
|
||||
con.subtarget = body
|
||||
|
||||
hinge_driver_path = pb[neck_ctrl].path_from_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.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = 1.0
|
||||
mod.coefficients[1] = -1.0
|
||||
|
||||
# Head hinge
|
||||
prop = rna_idprop_ui_prop_get(pb[head_ctrl], "hinge", create=True)
|
||||
pb[head_ctrl]["hinge"] = 0.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
prop["hard_min"] = 0.0
|
||||
prop["hard_max"] = 1.0
|
||||
|
||||
con = pb[head_hinge].constraints.new('COPY_LOCATION')
|
||||
con.name = "socket"
|
||||
con.target = obj
|
||||
con.subtarget = head_socket
|
||||
|
||||
con = pb[head_hinge].constraints.new('COPY_ROTATION')
|
||||
con.name = "hinge"
|
||||
con.target = obj
|
||||
con.subtarget = neck_ctrl
|
||||
|
||||
hinge_driver_path = pb[head_ctrl].path_from_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.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = 1.0
|
||||
mod.coefficients[1] = -1.0
|
||||
|
||||
# Neck rotation constraints
|
||||
for i in range(0, len(neck_neck)):
|
||||
con = pb[neck_neck[i]].constraints.new('COPY_ROTATION')
|
||||
con.name = "neck rotation"
|
||||
con.target = obj
|
||||
con.subtarget = neck_ctrl
|
||||
con.influence = (i+1) / len(neck_neck)
|
||||
|
||||
|
||||
# Head rotation constraints/drivers
|
||||
prop = rna_idprop_ui_prop_get(pb[head_ctrl], "extent", create=True)
|
||||
if "extent" in options:
|
||||
pb[head_ctrl]["extent"] = options["extent"]
|
||||
else:
|
||||
pb[head_ctrl]["extent"] = 0.5
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
prop["hard_min"] = 0.0
|
||||
prop["hard_max"] = 1.0
|
||||
|
||||
extent_prop_path = pb[head_ctrl].path_from_id() + '["extent"]'
|
||||
|
||||
for i in range(0, len(neck_head)):
|
||||
con = pb[neck_head[i]].constraints.new('COPY_ROTATION')
|
||||
con.name = "head rotation"
|
||||
con.target = obj
|
||||
con.subtarget = head_ctrl
|
||||
|
||||
if i < (len(neck_head)-1):
|
||||
inf = (i+1) / len(neck_head)
|
||||
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
var = driver.variables.new()
|
||||
var.name = "ext"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = extent_prop_path
|
||||
|
||||
driver.expression = "0 if ext == 0 else (((%s-1)/ext)+1)" % inf
|
||||
else:
|
||||
con.influence = 1.0
|
||||
|
||||
# Constrain original bones to the neck bones
|
||||
for i in range(0, len(neck)):
|
||||
con = pb[bone_definition[i+1]].constraints.new('COPY_TRANSFORMS')
|
||||
con.name = "copy_transform"
|
||||
con.target = obj
|
||||
con.subtarget = neck[i]
|
||||
|
||||
|
||||
# Set the controls' custom shapes to use other bones for transforms
|
||||
pb[neck_ctrl].custom_shape_transform = pb[bone_definition[len(bone_definition)//2]]
|
||||
pb[head_ctrl].custom_shape_transform = pb[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]].layers)
|
||||
for bone in neck:
|
||||
bb[bone].layers = layer
|
||||
|
||||
layer = list(arm.bones[bone_definition[1]].layers)
|
||||
bb[neck_ctrl].layers = layer
|
||||
bb[head_ctrl].layers = layer
|
||||
|
||||
|
||||
# no blending the result of this
|
||||
return None
|
||||
|
@ -1,348 +0,0 @@
|
||||
# ##### 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():
|
||||
# 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = True
|
||||
bone.parent = arm.edit_bones['neck.04']
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['head']
|
||||
pbone['type'] = 'neck_flex'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
'''
|
||||
The bone given is the head, its parent is the body,
|
||||
# its only child the first of a chain with matching basenames.
|
||||
eg.
|
||||
body -> head -> neck_01 -> neck_02 -> neck_03.... etc
|
||||
'''
|
||||
arm = obj.data
|
||||
head = arm.bones[orig_bone_name]
|
||||
body = head.parent
|
||||
|
||||
children = head.children
|
||||
if len(children) != 1:
|
||||
raise RigifyError("expected the head bone '%s' to have only 1 child." % orig_bone_name)
|
||||
|
||||
child = children[0]
|
||||
bone_definition = [body.name, head.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
|
||||
|
||||
|
||||
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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = False
|
||||
neck_e.parent = neck_e_parent
|
||||
neck_e_parent.use_connect = 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
|
||||
|
||||
# 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_from_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_from_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(fcurve.modifiers[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 constraint
|
||||
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(fcurve.modifiers[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_ROTATION')
|
||||
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]].layers)
|
||||
for attr in ex_chain.attr_names:
|
||||
getattr(ex_chain, attr + "_b").layers = layer
|
||||
for attr in ex.attr_names:
|
||||
getattr(ex, attr + "_b").layers = layer
|
||||
|
||||
layer = list(arm.bones[bone_definition[1]].layers)
|
||||
ex.head_ctrl_b.layers = layer
|
||||
|
||||
|
||||
# no blending the result of this
|
||||
return None
|
@ -1,270 +0,0 @@
|
||||
# ##### 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_utils import copy_bone_simple, get_side_name
|
||||
from rna_prop_ui import rna_idprop_ui_prop_get
|
||||
|
||||
# not used, defined for completeness
|
||||
METARIG_NAMES = tuple()
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('hand')
|
||||
bone.head[:] = 0.0004, -0.0629, 0.0000
|
||||
bone.tail[:] = 0.0021, -0.0209, 0.0000
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
bone = arm.edit_bones.new('palm.03')
|
||||
bone.head[:] = -0.0000, 0.0000, 0.0000
|
||||
bone.tail[:] = 0.0025, 0.0644, -0.0065
|
||||
bone.roll = -3.1396
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand']
|
||||
bone = arm.edit_bones.new('palm.02')
|
||||
bone.head[:] = 0.0252, -0.0000, 0.0000
|
||||
bone.tail[:] = 0.0324, 0.0627, -0.0065
|
||||
bone.roll = -3.1357
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand']
|
||||
bone = arm.edit_bones.new('palm.01')
|
||||
bone.head[:] = 0.0504, 0.0000, 0.0000
|
||||
bone.tail[:] = 0.0703, 0.0508, -0.0065
|
||||
bone.roll = -3.1190
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand']
|
||||
bone = arm.edit_bones.new('palm.04')
|
||||
bone.head[:] = -0.0252, 0.0000, 0.0000
|
||||
bone.tail[:] = -0.0286, 0.0606, -0.0065
|
||||
bone.roll = 3.1386
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand']
|
||||
bone = arm.edit_bones.new('palm.05')
|
||||
bone.head[:] = -0.0504, 0.0000, 0.0000
|
||||
bone.tail[:] = -0.0669, 0.0534, -0.0065
|
||||
bone.roll = 3.1239
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand']
|
||||
bone = arm.edit_bones.new('thumb')
|
||||
bone.head[:] = 0.0682, -0.0148, 0.0000
|
||||
bone.tail[:] = 0.1063, 0.0242, -0.0065
|
||||
bone.roll = -3.0929
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand']
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['palm.01']
|
||||
pbone['type'] = 'palm_curl'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
'''
|
||||
The bone given is the first in an array of siblings with a matching basename
|
||||
sorted with pointer first, little finger last.
|
||||
eg.
|
||||
[pointer, middle, ring, pinky... ] # any number of fingers
|
||||
'''
|
||||
arm = obj.data
|
||||
|
||||
palm_bone = arm.bones[orig_bone_name]
|
||||
palm_parent = palm_bone.parent
|
||||
palm_base = palm_bone.basename
|
||||
bone_definition = [bone.name for bone in palm_parent.children if bone.basename == palm_base]
|
||||
bone_definition.sort()
|
||||
bone_definition.reverse()
|
||||
|
||||
return [palm_parent.name] + bone_definition
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
for org_bone_name in definitions[1:]:
|
||||
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
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
arm = obj.data
|
||||
|
||||
children = bone_definition[1:]
|
||||
|
||||
# Make a copy of the pinky
|
||||
# simply assume the pinky has the lowest name
|
||||
pinky_ebone = arm.edit_bones[children[0]]
|
||||
ring_ebone = arm.edit_bones[children[1]]
|
||||
|
||||
# FIXME, why split the second one?
|
||||
base_name = base_names[pinky_ebone.name].rsplit('.', 2)[0]
|
||||
|
||||
control_ebone = copy_bone_simple(arm, pinky_ebone.name, base_name + get_side_name(base_names[pinky_ebone.name]), parent=True)
|
||||
control_name = control_ebone.name
|
||||
|
||||
offset = (pinky_ebone.head - ring_ebone.head)
|
||||
|
||||
control_ebone.translate(offset)
|
||||
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
arm = obj.data
|
||||
control_pbone = obj.pose.bones[control_name]
|
||||
pinky_pbone = obj.pose.bones[children[0]]
|
||||
|
||||
control_pbone.rotation_mode = 'YZX'
|
||||
control_pbone.lock_rotation = False, True, True
|
||||
control_pbone.lock_location = True, True, True
|
||||
|
||||
driver_fcurves = pinky_pbone.driver_add("rotation_euler")
|
||||
|
||||
|
||||
controller_path = control_pbone.path_from_id()
|
||||
|
||||
# add custom prop
|
||||
control_pbone["spread"] = 0.0
|
||||
prop = rna_idprop_ui_prop_get(control_pbone, "spread", create=True)
|
||||
prop["soft_min"] = -1.0
|
||||
prop["soft_max"] = 1.0
|
||||
prop["min"] = -1.0
|
||||
prop["max"] = 1.0
|
||||
|
||||
|
||||
# *****
|
||||
driver = driver_fcurves[0].driver
|
||||
driver.type = 'AVERAGE'
|
||||
|
||||
var = driver.variables.new()
|
||||
var.name = "x"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = controller_path + ".rotation_euler[0]"
|
||||
|
||||
|
||||
# *****
|
||||
driver = driver_fcurves[1].driver
|
||||
driver.expression = "-x/4.0"
|
||||
|
||||
var = driver.variables.new()
|
||||
var.name = "x"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = controller_path + ".rotation_euler[0]"
|
||||
|
||||
|
||||
# *****
|
||||
driver = driver_fcurves[2].driver
|
||||
driver.expression = "(1.0-cos(x))-s"
|
||||
|
||||
for fcurve in driver_fcurves:
|
||||
fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier
|
||||
|
||||
var = driver.variables.new()
|
||||
var.name = "x"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = controller_path + ".rotation_euler[0]"
|
||||
|
||||
var = driver.variables.new()
|
||||
var.name = "s"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = controller_path + '["spread"]'
|
||||
|
||||
|
||||
for i, child_name in enumerate(children):
|
||||
child_pbone = obj.pose.bones[child_name]
|
||||
child_pbone.rotation_mode = 'YZX'
|
||||
|
||||
if child_name != children[-1] and child_name != children[0]:
|
||||
|
||||
# this is somewhat arbitrary but seems to look good
|
||||
inf = i / (len(children) + 1)
|
||||
inf = 1.0 - inf
|
||||
inf = ((inf * inf) + inf) / 2.0
|
||||
|
||||
# used for X/Y constraint
|
||||
inf_minor = inf * inf
|
||||
|
||||
con = child_pbone.constraints.new('COPY_ROTATION')
|
||||
con.name = "Copy Z Rot"
|
||||
con.target = obj
|
||||
con.subtarget = children[0] # also pinky_pbone
|
||||
con.owner_space = con.target_space = 'LOCAL'
|
||||
con.use_x, con.use_y, con.use_z = False, False, True
|
||||
con.influence = inf
|
||||
|
||||
con = child_pbone.constraints.new('COPY_ROTATION')
|
||||
con.name = "Copy XY Rot"
|
||||
con.target = obj
|
||||
con.subtarget = children[0] # also pinky_pbone
|
||||
con.owner_space = con.target_space = 'LOCAL'
|
||||
con.use_x, con.use_y, con.use_z = True, True, False
|
||||
con.influence = inf_minor
|
||||
|
||||
|
||||
child_pbone = obj.pose.bones[children[-1]]
|
||||
child_pbone.rotation_mode = 'QUATERNION'
|
||||
|
||||
# fix at the end since there is some trouble with tx info not being updated otherwise
|
||||
def x_direction():
|
||||
# NOTE: the direction of the Z rotation depends on which side the palm is on.
|
||||
# we could do a simple side-of-x test but better to work out the direction
|
||||
# the hand is facing.
|
||||
from mathutils import Vector
|
||||
from math import degrees
|
||||
child_pbone_01 = obj.pose.bones[children[0]].bone
|
||||
child_pbone_02 = obj.pose.bones[children[1]].bone
|
||||
|
||||
rel_vec = child_pbone_01.head - child_pbone_02.head
|
||||
x_vec = child_pbone_01.matrix.rotation_part() * Vector((1.0, 0.0, 0.0))
|
||||
|
||||
return degrees(rel_vec.angle(x_vec)) > 90.0
|
||||
|
||||
if x_direction(): # flip
|
||||
driver.expression = "-(%s)" % driver.expression
|
||||
|
||||
|
||||
# last step setup layers
|
||||
arm.bones[control_name].layers = list(arm.bones[bone_definition[1]].layers)
|
||||
|
||||
|
||||
# no blending the result of this
|
||||
return None
|
@ -1,320 +0,0 @@
|
||||
# ##### 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 copy_bone_simple
|
||||
from rna_prop_ui import rna_idprop_ui_prop_get
|
||||
|
||||
#METARIG_NAMES = ("cpy",)
|
||||
RIG_TYPE = "shape_key_control"
|
||||
|
||||
|
||||
def addget_shape_key(obj, name="Key"):
|
||||
""" Fetches a shape key, or creates it if it doesn't exist
|
||||
"""
|
||||
# Create a shapekey set if it doesn't already exist
|
||||
if obj.data.shape_keys is None:
|
||||
shape = obj.add_shape_key(name="Basis", from_mix=False)
|
||||
obj.active_shape_key_index = 0
|
||||
|
||||
# Get the shapekey, or create it if it doesn't already exist
|
||||
if name in obj.data.shape_keys.keys:
|
||||
shape_key = obj.data.shape_keys.keys[name]
|
||||
else:
|
||||
shape_key = obj.add_shape_key(name=name, from_mix=False)
|
||||
|
||||
return shape_key
|
||||
|
||||
|
||||
def addget_shape_key_driver(obj, name="Key"):
|
||||
""" Fetches the driver for the shape key, or creates it if it doesn't
|
||||
already exist.
|
||||
"""
|
||||
driver_path = 'keys["' + name + '"].value'
|
||||
fcurve = None
|
||||
driver = None
|
||||
new = False
|
||||
if obj.data.shape_keys.animation_data is not None:
|
||||
for driver_s in obj.data.shape_keys.animation_data.drivers:
|
||||
if driver_s.data_path == driver_path:
|
||||
fcurve = driver_s
|
||||
if fcurve is None:
|
||||
fcurve = obj.data.shape_keys.keys[name].driver_add("value")
|
||||
fcurve.driver.type = 'AVERAGE'
|
||||
new = True
|
||||
|
||||
return fcurve, new
|
||||
|
||||
|
||||
# TODO:
|
||||
def metarig_template():
|
||||
# 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('Bone')
|
||||
#bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
#bone.tail[:] = 0.0000, 0.0000, 1.0000
|
||||
#bone.roll = 0.0000
|
||||
#bone.use_connect = False
|
||||
#
|
||||
#bpy.ops.object.mode_set(mode='OBJECT')
|
||||
#pbone = obj.pose.bones['Bone']
|
||||
#pbone['type'] = 'copy'
|
||||
pass
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
bone = obj.data.bones[orig_bone_name]
|
||||
return [bone.name]
|
||||
|
||||
|
||||
def main(obj, definitions, base_names, options):
|
||||
""" A rig that drives shape keys with the local transforms and/or custom
|
||||
properties of a single bone.
|
||||
A different shape can be driven by the negative value of a transform as
|
||||
well by giving a comma-separated list of two shapes.
|
||||
|
||||
Required options:
|
||||
mesh: name of mesh object(s) to add/get shapekeys to/from
|
||||
(if multiple objects, make a comma-separated list)
|
||||
Optional options:
|
||||
loc_<x/y/z>: name of the shape key to tie to translation of the bone
|
||||
loc_<x/y/z>_fac: default multiplier of the bone influence on the shape key
|
||||
rot_<x/y/z>: name of the shape key to tie to rotation of the bone
|
||||
rot_<x/y/z>_fac: default multiplier of the bone influence on the shape key
|
||||
scale_<x/y/z>: name of the shape key to tie to scale of the bone
|
||||
scale_<x/y/z>_fac: default multiplier of the bone influence on the shape key
|
||||
shape_key_sliders: comma-separated list of custom properties to create sliders out of for driving shape keys
|
||||
<custom_prop>: for each property listed in shape_key_sliders, specify a shape key for it to drive
|
||||
|
||||
"""
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
eb = obj.data.edit_bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
org_bone = definitions[0]
|
||||
|
||||
# Options
|
||||
req_options = ["mesh"]
|
||||
for option in req_options:
|
||||
if option not in options:
|
||||
raise RigifyError("'%s' rig type requires a '%s' option (bone: %s)" % (RIG_TYPE, option, base_names[definitions[0]]))
|
||||
|
||||
meshes = options["mesh"].replace(" ", "").split(",")
|
||||
|
||||
bone = copy_bone_simple(obj.data, org_bone, base_names[org_bone], parent=True).name
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Set rotation mode and axis locks
|
||||
pb[bone].rotation_mode = pb[org_bone].rotation_mode
|
||||
pb[bone].lock_location = tuple(pb[org_bone].lock_location)
|
||||
pb[bone].lock_rotation = tuple(pb[org_bone].lock_rotation)
|
||||
pb[bone].lock_rotation_w = pb[org_bone].lock_rotation_w
|
||||
pb[bone].lock_rotations_4d = pb[org_bone].lock_rotations_4d
|
||||
pb[bone].lock_scale = tuple(pb[org_bone].lock_scale)
|
||||
|
||||
# List of rig options for specifying shape keys
|
||||
# Append '_fac' to the end for the name of the corresponding 'factor
|
||||
# default' option for that shape
|
||||
shape_key_options = ["loc_x",
|
||||
"loc_y",
|
||||
"loc_z",
|
||||
"rot_x",
|
||||
"rot_y",
|
||||
"rot_z",
|
||||
"scale_x",
|
||||
"scale_y",
|
||||
"scale_z"]
|
||||
|
||||
driver_paths = {"loc_x":".location[0]",
|
||||
"loc_y":".location[1]",
|
||||
"loc_z":".location[2]",
|
||||
"rot_x":".rotation_euler[0]",
|
||||
"rot_y":".rotation_euler[1]",
|
||||
"rot_z":".rotation_euler[2]",
|
||||
"qrot_x":".rotation_quaternion[1]",
|
||||
"qrot_y":".rotation_quaternion[2]",
|
||||
"qrot_z":".rotation_quaternion[3]",
|
||||
"scale_x":".scale[0]",
|
||||
"scale_y":".scale[1]",
|
||||
"scale_z":".scale[2]"}
|
||||
|
||||
# Create the shape keys and drivers for transforms
|
||||
shape_info = []
|
||||
for option in shape_key_options:
|
||||
if option in options:
|
||||
shape_names = options[option].replace(" ", "").split(",")
|
||||
|
||||
var_name = bone.replace(".","").replace("-","_") + "_" + option
|
||||
# Different RNA paths for euler vs quat
|
||||
if option in (shape_key_options[3:6]+shape_key_options[12:15]) \
|
||||
and pb[bone].rotation_mode == 'QUATERNION':
|
||||
var_path = driver_paths['q' + option]
|
||||
else:
|
||||
var_path = driver_paths[option]
|
||||
|
||||
if (option+"_fac") in options:
|
||||
fac = options[option+"_fac"]
|
||||
else:
|
||||
fac = 1.0
|
||||
|
||||
# Positive
|
||||
if shape_names[0] != "":
|
||||
# Different expressions for loc/rot/scale and positive/negative
|
||||
if option in shape_key_options[:3]:
|
||||
# Location
|
||||
expression = var_name + " * " + str(fac)
|
||||
elif option in shape_key_options[3:6]:
|
||||
# Rotation
|
||||
# Different expressions for euler vs quats
|
||||
if pb[bone].rotation_mode == 'QUATERNION':
|
||||
expression = "2 * asin(" + var_name + ") * " + str(fac)
|
||||
else:
|
||||
expression = var_name + " * " + str(fac)
|
||||
elif option in shape_key_options[6:9]:
|
||||
# Scale
|
||||
expression = "(1.0 - " + var_name + ") * " + str(fac) + " * -2"
|
||||
shape_name = shape_names[0]
|
||||
create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, expression)
|
||||
|
||||
# Negative
|
||||
if shape_names[0] != "" and len(shape_names) > 1:
|
||||
# Different expressions for loc/rot/scale and positive/negative
|
||||
if option in shape_key_options[:3]:
|
||||
# Location
|
||||
expression = var_name + " * " + str(fac) + " * -1"
|
||||
elif option in shape_key_options[3:6]:
|
||||
# Rotation
|
||||
# Different expressions for euler vs quats
|
||||
if pb[bone].rotation_mode == 'QUATERNION':
|
||||
expression = "-2 * asin(" + var_name + ") * " + str(fac)
|
||||
else:
|
||||
expression = var_name + " * " + str(fac) + " * -1"
|
||||
elif option in shape_key_options[6:9]:
|
||||
# Scale
|
||||
expression = "(1.0 - " + var_name + ") * " + str(fac) + " * 2"
|
||||
shape_name = shape_names[1]
|
||||
create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, expression)
|
||||
|
||||
# Create the shape keys and drivers for custom-property sliders
|
||||
if "shape_key_sliders" in options:
|
||||
# Get the slider names
|
||||
slider_names = options["shape_key_sliders"].replace(" ", "").split(",")
|
||||
if slider_names[0] != "":
|
||||
# Loop through the slider names and check if they have
|
||||
# shape keys specified for them, and if so, set them up.
|
||||
for slider_name in slider_names:
|
||||
if slider_name in options:
|
||||
shape_names = options[slider_name].replace(" ", "").split(",")
|
||||
|
||||
# Set up the custom property on the bone
|
||||
prop = rna_idprop_ui_prop_get(pb[bone], slider_name, create=True)
|
||||
pb[bone][slider_name] = 0.0
|
||||
prop["min"] = 0.0
|
||||
prop["max"] = 1.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
if len(shape_names) > 1:
|
||||
prop["min"] = -1.0
|
||||
prop["soft_min"] = -1.0
|
||||
|
||||
# Add the shape drivers
|
||||
# Positive
|
||||
if shape_names[0] != "":
|
||||
# Set up the variables for creating the shape key driver
|
||||
shape_name = shape_names[0]
|
||||
var_name = slider_name.replace(".", "_").replace("-", "_")
|
||||
var_path = '["' + slider_name + '"]'
|
||||
if slider_name + "_fac" in options:
|
||||
fac = options[slider_name + "_fac"]
|
||||
else:
|
||||
fac = 1.0
|
||||
expression = var_name + " * " + str(fac)
|
||||
# Create the shape key driver
|
||||
create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, expression)
|
||||
# Negative
|
||||
if shape_names[0] != "" and len(shape_names) > 1:
|
||||
# Set up the variables for creating the shape key driver
|
||||
shape_name = shape_names[1]
|
||||
var_name = slider_name.replace(".", "_").replace("-", "_")
|
||||
var_path = '["' + slider_name + '"]'
|
||||
if slider_name + "_fac" in options:
|
||||
fac = options[slider_name + "_fac"]
|
||||
else:
|
||||
fac = 1.0
|
||||
expression = var_name + " * " + str(fac) + " * -1"
|
||||
# Create the shape key driver
|
||||
create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, expression)
|
||||
|
||||
|
||||
# Org bone copy transforms of control bone
|
||||
con = pb[org_bone].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = bone
|
||||
|
||||
return (None,)
|
||||
|
||||
|
||||
def create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, expression):
|
||||
""" Creates/gets a shape key and sets up a driver for it.
|
||||
|
||||
obj = armature object
|
||||
bone = driving bone name
|
||||
meshes = list of meshes to create the shapekey/driver on
|
||||
shape_name = name of the shape key
|
||||
var_name = name of the driving variable
|
||||
var_path = path to the property on the bone to drive with
|
||||
expression = python expression for the driver
|
||||
"""
|
||||
pb = obj.pose.bones
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
for mesh_name in meshes:
|
||||
mesh_obj = bpy.data.objects[mesh_name]
|
||||
|
||||
# Add/get the shape key
|
||||
shape = addget_shape_key(mesh_obj, name=shape_name)
|
||||
|
||||
# Add/get the shape key driver
|
||||
fcurve, a = addget_shape_key_driver(mesh_obj, name=shape_name)
|
||||
|
||||
# Set up the driver
|
||||
driver = fcurve.driver
|
||||
driver.type = 'SCRIPTED'
|
||||
driver.expression = expression
|
||||
|
||||
# Get the variable, or create it if it doesn't already exist
|
||||
if var_name in driver.variables:
|
||||
var = driver.variables[var_name]
|
||||
else:
|
||||
var = driver.variables.new()
|
||||
var.name = var_name
|
||||
|
||||
# Set up the variable
|
||||
var.type = "SINGLE_PROP"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = 'pose.bones["' + bone + '"]' + var_path
|
||||
|
||||
|
@ -1,172 +0,0 @@
|
||||
# ##### 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
|
||||
|
||||
#METARIG_NAMES = ("cpy",)
|
||||
RIG_TYPE = "shape_key_distance"
|
||||
|
||||
|
||||
def addget_shape_key(obj, name="Key"):
|
||||
""" Fetches a shape key, or creates it if it doesn't exist
|
||||
"""
|
||||
# Create a shapekey set if it doesn't already exist
|
||||
if obj.data.shape_keys is None:
|
||||
shape = obj.add_shape_key(name="Basis", from_mix=False)
|
||||
obj.active_shape_key_index = 0
|
||||
|
||||
# Get the shapekey, or create it if it doesn't already exist
|
||||
if name in obj.data.shape_keys.keys:
|
||||
shape_key = obj.data.shape_keys.keys[name]
|
||||
else:
|
||||
shape_key = obj.add_shape_key(name=name, from_mix=False)
|
||||
|
||||
return shape_key
|
||||
|
||||
|
||||
def addget_shape_key_driver(obj, name="Key"):
|
||||
""" Fetches the driver for the shape key, or creates it if it doesn't
|
||||
already exist.
|
||||
"""
|
||||
driver_path = 'keys["' + name + '"].value'
|
||||
fcurve = None
|
||||
driver = None
|
||||
if obj.data.shape_keys.animation_data is not None:
|
||||
for driver_s in obj.data.shape_keys.animation_data.drivers:
|
||||
if driver_s.data_path == driver_path:
|
||||
fcurve = driver_s
|
||||
if fcurve is None:
|
||||
fcurve = obj.data.shape_keys.keys[name].driver_add("value")
|
||||
fcurve.driver.type = 'AVERAGE'
|
||||
|
||||
return fcurve
|
||||
|
||||
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('Bone')
|
||||
bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
bone.tail[:] = 0.0000, 0.0000, 1.0000
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['Bone']
|
||||
pbone['type'] = 'copy'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
bone = obj.data.bones[orig_bone_name]
|
||||
return [bone.name]
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
eb = obj.data.edit_bones
|
||||
|
||||
bone_from = definitions[0]
|
||||
|
||||
|
||||
# Options
|
||||
req_options = ["to", "mesh", "shape_key"]
|
||||
for option in req_options:
|
||||
if option not in options:
|
||||
raise RigifyError("'%s' rig type requires a '%s' option (bone: %s)" % (RIG_TYPE, option, base_names[definitions[0]]))
|
||||
|
||||
bone_to = "ORG-" + options["to"]
|
||||
meshes = options["mesh"].replace(" ", "").split(",")
|
||||
shape_key_name = options["shape_key"]
|
||||
|
||||
if "dmul" in options:
|
||||
shape_blend_fac = options["dmul"]
|
||||
else:
|
||||
shape_blend_fac = 1.0
|
||||
|
||||
|
||||
# Calculate the distance between the bones
|
||||
distance = (eb[bone_from].head - eb[bone_to].head).length
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# For every listed mesh object
|
||||
for mesh_name in meshes:
|
||||
mesh_obj = bpy.data.objects[mesh_name]
|
||||
|
||||
# Add/get the shape key
|
||||
shape_key = addget_shape_key(mesh_obj, name=shape_key_name)
|
||||
|
||||
# Add/get the shape key driver
|
||||
fcurve = addget_shape_key_driver(mesh_obj, name=shape_key_name)
|
||||
driver = fcurve.driver
|
||||
|
||||
# Get the variable, or create it if it doesn't already exist
|
||||
var_name = base_names[bone_from]
|
||||
if var_name in driver.variables:
|
||||
var = driver.variables[var_name]
|
||||
else:
|
||||
var = driver.variables.new()
|
||||
var.name = var_name
|
||||
|
||||
# Set up the variable
|
||||
var.type = "LOC_DIFF"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].bone_target = bone_from
|
||||
var.targets[1].id_type = 'OBJECT'
|
||||
var.targets[1].id = obj
|
||||
var.targets[1].bone_target = bone_to
|
||||
|
||||
# Set fcurve offset, so zero is at the rest distance
|
||||
|
||||
mod = fcurve.modifiers[0]
|
||||
if distance > 0.00001:
|
||||
mod.coefficients[0] = -shape_blend_fac
|
||||
mod.coefficients[1] = shape_blend_fac / distance
|
||||
|
||||
return (None,)
|
||||
|
||||
|
||||
|
||||
|
||||
def control(obj, definitions, base_names, options):
|
||||
""" options:
|
||||
mesh: name of mesh object with the shape key
|
||||
shape_key: name of shape key
|
||||
to: name of bone to measure distance from
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
# Create control rig
|
||||
#control(obj, bone_definition, base_names, options)
|
||||
# Create deform rig
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
|
||||
return (None,)
|
||||
|
@ -1,172 +0,0 @@
|
||||
# ##### 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
|
||||
|
||||
#METARIG_NAMES = ("cpy",)
|
||||
RIG_TYPE = "shape_key_rotdiff"
|
||||
|
||||
|
||||
def addget_shape_key(obj, name="Key"):
|
||||
""" Fetches a shape key, or creates it if it doesn't exist
|
||||
"""
|
||||
# Create a shapekey set if it doesn't already exist
|
||||
if obj.data.shape_keys is None:
|
||||
shape = obj.add_shape_key(name="Basis", from_mix=False)
|
||||
obj.active_shape_key_index = 0
|
||||
|
||||
# Get the shapekey, or create it if it doesn't already exist
|
||||
if name in obj.data.shape_keys.keys:
|
||||
shape_key = obj.data.shape_keys.keys[name]
|
||||
else:
|
||||
shape_key = obj.add_shape_key(name=name, from_mix=False)
|
||||
|
||||
return shape_key
|
||||
|
||||
|
||||
def addget_shape_key_driver(obj, name="Key"):
|
||||
""" Fetches the driver for the shape key, or creates it if it doesn't
|
||||
already exist.
|
||||
"""
|
||||
driver_path = 'keys["' + name + '"].value'
|
||||
fcurve = None
|
||||
driver = None
|
||||
if obj.data.shape_keys.animation_data is not None:
|
||||
for driver_s in obj.data.shape_keys.animation_data.drivers:
|
||||
if driver_s.data_path == driver_path:
|
||||
fcurve = driver_s
|
||||
if fcurve is None:
|
||||
fcurve = obj.data.shape_keys.keys[name].driver_add("value")
|
||||
fcurve.driver.type = 'AVERAGE'
|
||||
|
||||
return fcurve
|
||||
|
||||
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('Bone')
|
||||
bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
bone.tail[:] = 0.0000, 0.0000, 1.0000
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['Bone']
|
||||
pbone['type'] = 'copy'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
bone = obj.data.bones[orig_bone_name]
|
||||
return [bone.name]
|
||||
|
||||
|
||||
def deform(obj, definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
eb = obj.data.edit_bones
|
||||
|
||||
bone_from = definitions[0]
|
||||
|
||||
|
||||
# Options
|
||||
req_options = ["to", "mesh", "shape_key"]
|
||||
for option in req_options:
|
||||
if option not in options:
|
||||
raise RigifyError("'%s' rig type requires a '%s' option (bone: %s)" % (RIG_TYPE, option, base_names[definitions[0]]))
|
||||
|
||||
bone_to = "ORG-" + options["to"]
|
||||
meshes = options["mesh"].replace(" ", "").split(",")
|
||||
shape_key_name = options["shape_key"]
|
||||
|
||||
if "dmul" in options:
|
||||
shape_blend_fac = options["dmul"]
|
||||
else:
|
||||
shape_blend_fac = 1.0
|
||||
|
||||
|
||||
# Calculate the rotation difference between the bones
|
||||
rotdiff = (eb[bone_from].matrix.to_quat() * eb[bone_to].matrix.to_quat()) * 2
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# For every listed mesh object
|
||||
for mesh_name in meshes:
|
||||
mesh_obj = bpy.data.objects[mesh_name]
|
||||
|
||||
# Add/get the shape key
|
||||
shape_key = addget_shape_key(mesh_obj, name=shape_key_name)
|
||||
|
||||
# Add/get the shape key driver
|
||||
fcurve = addget_shape_key_driver(mesh_obj, name=shape_key_name)
|
||||
driver = fcurve.driver
|
||||
|
||||
# Get the variable, or create it if it doesn't already exist
|
||||
var_name = base_names[bone_from]
|
||||
if var_name in driver.variables:
|
||||
var = driver.variables[var_name]
|
||||
else:
|
||||
var = driver.variables.new()
|
||||
var.name = var_name
|
||||
|
||||
# Set up the variable
|
||||
var.type = "ROTATION_DIFF"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].bone_target = bone_from
|
||||
var.targets[1].id_type = 'OBJECT'
|
||||
var.targets[1].id = obj
|
||||
var.targets[1].bone_target = bone_to
|
||||
|
||||
# Set fcurve offset, so zero is at the rest distance
|
||||
|
||||
mod = fcurve.modifiers[0]
|
||||
if rotdiff > 0.00001:
|
||||
mod.coefficients[0] = -shape_blend_fac
|
||||
mod.coefficients[1] = shape_blend_fac / rotdiff
|
||||
|
||||
return (None,)
|
||||
|
||||
|
||||
|
||||
|
||||
def control(obj, definitions, base_names, options):
|
||||
""" options:
|
||||
mesh: name of mesh object with the shape key
|
||||
shape_key: name of shape key
|
||||
to: name of bone to measure distance from
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
# Create control rig
|
||||
#control(obj, bone_definition, base_names, options)
|
||||
# Create deform rig
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
|
||||
return (None,)
|
||||
|
@ -1,481 +0,0 @@
|
||||
# ##### 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 = ("pelvis", "ribcage")
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('pelvis')
|
||||
bone.head[:] = 0.0000, -0.0306, 0.1039
|
||||
bone.tail[:] = 0.0000, -0.0306, -0.0159
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
bone = arm.edit_bones.new('rib_cage')
|
||||
bone.head[:] = 0.0000, -0.0306, 0.1039
|
||||
bone.tail[:] = 0.0000, -0.0306, 0.2236
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['pelvis']
|
||||
bone = arm.edit_bones.new('spine.01')
|
||||
bone.head[:] = 0.0000, 0.0000, -0.0000
|
||||
bone.tail[:] = 0.0000, -0.0306, 0.1039
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['rib_cage']
|
||||
bone = arm.edit_bones.new('spine.02')
|
||||
bone.head[:] = 0.0000, -0.0306, 0.1039
|
||||
bone.tail[:] = -0.0000, -0.0398, 0.2045
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['spine.01']
|
||||
bone = arm.edit_bones.new('spine.03')
|
||||
bone.head[:] = -0.0000, -0.0398, 0.2045
|
||||
bone.tail[:] = -0.0000, -0.0094, 0.2893
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['spine.02']
|
||||
bone = arm.edit_bones.new('spine.04')
|
||||
bone.head[:] = -0.0000, -0.0094, 0.2893
|
||||
bone.tail[:] = -0.0000, 0.0335, 0.3595
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['spine.03']
|
||||
bone = arm.edit_bones.new('spine.05')
|
||||
bone.head[:] = -0.0000, 0.0335, 0.3595
|
||||
bone.tail[:] = -0.0000, 0.0555, 0.4327
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['spine.04']
|
||||
bone = arm.edit_bones.new('spine.06')
|
||||
bone.head[:] = -0.0000, 0.0555, 0.4327
|
||||
bone.tail[:] = -0.0000, 0.0440, 0.5207
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['spine.05']
|
||||
bone = arm.edit_bones.new('spine.07')
|
||||
bone.head[:] = -0.0000, 0.0440, 0.5207
|
||||
bone.tail[:] = -0.0000, 0.0021, 0.5992
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['spine.06']
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['rib_cage']
|
||||
pbone['type'] = 'spine_pivot_flex'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
'''
|
||||
The bone given is the second in a chain.
|
||||
Expects at least 1 parent and a chain of children withe the same basename
|
||||
eg.
|
||||
pelvis -> rib_cage -> spine.01 -> spine.02 -> spine.03
|
||||
|
||||
note: same as neck.
|
||||
'''
|
||||
arm = obj.data
|
||||
ribcage = arm.bones[orig_bone_name]
|
||||
pelvis = ribcage.parent
|
||||
|
||||
if pelvis is None:
|
||||
raise RigifyError("expected the ribcage bone:'%s' to have a parent (ribcage)." % ribcage.name)
|
||||
|
||||
children = ribcage.children
|
||||
if len(children) != 1:
|
||||
raise RigifyError("expected the ribcage to have only 1 child.")
|
||||
|
||||
child = children[0]
|
||||
|
||||
bone_definition = [pelvis.name, ribcage.name, child.name]
|
||||
bone_definition.extend([child.name for child in child.children_recursive_basename])
|
||||
return bone_definition
|
||||
|
||||
|
||||
def fk(*args):
|
||||
main(*args)
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
from mathutils import Vector, Matrix
|
||||
from math import radians, pi
|
||||
|
||||
arm = obj.data
|
||||
|
||||
# Initialize container classes for convenience
|
||||
mt = bone_class_instance(obj, ["pelvis", "ribcage"]) # meta
|
||||
mt.pelvis = bone_definition[0]
|
||||
mt.ribcage = bone_definition[1]
|
||||
mt.update()
|
||||
|
||||
spine_chain_orig = tuple(bone_definition[2:])
|
||||
spine_chain = [arm.edit_bones[child_name] for child_name in spine_chain_orig]
|
||||
spine_chain_basename = base_names[spine_chain[0].name].rsplit(".", 1)[0] # probably 'ORG-spine.01' -> 'spine'
|
||||
spine_chain_len = len(spine_chain_orig)
|
||||
|
||||
child = spine_chain[0]
|
||||
spine_chain_segment_length = child.length
|
||||
#child.parent = mt.pelvis_e # was mt.ribcage
|
||||
|
||||
# The first bone in the chain happens to be the basis of others, create them now
|
||||
ex = bone_class_instance(obj, ["pelvis_copy", "ribcage_hinge", "ribcage_copy", "spine_rotate"])
|
||||
|
||||
ex.pelvis_copy_e = copy_bone_simple(arm, mt.pelvis, base_names[mt.pelvis]) # no parent
|
||||
ex.pelvis_copy = ex.pelvis_copy_e.name
|
||||
ex.pelvis_copy_e.use_local_location = False
|
||||
|
||||
# copy the pelvis, offset to make MCH-spine_rotate and MCH-ribcage_hinge
|
||||
ex.ribcage_hinge_e = copy_bone_simple(arm, mt.pelvis, "MCH-%s_hinge" % base_names[mt.ribcage])
|
||||
ex.ribcage_hinge = ex.ribcage_hinge_e.name
|
||||
ex.ribcage_hinge_e.translate(Vector((0.0, spine_chain_segment_length / 4.0, 0.0)))
|
||||
|
||||
ex.spine_rotate_e = copy_bone_simple(arm, mt.ribcage, "MCH-%s_rotate" % spine_chain_basename)
|
||||
ex.spine_rotate = ex.spine_rotate_e.name
|
||||
ex.spine_rotate_e.translate(Vector((0.0, spine_chain_segment_length / 2.0, 0.0)))
|
||||
ex.spine_rotate_e.use_connect = False
|
||||
ex.spine_rotate_e.parent = ex.pelvis_copy_e
|
||||
|
||||
|
||||
# Copy the last bone now
|
||||
child = spine_chain[-1]
|
||||
|
||||
ex.ribcage_copy_e = copy_bone_simple(arm, mt.ribcage, base_names[mt.ribcage])
|
||||
ex.ribcage_copy = ex.ribcage_copy_e.name
|
||||
ex.ribcage_copy_e.use_connect = False
|
||||
ex.ribcage_copy_e.parent = ex.ribcage_hinge_e
|
||||
|
||||
spine_chain = [child.name for child in spine_chain]
|
||||
|
||||
# We have 3 spine chains
|
||||
# - original (ORG_*)
|
||||
# - copy (*use original name*)
|
||||
# - reverse (MCH-rev_*)
|
||||
spine_chain_attrs = [("spine_%.2d" % (i + 1)) for i in range(spine_chain_len)]
|
||||
|
||||
mt_chain = bone_class_instance(obj, spine_chain_attrs) # ORG_*
|
||||
rv_chain = bone_class_instance(obj, spine_chain_attrs) # *
|
||||
ex_chain = bone_class_instance(obj, spine_chain_attrs) # MCH-rev_*
|
||||
del spine_chain_attrs
|
||||
|
||||
for i, child_name in enumerate(spine_chain):
|
||||
child_name_orig = base_names[spine_chain_orig[i]]
|
||||
|
||||
attr = mt_chain.attr_names[i] # eg. spine_04
|
||||
|
||||
setattr(mt_chain, attr, spine_chain_orig[i]) # the original bone
|
||||
|
||||
ebone = copy_bone_simple(arm, child_name, child_name_orig) # use the original name
|
||||
setattr(ex_chain, attr, ebone.name)
|
||||
|
||||
ebone = copy_bone_simple(arm, child_name, "MCH-rev_%s" % child_name_orig)
|
||||
setattr(rv_chain, attr, ebone.name)
|
||||
ebone.use_connect = False
|
||||
|
||||
mt_chain.update()
|
||||
ex_chain.update()
|
||||
rv_chain.update()
|
||||
|
||||
# Now we need to re-parent these chains
|
||||
for i, child_name in enumerate(spine_chain_orig):
|
||||
attr = ex_chain.attr_names[i] + "_e"
|
||||
ebone = getattr(ex_chain, attr)
|
||||
if i == 0:
|
||||
ebone.use_connect = False
|
||||
ebone.parent = ex.pelvis_copy_e
|
||||
else:
|
||||
attr_parent = ex_chain.attr_names[i - 1] + "_e"
|
||||
ebone.parent = getattr(ex_chain, attr_parent)
|
||||
|
||||
# intentional! get the parent from the other parallel chain member
|
||||
getattr(rv_chain, attr).parent = ebone
|
||||
|
||||
|
||||
# ex_chain needs to interlace bones!
|
||||
# Note, skip the first bone
|
||||
for i in range(1, spine_chain_len): # similar to neck
|
||||
child_name_orig = base_names[spine_chain_orig[i]]
|
||||
spine_e = getattr(mt_chain, mt_chain.attr_names[i] + "_e")
|
||||
|
||||
# dont store parent names, re-reference as each chain bones parent.
|
||||
spine_e_parent = arm.edit_bones.new("MCH-rot_%s" % child_name_orig)
|
||||
spine_e_parent.head = spine_e.head
|
||||
spine_e_parent.tail = spine_e.head + (mt.ribcage_e.vector.normalize() * spine_chain_segment_length / 2.0)
|
||||
spine_e_parent.roll = mt.ribcage_e.roll
|
||||
|
||||
|
||||
spine_e = getattr(ex_chain, ex_chain.attr_names[i] + "_e")
|
||||
orig_parent = spine_e.parent
|
||||
spine_e.use_connect = False
|
||||
spine_e.parent = spine_e_parent
|
||||
spine_e_parent.use_connect = False
|
||||
|
||||
spine_e_parent.parent = orig_parent
|
||||
|
||||
|
||||
# Rotate the rev chain 180 about the by the first bones center point
|
||||
pivot = (rv_chain.spine_01_e.head + rv_chain.spine_01_e.tail) * 0.5
|
||||
matrix = Matrix.Rotation(radians(180), 3, 'X')
|
||||
for i, attr in enumerate(rv_chain.attr_names): # similar to neck
|
||||
spine_e = getattr(rv_chain, attr + "_e")
|
||||
# use the first bone as the pivot
|
||||
|
||||
spine_e.head = ((spine_e.head - pivot) * matrix) + pivot
|
||||
spine_e.tail = ((spine_e.tail - pivot) * matrix) + pivot
|
||||
spine_e.roll += pi # 180d roll
|
||||
del spine_e
|
||||
|
||||
deform(obj, bone_definition, base_names, options)
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# refresh pose bones
|
||||
mt.update()
|
||||
ex.update()
|
||||
mt_chain.update()
|
||||
ex_chain.update()
|
||||
rv_chain.update()
|
||||
|
||||
# Axis locks
|
||||
ex.ribcage_copy_p.lock_location = True, True, True
|
||||
|
||||
con = ex.ribcage_hinge_p.constraints.new('COPY_ROTATION')
|
||||
con.name = "hinge"
|
||||
con.target = obj
|
||||
con.subtarget = ex.pelvis_copy
|
||||
|
||||
# add driver
|
||||
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 = ex.ribcage_copy_p.path_from_id() + '["hinge"]'
|
||||
|
||||
mod = fcurve.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = 1.0
|
||||
mod.coefficients[1] = -1.0
|
||||
|
||||
con = ex.spine_rotate_p.constraints.new('COPY_ROTATION')
|
||||
con.target = obj
|
||||
con.subtarget = ex.ribcage_copy
|
||||
|
||||
# ex.pelvis_copy_p / rib_cage
|
||||
con = ex.ribcage_copy_p.constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = ex.pelvis_copy
|
||||
con.head_tail = 0.0
|
||||
|
||||
# This stores all important ID props
|
||||
prop = rna_idprop_ui_prop_get(ex.ribcage_copy_p, "hinge", create=True)
|
||||
ex.ribcage_copy_p["hinge"] = 1.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
|
||||
prop = rna_idprop_ui_prop_get(ex.ribcage_copy_p, "pivot_slide", create=True)
|
||||
ex.ribcage_copy_p["pivot_slide"] = 1.0 / spine_chain_len
|
||||
prop["soft_min"] = 1.0 / spine_chain_len
|
||||
prop["soft_max"] = 1.0
|
||||
|
||||
|
||||
# Create a fake connected parent/child relationship with bone location constraints
|
||||
# positioned at the tip.
|
||||
|
||||
# reverse bones / MCH-rev_spine.##
|
||||
for i in range(1, spine_chain_len):
|
||||
spine_p = getattr(rv_chain, rv_chain.attr_names[i] + "_p")
|
||||
spine_fake_parent_name = getattr(rv_chain, rv_chain.attr_names[i - 1])
|
||||
|
||||
con = spine_p.constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = spine_fake_parent_name
|
||||
con.head_tail = 1.0
|
||||
del spine_p, spine_fake_parent_name, con
|
||||
|
||||
|
||||
# Constrain 'inbetween' bones
|
||||
target_names = [("b%.2d" % (i + 1)) for i in range(spine_chain_len - 1)]
|
||||
rib_driver_path = ex.ribcage_copy_p.path_from_id()
|
||||
|
||||
ex.ribcage_copy_p["bend_tot"] = 0.0
|
||||
fcurve = ex.ribcage_copy_p.driver_add('["bend_tot"]')
|
||||
driver = fcurve.driver
|
||||
driver.type = 'SUM'
|
||||
fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier
|
||||
|
||||
for i in range(spine_chain_len - 1):
|
||||
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 = rib_driver_path + ('["bend_%.2d"]' % (i + 1))
|
||||
|
||||
for i in range(1, spine_chain_len):
|
||||
|
||||
# Add bend prop
|
||||
prop_name = "bend_%.2d" % i
|
||||
prop = rna_idprop_ui_prop_get(ex.ribcage_copy_p, prop_name, create=True)
|
||||
if ("bend_%.2d" % i) in options:
|
||||
ex.ribcage_copy_p[prop_name] = options["bend_%.2d" % i]
|
||||
else:
|
||||
ex.ribcage_copy_p[prop_name] = 1.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
|
||||
spine_p = getattr(ex_chain, ex_chain.attr_names[i] + "_p")
|
||||
spine_p_parent = spine_p.parent # interlaced bone
|
||||
|
||||
con = spine_p_parent.constraints.new('COPY_ROTATION')
|
||||
con.target = obj
|
||||
con.subtarget = ex.spine_rotate
|
||||
con.owner_space = 'LOCAL'
|
||||
con.target_space = 'LOCAL'
|
||||
del spine_p
|
||||
|
||||
# add driver
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'SCRIPTED'
|
||||
driver.expression = "bend/bend_tot"
|
||||
|
||||
fcurve.modifiers.remove(fcurve.modifiers[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 = rib_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 = rib_driver_path + ('["%s"]' % prop_name)
|
||||
|
||||
|
||||
|
||||
# original bone drivers
|
||||
# note: the first bone has a lot more constraints, but also this simple one is first.
|
||||
for i, attr in enumerate(mt_chain.attr_names):
|
||||
spine_p = getattr(mt_chain, attr + "_p")
|
||||
|
||||
con = spine_p.constraints.new('COPY_ROTATION')
|
||||
con.target = obj
|
||||
con.subtarget = getattr(ex_chain, attr) # lock to the copy's rotation
|
||||
del spine_p
|
||||
|
||||
# pivot slide: - lots of copy location constraints.
|
||||
|
||||
con = mt_chain.spine_01_p.constraints.new('COPY_LOCATION')
|
||||
con.name = "base"
|
||||
con.target = obj
|
||||
con.subtarget = rv_chain.spine_01 # lock to the reverse location
|
||||
|
||||
for i in range(1, spine_chain_len + 1):
|
||||
con = mt_chain.spine_01_p.constraints.new('COPY_LOCATION')
|
||||
con.name = "slide_%d" % i
|
||||
con.target = obj
|
||||
|
||||
if i == spine_chain_len:
|
||||
attr = mt_chain.attr_names[i - 1]
|
||||
else:
|
||||
attr = mt_chain.attr_names[i]
|
||||
|
||||
con.subtarget = getattr(rv_chain, attr) # lock to the reverse location
|
||||
|
||||
if i == spine_chain_len:
|
||||
con.head_tail = 1.0
|
||||
|
||||
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 = rib_driver_path + '["pivot_slide"]'
|
||||
|
||||
mod = fcurve.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = - (i - 1)
|
||||
mod.coefficients[1] = spine_chain_len
|
||||
|
||||
|
||||
# Set pelvis and ribcage controls to use the first and last bone in the
|
||||
# spine respectively for their custom shape transform
|
||||
ex.ribcage_copy_p.custom_shape_transform = obj.pose.bones[bone_definition[len(bone_definition)-1]]
|
||||
ex.pelvis_copy_p.custom_shape_transform = obj.pose.bones[bone_definition[2]]
|
||||
|
||||
|
||||
# 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]].layers)
|
||||
for attr in ex.attr_names:
|
||||
getattr(ex, attr + "_b").layers = layer
|
||||
for attr in ex_chain.attr_names:
|
||||
getattr(ex_chain, attr + "_b").layers = layer
|
||||
for attr in rv_chain.attr_names:
|
||||
getattr(rv_chain, attr + "_b").layers = layer
|
||||
|
||||
layer = list(arm.bones[bone_definition[1]].layers)
|
||||
arm.bones[ex.pelvis_copy].layers = layer
|
||||
arm.bones[ex.ribcage_copy].layers = layer
|
||||
|
||||
# no support for blending chains
|
||||
return None
|
@ -1,109 +0,0 @@
|
||||
# ##### 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 copy_bone_simple
|
||||
|
||||
METARIG_NAMES = tuple()
|
||||
RIG_TYPE = "stretch"
|
||||
|
||||
# TODO
|
||||
#def metarig_template():
|
||||
# # 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('Bone')
|
||||
# bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
# bone.tail[:] = 0.0000, 0.0000, 1.0000
|
||||
# bone.roll = 0.0000
|
||||
# bone.use_connect = False
|
||||
#
|
||||
# bpy.ops.object.mode_set(mode='OBJECT')
|
||||
# pbone = obj.pose.bones['Bone']
|
||||
# pbone['type'] = 'copy'
|
||||
|
||||
bool_map = {0: False, 1: True,
|
||||
0.0: False, 1.0: True,
|
||||
"false": False, "true": True,
|
||||
"False": False, "True": True,
|
||||
"no": False, "yes": True,
|
||||
"No": False, "Yes": True}
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
return (orig_bone_name,)
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
""" A stretchy bone from one bone to another.
|
||||
Deformation only (no controls).
|
||||
"""
|
||||
# Verify required parameter
|
||||
if "to" not in options:
|
||||
raise RigifyError("'%s' rig type requires a 'to' parameter (bone: %s)" % (RIG_TYPE, base_names[bone_definition[0]]))
|
||||
if type(options["to"]) is not str:
|
||||
raise RigifyError("'%s' rig type 'to' parameter must be a string (bone: %s)" % (RIG_TYPE, base_names[bone_definition[0]]))
|
||||
if ("ORG-" + options["to"]) not in obj.data.bones:
|
||||
raise RigifyError("'%s' rig type 'to' parameter must name a bone in the metarig (bone: %s)" % (RIG_TYPE, base_names[bone_definition[0]]))
|
||||
|
||||
preserve_volume = None
|
||||
# Check optional parameter
|
||||
if "preserve_volume" in options:
|
||||
try:
|
||||
preserve_volume = bool_map[options["preserve_volume"]]
|
||||
except KeyError:
|
||||
preserve_volume = False
|
||||
|
||||
eb = obj.data.edit_bones
|
||||
bb = obj.data.bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
arm = obj.data
|
||||
|
||||
mbone1 = bone_definition[0]
|
||||
mbone2 = "ORG-" + options["to"]
|
||||
|
||||
bone_e = copy_bone_simple(obj.data, mbone1, "DEF-%s" % base_names[bone_definition[0]])
|
||||
bone_e.use_connect = False
|
||||
bone_e.parent = eb[mbone1]
|
||||
bone_e.tail = eb[mbone2].head
|
||||
bone = bone_e.name
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Constraints
|
||||
con = pb[bone].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = mbone2
|
||||
|
||||
con = pb[bone].constraints.new('STRETCH_TO')
|
||||
con.target = obj
|
||||
con.subtarget = mbone2
|
||||
con.rest_length = bb[bone].length
|
||||
if preserve_volume:
|
||||
con.volume = 'VOLUME_XZX'
|
||||
else:
|
||||
con.volume = 'NO_VOLUME'
|
||||
|
||||
return tuple()
|
@ -1,152 +0,0 @@
|
||||
# ##### 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 copy_bone_simple
|
||||
|
||||
METARIG_NAMES = tuple()
|
||||
RIG_TYPE = "stretch_twist"
|
||||
|
||||
# TODO
|
||||
#def metarig_template():
|
||||
# # 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('Bone')
|
||||
# bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
# bone.tail[:] = 0.0000, 0.0000, 1.0000
|
||||
# bone.roll = 0.0000
|
||||
# bone.use_connect = False
|
||||
#
|
||||
# bpy.ops.object.mode_set(mode='OBJECT')
|
||||
# pbone = obj.pose.bones['Bone']
|
||||
# pbone['type'] = 'copy'
|
||||
|
||||
bool_map = {0:False, 1:True,
|
||||
0.0:False, 1.0:True,
|
||||
"false":False, "true":True,
|
||||
"False":False, "True":True,
|
||||
"no":False, "yes":True,
|
||||
"No":False, "Yes":True}
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
return (orig_bone_name,)
|
||||
|
||||
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
""" A dual-bone stretchy bone setup. Each half follows the twist of the
|
||||
bone on its side.
|
||||
Deformation only (no controls).
|
||||
"""
|
||||
# Verify required parameter
|
||||
if "to" not in options:
|
||||
raise RigifyError("'%s' rig type requires a 'to' parameter (bone: %s)" % (RIG_TYPE, base_names[0]))
|
||||
if type(options["to"]) is not str:
|
||||
raise RigifyError("'%s' rig type 'to' parameter must be a string (bone: %s)" % (RIG_TYPE, base_names[0]))
|
||||
if ("ORG-" + options["to"]) not in obj.data.bones:
|
||||
raise RigifyError("'%s' rig type 'to' parameter must name a bone in the metarig (bone: %s)" % (RIG_TYPE, base_names[0]))
|
||||
|
||||
preserve_volume = None
|
||||
# Check optional parameter
|
||||
if "preserve_volume" in options:
|
||||
try:
|
||||
preserve_volume = bool_map[options["preserve_volume"]]
|
||||
except KeyError:
|
||||
preserve_volume = False
|
||||
|
||||
eb = obj.data.edit_bones
|
||||
bb = obj.data.bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
arm = obj.data
|
||||
|
||||
mbone1 = bone_definition[0]
|
||||
mbone2 = "ORG-" + options["to"]
|
||||
|
||||
bone_e = copy_bone_simple(obj.data, mbone1, "MCH-%s" % base_names[bone_definition[0]])
|
||||
bone_e.use_connect = False
|
||||
bone_e.parent = None
|
||||
bone_e.head = (eb[mbone1].head + eb[mbone2].head) / 2
|
||||
bone_e.tail = (bone_e.head[0], bone_e.head[1], bone_e.head[2]+0.1)
|
||||
mid_bone = bone_e.name
|
||||
|
||||
bone_e = copy_bone_simple(obj.data, mbone1, "DEF-%s.01" % base_names[bone_definition[0]])
|
||||
bone_e.use_connect = False
|
||||
bone_e.parent = eb[mbone1]
|
||||
bone_e.tail = eb[mid_bone].head
|
||||
bone1 = bone_e.name
|
||||
|
||||
bone_e = copy_bone_simple(obj.data, mbone2, "DEF-%s.02" % base_names[bone_definition[0]])
|
||||
bone_e.use_connect = False
|
||||
bone_e.parent = eb[mbone2]
|
||||
bone_e.tail = eb[mid_bone].head
|
||||
bone2 = bone_e.name
|
||||
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Constraints
|
||||
|
||||
# Mid bone
|
||||
con = pb[mid_bone].constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = mbone1
|
||||
|
||||
con = pb[mid_bone].constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = mbone2
|
||||
con.influence = 0.5
|
||||
|
||||
# Bone 1
|
||||
con = pb[bone1].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = mid_bone
|
||||
|
||||
con = pb[bone1].constraints.new('STRETCH_TO')
|
||||
con.target = obj
|
||||
con.subtarget = mid_bone
|
||||
con.rest_length = bb[bone1].length
|
||||
if preserve_volume:
|
||||
con.volume = 'VOLUME_XZX'
|
||||
else:
|
||||
con.volume = 'NO_VOLUME'
|
||||
|
||||
# Bone 2
|
||||
con = pb[bone2].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = mid_bone
|
||||
|
||||
con = pb[bone2].constraints.new('STRETCH_TO')
|
||||
con.target = obj
|
||||
con.subtarget = mid_bone
|
||||
con.rest_length = bb[bone2].length
|
||||
if preserve_volume:
|
||||
con.volume = 'VOLUME_XZX'
|
||||
else:
|
||||
con.volume = 'NO_VOLUME'
|
||||
|
||||
return tuple()
|
||||
|
@ -1,165 +0,0 @@
|
||||
# ##### 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
|
||||
from mathutils import Vector, Matrix
|
||||
from math import radians, pi
|
||||
|
||||
# not used, defined for completeness
|
||||
METARIG_NAMES = ("pelvis", "ribcage")
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# TODO
|
||||
pass
|
||||
# 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('tail.01')
|
||||
#bone.head[:] = 0.0000, -0.0306, 0.1039
|
||||
#bone.tail[:] = 0.0000, -0.0306, -0.0159
|
||||
#bone.roll = 0.0000
|
||||
#bone.use_connect = False
|
||||
|
||||
#bpy.ops.object.mode_set(mode='OBJECT')
|
||||
#pbone = obj.pose.bones['tail.01']
|
||||
#pbone['type'] = 'tail_spline_ik'
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
""" Collects and returns the relevent bones for the rig.
|
||||
The bone given is the first in the chain of tail bones.
|
||||
It includes bones in the chain up until it hits a bone that doesn't
|
||||
have the same name base.
|
||||
|
||||
tail.01 -> tail.02 -> tail.03 -> ... -> tail.n
|
||||
"""
|
||||
arm = obj.data
|
||||
tail_base = arm.bones[orig_bone_name]
|
||||
|
||||
if tail_base.parent is None:
|
||||
raise RigifyError("'tail_control' rig type on bone '%s' requires a parent." % orig_bone_name)
|
||||
|
||||
bone_definitions = [tail_base.name]
|
||||
bone_definitions.extend([child.name for child in tail_base.children_recursive_basename])
|
||||
return bone_definitions
|
||||
|
||||
|
||||
def main(obj, bone_definitions, base_names, options):
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
arm = obj.data
|
||||
bb = obj.data.bones
|
||||
eb = obj.data.edit_bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
# Create bones for hinge/free
|
||||
# hinge 1 sticks with the parent
|
||||
# hinge 2 is the parent of the tail controls
|
||||
hinge1 = copy_bone_simple(arm, bone_definitions[0], "MCH-%s.hinge1" % base_names[bone_definitions[0]], parent=True).name
|
||||
hinge2 = copy_bone_simple(arm, bone_definitions[0], "MCH-%s.hinge2" % base_names[bone_definitions[0]], parent=False).name
|
||||
|
||||
# Create tail control bones
|
||||
bones = []
|
||||
i = 0
|
||||
for bone_def in bone_definitions:
|
||||
bone = copy_bone_simple(arm, bone_def, base_names[bone_def], parent=True).name
|
||||
if i == 1: # Don't change parent of first tail bone
|
||||
eb[bone].use_connect = False
|
||||
eb[bone].parent = eb[hinge2]
|
||||
eb[bone].use_local_location = False
|
||||
i = 1
|
||||
bones += [bone]
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Rotation mode and axis locks
|
||||
for bone, org_bone in zip(bones, bone_definitions):
|
||||
pb[bone].rotation_mode = pb[org_bone].rotation_mode
|
||||
pb[bone].lock_location = tuple(pb[org_bone].lock_location)
|
||||
pb[bone].lock_rotations_4d = pb[org_bone].lock_rotations_4d
|
||||
pb[bone].lock_rotation = tuple(pb[org_bone].lock_rotation)
|
||||
pb[bone].lock_rotation_w = pb[org_bone].lock_rotation_w
|
||||
pb[bone].lock_scale = tuple(pb[org_bone].lock_scale)
|
||||
|
||||
# Add custom properties
|
||||
pb[bones[0]]["hinge"] = 0.0
|
||||
prop = rna_idprop_ui_prop_get(pb[bones[0]], "hinge", create=True)
|
||||
prop["min"] = 0.0
|
||||
prop["max"] = 1.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
|
||||
pb[bones[0]]["free"] = 0.0
|
||||
prop = rna_idprop_ui_prop_get(pb[bones[0]], "free", create=True)
|
||||
prop["min"] = 0.0
|
||||
prop["max"] = 1.0
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
|
||||
# Add constraints
|
||||
for bone, org_bone in zip(bones, bone_definitions):
|
||||
con = pb[org_bone].constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = bone
|
||||
|
||||
con_f = pb[hinge2].constraints.new('COPY_LOCATION')
|
||||
con_f.target = obj
|
||||
con_f.subtarget = hinge1
|
||||
|
||||
con_h = pb[hinge2].constraints.new('COPY_TRANSFORMS')
|
||||
con_h.target = obj
|
||||
con_h.subtarget = hinge1
|
||||
|
||||
# Add drivers
|
||||
bone_path = pb[bones[0]].path_from_id()
|
||||
|
||||
driver_fcurve = con_f.driver_add("influence")
|
||||
driver = driver_fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.name = "free"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = bone_path + '["free"]'
|
||||
mod = driver_fcurve.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = 1.0
|
||||
mod.coefficients[1] = -1.0
|
||||
|
||||
driver_fcurve = con_h.driver_add("influence")
|
||||
driver = driver_fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
var = driver.variables.new()
|
||||
var.name = "hinge"
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = bone_path + '["hinge"]'
|
||||
mod = driver_fcurve.modifiers[0]
|
||||
mod.poly_order = 1
|
||||
mod.coefficients[0] = 1.0
|
||||
mod.coefficients[1] = -1.0
|
||||
|
||||
|
||||
return None
|
@ -1,361 +0,0 @@
|
||||
# ##### 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = False
|
||||
neck_e.parent = neck_e_parent
|
||||
neck_e_parent.use_connect = 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(fcurve.modifiers[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(fcurve.modifiers[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]].layers)
|
||||
for attr in ex_chain.attr_names:
|
||||
getattr(ex_chain, attr + "_b").layers = layer
|
||||
for attr in ex.attr_names:
|
||||
getattr(ex, attr + "_b").layers = layer
|
||||
|
||||
layer = list(arm.bones[bone_definition[1]].layers)
|
||||
ex.head_ctrl_b.layers = layer
|
||||
|
||||
|
||||
# no blending the result of this
|
||||
return None
|
||||
|
@ -1,110 +0,0 @@
|
||||
# ##### 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 copy_bone_simple
|
||||
|
||||
METARIG_NAMES = tuple()
|
||||
RIG_TYPE = "track_dual"
|
||||
|
||||
# TODO
|
||||
#def metarig_template():
|
||||
# # 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('Bone')
|
||||
# bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
# bone.tail[:] = 0.0000, 0.0000, 1.0000
|
||||
# bone.roll = 0.0000
|
||||
# bone.use_connect = False
|
||||
#
|
||||
# bpy.ops.object.mode_set(mode='OBJECT')
|
||||
# pbone = obj.pose.bones['Bone']
|
||||
# pbone['type'] = 'copy'
|
||||
|
||||
bool_map = {0: False, 1: True,
|
||||
0.0: False, 1.0: True,
|
||||
"false": False, "true": True,
|
||||
"False": False, "True": True,
|
||||
"no": False, "yes": True,
|
||||
"No": False, "Yes": True}
|
||||
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
return (orig_bone_name,)
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
""" A dual-bone track setup.
|
||||
Deformation only (no controls).
|
||||
"""
|
||||
# Verify required parameter
|
||||
if "to" not in options:
|
||||
raise RigifyError("'%s' rig type requires a 'to' parameter (bone: %s)" % (RIG_TYPE, base_names[0]))
|
||||
if type(options["to"]) is not str:
|
||||
raise RigifyError("'%s' rig type 'to' parameter must be a string (bone: %s)" % (RIG_TYPE, base_names[0]))
|
||||
if ("ORG-" + options["to"]) not in obj.data.bones:
|
||||
raise RigifyError("'%s' rig type 'to' parameter must name a bone in the metarig (bone: %s)" % (RIG_TYPE, base_names[0]))
|
||||
|
||||
eb = obj.data.edit_bones
|
||||
bb = obj.data.bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
arm = obj.data
|
||||
|
||||
mbone1 = bone_definition[0]
|
||||
mbone2 = "ORG-" + options["to"]
|
||||
|
||||
bone_e = copy_bone_simple(obj.data, mbone1, "DEF-%s.01" % base_names[bone_definition[0]])
|
||||
bone_e.use_connect = False
|
||||
bone_e.parent = eb[mbone1]
|
||||
bone_e.tail = (eb[mbone1].head + eb[mbone2].head) / 2
|
||||
bone1 = bone_e.name
|
||||
|
||||
bone_e = copy_bone_simple(obj.data, mbone2, "DEF-%s.02" % base_names[bone_definition[0]])
|
||||
bone_e.use_connect = False
|
||||
bone_e.parent = eb[mbone1]
|
||||
bone_e.tail = (eb[mbone1].head + eb[mbone2].head) / 2
|
||||
bone2 = bone_e.name
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Constraints
|
||||
# Bone 1
|
||||
con = pb[bone1].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = mbone2
|
||||
|
||||
|
||||
# Bone 2
|
||||
con = pb[bone2].constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = mbone2
|
||||
|
||||
con = pb[bone2].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = mbone1
|
||||
|
||||
|
||||
return tuple()
|
@ -1,100 +0,0 @@
|
||||
# ##### 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 copy_bone_simple
|
||||
|
||||
METARIG_NAMES = tuple()
|
||||
RIG_TYPE = "track_reverse"
|
||||
|
||||
# TODO
|
||||
#def metarig_template():
|
||||
# # 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('Bone')
|
||||
# bone.head[:] = 0.0000, 0.0000, 0.0000
|
||||
# bone.tail[:] = 0.0000, 0.0000, 1.0000
|
||||
# bone.roll = 0.0000
|
||||
# bone.use_connect = False
|
||||
#
|
||||
# bpy.ops.object.mode_set(mode='OBJECT')
|
||||
# pbone = obj.pose.bones['Bone']
|
||||
# pbone['type'] = 'copy'
|
||||
|
||||
bool_map = {0:False, 1:True,
|
||||
0.0:False, 1.0:True,
|
||||
"false":False, "true":True,
|
||||
"False":False, "True":True,
|
||||
"no":False, "yes":True,
|
||||
"No":False, "Yes":True}
|
||||
|
||||
def metarig_definition(obj, orig_bone_name):
|
||||
return (orig_bone_name,)
|
||||
|
||||
|
||||
|
||||
|
||||
def main(obj, bone_definition, base_names, options):
|
||||
""" A bone that tracks bakwards towards its parent, while copying the
|
||||
location of it's target.
|
||||
Deformation only (no controls).
|
||||
"""
|
||||
# Verify required parameter
|
||||
if "to" not in options:
|
||||
raise RigifyError("'%s' rig type requires a 'to' parameter (bone: %s)" % (RIG_TYPE, base_names[0]))
|
||||
if type(options["to"]) is not str:
|
||||
raise RigifyError("'%s' rig type 'to' parameter must be a string (bone: %s)" % (RIG_TYPE, base_names[0]))
|
||||
if ("ORG-" + options["to"]) not in obj.data.bones:
|
||||
raise RigifyError("'%s' rig type 'to' parameter must name a bone in the metarig (bone: %s)" % (RIG_TYPE, base_names[0]))
|
||||
|
||||
eb = obj.data.edit_bones
|
||||
bb = obj.data.bones
|
||||
pb = obj.pose.bones
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
arm = obj.data
|
||||
|
||||
mbone1 = bone_definition[0]
|
||||
mbone2 = "ORG-" + options["to"]
|
||||
|
||||
bone_e = copy_bone_simple(obj.data, mbone2, "DEF-%s.02" % base_names[bone_definition[0]])
|
||||
bone_e.use_connect = False
|
||||
bone_e.parent = eb[mbone1]
|
||||
bone_e.tail = eb[mbone1].head
|
||||
bone = bone_e.name
|
||||
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
# Constraints
|
||||
con = pb[bone].constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = mbone2
|
||||
|
||||
con = pb[bone].constraints.new('DAMPED_TRACK')
|
||||
con.target = obj
|
||||
con.subtarget = mbone1
|
||||
|
||||
|
||||
return tuple()
|
@ -1,467 +0,0 @@
|
||||
# ##### 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>
|
||||
|
||||
# rigify its self does not depend on this module, however some of the
|
||||
# rigify templates use these utility functions.
|
||||
#
|
||||
# So even though this can be for general purpose use, this module was created
|
||||
# for rigify so in some cases seemingly generic functions make assumptions
|
||||
# that a generic function would need to check for.
|
||||
|
||||
import bpy
|
||||
from mathutils import Vector
|
||||
from rna_prop_ui import rna_idprop_ui_prop_get
|
||||
|
||||
DELIMITER = '-._'
|
||||
EMPTY_LAYER = [False] * 32
|
||||
|
||||
|
||||
def add_stretch_to(obj, from_name, to_name, name):
|
||||
'''
|
||||
Adds a bone that stretches from one to another
|
||||
'''
|
||||
|
||||
mode_orig = obj.mode
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
arm = obj.data
|
||||
stretch_ebone = arm.edit_bones.new(name)
|
||||
stretch_name = stretch_ebone.name
|
||||
del name
|
||||
|
||||
head = stretch_ebone.head = arm.edit_bones[from_name].head.copy()
|
||||
#tail = stretch_ebone.tail = arm.edit_bones[to_name].head.copy()
|
||||
|
||||
# annoying exception for zero length bones, since its using stretch_to the rest pose doesnt really matter
|
||||
#if (head - tail).length < 0.1:
|
||||
if 1:
|
||||
tail = stretch_ebone.tail = arm.edit_bones[from_name].tail.copy()
|
||||
|
||||
|
||||
# Now for the constraint
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
stretch_pbone = obj.pose.bones[stretch_name]
|
||||
|
||||
con = stretch_pbone.constraints.new('COPY_LOCATION')
|
||||
con.target = obj
|
||||
con.subtarget = from_name
|
||||
|
||||
con = stretch_pbone.constraints.new('STRETCH_TO')
|
||||
con.target = obj
|
||||
con.subtarget = to_name
|
||||
con.rest_length = (head - tail).length
|
||||
con.keep_axis = 'PLANE_X'
|
||||
con.volume = 'NO_VOLUME'
|
||||
|
||||
bpy.ops.object.mode_set(mode=mode_orig)
|
||||
|
||||
return stretch_name
|
||||
|
||||
|
||||
def copy_bone_simple(arm, from_bone, name, parent=False):
|
||||
ebone = arm.edit_bones[from_bone]
|
||||
ebone_new = arm.edit_bones.new(name)
|
||||
|
||||
if parent:
|
||||
ebone_new.use_connect = ebone.use_connect
|
||||
ebone_new.parent = ebone.parent
|
||||
|
||||
ebone_new.head = ebone.head
|
||||
ebone_new.tail = ebone.tail
|
||||
ebone_new.roll = ebone.roll
|
||||
ebone_new.layers = list(ebone.layers)
|
||||
return ebone_new
|
||||
|
||||
|
||||
def copy_bone_simple_list(arm, from_bones, to_bones, parent=False):
|
||||
|
||||
if len(from_bones) != len(to_bones):
|
||||
raise Exception("bone list sizes must match")
|
||||
|
||||
copy_bones = [copy_bone_simple(arm, bone_name, to_bones[i], True) for i, bone_name in enumerate(from_bones)]
|
||||
|
||||
# now we need to re-parent
|
||||
for ebone in copy_bones:
|
||||
parent = ebone.parent
|
||||
if parent:
|
||||
try:
|
||||
i = from_bones.index(parent.name)
|
||||
except:
|
||||
i = -1
|
||||
|
||||
if i == -1:
|
||||
ebone.parent = None
|
||||
else:
|
||||
ebone.parent = copy_bones[i]
|
||||
|
||||
return copy_bones
|
||||
|
||||
|
||||
def blend_bone_list(obj, apply_bones, from_bones, to_bones, target_bone=None, target_prop="blend", blend_default=0.5):
|
||||
|
||||
if obj.mode == 'EDIT':
|
||||
raise Exception("blending cant be called in editmode")
|
||||
|
||||
if len(apply_bones) != len(from_bones):
|
||||
raise Exception("lists differ in length (from -> apply): \n\t%s\n\t%s" % (from_bones, apply_bones))
|
||||
if len(apply_bones) != len(to_bones):
|
||||
raise Exception("lists differ in length (to -> apply): \n\t%s\n\t%s" % (to_bones, apply_bones))
|
||||
|
||||
# setup the blend property
|
||||
if target_bone is None:
|
||||
target_bone = apply_bones[-1] # default to the last bone
|
||||
|
||||
prop_pbone = obj.pose.bones[target_bone]
|
||||
if prop_pbone.get(target_bone) is None:
|
||||
prop = rna_idprop_ui_prop_get(prop_pbone, target_prop, create=True)
|
||||
prop_pbone[target_prop] = blend_default
|
||||
prop["soft_min"] = 0.0
|
||||
prop["soft_max"] = 1.0
|
||||
|
||||
driver_path = prop_pbone.path_from_id() + ('["%s"]' % target_prop)
|
||||
|
||||
def blend_target(driver):
|
||||
var = driver.variables.new()
|
||||
var.name = target_bone
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = driver_path
|
||||
|
||||
def blend_transforms(new_pbone, from_bone_name, to_bone_name):
|
||||
con = new_pbone.constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = from_bone_name
|
||||
|
||||
con = new_pbone.constraints.new('COPY_TRANSFORMS')
|
||||
con.target = obj
|
||||
con.subtarget = to_bone_name
|
||||
|
||||
fcurve = con.driver_add("influence")
|
||||
driver = fcurve.driver
|
||||
driver.type = 'AVERAGE'
|
||||
fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier
|
||||
|
||||
blend_target(driver)
|
||||
|
||||
for i, new_bone_name in enumerate(apply_bones):
|
||||
from_bone_name = from_bones[i]
|
||||
to_bone_name = to_bones[i]
|
||||
|
||||
# allow skipping some bones by having None in the list
|
||||
if None in (new_bone_name, from_bone_name, to_bone_name):
|
||||
continue
|
||||
|
||||
new_pbone = obj.pose.bones[new_bone_name]
|
||||
|
||||
blend_transforms(new_pbone, from_bone_name, to_bone_name)
|
||||
|
||||
|
||||
def add_pole_target_bone(obj, base_bone_name, name, mode='CROSS'):
|
||||
'''
|
||||
Does not actually create a poll target, just the bone to use as a poll target
|
||||
'''
|
||||
mode_orig = obj.mode
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
arm = obj.data
|
||||
|
||||
poll_ebone = arm.edit_bones.new(name)
|
||||
base_ebone = arm.edit_bones[base_bone_name]
|
||||
poll_name = poll_ebone.name
|
||||
parent_ebone = base_ebone.parent
|
||||
|
||||
base_head = base_ebone.head.copy()
|
||||
base_tail = base_ebone.tail.copy()
|
||||
base_dir = base_head - base_tail
|
||||
|
||||
parent_head = parent_ebone.head.copy()
|
||||
parent_tail = parent_ebone.tail.copy()
|
||||
parent_dir = parent_head - parent_tail
|
||||
|
||||
distance = (base_dir.length + parent_dir.length)
|
||||
|
||||
if mode == 'CROSS':
|
||||
# direction from the angle of the joint
|
||||
offset = base_dir.copy().normalize() - parent_dir.copy().normalize()
|
||||
offset.length = distance
|
||||
elif mode == 'ZAVERAGE':
|
||||
# between both bones Z axis
|
||||
z_axis_a = base_ebone.matrix.copy().rotation_part() * Vector((0.0, 0.0, -1.0))
|
||||
z_axis_b = parent_ebone.matrix.copy().rotation_part() * Vector((0.0, 0.0, -1.0))
|
||||
offset = (z_axis_a + z_axis_b).normalize() * distance
|
||||
else:
|
||||
# preset axis
|
||||
offset = Vector((0.0, 0.0, 0.0))
|
||||
if mode[0] == "+":
|
||||
val = distance
|
||||
else:
|
||||
val = - distance
|
||||
|
||||
setattr(offset, mode[1].lower(), val)
|
||||
|
||||
poll_ebone.head = base_head + offset
|
||||
poll_ebone.tail = base_head + (offset * (1.0 - (1.0 / 4.0)))
|
||||
|
||||
bpy.ops.object.mode_set(mode=mode_orig)
|
||||
|
||||
return poll_name
|
||||
|
||||
|
||||
def get_side_name(name):
|
||||
'''
|
||||
Returns the last part of a string (typically a bone's name) indicating
|
||||
whether it is a a left or right (or center, or whatever) bone.
|
||||
Returns an empty string if nothing is found.
|
||||
'''
|
||||
if name[-2] in DELIMITER:
|
||||
return name[-2:]
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
def get_base_name(name):
|
||||
'''
|
||||
Returns the part of a string (typically a bone's name) corresponding to it's
|
||||
base name (no sidedness, no ORG prefix).
|
||||
'''
|
||||
if name[-2] in DELIMITER:
|
||||
return name[:-2]
|
||||
else:
|
||||
return name
|
||||
|
||||
|
||||
def write_meta_rig(obj, func_name="metarig_template"):
|
||||
'''
|
||||
Write a metarig as a python script, this rig is to have all info needed for
|
||||
generating the real rig with rigify.
|
||||
'''
|
||||
code = []
|
||||
|
||||
code.append("def %s():" % func_name)
|
||||
code.append(" # generated by rigify.write_meta_rig")
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
code.append(" bpy.ops.object.mode_set(mode='EDIT')")
|
||||
|
||||
code.append(" obj = bpy.context.active_object")
|
||||
code.append(" arm = obj.data")
|
||||
|
||||
arm = obj.data
|
||||
# write parents first
|
||||
bones = [(len(bone.parent_recursive), bone.name) for bone in arm.edit_bones]
|
||||
bones.sort(key=lambda item: item[0])
|
||||
bones = [item[1] for item in bones]
|
||||
|
||||
|
||||
for bone_name in bones:
|
||||
bone = arm.edit_bones[bone_name]
|
||||
code.append(" bone = arm.edit_bones.new('%s')" % bone.name)
|
||||
code.append(" bone.head[:] = %.4f, %.4f, %.4f" % bone.head.to_tuple(4))
|
||||
code.append(" bone.tail[:] = %.4f, %.4f, %.4f" % bone.tail.to_tuple(4))
|
||||
code.append(" bone.roll = %.4f" % bone.roll)
|
||||
code.append(" bone.use_connect = %s" % str(bone.use_connect))
|
||||
if bone.parent:
|
||||
code.append(" bone.parent = arm.edit_bones['%s']" % bone.parent.name)
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
code.append("")
|
||||
code.append(" bpy.ops.object.mode_set(mode='OBJECT')")
|
||||
|
||||
for bone_name in bones:
|
||||
pbone = obj.pose.bones[bone_name]
|
||||
pbone_written = False
|
||||
|
||||
# Only 1 level of props, simple types supported
|
||||
for key, value in pbone.items():
|
||||
if key.startswith("_"):
|
||||
continue
|
||||
|
||||
if type(value) not in (float, str, int):
|
||||
print("Unsupported ID Prop:", str((key, value)))
|
||||
continue
|
||||
|
||||
if type(value) == str:
|
||||
value = "'" + value + "'"
|
||||
|
||||
if not pbone_written: # only write bones we need
|
||||
code.append(" pbone = obj.pose.bones['%s']" % bone_name)
|
||||
|
||||
code.append(" pbone['%s'] = %s" % (key, value))
|
||||
|
||||
return "\n".join(code)
|
||||
|
||||
|
||||
# *** bone class collection ***
|
||||
|
||||
|
||||
def bone_class_instance(obj, slots, name="BoneContainer"):
|
||||
'''
|
||||
bone collection utility class to help manage cases with
|
||||
edit/pose/bone bones where switching modes can invalidate some of the members.
|
||||
|
||||
there are also utility functions for manipulating all members.
|
||||
'''
|
||||
|
||||
attr_names = tuple(slots) # dont modify the original
|
||||
|
||||
if len(slots) != len(set(slots)):
|
||||
raise Exception("duplicate entries found %s" % attr_names)
|
||||
|
||||
slots = list(slots) # dont modify the original
|
||||
for i in range(len(slots)):
|
||||
member = slots[i]
|
||||
slots.append(member + "_b") # bone bone
|
||||
slots.append(member + "_p") # pose bone
|
||||
slots.append(member + "_e") # edit bone
|
||||
|
||||
class_dict = { \
|
||||
"obj": obj, \
|
||||
"attr_names": attr_names, \
|
||||
"attr_initialize": _bone_class_instance_attr_initialize, \
|
||||
"update": _bone_class_instance_update, \
|
||||
"rename": _bone_class_instance_rename, \
|
||||
"names": _bone_class_instance_names, \
|
||||
"copy": _bone_class_instance_copy, \
|
||||
"blend": _bone_class_instance_blend, \
|
||||
}
|
||||
|
||||
instance = auto_class_instance(slots, name, class_dict)
|
||||
return instance
|
||||
|
||||
|
||||
def auto_class(slots, name="ContainerClass", class_dict=None):
|
||||
|
||||
if class_dict:
|
||||
class_dict = class_dict.copy()
|
||||
else:
|
||||
class_dict = {}
|
||||
|
||||
class_dict["__slots__"] = tuple(slots)
|
||||
|
||||
return type(name, (object,), class_dict)
|
||||
|
||||
|
||||
def auto_class_instance(slots, name="ContainerClass", class_dict=None):
|
||||
return auto_class(slots, name, class_dict)()
|
||||
|
||||
|
||||
def _bone_class_instance_attr_initialize(self, attr_names, bone_names):
|
||||
''' Initializes attributes, both lists must be aligned
|
||||
'''
|
||||
for attr in self.attr_names:
|
||||
i = attr_names.index(attr)
|
||||
setattr(self, attr, bone_names[i])
|
||||
|
||||
self.update()
|
||||
|
||||
|
||||
def _bone_class_instance_update(self):
|
||||
''' Re-Assigns bones from the blender data
|
||||
'''
|
||||
arm = self.obj.data
|
||||
bbones = arm.bones
|
||||
pbones = self.obj.pose.bones
|
||||
ebones = arm.edit_bones
|
||||
|
||||
for member in self.attr_names:
|
||||
name = getattr(self, member, None)
|
||||
if name is not None:
|
||||
setattr(self, member + "_b", bbones.get(name))
|
||||
setattr(self, member + "_p", pbones.get(name))
|
||||
setattr(self, member + "_e", ebones.get(name))
|
||||
|
||||
|
||||
def _bone_class_instance_rename(self, attr, new_name):
|
||||
''' Rename bones, editmode only
|
||||
'''
|
||||
|
||||
if self.obj.mode != 'EDIT':
|
||||
raise Exception("Only rename in editmode supported")
|
||||
|
||||
ebone = getattr(self, attr + "_e")
|
||||
ebone.name = new_name
|
||||
|
||||
# we may not get what is asked for so get the name from the editbone
|
||||
setattr(self, attr, ebone.name)
|
||||
|
||||
|
||||
def _bone_class_instance_copy(self, from_fmt="%s", to_fmt="%s", exclude_attrs=(), base_names=None):
|
||||
from_name_ls = []
|
||||
new_name_ls = []
|
||||
new_slot_ls = []
|
||||
|
||||
for attr in self.attr_names:
|
||||
|
||||
if attr in exclude_attrs:
|
||||
continue
|
||||
|
||||
bone_name_orig = getattr(self, attr)
|
||||
ebone = getattr(self, attr + "_e")
|
||||
# orig_names[attr] = bone_name_orig
|
||||
|
||||
# insert formatting
|
||||
if from_fmt != "%s":
|
||||
bone_name = from_fmt % bone_name_orig
|
||||
ebone.name = bone_name
|
||||
bone_name = ebone.name # cant be sure we get what we ask for
|
||||
else:
|
||||
bone_name = bone_name_orig
|
||||
|
||||
setattr(self, attr, bone_name)
|
||||
|
||||
new_slot_ls.append(attr)
|
||||
from_name_ls.append(bone_name)
|
||||
if base_names:
|
||||
bone_name_orig = base_names[bone_name_orig]
|
||||
new_name_ls.append(to_fmt % bone_name_orig)
|
||||
|
||||
new_bones = copy_bone_simple_list(self.obj.data, from_name_ls, new_name_ls, True)
|
||||
new_bc = bone_class_instance(self.obj, new_slot_ls)
|
||||
|
||||
for i, attr in enumerate(new_slot_ls):
|
||||
ebone = new_bones[i]
|
||||
setattr(new_bc, attr + "_e", ebone)
|
||||
setattr(new_bc, attr, ebone.name)
|
||||
|
||||
return new_bc
|
||||
|
||||
|
||||
def _bone_class_instance_names(self):
|
||||
return [getattr(self, attr) for attr in self.attr_names]
|
||||
|
||||
|
||||
def _bone_class_instance_blend(self, from_bc, to_bc, target_bone=None, target_prop="blend"):
|
||||
'''
|
||||
Use for blending bone chains.
|
||||
|
||||
blend_target = (bone_name, bone_property)
|
||||
default to the last bone, blend prop
|
||||
|
||||
XXX - toggles editmode, need to re-validate all editbones :(
|
||||
'''
|
||||
|
||||
if self.attr_names != from_bc.attr_names or self.attr_names != to_bc.attr_names:
|
||||
raise Exception("can only blend between matching chains")
|
||||
|
||||
apply_bones = [getattr(self, attr) for attr in self.attr_names]
|
||||
from_bones = [getattr(from_bc, attr) for attr in from_bc.attr_names]
|
||||
to_bones = [getattr(to_bc, attr) for attr in to_bc.attr_names]
|
||||
|
||||
blend_bone_list(self.obj, apply_bones, from_bones, to_bones, target_bone, target_prop)
|
@ -1,616 +0,0 @@
|
||||
# ##### 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-80 compliant>
|
||||
import bpy
|
||||
import mathutils
|
||||
from math import cos, sin, pi
|
||||
|
||||
# could this be stored elsewhere?
|
||||
|
||||
|
||||
def metarig_template():
|
||||
# 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('pelvis')
|
||||
bone.head[:] = -0.0000, -0.0145, 1.1263
|
||||
bone.tail[:] = -0.0000, -0.0145, 0.9563
|
||||
bone.roll = 3.1416
|
||||
bone.use_connect = False
|
||||
bone = arm.edit_bones.new('torso')
|
||||
bone.head[:] = -0.0000, -0.0145, 1.1263
|
||||
bone.tail[:] = -0.0000, -0.0145, 1.2863
|
||||
bone.roll = 3.1416
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['pelvis']
|
||||
bone = arm.edit_bones.new('spine.01')
|
||||
bone.head[:] = 0.0000, 0.0394, 0.9688
|
||||
bone.tail[:] = -0.0000, -0.0145, 1.1263
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['torso']
|
||||
bone = arm.edit_bones.new('spine.02')
|
||||
bone.head[:] = -0.0000, -0.0145, 1.1263
|
||||
bone.tail[:] = -0.0000, -0.0213, 1.2884
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['spine.01']
|
||||
bone = arm.edit_bones.new('thigh.L')
|
||||
bone.head[:] = 0.0933, -0.0421, 1.0434
|
||||
bone.tail[:] = 0.0933, -0.0516, 0.5848
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['spine.01']
|
||||
bone = arm.edit_bones.new('thigh.R')
|
||||
bone.head[:] = -0.0933, -0.0421, 1.0434
|
||||
bone.tail[:] = -0.0933, -0.0516, 0.5848
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['spine.01']
|
||||
bone = arm.edit_bones.new('spine.03')
|
||||
bone.head[:] = -0.0000, -0.0213, 1.2884
|
||||
bone.tail[:] = -0.0000, 0.0160, 1.3705
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['spine.02']
|
||||
bone = arm.edit_bones.new('shin.L')
|
||||
bone.head[:] = 0.0933, -0.0516, 0.5848
|
||||
bone.tail[:] = 0.0915, 0.0100, 0.1374
|
||||
bone.roll = 0.0034
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['thigh.L']
|
||||
bone = arm.edit_bones.new('shin.R')
|
||||
bone.head[:] = -0.0933, -0.0516, 0.5848
|
||||
bone.tail[:] = -0.0915, 0.0100, 0.1374
|
||||
bone.roll = -0.0034
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['thigh.R']
|
||||
bone = arm.edit_bones.new('spine.04')
|
||||
bone.head[:] = -0.0000, 0.0160, 1.3705
|
||||
bone.tail[:] = -0.0000, 0.0590, 1.4497
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['spine.03']
|
||||
bone = arm.edit_bones.new('foot.L')
|
||||
bone.head[:] = 0.0915, 0.0100, 0.1374
|
||||
bone.tail[:] = 0.1033, -0.0968, 0.0510
|
||||
bone.roll = 2.8964
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['shin.L']
|
||||
bone = arm.edit_bones.new('foot.R')
|
||||
bone.head[:] = -0.0915, 0.0100, 0.1374
|
||||
bone.tail[:] = -0.1033, -0.0968, 0.0510
|
||||
bone.roll = -2.8793
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['shin.R']
|
||||
bone = arm.edit_bones.new('neck_base')
|
||||
bone.head[:] = -0.0000, 0.0590, 1.4497
|
||||
bone.tail[:] = -0.0000, 0.0401, 1.5389
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['spine.04']
|
||||
bone = arm.edit_bones.new('toe.L')
|
||||
bone.head[:] = 0.1033, -0.0968, 0.0510
|
||||
bone.tail[:] = 0.1136, -0.1848, 0.0510
|
||||
bone.roll = 0.0001
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['foot.L']
|
||||
bone = arm.edit_bones.new('heel.L')
|
||||
bone.head[:] = 0.0809, 0.0969, -0.0000
|
||||
bone.tail[:] = 0.1020, -0.0846, -0.0000
|
||||
bone.roll = -0.0001
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['foot.L']
|
||||
bone = arm.edit_bones.new('toe.R')
|
||||
bone.head[:] = -0.1033, -0.0968, 0.0510
|
||||
bone.tail[:] = -0.1136, -0.1848, 0.0510
|
||||
bone.roll = -0.0002
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['foot.R']
|
||||
bone = arm.edit_bones.new('heel.R')
|
||||
bone.head[:] = -0.0809, 0.0969, -0.0000
|
||||
bone.tail[:] = -0.1020, -0.0846, -0.0000
|
||||
bone.roll = -0.0000
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['foot.R']
|
||||
bone = arm.edit_bones.new('head')
|
||||
bone.head[:] = -0.0000, 0.0401, 1.5389
|
||||
bone.tail[:] = -0.0000, 0.0401, 1.5979
|
||||
bone.roll = 3.1416
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['neck_base']
|
||||
bone = arm.edit_bones.new('DLT-shoulder.L')
|
||||
bone.head[:] = 0.0141, -0.0346, 1.4991
|
||||
bone.tail[:] = 0.1226, 0.0054, 1.4991
|
||||
bone.roll = 0.0005
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['neck_base']
|
||||
bone = arm.edit_bones.new('DLT-shoulder.R')
|
||||
bone.head[:] = -0.0141, -0.0346, 1.4991
|
||||
bone.tail[:] = -0.1226, 0.0054, 1.4991
|
||||
bone.roll = -0.0005
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['neck_base']
|
||||
bone = arm.edit_bones.new('neck.01')
|
||||
bone.head[:] = -0.0000, 0.0401, 1.5389
|
||||
bone.tail[:] = -0.0000, 0.0176, 1.5916
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['head']
|
||||
bone = arm.edit_bones.new('shoulder.L')
|
||||
bone.head[:] = 0.0141, -0.0346, 1.4991
|
||||
bone.tail[:] = 0.1226, 0.0216, 1.5270
|
||||
bone.roll = -0.1225
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['DLT-shoulder.L']
|
||||
bone = arm.edit_bones.new('shoulder.R')
|
||||
bone.head[:] = -0.0141, -0.0346, 1.4991
|
||||
bone.tail[:] = -0.1226, 0.0216, 1.5270
|
||||
bone.roll = 0.0849
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['DLT-shoulder.R']
|
||||
bone = arm.edit_bones.new('neck.02')
|
||||
bone.head[:] = -0.0000, 0.0176, 1.5916
|
||||
bone.tail[:] = -0.0000, 0.0001, 1.6499
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['neck.01']
|
||||
bone = arm.edit_bones.new('DLT-upper_arm.L')
|
||||
bone.head[:] = 0.1482, 0.0483, 1.4943
|
||||
bone.tail[:] = 0.2586, 0.1057, 1.5124
|
||||
bone.roll = 1.4969
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['shoulder.L']
|
||||
bone = arm.edit_bones.new('DLT-upper_arm.R')
|
||||
bone.head[:] = -0.1482, 0.0483, 1.4943
|
||||
bone.tail[:] = -0.2586, 0.1057, 1.5124
|
||||
bone.roll = -1.4482
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['shoulder.R']
|
||||
bone = arm.edit_bones.new('neck.03')
|
||||
bone.head[:] = -0.0000, 0.0001, 1.6499
|
||||
bone.tail[:] = -0.0000, 0.0001, 1.8522
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['neck.02']
|
||||
bone = arm.edit_bones.new('upper_arm.L')
|
||||
bone.head[:] = 0.1482, 0.0483, 1.4943
|
||||
bone.tail[:] = 0.3929, 0.0522, 1.4801
|
||||
bone.roll = 1.6281
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['DLT-upper_arm.L']
|
||||
bone = arm.edit_bones.new('upper_arm.R')
|
||||
bone.head[:] = -0.1482, 0.0483, 1.4943
|
||||
bone.tail[:] = -0.3929, 0.0522, 1.4801
|
||||
bone.roll = -1.6281
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['DLT-upper_arm.R']
|
||||
bone = arm.edit_bones.new('forearm.L')
|
||||
bone.head[:] = 0.3929, 0.0522, 1.4801
|
||||
bone.tail[:] = 0.6198, 0.0364, 1.4906
|
||||
bone.roll = 1.5240
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['upper_arm.L']
|
||||
bone = arm.edit_bones.new('forearm.R')
|
||||
bone.head[:] = -0.3929, 0.0522, 1.4801
|
||||
bone.tail[:] = -0.6198, 0.0364, 1.4906
|
||||
bone.roll = -1.5219
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['upper_arm.R']
|
||||
bone = arm.edit_bones.new('hand.L')
|
||||
bone.head[:] = 0.6198, 0.0364, 1.4906
|
||||
bone.tail[:] = 0.6592, 0.0364, 1.4853
|
||||
bone.roll = -3.0065
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['forearm.L']
|
||||
bone = arm.edit_bones.new('hand.R')
|
||||
bone.head[:] = -0.6198, 0.0364, 1.4906
|
||||
bone.tail[:] = -0.6592, 0.0364, 1.4853
|
||||
bone.roll = 3.0065
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['forearm.R']
|
||||
bone = arm.edit_bones.new('palm.04.L')
|
||||
bone.head[:] = 0.6514, 0.0658, 1.4906
|
||||
bone.tail[:] = 0.7287, 0.0810, 1.4747
|
||||
bone.roll = -3.0715
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand.L']
|
||||
bone = arm.edit_bones.new('palm.03.L')
|
||||
bone.head[:] = 0.6533, 0.0481, 1.4943
|
||||
bone.tail[:] = 0.7386, 0.0553, 1.4781
|
||||
bone.roll = -3.0290
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand.L']
|
||||
bone = arm.edit_bones.new('palm.02.L')
|
||||
bone.head[:] = 0.6539, 0.0305, 1.4967
|
||||
bone.tail[:] = 0.7420, 0.0250, 1.4835
|
||||
bone.roll = -3.0669
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand.L']
|
||||
bone = arm.edit_bones.new('palm.01.L')
|
||||
bone.head[:] = 0.6514, 0.0116, 1.4961
|
||||
bone.tail[:] = 0.7361, -0.0074, 1.4823
|
||||
bone.roll = -2.9422
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand.L']
|
||||
bone = arm.edit_bones.new('thumb.01.L')
|
||||
bone.head[:] = 0.6380, -0.0005, 1.4848
|
||||
bone.tail[:] = 0.6757, -0.0408, 1.4538
|
||||
bone.roll = -0.7041
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand.L']
|
||||
bone = arm.edit_bones.new('palm.04.R')
|
||||
bone.head[:] = -0.6514, 0.0658, 1.4906
|
||||
bone.tail[:] = -0.7287, 0.0810, 1.4747
|
||||
bone.roll = 3.0715
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand.R']
|
||||
bone = arm.edit_bones.new('palm.03.R')
|
||||
bone.head[:] = -0.6533, 0.0481, 1.4943
|
||||
bone.tail[:] = -0.7386, 0.0553, 1.4781
|
||||
bone.roll = 3.0290
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand.R']
|
||||
bone = arm.edit_bones.new('palm.02.R')
|
||||
bone.head[:] = -0.6539, 0.0305, 1.4967
|
||||
bone.tail[:] = -0.7420, 0.0250, 1.4835
|
||||
bone.roll = 3.0669
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand.R']
|
||||
bone = arm.edit_bones.new('thumb.01.R')
|
||||
bone.head[:] = -0.6380, -0.0005, 1.4848
|
||||
bone.tail[:] = -0.6757, -0.0408, 1.4538
|
||||
bone.roll = 0.7041
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand.R']
|
||||
bone = arm.edit_bones.new('palm.01.R')
|
||||
bone.head[:] = -0.6514, 0.0116, 1.4961
|
||||
bone.tail[:] = -0.7361, -0.0074, 1.4823
|
||||
bone.roll = 2.9332
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones['hand.R']
|
||||
bone = arm.edit_bones.new('finger_pinky.01.L')
|
||||
bone.head[:] = 0.7287, 0.0810, 1.4747
|
||||
bone.tail[:] = 0.7698, 0.0947, 1.4635
|
||||
bone.roll = -3.0949
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['palm.04.L']
|
||||
bone = arm.edit_bones.new('finger_ring.01.L')
|
||||
bone.head[:] = 0.7386, 0.0553, 1.4781
|
||||
bone.tail[:] = 0.7890, 0.0615, 1.4667
|
||||
bone.roll = -3.0081
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['palm.03.L']
|
||||
bone = arm.edit_bones.new('finger_middle.01.L')
|
||||
bone.head[:] = 0.7420, 0.0250, 1.4835
|
||||
bone.tail[:] = 0.7975, 0.0221, 1.4712
|
||||
bone.roll = -2.9982
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['palm.02.L']
|
||||
bone = arm.edit_bones.new('finger_index.01.L')
|
||||
bone.head[:] = 0.7361, -0.0074, 1.4823
|
||||
bone.tail[:] = 0.7843, -0.0204, 1.4718
|
||||
bone.roll = -3.0021
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['palm.01.L']
|
||||
bone = arm.edit_bones.new('thumb.02.L')
|
||||
bone.head[:] = 0.6757, -0.0408, 1.4538
|
||||
bone.tail[:] = 0.6958, -0.0568, 1.4376
|
||||
bone.roll = -0.6963
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['thumb.01.L']
|
||||
bone = arm.edit_bones.new('finger_pinky.01.R')
|
||||
bone.head[:] = -0.7287, 0.0810, 1.4747
|
||||
bone.tail[:] = -0.7698, 0.0947, 1.4635
|
||||
bone.roll = 3.0949
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['palm.04.R']
|
||||
bone = arm.edit_bones.new('finger_ring.01.R')
|
||||
bone.head[:] = -0.7386, 0.0553, 1.4781
|
||||
bone.tail[:] = -0.7890, 0.0615, 1.4667
|
||||
bone.roll = 2.9892
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['palm.03.R']
|
||||
bone = arm.edit_bones.new('finger_middle.01.R')
|
||||
bone.head[:] = -0.7420, 0.0250, 1.4835
|
||||
bone.tail[:] = -0.7975, 0.0221, 1.4712
|
||||
bone.roll = 2.9816
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['palm.02.R']
|
||||
bone = arm.edit_bones.new('thumb.02.R')
|
||||
bone.head[:] = -0.6757, -0.0408, 1.4538
|
||||
bone.tail[:] = -0.6958, -0.0568, 1.4376
|
||||
bone.roll = 0.6963
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['thumb.01.R']
|
||||
bone = arm.edit_bones.new('finger_index.01.R')
|
||||
bone.head[:] = -0.7361, -0.0074, 1.4823
|
||||
bone.tail[:] = -0.7843, -0.0204, 1.4718
|
||||
bone.roll = 2.9498
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['palm.01.R']
|
||||
bone = arm.edit_bones.new('finger_pinky.02.L')
|
||||
bone.head[:] = 0.7698, 0.0947, 1.4635
|
||||
bone.tail[:] = 0.7910, 0.1018, 1.4577
|
||||
bone.roll = -3.0949
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_pinky.01.L']
|
||||
bone = arm.edit_bones.new('finger_ring.02.L')
|
||||
bone.head[:] = 0.7890, 0.0615, 1.4667
|
||||
bone.tail[:] = 0.8177, 0.0650, 1.4600
|
||||
bone.roll = -3.0006
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_ring.01.L']
|
||||
bone = arm.edit_bones.new('finger_middle.02.L')
|
||||
bone.head[:] = 0.7975, 0.0221, 1.4712
|
||||
bone.tail[:] = 0.8289, 0.0206, 1.4643
|
||||
bone.roll = -2.9995
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_middle.01.L']
|
||||
bone = arm.edit_bones.new('finger_index.02.L')
|
||||
bone.head[:] = 0.7843, -0.0204, 1.4718
|
||||
bone.tail[:] = 0.8117, -0.0275, 1.4660
|
||||
bone.roll = -3.0064
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_index.01.L']
|
||||
bone = arm.edit_bones.new('thumb.03.L')
|
||||
bone.head[:] = 0.6958, -0.0568, 1.4376
|
||||
bone.tail[:] = 0.7196, -0.0671, 1.4210
|
||||
bone.roll = -0.8072
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['thumb.02.L']
|
||||
bone = arm.edit_bones.new('finger_pinky.02.R')
|
||||
bone.head[:] = -0.7698, 0.0947, 1.4635
|
||||
bone.tail[:] = -0.7910, 0.1018, 1.4577
|
||||
bone.roll = 3.0949
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_pinky.01.R']
|
||||
bone = arm.edit_bones.new('finger_ring.02.R')
|
||||
bone.head[:] = -0.7890, 0.0615, 1.4667
|
||||
bone.tail[:] = -0.8177, 0.0650, 1.4600
|
||||
bone.roll = 3.0341
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_ring.01.R']
|
||||
bone = arm.edit_bones.new('finger_middle.02.R')
|
||||
bone.head[:] = -0.7975, 0.0221, 1.4712
|
||||
bone.tail[:] = -0.8289, 0.0206, 1.4643
|
||||
bone.roll = 3.0291
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_middle.01.R']
|
||||
bone = arm.edit_bones.new('thumb.03.R')
|
||||
bone.head[:] = -0.6958, -0.0568, 1.4376
|
||||
bone.tail[:] = -0.7196, -0.0671, 1.4210
|
||||
bone.roll = 0.8072
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['thumb.02.R']
|
||||
bone = arm.edit_bones.new('finger_index.02.R')
|
||||
bone.head[:] = -0.7843, -0.0204, 1.4718
|
||||
bone.tail[:] = -0.8117, -0.0275, 1.4660
|
||||
bone.roll = 3.0705
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_index.01.R']
|
||||
bone = arm.edit_bones.new('finger_pinky.03.L')
|
||||
bone.head[:] = 0.7910, 0.1018, 1.4577
|
||||
bone.tail[:] = 0.8109, 0.1085, 1.4523
|
||||
bone.roll = -3.0949
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_pinky.02.L']
|
||||
bone = arm.edit_bones.new('finger_ring.03.L')
|
||||
bone.head[:] = 0.8177, 0.0650, 1.4600
|
||||
bone.tail[:] = 0.8396, 0.0677, 1.4544
|
||||
bone.roll = -2.9819
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_ring.02.L']
|
||||
bone = arm.edit_bones.new('finger_middle.03.L')
|
||||
bone.head[:] = 0.8289, 0.0206, 1.4643
|
||||
bone.tail[:] = 0.8534, 0.0193, 1.4589
|
||||
bone.roll = -3.0004
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_middle.02.L']
|
||||
bone = arm.edit_bones.new('finger_index.03.L')
|
||||
bone.head[:] = 0.8117, -0.0275, 1.4660
|
||||
bone.tail[:] = 0.8331, -0.0333, 1.4615
|
||||
bone.roll = -3.0103
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_index.02.L']
|
||||
bone = arm.edit_bones.new('finger_pinky.03.R')
|
||||
bone.head[:] = -0.7910, 0.1018, 1.4577
|
||||
bone.tail[:] = -0.8109, 0.1085, 1.4523
|
||||
bone.roll = 3.0949
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_pinky.02.R']
|
||||
bone = arm.edit_bones.new('finger_ring.03.R')
|
||||
bone.head[:] = -0.8177, 0.0650, 1.4600
|
||||
bone.tail[:] = -0.8396, 0.0677, 1.4544
|
||||
bone.roll = 2.9819
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_ring.02.R']
|
||||
bone = arm.edit_bones.new('finger_middle.03.R')
|
||||
bone.head[:] = -0.8289, 0.0206, 1.4643
|
||||
bone.tail[:] = -0.8534, 0.0193, 1.4589
|
||||
bone.roll = 3.0004
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_middle.02.R']
|
||||
bone = arm.edit_bones.new('finger_index.03.R')
|
||||
bone.head[:] = -0.8117, -0.0275, 1.4660
|
||||
bone.tail[:] = -0.8331, -0.0333, 1.4615
|
||||
bone.roll = 2.9917
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones['finger_index.02.R']
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones['torso']
|
||||
pbone['type'] = 'spine_pivot_flex'
|
||||
pbone = obj.pose.bones['torso']
|
||||
pbone['spine_pivot_flex.later_main'] = 1
|
||||
pbone = obj.pose.bones['torso']
|
||||
pbone['spine_pivot_flex.layer_extra'] = 2
|
||||
pbone = obj.pose.bones['thigh.L']
|
||||
pbone['type'] = 'leg_biped'
|
||||
pbone = obj.pose.bones['thigh.L']
|
||||
pbone['leg_biped_generic.layer_ik'] = 12
|
||||
pbone = obj.pose.bones['thigh.L']
|
||||
pbone['leg_biped_generic.layer_fk'] = 11
|
||||
pbone = obj.pose.bones['thigh.R']
|
||||
pbone['type'] = 'leg_biped'
|
||||
pbone = obj.pose.bones['thigh.R']
|
||||
pbone['leg_biped_generic.layer_ik'] = 14
|
||||
pbone = obj.pose.bones['thigh.R']
|
||||
pbone['leg_biped_generic.layer_fk'] = 13
|
||||
pbone = obj.pose.bones['head']
|
||||
pbone['type'] = 'neck_flex'
|
||||
pbone = obj.pose.bones['head']
|
||||
pbone['neck_flex.layer_extra'] = 4
|
||||
pbone = obj.pose.bones['head']
|
||||
pbone['neck_flex.layer_main'] = 3
|
||||
pbone = obj.pose.bones['DLT-shoulder.L']
|
||||
pbone['type'] = 'delta'
|
||||
pbone = obj.pose.bones['DLT-shoulder.R']
|
||||
pbone['type'] = 'delta'
|
||||
pbone = obj.pose.bones['shoulder.L']
|
||||
pbone['type'] = 'copy'
|
||||
pbone = obj.pose.bones['shoulder.L']
|
||||
pbone['copy.layers'] = 1
|
||||
pbone = obj.pose.bones['shoulder.R']
|
||||
pbone['type'] = 'copy'
|
||||
pbone = obj.pose.bones['shoulder.R']
|
||||
pbone['copy.layers'] = 1
|
||||
pbone = obj.pose.bones['DLT-upper_arm.L']
|
||||
pbone['type'] = 'delta'
|
||||
pbone = obj.pose.bones['DLT-upper_arm.R']
|
||||
pbone['type'] = 'delta'
|
||||
pbone = obj.pose.bones['upper_arm.L']
|
||||
pbone['type'] = 'arm_biped'
|
||||
pbone = obj.pose.bones['upper_arm.L']
|
||||
pbone['arm_biped_generic.elbow_parent'] = 'spine.04'
|
||||
pbone = obj.pose.bones['upper_arm.L']
|
||||
pbone['arm_biped_generic.layer_fk'] = 7
|
||||
pbone = obj.pose.bones['upper_arm.L']
|
||||
pbone['arm_biped_generic.layer_ik'] = 8
|
||||
pbone = obj.pose.bones['upper_arm.R']
|
||||
pbone['type'] = 'arm_biped'
|
||||
pbone = obj.pose.bones['upper_arm.R']
|
||||
pbone['arm_biped_generic.layer_fk'] = 9
|
||||
pbone = obj.pose.bones['upper_arm.R']
|
||||
pbone['arm_biped_generic.layer_ik'] = 10
|
||||
pbone = obj.pose.bones['upper_arm.R']
|
||||
pbone['arm_biped_generic.elbow_parent'] = 'spine.04'
|
||||
pbone = obj.pose.bones['palm.01.L']
|
||||
pbone['type'] = 'palm_curl'
|
||||
pbone = obj.pose.bones['palm.01.L']
|
||||
pbone['palm_curl.layers'] = 5
|
||||
pbone = obj.pose.bones['thumb.01.L']
|
||||
pbone['type'] = 'finger_curl'
|
||||
pbone = obj.pose.bones['thumb.01.L']
|
||||
pbone['finger_curl.layer_main'] = 5
|
||||
pbone = obj.pose.bones['thumb.01.L']
|
||||
pbone['finger_curl.layer_extra'] = 6
|
||||
pbone = obj.pose.bones['thumb.01.R']
|
||||
pbone['type'] = 'finger_curl'
|
||||
pbone = obj.pose.bones['thumb.01.R']
|
||||
pbone['finger_curl.layer_main'] = 5
|
||||
pbone = obj.pose.bones['thumb.01.R']
|
||||
pbone['finger_curl.layer_extra'] = 6
|
||||
pbone = obj.pose.bones['palm.01.R']
|
||||
pbone['type'] = 'palm_curl'
|
||||
pbone = obj.pose.bones['palm.01.R']
|
||||
pbone['palm_curl.layers'] = 5
|
||||
pbone = obj.pose.bones['finger_pinky.01.L']
|
||||
pbone['type'] = 'finger_curl'
|
||||
pbone = obj.pose.bones['finger_pinky.01.L']
|
||||
pbone['finger_curl.layer_main'] = 5
|
||||
pbone = obj.pose.bones['finger_pinky.01.L']
|
||||
pbone['finger_curl.layer_extra'] = 6
|
||||
pbone = obj.pose.bones['finger_ring.01.L']
|
||||
pbone['type'] = 'finger_curl'
|
||||
pbone = obj.pose.bones['finger_ring.01.L']
|
||||
pbone['finger_curl.layer_main'] = 5
|
||||
pbone = obj.pose.bones['finger_ring.01.L']
|
||||
pbone['finger_curl.layer_extra'] = 6
|
||||
pbone = obj.pose.bones['finger_middle.01.L']
|
||||
pbone['type'] = 'finger_curl'
|
||||
pbone = obj.pose.bones['finger_middle.01.L']
|
||||
pbone['finger_curl.layer_main'] = 5
|
||||
pbone = obj.pose.bones['finger_middle.01.L']
|
||||
pbone['finger_curl.layer_extra'] = 6
|
||||
pbone = obj.pose.bones['finger_index.01.L']
|
||||
pbone['type'] = 'finger_curl'
|
||||
pbone = obj.pose.bones['finger_index.01.L']
|
||||
pbone['finger_curl.layer_main'] = 5
|
||||
pbone = obj.pose.bones['finger_index.01.L']
|
||||
pbone['finger_curl.layer_extra'] = 6
|
||||
pbone = obj.pose.bones['finger_pinky.01.R']
|
||||
pbone['type'] = 'finger_curl'
|
||||
pbone = obj.pose.bones['finger_pinky.01.R']
|
||||
pbone['finger_curl.layer_main'] = 5
|
||||
pbone = obj.pose.bones['finger_pinky.01.R']
|
||||
pbone['finger_curl.layer_extra'] = 6
|
||||
pbone = obj.pose.bones['finger_ring.01.R']
|
||||
pbone['type'] = 'finger_curl'
|
||||
pbone = obj.pose.bones['finger_ring.01.R']
|
||||
pbone['finger_curl.layer_main'] = 5
|
||||
pbone = obj.pose.bones['finger_ring.01.R']
|
||||
pbone['finger_curl.layer_extra'] = 6
|
||||
pbone = obj.pose.bones['finger_middle.01.R']
|
||||
pbone['type'] = 'finger_curl'
|
||||
pbone = obj.pose.bones['finger_middle.01.R']
|
||||
pbone['finger_curl.layer_main'] = 5
|
||||
pbone = obj.pose.bones['finger_middle.01.R']
|
||||
pbone['finger_curl.layer_extra'] = 6
|
||||
pbone = obj.pose.bones['finger_index.01.R']
|
||||
pbone['type'] = 'finger_curl'
|
||||
pbone = obj.pose.bones['finger_index.01.R']
|
||||
pbone['finger_curl.layer_main'] = 5
|
||||
pbone = obj.pose.bones['finger_index.01.R']
|
||||
pbone['finger_curl.layer_extra'] = 6
|
||||
|
||||
|
||||
class AddHuman(bpy.types.Operator):
|
||||
'''Add an advanced human metarig base'''
|
||||
bl_idname = "object.armature_human_advanced_add"
|
||||
bl_label = "Add Humanoid (advanced metarig)"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
bpy.ops.object.armature_add()
|
||||
obj = context.active_object
|
||||
mode_orig = obj.mode
|
||||
bpy.ops.object.mode_set(mode='EDIT') # grr, remove bone
|
||||
bones = context.active_object.data.edit_bones
|
||||
bones.remove(bones[0])
|
||||
metarig_template()
|
||||
bpy.ops.object.mode_set(mode=mode_orig)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# Add to a menu
|
||||
menu_func = (lambda self, context: self.layout.operator(AddHuman.bl_idname,
|
||||
icon='OUTLINER_OB_ARMATURE', text="Human (Meta-Rig)"))
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.INFO_MT_armature_add.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.INFO_MT_armature_add.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
@ -1,334 +0,0 @@
|
||||
# ##### 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 bpy.props import *
|
||||
|
||||
|
||||
class PoseTemplate(bpy.types.IDPropertyGroup):
|
||||
name = StringProperty(name="Name of the slave", description="", maxlen=64, default="")
|
||||
|
||||
|
||||
class PoseTemplateSettings(bpy.types.IDPropertyGroup):
|
||||
templates = CollectionProperty(type=PoseTemplate, name="Templates", description="")
|
||||
active_template_index = IntProperty(name="Index of the active slave", description="", default=-1, min=-1, max=65535)
|
||||
use_generate_deform_rig = BoolProperty(name="Create Deform Rig", description="Create a copy of the metarig, constrainted by the generated rig", default=False)
|
||||
|
||||
|
||||
def metarig_templates():
|
||||
import rigify
|
||||
return rigify.get_submodule_types()
|
||||
|
||||
|
||||
class DATA_PT_template(bpy.types.Panel):
|
||||
bl_label = "Meta-Rig Templates"
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "data"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
templates = []
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.armature:
|
||||
return False
|
||||
obj = context.object
|
||||
if obj:
|
||||
return (obj.mode in ('POSE', 'OBJECT'))
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
try:
|
||||
active_type = context.active_pose_bone["type"]
|
||||
except:
|
||||
active_type = None
|
||||
|
||||
scene = context.scene
|
||||
pose_templates = scene.pose_templates
|
||||
|
||||
if pose_templates.active_template_index == -1:
|
||||
pose_templates.active_template_index = 0
|
||||
|
||||
if not self.templates:
|
||||
self.templates[:] = metarig_templates()
|
||||
|
||||
while(len(pose_templates.templates) < len(self.templates)):
|
||||
pose_templates.templates.add()
|
||||
while(len(pose_templates.templates) > len(self.templates)):
|
||||
pose_templates.templates.remove(0)
|
||||
|
||||
for i, template_name in enumerate(self.templates):
|
||||
template = pose_templates.templates[i]
|
||||
if active_type == template_name:
|
||||
template.name = "<%s>" % template_name.replace("_", " ")
|
||||
else:
|
||||
template.name = " %s " % template_name.replace("_", " ")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("pose.metarig_generate", text="Generate")
|
||||
row.operator("pose.metarig_validate", text="Check")
|
||||
row.operator("pose.metarig_graph", text="Graph")
|
||||
row = layout.row()
|
||||
row.prop(pose_templates, "use_generate_deform_rig")
|
||||
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.template_list(pose_templates, "templates", pose_templates, "active_template_index", rows=1)
|
||||
|
||||
subrow = col.split(percentage=0.5, align=True)
|
||||
subsubrow = subrow.row(align=True)
|
||||
subsubrow.operator("pose.metarig_assign", text="Assign")
|
||||
subsubrow.operator("pose.metarig_clear", text="Clear")
|
||||
|
||||
if self.templates:
|
||||
subsubrow = subrow.split(percentage=0.8)
|
||||
subsubrow.operator("pose.metarig_sample_add", text="Sample").metarig_type = self.templates[pose_templates.active_template_index]
|
||||
subsubrow.operator("pose.metarig_sample_add", text="All").metarig_type = "" # self.templates[pose_templates.active_template_index]
|
||||
|
||||
sub = row.column(align=True)
|
||||
sub.operator("pose.metarig_reload", icon="FILE_REFRESH", text="")
|
||||
|
||||
|
||||
class Reload(bpy.types.Operator):
|
||||
'''Re-Scan the metarig package directory for scripts'''
|
||||
|
||||
bl_idname = "pose.metarig_reload"
|
||||
bl_label = "Re-Scan the list of metarig types"
|
||||
|
||||
def execute(self, context):
|
||||
DATA_PT_template.templates[:] = metarig_templates()
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def rigify_report_exception(operator, exception):
|
||||
import traceback
|
||||
import sys
|
||||
import os
|
||||
# find the module name where the error happened
|
||||
# hint, this is the metarig type!
|
||||
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
|
||||
fn = traceback.extract_tb(exceptionTraceback)[-1][0]
|
||||
fn = os.path.basename(fn)
|
||||
fn = os.path.splitext(fn)[0]
|
||||
message = []
|
||||
if fn.startswith("__"):
|
||||
message.append("Incorrect armature...")
|
||||
else:
|
||||
message.append("Incorrect armature for type '%s'" % fn)
|
||||
message.append(exception.message)
|
||||
|
||||
message.reverse() # XXX - stupid! menu's are upside down!
|
||||
|
||||
operator.report(set(['INFO']), '\n'.join(message))
|
||||
|
||||
|
||||
class Generate(bpy.types.Operator):
|
||||
'''Generates a metarig from the active armature'''
|
||||
|
||||
bl_idname = "pose.metarig_generate"
|
||||
bl_label = "Generate Metarig"
|
||||
|
||||
def execute(self, context):
|
||||
import rigify
|
||||
reload(rigify)
|
||||
|
||||
meta_def = context.scene.pose_templates.use_generate_deform_rig
|
||||
|
||||
try:
|
||||
rigify.generate_rig(context, context.object, META_DEF=meta_def)
|
||||
except rigify.RigifyError as rig_exception:
|
||||
rigify_report_exception(self, rig_exception)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class Validate(bpy.types.Operator):
|
||||
'''Validate a metarig from the active armature'''
|
||||
|
||||
bl_idname = "pose.metarig_validate"
|
||||
bl_label = "Validate Metarig"
|
||||
|
||||
def execute(self, context):
|
||||
import rigify
|
||||
reload(rigify)
|
||||
try:
|
||||
rigify.validate_rig(context, context.object)
|
||||
except rigify.RigifyError as rig_exception:
|
||||
rigify_report_exception(self, rig_exception)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class Sample(bpy.types.Operator):
|
||||
'''Create a sample metarig to be modified before generating the final rig.'''
|
||||
|
||||
bl_idname = "pose.metarig_sample_add"
|
||||
bl_label = "Re-Scan Metarig Scripts"
|
||||
|
||||
metarig_type = StringProperty(name="Type", description="Name of the rig type to generate a sample of, a blank string for all", maxlen=128, default="")
|
||||
|
||||
def execute(self, context):
|
||||
import rigify
|
||||
reload(rigify)
|
||||
final = (self.metarig_type == "")
|
||||
objects = rigify.generate_test(context, metarig_type=self.metarig_type, GENERATE_FINAL=final)
|
||||
|
||||
if len(objects) > 1:
|
||||
for i, (obj_meta, obj_gen) in enumerate(objects):
|
||||
obj_meta.location.x = i * 1.0
|
||||
if obj_gen:
|
||||
obj_gen.location.x = i * 1.0
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class Graph(bpy.types.Operator):
|
||||
'''Create a graph from the active armature through graphviz'''
|
||||
|
||||
bl_idname = "pose.metarig_graph"
|
||||
bl_label = "Pose Graph"
|
||||
|
||||
def execute(self, context):
|
||||
import os
|
||||
import graphviz_export
|
||||
import bpy
|
||||
reload(graphviz_export)
|
||||
obj = bpy.context.object
|
||||
if(bpy.data.filepath):
|
||||
path = os.path.splitext(bpy.data.filepath)[0] + "-" + bpy.path.clean_name(obj.name)
|
||||
else:
|
||||
import tempfile
|
||||
path = tempfile.mktemp(prefix=bpy.app.tempdir) + "-" + bpy.path.clean_name(obj.name)
|
||||
path_dot = path + ".dot"
|
||||
path_png = path + ".png"
|
||||
saved = graphviz_export.graph_armature(bpy.context.object, path_dot, CONSTRAINTS=False, DRIVERS=False)
|
||||
|
||||
if saved:
|
||||
# if we seriously want this working everywhere we'll need some new approach
|
||||
os.system("dot -Tpng %r > %r" % (path_dot, path_png))
|
||||
if not os.path.exists(path_png) or os.stat(path_png)[6] == 0:
|
||||
self.report('ERROR', "Graphvis could not create %r check graphviz is installed" % path_png)
|
||||
return {'CANCELLED'}
|
||||
|
||||
bpy.ops.image.external_edit(filepath=path_png)
|
||||
#os.system("python /b/xdot.py '%s' &" % path_dot)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class AsScript(bpy.types.Operator):
|
||||
'''Write the edit armature out as a python script'''
|
||||
|
||||
bl_idname = "pose.metarig_to_script"
|
||||
bl_label = "Write Metarig to Script"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
filepath = StringProperty(name="File Path", description="File path used for exporting the Armature file", maxlen=1024, default="")
|
||||
|
||||
def execute(self, context):
|
||||
import rigify_utils
|
||||
reload(rigify_utils)
|
||||
obj = context.object
|
||||
code = rigify_utils.write_meta_rig(obj)
|
||||
path = self.filepath
|
||||
file = open(path, "w")
|
||||
file.write(code)
|
||||
file.close()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
import os
|
||||
obj = context.object
|
||||
self.filepath = os.path.splitext(bpy.data.filepath)[0] + "-" + bpy.path.clean_name(obj.name) + ".py"
|
||||
wm = context.window_manager
|
||||
wm.add_fileselect(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
# operators that use the GUI
|
||||
class ActiveAssign(bpy.types.Operator):
|
||||
'''Assign to the active posebone'''
|
||||
|
||||
bl_idname = "pose.metarig_assign"
|
||||
bl_label = "Assign to the active posebone"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
bone = context.active_pose_bone
|
||||
return bool(bone and bone.id_data.mode == 'POSE')
|
||||
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
pose_templates = scene.pose_templates
|
||||
template_name = DATA_PT_template.templates[pose_templates.active_template_index]
|
||||
context.active_pose_bone["type"] = template_name
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class ActiveClear(bpy.types.Operator):
|
||||
'''Clear type from the active posebone'''
|
||||
|
||||
bl_idname = "pose.metarig_clear"
|
||||
bl_label = "Metarig Clear Type"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
bone = context.active_pose_bone
|
||||
return bool(bone and bone.id_data.mode == 'POSE')
|
||||
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
try:
|
||||
del context.active_pose_bone["type"]
|
||||
except:
|
||||
return {'CANCELLED'}
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class INFO_MT_armature_metarig_add(bpy.types.Menu):
|
||||
bl_idname = "INFO_MT_armature_metarig_add"
|
||||
bl_label = "Meta-Rig"
|
||||
|
||||
def draw(self, context):
|
||||
import rigify
|
||||
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
|
||||
for submodule_type in rigify.get_submodule_types():
|
||||
text = bpy.path.display_name(submodule_type)
|
||||
layout.operator("pose.metarig_sample_add", text=text, icon='OUTLINER_OB_ARMATURE').metarig_type = submodule_type
|
||||
|
||||
menu_func = (lambda self, context: self.layout.menu("INFO_MT_armature_metarig_add", icon='OUTLINER_OB_ARMATURE'))
|
||||
import space_info # ensure the menu is loaded first
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.pose_templates = PointerProperty(type=PoseTemplateSettings, name="Pose Templates", description="Pose Template Settings")
|
||||
space_info.INFO_MT_armature_add.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.pose_templates
|
||||
space_info.INFO_MT_armature_add.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
Loading…
x
Reference in New Issue
Block a user