Merge branch 'master' into xr-actions-D9124
This commit is contained in:
commit
27c29fbc18
|
@ -503,7 +503,8 @@ def automap(target_object=None, target_slot=None, tex_size=1, bg_exception=False
|
|||
if mat_props.automap:
|
||||
tob = bpy.data.objects[target_object]
|
||||
# only automap mesh models
|
||||
if tob.type == 'MESH':
|
||||
if tob.type == 'MESH' and len(tob.data.polygons)>0:
|
||||
#check polycount for a rare case where no polys are in editmesh
|
||||
actob = bpy.context.active_object
|
||||
bpy.context.view_layer.objects.active = tob
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ import ntpath
|
|||
import re
|
||||
import shutil
|
||||
import pathlib
|
||||
import stat
|
||||
|
||||
|
||||
import time
|
||||
|
@ -59,7 +60,7 @@ from bpy.props import (
|
|||
StringProperty,
|
||||
PointerProperty,
|
||||
)
|
||||
|
||||
only_one_time = True
|
||||
global_exchange_folder = ''
|
||||
foundExchangeFolder = True
|
||||
saved_exchange_folder = ''
|
||||
|
@ -72,6 +73,11 @@ def every_3_seconds():
|
|||
global global_exchange_folder
|
||||
global liveUpdate
|
||||
global mTime
|
||||
global only_one_time
|
||||
|
||||
if(only_one_time):
|
||||
only_one_time = False
|
||||
folders.loadExchangeFolder()
|
||||
|
||||
|
||||
try:
|
||||
|
@ -87,9 +93,6 @@ def every_3_seconds():
|
|||
tex.updatetextures(objekti)
|
||||
|
||||
mTime = os.path.getmtime(Export_folder)
|
||||
|
||||
if (os.path.normpath(global_exchange_folder) != os.path.normpath(coat3D.exchangeFolder) and coat3D.exchangeFolder != ''):
|
||||
folders.updateExchangeFile(coat3D.exchangeFolder)
|
||||
|
||||
except:
|
||||
pass
|
||||
|
@ -222,7 +225,7 @@ class SCENE_OT_getback(bpy.types.Operator):
|
|||
bl_label = "Export your custom property"
|
||||
bl_description = "Export your custom property"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
|
||||
def invoke(self, context, event):
|
||||
|
||||
global global_exchange_folder
|
||||
|
@ -255,6 +258,32 @@ class SCENE_OT_getback(bpy.types.Operator):
|
|||
|
||||
return {'FINISHED'}
|
||||
|
||||
class SCENE_OT_savenew(bpy.types.Operator):
|
||||
bl_idname = "save_new_export.pilgway_3d_coat"
|
||||
bl_label = "Export your custom property"
|
||||
bl_description = "Export your custom property"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
|
||||
coat3D = bpy.context.scene.coat3D
|
||||
platform = os.sys.platform
|
||||
|
||||
if(platform == 'win32' or platform == 'darwin'):
|
||||
exchangeFile = os.path.expanduser("~") + os.sep + 'Documents' + os.sep + '3DC2Blender' + os.sep + 'Exchange_folder.txt'
|
||||
else:
|
||||
exchangeFile = os.path.expanduser("~") + os.sep + '3DC2Blender' + os.sep + 'Exchange_folder.txt'
|
||||
if(os.path.isfile(exchangeFile)):
|
||||
folderPath = ''
|
||||
|
||||
if(os.path.isfile(exchangeFile)):
|
||||
file = open(exchangeFile, "w")
|
||||
file.write("%s"%(coat3D.exchangeFolder))
|
||||
file.close()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class SCENE_OT_folder(bpy.types.Operator):
|
||||
bl_idname = "update_exchange_folder.pilgway_3d_coat"
|
||||
bl_label = "Export your custom property"
|
||||
|
@ -266,8 +295,7 @@ class SCENE_OT_folder(bpy.types.Operator):
|
|||
coat3D = bpy.context.scene.coat3D
|
||||
if(os.path.isdir(coat3D.exchangeFolder)):
|
||||
foundExchangeFolder= True
|
||||
else:
|
||||
foundExchangeFolder = False
|
||||
folders.updateExchangeFile(coat3D.exchangeFolder)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
@ -1497,6 +1525,7 @@ class SCENE_PT_Settings_Folders(ObjectButtonsPanel, bpy.types.Panel):
|
|||
|
||||
col = flow.column()
|
||||
col.prop(coat3D, "exchangeFolder", text="Exchange folder")
|
||||
col.operator("save_new_export.pilgway_3d_coat", text="Save new Exchange folder")
|
||||
|
||||
col = flow.column()
|
||||
col.prop(coat3D, "defaultfolder", text="Object/Texture folder")
|
||||
|
@ -1918,6 +1947,7 @@ classes = (
|
|||
SCENE_OT_opencoat,
|
||||
SCENE_OT_export,
|
||||
SCENE_OT_getback,
|
||||
SCENE_OT_savenew,
|
||||
SCENE_OT_delete_material_nodes,
|
||||
SCENE_OT_delete_object_nodes,
|
||||
SCENE_OT_delete_collection_nodes,
|
||||
|
|
|
@ -14,26 +14,30 @@ def InitFolders():
|
|||
# 1. #################################################################
|
||||
|
||||
if(platform == 'win32' or platform == 'darwin'):
|
||||
exchangeFile = os.path.expanduser("~") + os.sep + 'Documents' + os.sep + '3DC2Blender' + os.sep + 'Exchange_folder.txt'
|
||||
DC2Folder = os.path.expanduser("~") + os.sep + 'Documents' + os.sep + '3DC2Blender'
|
||||
else:
|
||||
exchangeFile = os.path.expanduser("~") + os.sep + '3DC2Blender' + os.sep + 'Exchange_folder.txt'
|
||||
if(os.path.isfile(exchangeFile)):
|
||||
folderPath = ''
|
||||
DC2Folder = os.path.expanduser("~") + os.sep + '3DC2Blender'
|
||||
|
||||
exchangeFile = DC2Folder + os.sep + 'Exchange_folder.txt'
|
||||
|
||||
folderPathh = open(exchangeFile)
|
||||
for line in folderPathh:
|
||||
folderPath = line
|
||||
if(not os.path.isdir(DC2Folder)):
|
||||
os.mkdir(DC2Folder)
|
||||
|
||||
if(not os.path.isfile(exchangeFile)):
|
||||
file = open(exchangeFile, 'w')
|
||||
file.close()
|
||||
else:
|
||||
savedExchangePath = ''
|
||||
folderPath = open(exchangeFile)
|
||||
|
||||
for line in folderPath:
|
||||
savedExchangePath = line
|
||||
break
|
||||
folderPathh.close()
|
||||
folderPath.close()
|
||||
|
||||
if(os.path.isdir(os.path.abspath(folderPath)) and folderPath.rfind('Exchange') >= 0):
|
||||
coat3D.exchangeFolder = folderPath
|
||||
return True, coat3D.exchangeFolder
|
||||
else:
|
||||
try:
|
||||
os.makedirs(os.path.dirname(exchangeFile))
|
||||
except:
|
||||
pass
|
||||
|
||||
coat3D.exchangeFolder = savedExchangePath
|
||||
return True, coat3D.exchangeFolder
|
||||
|
||||
|
||||
# 2. #################################################################
|
||||
|
@ -50,7 +54,7 @@ def InitFolders():
|
|||
Blender_folder = ("%s%sBlender"%(exchangeFolder,os.sep))
|
||||
|
||||
if(not(os.path.isdir(Blender_folder))):
|
||||
os.makedirs(Blender_folder)
|
||||
os.makedirs(Blender_folder, mode = 0o666)
|
||||
Blender_folder1 = os.path.join(Blender_folder,"run.txt")
|
||||
file = open(Blender_folder1, "w")
|
||||
file.close()
|
||||
|
@ -90,6 +94,35 @@ def updateExchangeFile(newPath):
|
|||
file.write("%s"%(newPath))
|
||||
file.close()
|
||||
|
||||
def loadExchangeFolder():
|
||||
|
||||
platform = os.sys.platform
|
||||
coat3D = bpy.context.scene.coat3D
|
||||
|
||||
if(platform == 'win32' or platform == 'darwin'):
|
||||
DC2Folder = os.path.expanduser("~") + os.sep + 'Documents' + os.sep + '3DC2Blender'
|
||||
else:
|
||||
DC2Folder = os.path.expanduser("~") + os.sep + '3DC2Blender'
|
||||
|
||||
exchangeFile = DC2Folder + os.sep + 'Exchange_folder.txt'
|
||||
|
||||
if(not os.path.isdir(DC2Folder)):
|
||||
os.mkdir(DC2Folder)
|
||||
|
||||
if(not os.path.isfile(exchangeFile)):
|
||||
file = open(exchangeFile, 'w')
|
||||
file.close()
|
||||
else:
|
||||
savedExchangePath = ''
|
||||
folderPath = open(exchangeFile)
|
||||
|
||||
for line in folderPath:
|
||||
savedExchangePath = line
|
||||
break
|
||||
folderPath.close()
|
||||
coat3D.exchangeFolder = savedExchangePath
|
||||
|
||||
|
||||
def set_working_folders():
|
||||
|
||||
platform = os.sys.platform
|
||||
|
@ -101,13 +134,13 @@ def set_working_folders():
|
|||
else:
|
||||
folder_objects = os.path.expanduser("~") + os.sep + 'Documents' + os.sep + '3DC2Blender' + os.sep + 'ApplinkObjects'
|
||||
if(not(os.path.isdir(folder_objects))):
|
||||
os.makedirs(folder_objects)
|
||||
os.makedirs(folder_objects, mode = 0o666)
|
||||
else:
|
||||
if (coat3D.defaultfolder != '' and os.path.isdir(coat3D.defaultfolder)):
|
||||
return coat3D.defaultfolder
|
||||
else:
|
||||
folder_objects = os.path.expanduser("~") + os.sep + '3DC2Blender' + os.sep + 'ApplinkObjects'
|
||||
if(not(os.path.isdir(folder_objects))):
|
||||
os.makedirs(folder_objects)
|
||||
os.makedirs(folder_objects, mode = 0o666)
|
||||
|
||||
return folder_objects
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
bl_info = {
|
||||
"name": "FBX format",
|
||||
"author": "Campbell Barton, Bastien Montagne, Jens Restemeier",
|
||||
"version": (4, 21, 3),
|
||||
"version": (4, 22, 0),
|
||||
"blender": (2, 90, 0),
|
||||
"location": "File > Import-Export",
|
||||
"description": "FBX IO meshes, UV's, vertex colors, materials, textures, cameras, lamps and actions",
|
||||
|
@ -426,6 +426,13 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
|
|||
"(Blender uses FBX scale to detect units on import, "
|
||||
"but many other applications do not handle the same way)",
|
||||
)
|
||||
|
||||
use_space_transform: BoolProperty(
|
||||
name="Use Space Transform",
|
||||
description="Apply global space transform to the object rotations. When disabled "
|
||||
"only the axis space is written to the file and all object transforms are left as-is",
|
||||
default=True,
|
||||
)
|
||||
bake_space_transform: BoolProperty(
|
||||
name="Apply Transform",
|
||||
description="Bake space transform into object data, avoids getting unwanted rotations to objects when "
|
||||
|
@ -623,7 +630,8 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
|
|||
|
||||
global_matrix = (axis_conversion(to_forward=self.axis_forward,
|
||||
to_up=self.axis_up,
|
||||
).to_4x4())
|
||||
).to_4x4()
|
||||
if self.use_space_transform else Matrix())
|
||||
|
||||
keywords = self.as_keywords(ignore=("check_existing",
|
||||
"filter_glob",
|
||||
|
@ -727,6 +735,7 @@ class FBX_PT_export_transform(bpy.types.Panel):
|
|||
layout.prop(operator, "axis_up")
|
||||
|
||||
layout.prop(operator, "apply_unit_scale")
|
||||
layout.prop(operator, "use_space_transform")
|
||||
row = layout.row()
|
||||
row.prop(operator, "bake_space_transform")
|
||||
row.label(text="", icon='ERROR')
|
||||
|
|
|
@ -1079,6 +1079,12 @@ def blen_read_geom_layer_color(fbx_obj, mesh):
|
|||
|
||||
# Always init our new layers with full white opaque color.
|
||||
color_lay = mesh.vertex_colors.new(name=fbx_layer_name, do_init=False)
|
||||
|
||||
if color_lay is None:
|
||||
print("Failed to add {%r %r} vertex color layer to %r (probably too many of them?)"
|
||||
"" % (layer_id, fbx_layer_name, mesh.name))
|
||||
continue
|
||||
|
||||
blen_data = color_lay.data
|
||||
|
||||
# some valid files omit this data
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
bl_info = {
|
||||
'name': 'glTF 2.0 format',
|
||||
'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
|
||||
"version": (1, 5, 1),
|
||||
"version": (1, 5, 2),
|
||||
'blender': (2, 91, 0),
|
||||
'location': 'File > Import-Export',
|
||||
'description': 'Import-Export as glTF 2.0',
|
||||
|
|
|
@ -275,12 +275,22 @@ def do_primitives(gltf, mesh_idx, skin_idx, mesh, ob):
|
|||
for uv_i in range(num_uvs):
|
||||
name = 'UVMap' if uv_i == 0 else 'UVMap.%03d' % uv_i
|
||||
layer = mesh.uv_layers.new(name=name)
|
||||
|
||||
if layer is None:
|
||||
print("WARNING: UV map is ignored because the maximum number of UV layers has been reached.")
|
||||
break
|
||||
|
||||
layer.data.foreach_set('uv', squish(loop_uvs[uv_i]))
|
||||
|
||||
for col_i in range(num_cols):
|
||||
name = 'Col' if col_i == 0 else 'Col.%03d' % col_i
|
||||
layer = mesh.vertex_colors.new(name=name)
|
||||
|
||||
if layer is None:
|
||||
print("WARNING: Vertex colors are ignored because the maximum number of vertex color layers has been "
|
||||
"reached.")
|
||||
break
|
||||
|
||||
layer.data.foreach_set('color', squish(loop_cols[col_i]))
|
||||
|
||||
# Skinning
|
||||
|
|
|
@ -359,6 +359,10 @@ class BaseGenerator:
|
|||
self.__run_object_stage('configure_bones')
|
||||
|
||||
|
||||
def invoke_preapply_bones(self):
|
||||
self.__run_object_stage('preapply_bones')
|
||||
|
||||
|
||||
def invoke_apply_bones(self):
|
||||
self.__run_edit_stage('apply_bones')
|
||||
|
||||
|
|
|
@ -119,6 +119,13 @@ class GenerateCallbackHost(BaseStagedClass, define_stages=True):
|
|||
"""
|
||||
pass
|
||||
|
||||
def preapply_bones(self):
|
||||
"""
|
||||
Read bone matrices for applying to edit mode.
|
||||
Called in Object mode. May not do Edit mode operations.
|
||||
"""
|
||||
pass
|
||||
|
||||
def apply_bones(self):
|
||||
"""
|
||||
Can be used to apply some constraints to rest pose, and for final parenting.
|
||||
|
|
|
@ -30,6 +30,7 @@ from .utils.widgets import WGT_PREFIX
|
|||
from .utils.widgets_special import create_root_widget
|
||||
from .utils.misc import gamma_correct, select_object
|
||||
from .utils.collections import ensure_widget_collection, list_layer_collections, filter_layer_collections_by_object
|
||||
from .utils.rig import get_rigify_type
|
||||
|
||||
from . import base_generate
|
||||
from . import rig_ui_template
|
||||
|
@ -198,9 +199,12 @@ class Generator(base_generate.BaseGenerator):
|
|||
|
||||
# Add the ORG_PREFIX to the original bones.
|
||||
for i in range(0, len(original_bones)):
|
||||
new_name = make_original_name(original_bones[i])
|
||||
obj.data.bones[original_bones[i]].name = new_name
|
||||
original_bones[i] = new_name
|
||||
bone = obj.pose.bones[original_bones[i]]
|
||||
|
||||
# This rig type is special in that it preserves the name of the bone.
|
||||
if get_rigify_type(bone) != 'basic.raw_copy':
|
||||
bone.name = make_original_name(original_bones[i])
|
||||
original_bones[i] = bone.name
|
||||
|
||||
self.original_bones = original_bones
|
||||
|
||||
|
@ -428,6 +432,13 @@ class Generator(base_generate.BaseGenerator):
|
|||
|
||||
t.tick("Configure bones: ")
|
||||
|
||||
#------------------------------------------
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
self.invoke_preapply_bones()
|
||||
|
||||
t.tick("Preapply bones: ")
|
||||
|
||||
#------------------------------------------
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -125,6 +125,11 @@ def get_pose_matrix_in_other_space(mat, pose_bone):
|
|||
return pose_bone.id_data.convert_space(matrix=mat, pose_bone=pose_bone, from_space='POSE', to_space='LOCAL')
|
||||
|
||||
|
||||
def convert_pose_matrix_via_rest_delta(mat, from_bone, to_bone):
|
||||
"""Convert pose of one bone to another bone, preserving the rest pose difference between them."""
|
||||
return mat @ from_bone.bone.matrix_local.inverted() @ to_bone.bone.matrix_local
|
||||
|
||||
|
||||
def get_local_pose_matrix(pose_bone):
|
||||
""" Returns the local transform matrix of the given pose bone.
|
||||
"""
|
||||
|
@ -193,39 +198,41 @@ def match_pose_scale(pose_bone, target_bone):
|
|||
## IK/FK snapping functions ##
|
||||
##############################
|
||||
|
||||
def correct_rotation(view_layer, bone_ik, target_matrix):
|
||||
def correct_rotation(view_layer, bone_ik, target_matrix, *, ctrl_ik=None):
|
||||
""" Corrects the ik rotation in ik2fk snapping functions
|
||||
"""
|
||||
|
||||
axis = target_matrix.to_3x3().col[1].normalized()
|
||||
ctrl_ik = ctrl_ik or bone_ik
|
||||
|
||||
def distance(angle):
|
||||
# Rotate the bone and return the actual angle between bones
|
||||
bone_ik.rotation_euler[1] = angle
|
||||
ctrl_ik.rotation_euler[1] = angle
|
||||
view_layer.update()
|
||||
|
||||
return -(bone_ik.vector.normalized().dot(axis))
|
||||
|
||||
if bone_ik.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}:
|
||||
bone_ik.rotation_mode = 'ZXY'
|
||||
if ctrl_ik.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}:
|
||||
ctrl_ik.rotation_mode = 'ZXY'
|
||||
|
||||
start_angle = bone_ik.rotation_euler[1]
|
||||
start_angle = ctrl_ik.rotation_euler[1]
|
||||
|
||||
alfarange = find_min_range(distance, start_angle)
|
||||
alfamin = ternarySearch(distance, alfarange[0], alfarange[1], pi / 180)
|
||||
|
||||
bone_ik.rotation_euler[1] = alfamin
|
||||
ctrl_ik.rotation_euler[1] = alfamin
|
||||
view_layer.update()
|
||||
|
||||
|
||||
def correct_scale(view_layer, bone_ik, target_matrix):
|
||||
def correct_scale(view_layer, bone_ik, target_matrix, *, ctrl_ik=None):
|
||||
""" Correct the scale of the base IK bone. """
|
||||
input_scale = target_matrix.to_scale()
|
||||
ctrl_ik = ctrl_ik or bone_ik
|
||||
|
||||
for i in range(3):
|
||||
cur_scale = bone_ik.matrix.to_scale()
|
||||
|
||||
bone_ik.scale = [
|
||||
ctrl_ik.scale = [
|
||||
v * i / c for v, i, c in zip(bone_ik.scale, input_scale, cur_scale)
|
||||
]
|
||||
|
||||
|
@ -456,8 +463,8 @@ def fk2ik_leg(obj, fk, ik):
|
|||
view_layer.update()
|
||||
|
||||
# Foot position
|
||||
mat = mfoot.bone.matrix_local.inverted() @ foot.bone.matrix_local
|
||||
footmat = get_pose_matrix_in_other_space(mfooti.matrix, foot) @ mat
|
||||
footmat = get_pose_matrix_in_other_space(mfooti.matrix, foot)
|
||||
footmat = convert_pose_matrix_via_rest_delta(footmat, mfoot, foot)
|
||||
set_pose_rotation(foot, footmat)
|
||||
set_pose_scale(foot, footmat)
|
||||
view_layer.update()
|
||||
|
@ -475,8 +482,8 @@ def fk2ik_leg(obj, fk, ik):
|
|||
view_layer.update()
|
||||
|
||||
# Foot position
|
||||
mat = mfoot.bone.matrix_local.inverted() @ foot.bone.matrix_local
|
||||
footmat = get_pose_matrix_in_other_space(mfooti.matrix, foot) @ mat
|
||||
footmat = get_pose_matrix_in_other_space(mfooti.matrix, foot)
|
||||
footmat = convert_pose_matrix_via_rest_delta(footmat, mfoot, foot)
|
||||
set_pose_rotation(foot, footmat)
|
||||
set_pose_scale(foot, footmat)
|
||||
view_layer.update()
|
||||
|
@ -516,8 +523,8 @@ def ik2fk_leg(obj, fk, ik):
|
|||
view_layer.update()
|
||||
|
||||
# Foot position
|
||||
mat = mfooti.bone.matrix_local.inverted() @ footi.bone.matrix_local
|
||||
footmat = get_pose_matrix_in_other_space(foot.matrix, footi) @ mat
|
||||
footmat = get_pose_matrix_in_other_space(foot.matrix, footi)
|
||||
footmat = convert_pose_matrix_via_rest_delta(footmat, mfooti, footi)
|
||||
set_pose_translation(footi, footmat)
|
||||
set_pose_rotation(footi, footmat)
|
||||
set_pose_scale(footi, footmat)
|
||||
|
@ -544,8 +551,8 @@ def ik2fk_leg(obj, fk, ik):
|
|||
view_layer.update()
|
||||
|
||||
# Foot position
|
||||
mat = mfooti.bone.matrix_local.inverted() @ footi.bone.matrix_local
|
||||
footmat = get_pose_matrix_in_other_space(mfoot.matrix, footi) @ mat
|
||||
footmat = get_pose_matrix_in_other_space(mfoot.matrix, footi)
|
||||
footmat = convert_pose_matrix_via_rest_delta(footmat, mfooti, footi)
|
||||
set_pose_translation(footi, footmat)
|
||||
set_pose_rotation(footi, footmat)
|
||||
set_pose_scale(footi, footmat)
|
||||
|
|
|
@ -27,6 +27,8 @@ from ...base_generate import SubstitutionRig
|
|||
|
||||
from itertools import repeat
|
||||
|
||||
'''
|
||||
Due to T80764, bone name handling for 'limbs.raw_copy' was hard-coded in generate.py
|
||||
|
||||
class Rig(SubstitutionRig):
|
||||
""" A raw copy rig, preserving the metarig bone as is, without the ORG prefix. """
|
||||
|
@ -37,7 +39,7 @@ class Rig(SubstitutionRig):
|
|||
new_name = self.generator.rename_org_bone(self.base_bone, new_name)
|
||||
|
||||
return [ self.instantiate_rig(InstanceRig, new_name) ]
|
||||
|
||||
'''
|
||||
|
||||
class RelinkConstraintsMixin:
|
||||
""" Utilities for constraint relinking. """
|
||||
|
@ -119,8 +121,10 @@ class RelinkConstraintsMixin:
|
|||
r = layout.row()
|
||||
r.prop(params, "parent_bone")
|
||||
|
||||
layout.label(text="Constraint names have special meanings.", icon='ERROR')
|
||||
|
||||
class InstanceRig(BaseRig, RelinkConstraintsMixin):
|
||||
|
||||
class Rig(BaseRig, RelinkConstraintsMixin):
|
||||
def find_org_bones(self, pose_bone):
|
||||
return pose_bone.name
|
||||
|
||||
|
@ -146,8 +150,8 @@ class InstanceRig(BaseRig, RelinkConstraintsMixin):
|
|||
self.add_relink_constraints_ui(layout, params)
|
||||
|
||||
|
||||
add_parameters = InstanceRig.add_parameters
|
||||
parameters_ui = InstanceRig.parameters_ui
|
||||
#add_parameters = InstanceRig.add_parameters
|
||||
#parameters_ui = InstanceRig.parameters_ui
|
||||
|
||||
|
||||
def create_sample(obj):
|
||||
|
|
|
@ -37,10 +37,9 @@ from .limb_rigs import BaseLimbRig
|
|||
class Rig(BaseLimbRig):
|
||||
"""Human arm rig."""
|
||||
|
||||
def initialize(self):
|
||||
if len(self.bones.org.main) != 3:
|
||||
self.raise_error("Input to rig type must be a chain of 3 bones.")
|
||||
min_valid_orgs = max_valid_orgs = 3
|
||||
|
||||
def initialize(self):
|
||||
super().initialize()
|
||||
|
||||
self.make_wrist_pivot = self.params.make_ik_wrist_pivot
|
||||
|
|
|
@ -0,0 +1,288 @@
|
|||
#====================== BEGIN GPL LICENSE BLOCK ======================
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
#======================= END GPL LICENSE BLOCK ========================
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
import bpy
|
||||
|
||||
from ...utils.bones import align_bone_roll, put_bone, copy_bone_position, flip_bone
|
||||
from ...utils.naming import make_derived_name
|
||||
from ...utils.misc import map_list
|
||||
|
||||
from itertools import count
|
||||
|
||||
from ...base_rig import stage
|
||||
|
||||
from .limb_rigs import BaseLimbRig
|
||||
from .paw import Rig as pawRig
|
||||
|
||||
|
||||
class Rig(pawRig):
|
||||
"""Front paw rig with special IK automation."""
|
||||
|
||||
####################################################
|
||||
# EXTRA BONES
|
||||
#
|
||||
# mch:
|
||||
# ik2_chain[2]
|
||||
# Second IK system (pre-driving heel)
|
||||
# heel_track
|
||||
# Bone tracking IK2 to rotate heel
|
||||
# heel_parent
|
||||
# Parent of the heel control
|
||||
#
|
||||
####################################################
|
||||
|
||||
####################################################
|
||||
# IK controls
|
||||
|
||||
def get_middle_ik_controls(self):
|
||||
return [self.bones.ctrl.heel]
|
||||
|
||||
def get_ik_fk_position_chains(self):
|
||||
ik_chain, fk_chain = super().get_ik_fk_position_chains()
|
||||
if not self.use_heel2:
|
||||
return [*ik_chain, ik_chain[-1]], [*fk_chain, fk_chain[-1]]
|
||||
return ik_chain, fk_chain
|
||||
|
||||
def get_extra_ik_controls(self):
|
||||
extra = [self.bones.ctrl.heel2] if self.use_heel2 else []
|
||||
return BaseLimbRig.get_extra_ik_controls(self) + extra
|
||||
|
||||
def get_ik_pole_parents(self):
|
||||
return [(self.get_ik2_target_bone(), self.bones.ctrl.ik)]
|
||||
|
||||
|
||||
####################################################
|
||||
# Second IK system (pre-driving heel)
|
||||
|
||||
use_mch_ik_base = True
|
||||
|
||||
def get_ik2_target_bone(self):
|
||||
return self.bones.mch.ik2_target if self.use_heel2 else self.bones.mch.toe_socket
|
||||
|
||||
@stage.generate_bones
|
||||
def make_ik2_mch_chain(self):
|
||||
orgs = self.bones.org.main
|
||||
chain = map_list(self.make_ik2_mch_bone, count(0), orgs[0:2])
|
||||
self.bones.mch.ik2_chain = chain
|
||||
|
||||
if self.use_heel2:
|
||||
self.bones.mch.ik2_target = self.make_ik2_mch_target_bone(orgs)
|
||||
|
||||
# Connect the chain end to the target
|
||||
self.get_bone(chain[1]).tail = self.get_bone(orgs[2]).tail
|
||||
align_bone_roll(self.obj, chain[1], orgs[1])
|
||||
|
||||
def make_ik2_mch_target_bone(self, orgs):
|
||||
return self.copy_bone(orgs[3], make_derived_name(orgs[0], 'mch', '_ik2_target'), scale=1/2)
|
||||
|
||||
def make_ik2_mch_bone(self, i, org):
|
||||
return self.copy_bone(org, make_derived_name(org, 'mch', '_ik2'))
|
||||
|
||||
@stage.parent_bones
|
||||
def parent_ik2_mch_chain(self):
|
||||
mch = self.bones.mch
|
||||
if self.use_heel2:
|
||||
self.set_bone_parent(mch.ik2_target, self.bones.ctrl.heel2)
|
||||
self.set_bone_parent(mch.ik2_chain[0], self.bones.ctrl.ik_base, inherit_scale='AVERAGE')
|
||||
self.parent_bone_chain(mch.ik2_chain, use_connect=True)
|
||||
|
||||
@stage.configure_bones
|
||||
def configure_ik2_mch_chain(self):
|
||||
for i, mch in enumerate(self.bones.mch.ik2_chain):
|
||||
self.configure_ik2_mch_bone(i, mch)
|
||||
|
||||
def configure_ik2_mch_bone(self, i, mch):
|
||||
bone = self.get_bone(mch)
|
||||
bone.ik_stretch = 0.1
|
||||
if i == 1:
|
||||
bone.lock_ik_x = bone.lock_ik_y = bone.lock_ik_z = True
|
||||
setattr(bone, 'lock_ik_' + self.main_axis, False)
|
||||
|
||||
@stage.rig_bones
|
||||
def rig_ik2_mch_chain(self):
|
||||
target_bone = self.get_ik2_target_bone()
|
||||
self.rig_ik_mch_end_bone(self.bones.mch.ik2_chain[-1], target_bone, self.bones.ctrl.ik_pole)
|
||||
|
||||
|
||||
####################################################
|
||||
# Heel tracking from IK2
|
||||
|
||||
@stage.generate_bones
|
||||
def make_heel_track_bones(self):
|
||||
orgs = self.bones.org.main
|
||||
mch = self.bones.mch
|
||||
mch.heel_track = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'mch', '_track'))
|
||||
mch.heel_parent = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'mch', '_parent'))
|
||||
|
||||
# This two bone setup is used to move the damped track singularity out
|
||||
# of the way to a forbidden zone of the rig, and thus avoid flipping.
|
||||
# The bones are aligned to the center of the valid transformation zone.
|
||||
self.align_ik_control_bone(mch.heel_track)
|
||||
put_bone(self.obj, mch.heel_track, self.get_bone(orgs[2]).tail, scale=1/3)
|
||||
copy_bone_position(self.obj, mch.heel_track, mch.heel_parent, scale=3/4)
|
||||
|
||||
@stage.parent_bones
|
||||
def parent_heel_control_bone(self):
|
||||
self.set_bone_parent(self.bones.ctrl.heel, self.bones.mch.heel_parent)
|
||||
|
||||
@stage.parent_bones
|
||||
def parent_heel_track_bones(self):
|
||||
# Parenting heel_parent deferred to apply_bones.
|
||||
self.set_bone_parent(self.bones.mch.heel_track, self.get_ik2_target_bone())
|
||||
|
||||
@stage.configure_bones
|
||||
def prerig_heel_track_bones(self):
|
||||
# Assign the constraint before the apply stage.
|
||||
self.make_constraint(
|
||||
self.bones.mch.heel_track, 'DAMPED_TRACK', self.bones.mch.ik2_chain[1],
|
||||
influence=self.params.front_paw_heel_influence
|
||||
)
|
||||
|
||||
@stage.preapply_bones
|
||||
def preapply_heel_track_bones(self):
|
||||
# Assign local transform negating the effect of the constraint at rest.
|
||||
track_bone = self.get_bone(self.bones.mch.heel_track)
|
||||
bone = self.get_bone(self.bones.mch.heel_parent)
|
||||
bone.matrix_basis = track_bone.matrix.inverted() @ bone.matrix
|
||||
|
||||
@stage.apply_bones
|
||||
def apply_heel_track_bones(self):
|
||||
# Complete the parent chain.
|
||||
self.set_bone_parent(self.bones.mch.heel_parent, self.bones.mch.heel_track)
|
||||
|
||||
|
||||
####################################################
|
||||
# Settings
|
||||
|
||||
@classmethod
|
||||
def add_parameters(self, params):
|
||||
super().add_parameters(params)
|
||||
|
||||
params.front_paw_heel_influence = bpy.props.FloatProperty(
|
||||
name = 'Heel IK Influence',
|
||||
default = 0.8,
|
||||
min = 0,
|
||||
max = 1,
|
||||
description = 'Influence of the secondary IK on the heel control rotation'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def parameters_ui(self, layout, params):
|
||||
r = layout.row()
|
||||
r.prop(params, "front_paw_heel_influence", slider=True)
|
||||
|
||||
super().parameters_ui(layout, params)
|
||||
|
||||
|
||||
def create_sample(obj):
|
||||
# generated by rigify.utils.write_metarig
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
arm = obj.data
|
||||
|
||||
bones = {}
|
||||
|
||||
bone = arm.edit_bones.new('front_thigh.L')
|
||||
bone.head = 0.0000, 0.0000, 0.6902
|
||||
bone.tail = 0.0000, 0.0916, 0.4418
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
bones['front_thigh.L'] = bone.name
|
||||
bone = arm.edit_bones.new('front_shin.L')
|
||||
bone.head = 0.0000, 0.0916, 0.4418
|
||||
bone.tail = 0.0000, 0.1014, 0.1698
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones[bones['front_thigh.L']]
|
||||
bones['front_shin.L'] = bone.name
|
||||
bone = arm.edit_bones.new('front_foot.L')
|
||||
bone.head = 0.0000, 0.1014, 0.1698
|
||||
bone.tail = 0.0000, 0.0699, 0.0411
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones[bones['front_shin.L']]
|
||||
bones['front_foot.L'] = bone.name
|
||||
bone = arm.edit_bones.new('front_toe.L')
|
||||
bone.head = 0.0000, 0.0699, 0.0411
|
||||
bone.tail = 0.0000, -0.0540, 0.0000
|
||||
bone.roll = 3.1416
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones[bones['front_foot.L']]
|
||||
bones['front_toe.L'] = bone.name
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones[bones['front_thigh.L']]
|
||||
pbone.rigify_type = 'limbs.front_paw'
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
try:
|
||||
pbone.rigify_parameters.limb_type = "paw"
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
pbone.rigify_parameters.fk_layers = [False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
|
||||
except AttributeError:
|
||||
pass
|
||||
pbone = obj.pose.bones[bones['front_shin.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['front_foot.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['front_toe.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
try:
|
||||
pbone.rigify_parameters.limb_type = "paw"
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
for bone in arm.edit_bones:
|
||||
bone.select = False
|
||||
bone.select_head = False
|
||||
bone.select_tail = False
|
||||
for b in bones:
|
||||
bone = arm.edit_bones[bones[b]]
|
||||
bone.select = True
|
||||
bone.select_head = True
|
||||
bone.select_tail = True
|
||||
bone.bbone_x = bone.bbone_z = bone.length * 0.05
|
||||
arm.edit_bones.active = bone
|
||||
|
||||
return bones
|
|
@ -44,6 +44,8 @@ ALL_TRUE = (True, True, True)
|
|||
class Rig(BaseLimbRig):
|
||||
"""Human leg rig."""
|
||||
|
||||
min_valid_orgs = max_valid_orgs = 4
|
||||
|
||||
def find_org_bones(self, bone):
|
||||
bones = super().find_org_bones(bone)
|
||||
|
||||
|
@ -57,9 +59,6 @@ class Rig(BaseLimbRig):
|
|||
return bones
|
||||
|
||||
def initialize(self):
|
||||
if len(self.bones.org.main) != 4:
|
||||
self.raise_error("Input to rig type must be a chain of 4 bones.")
|
||||
|
||||
super().initialize()
|
||||
|
||||
self.pivot_type = self.params.foot_pivot_type
|
||||
|
|
|
@ -50,6 +50,8 @@ class BaseLimbRig(BaseRig):
|
|||
"""Common base for limb rigs."""
|
||||
|
||||
segmented_orgs = 2 # Number of org bones to segment
|
||||
min_valid_orgs = None
|
||||
max_valid_orgs = None
|
||||
|
||||
def find_org_bones(self, bone):
|
||||
return BoneDict(
|
||||
|
@ -59,8 +61,11 @@ class BaseLimbRig(BaseRig):
|
|||
def initialize(self):
|
||||
orgs = self.bones.org.main
|
||||
|
||||
if len(orgs) < self.segmented_orgs + 1:
|
||||
self.raise_error("Input to rig type must be a chain of at least 3 bones.")
|
||||
min_length = max(self.segmented_orgs + 1, self.min_valid_orgs or 0)
|
||||
if len(orgs) < min_length:
|
||||
self.raise_error("Input to rig type must be a chain of at least {} bones.", min_length)
|
||||
if self.max_valid_orgs and len(orgs) > self.max_valid_orgs:
|
||||
self.raise_error("Input to rig type must be a chain of at most {} bones.", self.max_valid_orgs)
|
||||
|
||||
self.segments = self.params.segments
|
||||
self.bbone_segments = self.params.bbones
|
||||
|
@ -161,6 +166,8 @@ class BaseLimbRig(BaseRig):
|
|||
# IK stretch switch implementation.
|
||||
# ik_target
|
||||
# Corrected target position.
|
||||
# ik_base
|
||||
# Optionally the base of the ik chain (otherwise ctrl.ik_base)
|
||||
# ik_end
|
||||
# End of the IK chain: [ik_base, ik_end]
|
||||
# deform[]:
|
||||
|
@ -242,8 +249,10 @@ class BaseLimbRig(BaseRig):
|
|||
def make_fk_control_chain(self):
|
||||
self.bones.ctrl.fk = map_list(self.make_fk_control_bone, count(0), self.bones.org.main)
|
||||
|
||||
fk_name_suffix_cutoff = 2
|
||||
|
||||
def get_fk_name(self, i, org, kind):
|
||||
return make_derived_name(org, kind, '_fk' if i <= 2 else '')
|
||||
return make_derived_name(org, kind, '_fk' if i <= self.fk_name_suffix_cutoff else '')
|
||||
|
||||
def make_fk_control_bone(self, i, org):
|
||||
return self.copy_bone(org, self.get_fk_name(i, org, 'ctrl'))
|
||||
|
@ -296,7 +305,7 @@ class BaseLimbRig(BaseRig):
|
|||
self.bones.mch.fk = map_list(self.make_fk_parent_bone, count(0), self.bones.org.main)
|
||||
|
||||
def make_fk_parent_bone(self, i, org):
|
||||
if 2 <= i <= 3:
|
||||
if i >= 2:
|
||||
return self.copy_bone(org, self.get_fk_name(i, org, 'mch'), parent=True, scale=1/4)
|
||||
|
||||
@stage.parent_bones
|
||||
|
@ -307,7 +316,7 @@ class BaseLimbRig(BaseRig):
|
|||
self.parent_fk_parent_bone(*args)
|
||||
|
||||
def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org):
|
||||
if i == 2:
|
||||
if i >= 2:
|
||||
self.set_bone_parent(parent_mch, prev_ctrl, use_connect=True, inherit_scale='NONE')
|
||||
|
||||
@stage.rig_bones
|
||||
|
@ -316,7 +325,7 @@ class BaseLimbRig(BaseRig):
|
|||
self.rig_fk_parent_bone(*args)
|
||||
|
||||
def rig_fk_parent_bone(self, i, parent_mch, org):
|
||||
if i == 2:
|
||||
if i >= 2:
|
||||
self.make_constraint(parent_mch, 'COPY_SCALE', 'root', use_make_uniform=True)
|
||||
|
||||
|
||||
|
@ -329,10 +338,19 @@ class BaseLimbRig(BaseRig):
|
|||
else:
|
||||
return []
|
||||
|
||||
def get_all_ik_controls(self):
|
||||
def get_middle_ik_controls(self):
|
||||
return []
|
||||
|
||||
def get_ik_fk_position_chains(self):
|
||||
ik_chain = self.get_ik_output_chain()
|
||||
return ik_chain, self.bones.ctrl.fk[0:len(ik_chain)]
|
||||
|
||||
def get_ik_control_chain(self):
|
||||
ctrl = self.bones.ctrl
|
||||
controls = [ctrl.ik_base, ctrl.ik_pole, ctrl.ik]
|
||||
return controls + self.get_extra_ik_controls()
|
||||
return [ctrl.ik_base, ctrl.ik_pole, *self.get_middle_ik_controls(), ctrl.ik]
|
||||
|
||||
def get_all_ik_controls(self):
|
||||
return self.get_ik_control_chain() + self.get_extra_ik_controls()
|
||||
|
||||
@stage.generate_bones
|
||||
def make_ik_controls(self):
|
||||
|
@ -371,6 +389,9 @@ class BaseLimbRig(BaseRig):
|
|||
else:
|
||||
return self.bones.ctrl.ik
|
||||
|
||||
def get_ik_pole_parents(self):
|
||||
return [(self.bones.mch.ik_target, self.bones.ctrl.ik)]
|
||||
|
||||
def register_switch_parents(self, pbuilder):
|
||||
if self.rig_parent_bone:
|
||||
pbuilder.register_parent(self, self.rig_parent_bone)
|
||||
|
@ -385,7 +406,6 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
master = lambda: self.bones.ctrl.master
|
||||
pcontrols = lambda: [ ctrl.master ] + self.get_all_ik_controls()
|
||||
pole_parents = lambda: [(self.bones.mch.ik_target, ctrl.ik)]
|
||||
|
||||
self.register_switch_parents(pbuilder)
|
||||
|
||||
|
@ -395,7 +415,7 @@ class BaseLimbRig(BaseRig):
|
|||
)
|
||||
|
||||
pbuilder.build_child(
|
||||
self, ctrl.ik_pole, prop_bone=master, extra_parents=pole_parents,
|
||||
self, ctrl.ik_pole, prop_bone=master, extra_parents=self.get_ik_pole_parents,
|
||||
prop_id='pole_parent', prop_name='Pole Parent', controls=pcontrols,
|
||||
no_fix_rotation=True, no_fix_scale=True,
|
||||
)
|
||||
|
@ -409,7 +429,6 @@ class BaseLimbRig(BaseRig):
|
|||
base = self.get_bone(self.bones.ctrl.ik_base)
|
||||
base.rotation_mode = 'ZXY'
|
||||
base.lock_rotation = True, False, True
|
||||
base.ik_stretch = 0.1
|
||||
|
||||
@stage.rig_bones
|
||||
def rig_ik_controls(self):
|
||||
|
@ -421,6 +440,9 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
set_bone_widget_transform(self.obj, ctrl.ik, self.get_ik_control_output())
|
||||
|
||||
if self.use_mch_ik_base:
|
||||
set_bone_widget_transform(self.obj, ctrl.ik_base, self.bones.mch.ik_base, target_size=True)
|
||||
|
||||
self.make_ik_base_widget(ctrl.ik_base)
|
||||
self.make_ik_pole_widget(ctrl.ik_pole)
|
||||
self.make_ik_ctrl_widget(ctrl.ik)
|
||||
|
@ -475,19 +497,31 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
ik_input_head_tail = 0.0
|
||||
|
||||
use_mch_ik_base = False
|
||||
|
||||
def get_ik_input_bone(self):
|
||||
return self.get_ik_control_output()
|
||||
|
||||
def get_ik_chain_base(self):
|
||||
return self.bones.mch.ik_base if self.use_mch_ik_base else self.bones.ctrl.ik_base
|
||||
|
||||
def get_ik_output_chain(self):
|
||||
return [self.bones.ctrl.ik_base, self.bones.mch.ik_end, self.bones.mch.ik_target]
|
||||
return [self.get_ik_chain_base(), self.bones.mch.ik_end, self.bones.mch.ik_target]
|
||||
|
||||
@stage.generate_bones
|
||||
def make_ik_mch_chain(self):
|
||||
orgs = self.bones.org.main
|
||||
|
||||
if self.use_mch_ik_base:
|
||||
self.bones.mch.ik_base = self.make_ik_mch_base_bone(orgs)
|
||||
|
||||
self.bones.mch.ik_stretch = self.make_ik_mch_stretch_bone(orgs)
|
||||
self.bones.mch.ik_target = self.make_ik_mch_target_bone(orgs)
|
||||
self.bones.mch.ik_end = self.copy_bone(orgs[1], make_derived_name(orgs[1], 'mch', '_ik'))
|
||||
|
||||
def make_ik_mch_base_bone(self, orgs):
|
||||
return self.copy_bone(orgs[0], make_derived_name(orgs[0], 'mch', '_ik'))
|
||||
|
||||
def make_ik_mch_stretch_bone(self, orgs):
|
||||
name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'mch', '_ik_stretch'))
|
||||
self.get_bone(name).tail = self.get_bone(orgs[2]).head
|
||||
|
@ -498,12 +532,24 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
@stage.parent_bones
|
||||
def parent_ik_mch_chain(self):
|
||||
if self.use_mch_ik_base:
|
||||
self.set_bone_parent(self.bones.mch.ik_base, self.bones.ctrl.ik_base, inherit_scale='AVERAGE')
|
||||
self.set_bone_parent(self.bones.mch.ik_stretch, self.bones.mch.follow)
|
||||
self.set_bone_parent(self.bones.mch.ik_target, self.get_ik_input_bone())
|
||||
self.set_bone_parent(self.bones.mch.ik_end, self.bones.ctrl.ik_base)
|
||||
self.set_bone_parent(self.bones.mch.ik_end, self.get_ik_chain_base())
|
||||
|
||||
@stage.configure_bones
|
||||
def configure_ik_mch_chain(self):
|
||||
bone = self.get_bone(self.get_ik_chain_base())
|
||||
bone.ik_stretch = 0.1
|
||||
|
||||
bone = self.get_bone(self.bones.mch.ik_end)
|
||||
bone.ik_stretch = 0.1
|
||||
bone.lock_ik_x = bone.lock_ik_y = bone.lock_ik_z = True
|
||||
setattr(bone, 'lock_ik_' + self.main_axis, False)
|
||||
|
||||
@stage.configure_bones
|
||||
def configure_ik_mch_panel(self):
|
||||
ctrl = self.bones.ctrl
|
||||
panel = self.script.panel_with_selected_check(self, ctrl.flatten())
|
||||
|
||||
|
@ -526,32 +572,34 @@ class BaseLimbRig(BaseRig):
|
|||
def add_global_buttons(self, panel, rig_name):
|
||||
ctrl = self.bones.ctrl
|
||||
ik_chain = self.get_ik_output_chain()
|
||||
fk_chain = ctrl.fk[0:len(ik_chain)]
|
||||
|
||||
add_generic_snap_fk_to_ik(
|
||||
panel,
|
||||
fk_bones=self.bones.ctrl.fk[0:len(ik_chain)],
|
||||
ik_bones=ik_chain,
|
||||
fk_bones=fk_chain, ik_bones=ik_chain,
|
||||
ik_ctrl_bones=self.get_all_ik_controls(),
|
||||
rig_name=rig_name
|
||||
)
|
||||
|
||||
ik_chain, fk_chain = self.get_ik_fk_position_chains()
|
||||
|
||||
add_limb_snap_ik_to_fk(
|
||||
panel,
|
||||
master=ctrl.master,
|
||||
fk_bones=self.bones.ctrl.fk, ik_bones=ik_chain,
|
||||
ik_ctrl_bones=[ctrl.ik_base, ctrl.ik, ctrl.ik_pole],
|
||||
fk_bones=fk_chain, ik_bones=ik_chain,
|
||||
ik_ctrl_bones=self.get_ik_control_chain(),
|
||||
ik_extra_ctrls=self.get_extra_ik_controls(),
|
||||
rig_name=rig_name
|
||||
)
|
||||
|
||||
def add_ik_only_buttons(self, panel, rig_name):
|
||||
ctrl = self.bones.ctrl
|
||||
ik_chain = self.get_ik_output_chain()
|
||||
ik_chain, fk_chain = self.get_ik_fk_position_chains()
|
||||
|
||||
add_limb_toggle_pole(
|
||||
panel, master=ctrl.master,
|
||||
ik_bones=ik_chain,
|
||||
ik_ctrl_bones=[ctrl.ik_base, ctrl.ik, ctrl.ik_pole],
|
||||
ik_ctrl_bones=self.get_ik_control_chain(),
|
||||
ik_extra_ctrls=self.get_extra_ik_controls(),
|
||||
)
|
||||
|
||||
|
@ -560,35 +608,35 @@ class BaseLimbRig(BaseRig):
|
|||
mch = self.bones.mch
|
||||
input_bone = self.get_ik_input_bone()
|
||||
|
||||
self.rig_ik_mch_stretch_bone(mch.ik_stretch, input_bone)
|
||||
self.rig_ik_mch_target_bone(mch.ik_target, mch.ik_stretch, input_bone)
|
||||
self.rig_ik_mch_stretch_bones(mch.ik_target, mch.ik_stretch, input_bone, self.ik_input_head_tail, 2)
|
||||
self.rig_ik_mch_end_bone(mch.ik_end, mch.ik_target, self.bones.ctrl.ik_pole)
|
||||
|
||||
def rig_ik_mch_stretch_bone(self, mch_stretch, input_bone):
|
||||
self.make_constraint(mch_stretch, 'STRETCH_TO', input_bone, head_tail=self.ik_input_head_tail, keep_axis='SWING_Y')
|
||||
def rig_ik_mch_stretch_bones(self, mch_target, mch_stretch, input_bone, head_tail, org_count, bias=1.035):
|
||||
# Compute increase in length to fully straighten
|
||||
orgs = self.bones.org.main[0:org_count]
|
||||
len_cur = (self.get_bone(orgs[-1]).tail - self.get_bone(orgs[0]).head).length
|
||||
len_full = sum(self.get_bone(org).length for org in orgs)
|
||||
len_scale = len_full / len_cur
|
||||
|
||||
con = self.make_constraint(mch_stretch, 'LIMIT_SCALE', min_y=0.0, max_y=1.05, owner_space='LOCAL')
|
||||
# Limited stretch on the stretch bone
|
||||
self.make_constraint(mch_stretch, 'STRETCH_TO', input_bone, head_tail=head_tail, keep_axis='SWING_Y')
|
||||
|
||||
con = self.make_constraint(mch_stretch, 'LIMIT_SCALE', min_y=0.0, max_y=len_scale*bias, owner_space='LOCAL')
|
||||
|
||||
self.make_driver(con, "influence", variables=[(self.prop_bone, 'IK_Stretch')], polynomial=[1.0, -1.0])
|
||||
|
||||
def rig_ik_mch_target_bone(self, mch_target, mch_stretch, input_bone):
|
||||
# Snap the target to the end of the stretch bone
|
||||
self.make_constraint(mch_target, 'COPY_LOCATION', mch_stretch, head_tail=1.0)
|
||||
|
||||
def rig_ik_mch_end_bone(self, mch_ik, mch_target, ctrl_pole):
|
||||
bone = self.get_bone(mch_ik)
|
||||
bone.ik_stretch = 0.1
|
||||
|
||||
bone.lock_ik_x = bone.lock_ik_y = bone.lock_ik_z = True
|
||||
setattr(bone, 'lock_ik_' + self.main_axis, False)
|
||||
|
||||
def rig_ik_mch_end_bone(self, mch_ik, mch_target, ctrl_pole, chain=2):
|
||||
con = self.make_constraint(
|
||||
mch_ik, 'IK', mch_target, chain_count=2,
|
||||
mch_ik, 'IK', mch_target, chain_count=chain,
|
||||
)
|
||||
|
||||
self.make_driver(con, "mute", variables=[(self.prop_bone, 'pole_vector')], polynomial=[0.0, 1.0])
|
||||
|
||||
con_pole = self.make_constraint(
|
||||
mch_ik, 'IK', mch_target, chain_count=2,
|
||||
mch_ik, 'IK', mch_target, chain_count=chain,
|
||||
pole_target=self.obj, pole_subtarget=ctrl_pole, pole_angle=self.pole_angle,
|
||||
)
|
||||
|
||||
|
@ -901,26 +949,32 @@ class RigifyLimbIk2FkBase:
|
|||
if use_pole:
|
||||
match_pole_target(
|
||||
context.view_layer,
|
||||
ik_bones[0], ik_bones[1], ctrl_bones[2], matrices[0],
|
||||
ik_bones[0], ik_bones[1], ctrl_bones[1], matrices[0],
|
||||
(ik_bones[0].length + ik_bones[1].length)
|
||||
)
|
||||
|
||||
else:
|
||||
correct_rotation(context.view_layer, ctrl_bones[0], matrices[0])
|
||||
correct_rotation(context.view_layer, ik_bones[0], matrices[0], ctrl_ik=ctrl_bones[0])
|
||||
|
||||
def assign_middle_controls(self, context, obj, matrices, ik_bones, ctrl_bones, *, lock=False, keyflags=None):
|
||||
for mat, ik, ctrl in reversed(list(zip(matrices[2:-1], ik_bones[2:-1], ctrl_bones[2:-1]))):
|
||||
ctrl.bone.use_inherit_rotation = not lock
|
||||
ctrl.bone.inherit_scale = 'NONE' if lock else 'FULL'
|
||||
context.view_layer.update()
|
||||
mat = convert_pose_matrix_via_rest_delta(mat, ik, ctrl)
|
||||
set_transform_from_matrix(obj, ctrl.name, mat, keyflags=keyflags)
|
||||
|
||||
def apply_frame_state(self, context, obj, matrices):
|
||||
ik_bones = [ obj.pose.bones[k] for k in self.ik_bone_list ]
|
||||
ctrl_bones = [ obj.pose.bones[k] for k in self.ctrl_bone_list ]
|
||||
|
||||
use_pole = len(ctrl_bones) > 2 and self.get_use_pole(obj)
|
||||
use_pole = self.get_use_pole(obj)
|
||||
|
||||
# Set the end control position
|
||||
tgt_matrix = ik_bones[2].bone.matrix_local
|
||||
ctrl_matrix = ctrl_bones[1].bone.matrix_local
|
||||
endmat = matrices[2] @ tgt_matrix.inverted() @ ctrl_matrix
|
||||
endmat = convert_pose_matrix_via_rest_delta(matrices[-1], ik_bones[-1], ctrl_bones[-1])
|
||||
|
||||
set_transform_from_matrix(
|
||||
obj, self.ctrl_bone_list[1], endmat, keyflags=self.keyflags
|
||||
obj, self.ctrl_bone_list[-1], endmat, keyflags=self.keyflags
|
||||
)
|
||||
|
||||
# Remove foot heel transform, if present
|
||||
|
@ -937,15 +991,22 @@ class RigifyLimbIk2FkBase:
|
|||
no_scale=True, no_rot=use_pole,
|
||||
)
|
||||
|
||||
# Lock middle control transforms (first pass)
|
||||
self.assign_middle_controls(context, obj, matrices, ik_bones, ctrl_bones, lock=True)
|
||||
|
||||
# Adjust the base bone state
|
||||
self.compute_base_rotation(context, ik_bones, ctrl_bones, matrices, use_pole)
|
||||
|
||||
correct_scale(context.view_layer, ctrl_bones[0], matrices[0])
|
||||
correct_scale(context.view_layer, ik_bones[0], matrices[0], ctrl_ik=ctrl_bones[0])
|
||||
|
||||
# Assign middle control transforms (final pass)
|
||||
self.assign_middle_controls(context, obj, matrices, ik_bones, ctrl_bones, keyflags=self.keyflags)
|
||||
|
||||
# Keyframe controls
|
||||
if self.keyflags is not None:
|
||||
if use_pole:
|
||||
keyframe_transform_properties(
|
||||
obj, self.ctrl_bone_list[2], self.keyflags,
|
||||
obj, self.ctrl_bone_list[1], self.keyflags,
|
||||
no_rot=True, no_scale=True,
|
||||
)
|
||||
|
||||
|
@ -1015,11 +1076,17 @@ class RigifyLimbTogglePoleBase(RigifyLimbIk2FkBase):
|
|||
keyflags=self.keyflags_switch
|
||||
)
|
||||
|
||||
# Lock middle control transforms
|
||||
self.assign_middle_controls(context, obj, matrices, ik_bones, ctrl_bones, lock=True)
|
||||
|
||||
# Reset the base bone rotation
|
||||
set_pose_rotation(ctrl_bones[0], Matrix.Identity(4))
|
||||
|
||||
self.compute_base_rotation(context, ik_bones, ctrl_bones, matrices, self.use_pole)
|
||||
|
||||
# Assign middle control transforms (final pass)
|
||||
self.assign_middle_controls(context, obj, matrices, ik_bones, ctrl_bones, keyflags=self.keyflags)
|
||||
|
||||
# Keyframe controls
|
||||
if self.keyflags is not None:
|
||||
if self.use_pole:
|
||||
|
|
|
@ -23,6 +23,7 @@ import bpy
|
|||
from ...utils.bones import compute_chain_x_axis, align_bone_x_axis, align_bone_z_axis
|
||||
from ...utils.bones import align_bone_to_axis, flip_bone
|
||||
from ...utils.naming import make_derived_name
|
||||
from ...utils.widgets_basic import create_circle_widget, create_limb_widget
|
||||
|
||||
from ..widgets import create_foot_widget, create_ballsocket_widget
|
||||
|
||||
|
@ -32,13 +33,19 @@ from .limb_rigs import BaseLimbRig
|
|||
|
||||
|
||||
class Rig(BaseLimbRig):
|
||||
"""Paw rig."""
|
||||
"""Paw rig with an optional second heel control."""
|
||||
|
||||
segmented_orgs = 3
|
||||
min_valid_orgs = 4
|
||||
max_valid_orgs = 5
|
||||
toe_bone_index = 3
|
||||
|
||||
def initialize(self):
|
||||
if len(self.bones.org.main) != 4:
|
||||
self.raise_error("Input to rig type must be a chain of 4 bones.")
|
||||
self.use_heel2 = len(self.bones.org.main) > 4
|
||||
|
||||
if self.use_heel2:
|
||||
self.toe_bone_index = 4
|
||||
self.fk_name_suffix_cutoff = 3
|
||||
|
||||
super().initialize()
|
||||
|
||||
|
@ -61,28 +68,10 @@ class Rig(BaseLimbRig):
|
|||
align_bone_z_axis(self.obj, orgs[2], foot_x)
|
||||
align_bone_z_axis(self.obj, orgs[3], -foot_x)
|
||||
|
||||
|
||||
####################################################
|
||||
# EXTRA BONES
|
||||
#
|
||||
# ctrl:
|
||||
# heel:
|
||||
# Foot heel control
|
||||
# mch:
|
||||
# toe_socket:
|
||||
# IK toe orientation bone.
|
||||
#
|
||||
####################################################
|
||||
# Utilities
|
||||
|
||||
####################################################
|
||||
# IK controls
|
||||
|
||||
def get_extra_ik_controls(self):
|
||||
return super().get_extra_ik_controls() + [self.bones.ctrl.heel]
|
||||
|
||||
def make_ik_control_bone(self, orgs):
|
||||
name = self.copy_bone(orgs[3], make_derived_name(orgs[2], 'ctrl', '_ik'))
|
||||
|
||||
def align_ik_control_bone(self, name):
|
||||
if self.params.rotation_axis == 'automatic' or self.params.auto_align_extremity:
|
||||
align_bone_to_axis(self.obj, name, 'y', flip=True)
|
||||
|
||||
|
@ -93,7 +82,42 @@ class Rig(BaseLimbRig):
|
|||
bone.tail[2] = bone.head[2]
|
||||
bone.roll = 0
|
||||
|
||||
vec = self.get_bone(orgs[3]).tail - self.get_bone(orgs[2]).head
|
||||
|
||||
####################################################
|
||||
# EXTRA BONES
|
||||
#
|
||||
# ctrl:
|
||||
# heel:
|
||||
# Foot heel control
|
||||
# heel2 (optional):
|
||||
# Second foot heel control
|
||||
# mch:
|
||||
# toe_socket:
|
||||
# IK toe orientation bone.
|
||||
# ik_heel2 (optional):
|
||||
# Final position of heel2 in the IK output.
|
||||
#
|
||||
####################################################
|
||||
|
||||
####################################################
|
||||
# IK controls
|
||||
|
||||
def get_middle_ik_controls(self):
|
||||
return [self.bones.ctrl.heel] if self.use_heel2 else []
|
||||
|
||||
def get_extra_ik_controls(self):
|
||||
extra = [self.bones.ctrl.heel2] if self.use_heel2 else [self.bones.ctrl.heel]
|
||||
return super().get_extra_ik_controls() + extra
|
||||
|
||||
def make_ik_control_bone(self, orgs):
|
||||
return self.make_paw_ik_control_bone(orgs[-2], orgs[-1], orgs[2])
|
||||
|
||||
def make_paw_ik_control_bone(self, org_one, org_two, org_name):
|
||||
name = self.copy_bone(org_two, make_derived_name(org_name, 'ctrl', '_ik'))
|
||||
|
||||
self.align_ik_control_bone(name)
|
||||
|
||||
vec = self.get_bone(org_two).tail - self.get_bone(org_one).head
|
||||
self.get_bone(name).length = self.vector_without_z(vec).length
|
||||
|
||||
return name
|
||||
|
@ -120,37 +144,83 @@ class Rig(BaseLimbRig):
|
|||
|
||||
@stage.parent_bones
|
||||
def parent_heel_control_bone(self):
|
||||
self.set_bone_parent(self.bones.ctrl.heel, self.get_ik_control_output())
|
||||
if self.use_heel2:
|
||||
self.set_bone_parent(self.bones.ctrl.heel, self.bones.ctrl.heel2)
|
||||
else:
|
||||
self.set_bone_parent(self.bones.ctrl.heel, self.get_ik_control_output())
|
||||
|
||||
@stage.configure_bones
|
||||
def configure_heel_control_bone(self):
|
||||
bone = self.get_bone(self.bones.ctrl.heel)
|
||||
bone.lock_location = True, True, True
|
||||
bone.lock_scale = True, True, True
|
||||
|
||||
@stage.generate_widgets
|
||||
def generate_heel_control_widget(self):
|
||||
create_ballsocket_widget(self.obj, self.bones.ctrl.heel)
|
||||
|
||||
|
||||
####################################################
|
||||
# Second Heel control
|
||||
|
||||
@stage.generate_bones
|
||||
def make_heel2_control_bone(self):
|
||||
if self.use_heel2:
|
||||
org = self.bones.org.main[3]
|
||||
name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_ik'))
|
||||
self.bones.ctrl.heel2 = name
|
||||
|
||||
flip_bone(self.obj, name)
|
||||
|
||||
@stage.parent_bones
|
||||
def parent_heel2_control_bone(self):
|
||||
if self.use_heel2:
|
||||
self.set_bone_parent(self.bones.ctrl.heel2, self.get_ik_control_output())
|
||||
|
||||
@stage.configure_bones
|
||||
def configure_heel2_control_bone(self):
|
||||
if self.use_heel2:
|
||||
bone = self.get_bone(self.bones.ctrl.heel2)
|
||||
bone.lock_location = True, True, True
|
||||
|
||||
@stage.generate_widgets
|
||||
def generate_heel2_control_widget(self):
|
||||
if self.use_heel2:
|
||||
create_ballsocket_widget(self.obj, self.bones.ctrl.heel2)
|
||||
|
||||
|
||||
####################################################
|
||||
# FK control chain
|
||||
|
||||
def make_fk_control_widget(self, i, ctrl):
|
||||
if i < self.toe_bone_index - 1:
|
||||
create_limb_widget(self.obj, ctrl)
|
||||
elif i == self.toe_bone_index - 1:
|
||||
create_circle_widget(self.obj, ctrl, radius=0.4, head_tail=0.0)
|
||||
else:
|
||||
create_circle_widget(self.obj, ctrl, radius=0.4, head_tail=0.5)
|
||||
|
||||
|
||||
####################################################
|
||||
# FK parents MCH chain
|
||||
|
||||
@stage.generate_bones
|
||||
def make_toe_socket_bone(self):
|
||||
org = self.bones.org.main[3]
|
||||
org = self.bones.org.main[self.toe_bone_index]
|
||||
self.bones.mch.toe_socket = self.copy_bone(org, make_derived_name(org, 'mch', '_ik_socket'))
|
||||
|
||||
@stage.parent_bones
|
||||
def parent_toe_socket_bone(self):
|
||||
self.set_bone_parent(self.bones.mch.toe_socket, self.get_ik_control_output())
|
||||
|
||||
def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org):
|
||||
if i == 3:
|
||||
if i == self.toe_bone_index:
|
||||
self.set_bone_parent(parent_mch, prev_org, use_connect=True)
|
||||
self.set_bone_parent(self.bones.mch.toe_socket, self.get_ik_control_output())
|
||||
|
||||
else:
|
||||
super().parent_fk_parent_bone(i, parent_mch, prev_ctrl, org, prev_org)
|
||||
|
||||
def rig_fk_parent_bone(self, i, parent_mch, org):
|
||||
if i == 3:
|
||||
if i == self.toe_bone_index:
|
||||
con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.toe_socket)
|
||||
|
||||
self.make_driver(con, 'influence', variables=[(self.prop_bone, 'IK_FK')], polynomial=[1.0, -1.0])
|
||||
|
@ -174,6 +244,30 @@ class Rig(BaseLimbRig):
|
|||
self.set_bone_parent(self.bones.mch.ik_target, self.bones.ctrl.heel)
|
||||
|
||||
|
||||
####################################################
|
||||
# IK heel2 output
|
||||
|
||||
def get_ik_output_chain(self):
|
||||
tail = [self.bones.mch.ik_heel2] if self.use_heel2 else []
|
||||
return super().get_ik_output_chain() + tail
|
||||
|
||||
@stage.generate_bones
|
||||
def make_ik_heel2_bone(self):
|
||||
if self.use_heel2:
|
||||
orgs = self.bones.org.main
|
||||
self.bones.mch.ik_heel2 = self.copy_bone(orgs[3], make_derived_name(orgs[3], 'mch', '_ik_out'))
|
||||
|
||||
@stage.parent_bones
|
||||
def parent_ik_heel2_bone(self):
|
||||
if self.use_heel2:
|
||||
self.set_bone_parent(self.bones.mch.ik_heel2, self.bones.ctrl.heel2)
|
||||
|
||||
@stage.rig_bones
|
||||
def rig_ik_heel2_bone(self):
|
||||
if self.use_heel2:
|
||||
self.make_constraint(self.bones.mch.ik_heel2, 'COPY_LOCATION', self.bones.mch.ik_target, head_tail=1)
|
||||
|
||||
|
||||
####################################################
|
||||
# Deform chain
|
||||
|
||||
|
@ -284,3 +378,5 @@ def create_sample(obj):
|
|||
bone.select_head = True
|
||||
bone.select_tail = True
|
||||
arm.edit_bones.active = bone
|
||||
|
||||
return bones
|
||||
|
|
|
@ -1,300 +1,194 @@
|
|||
#====================== 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 .paw import Rig as pawRig
|
||||
from ...utils.bones import align_bone_roll
|
||||
from ...utils.naming import make_derived_name
|
||||
from ...utils.misc import map_list
|
||||
|
||||
from itertools import count
|
||||
|
||||
IMPLEMENTATION = True # Include and set True if Rig is just an implementation for a wrapper class
|
||||
# add_parameters and parameters_ui are unused for implementation classes
|
||||
from ...base_rig import stage
|
||||
|
||||
from .limb_rigs import BaseLimbRig
|
||||
from .paw import Rig as pawRig, create_sample as create_paw_sample
|
||||
|
||||
|
||||
class Rig(pawRig):
|
||||
pass
|
||||
"""Rear paw rig with special IK automation."""
|
||||
|
||||
####################################################
|
||||
# EXTRA BONES
|
||||
#
|
||||
# mch:
|
||||
# ik2_stretch, ik2_target
|
||||
# Three bone IK stretch limit
|
||||
# ik2_chain[2]
|
||||
# Second IK system (pre-driving thigh and ik3)
|
||||
# ik3_chain[2]
|
||||
# Third IK system (pre-driving heel)
|
||||
#
|
||||
####################################################
|
||||
|
||||
####################################################
|
||||
# IK controls
|
||||
|
||||
def get_middle_ik_controls(self):
|
||||
return [self.bones.ctrl.heel]
|
||||
|
||||
def get_ik_fk_position_chains(self):
|
||||
ik_chain, fk_chain = super().get_ik_fk_position_chains()
|
||||
if not self.use_heel2:
|
||||
return [*ik_chain, ik_chain[-1]], [*fk_chain, fk_chain[-1]]
|
||||
return ik_chain, fk_chain
|
||||
|
||||
def get_extra_ik_controls(self):
|
||||
extra = [self.bones.ctrl.heel2] if self.use_heel2 else []
|
||||
return BaseLimbRig.get_extra_ik_controls(self) + extra
|
||||
|
||||
def get_ik_pole_parents(self):
|
||||
return [(self.bones.mch.ik2_target, self.bones.ctrl.ik)]
|
||||
|
||||
|
||||
####################################################
|
||||
# Heel control
|
||||
|
||||
@stage.parent_bones
|
||||
def parent_heel_control_bone(self):
|
||||
self.set_bone_parent(self.bones.ctrl.heel, self.bones.mch.ik3_chain[-1])
|
||||
|
||||
|
||||
####################################################
|
||||
# Second IK system (pre-driving thigh)
|
||||
|
||||
use_mch_ik_base = True
|
||||
|
||||
def get_ik2_input_bone(self):
|
||||
return self.bones.ctrl.heel2 if self.use_heel2 else self.bones.mch.toe_socket
|
||||
|
||||
@stage.generate_bones
|
||||
def make_ik2_mch_stretch(self):
|
||||
orgs = self.bones.org.main
|
||||
|
||||
self.bones.mch.ik2_stretch = self.make_ik2_mch_stretch_bone(orgs)
|
||||
self.bones.mch.ik2_target = self.make_ik2_mch_target_bone(orgs)
|
||||
|
||||
def make_ik2_mch_stretch_bone(self, orgs):
|
||||
name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'mch', '_ik2_stretch'))
|
||||
self.get_bone(name).tail = self.get_bone(orgs[3]).head
|
||||
return name
|
||||
|
||||
def make_ik2_mch_target_bone(self, orgs):
|
||||
return self.copy_bone(orgs[3], make_derived_name(orgs[0], 'mch', '_ik2_target'), scale=1/2)
|
||||
|
||||
@stage.generate_bones
|
||||
def make_ik2_mch_chain(self):
|
||||
orgs = self.bones.org.main
|
||||
chain = map_list(self.make_ik2_mch_bone, count(0), orgs[0:2])
|
||||
self.bones.mch.ik2_chain = chain
|
||||
|
||||
org_bones = map_list(self.get_bone, orgs)
|
||||
chain_bones = map_list(self.get_bone, chain)
|
||||
|
||||
# Extend the base IK control (used in the ik2 chain) with the projected length of org2
|
||||
chain_bones[0].length += org_bones[2].vector.dot(chain_bones[0].vector.normalized())
|
||||
chain_bones[1].head = chain_bones[0].tail
|
||||
chain_bones[1].tail = org_bones[2].tail
|
||||
align_bone_roll(self.obj, chain[1], orgs[1])
|
||||
|
||||
def make_ik2_mch_bone(self, i, org):
|
||||
return self.copy_bone(org, make_derived_name(org, 'mch', '_ik2'))
|
||||
|
||||
@stage.parent_bones
|
||||
def parent_ik2_mch_chain(self):
|
||||
mch = self.bones.mch
|
||||
self.set_bone_parent(mch.ik2_stretch, mch.follow)
|
||||
self.set_bone_parent(mch.ik2_target, self.get_ik2_input_bone())
|
||||
self.set_bone_parent(mch.ik2_chain[0], self.bones.ctrl.ik_base, inherit_scale='AVERAGE')
|
||||
self.parent_bone_chain(mch.ik2_chain, use_connect=True)
|
||||
|
||||
@stage.configure_bones
|
||||
def configure_ik2_mch_chain(self):
|
||||
for i, mch in enumerate(self.bones.mch.ik2_chain):
|
||||
self.configure_ik2_mch_bone(i, mch)
|
||||
|
||||
def configure_ik2_mch_bone(self, i, mch):
|
||||
bone = self.get_bone(mch)
|
||||
bone.ik_stretch = 0.1
|
||||
if i == 1:
|
||||
bone.lock_ik_x = bone.lock_ik_y = bone.lock_ik_z = True
|
||||
setattr(bone, 'lock_ik_' + self.main_axis, False)
|
||||
|
||||
@stage.rig_bones
|
||||
def rig_ik2_mch_chain(self):
|
||||
mch = self.bones.mch
|
||||
input_bone = self.get_ik2_input_bone()
|
||||
head_tail = 1 if self.use_heel2 else 0
|
||||
|
||||
self.rig_ik_mch_stretch_bones(mch.ik2_target, mch.ik2_stretch, input_bone, head_tail, 3)
|
||||
self.rig_ik_mch_end_bone(mch.ik2_chain[-1], mch.ik2_target, self.bones.ctrl.ik_pole)
|
||||
|
||||
|
||||
####################################################
|
||||
# Third IK system (pre-driving heel control)
|
||||
|
||||
@stage.generate_bones
|
||||
def make_ik3_mch_chain(self):
|
||||
self.bones.mch.ik3_chain = map_list(self.make_ik3_mch_bone, count(0), self.bones.org.main[1:3])
|
||||
|
||||
def make_ik3_mch_bone(self, i, org):
|
||||
return self.copy_bone(org, make_derived_name(org, 'mch', '_ik3'))
|
||||
|
||||
@stage.parent_bones
|
||||
def parent_ik3_mch_chain(self):
|
||||
mch = self.bones.mch
|
||||
|
||||
self.set_bone_parent(mch.ik3_chain[0], mch.ik2_chain[0])
|
||||
self.parent_bone_chain(mch.ik3_chain, use_connect=True)
|
||||
|
||||
@stage.configure_bones
|
||||
def configure_ik3_mch_chain(self):
|
||||
for i, mch in enumerate(self.bones.mch.ik3_chain):
|
||||
self.configure_ik3_mch_bone(i, mch)
|
||||
|
||||
def configure_ik3_mch_bone(self, i, mch):
|
||||
bone = self.get_bone(mch)
|
||||
bone.ik_stretch = 0.1
|
||||
if i == 0:
|
||||
bone.lock_ik_x = bone.lock_ik_y = bone.lock_ik_z = True
|
||||
setattr(bone, 'lock_ik_' + self.main_axis, False)
|
||||
|
||||
@stage.rig_bones
|
||||
def rig_ik3_mch_chain(self):
|
||||
mch = self.bones.mch
|
||||
# Mostly cancel ik2 scaling.
|
||||
self.make_constraint(
|
||||
mch.ik3_chain[0], 'COPY_SCALE', self.bones.ctrl.ik_base,
|
||||
use_make_uniform=True, influence=0.75,
|
||||
)
|
||||
self.make_constraint(mch.ik3_chain[-1], 'IK', mch.ik2_target, chain_count=2)
|
||||
|
||||
|
||||
def create_sample(obj):
|
||||
# generated by rigify.utils.write_metarig
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
arm = obj.data
|
||||
|
||||
bones = {}
|
||||
|
||||
bone = arm.edit_bones.new('thigh.L')
|
||||
bone.head[:] = 0.0291, 0.1181, 0.2460
|
||||
bone.tail[:] = 0.0293, 0.1107, 0.1682
|
||||
bone.roll = 3.1383
|
||||
bone.use_connect = False
|
||||
bones['thigh.L'] = bone.name
|
||||
bone = arm.edit_bones.new('shin.L')
|
||||
bone.head[:] = 0.0293, 0.1107, 0.1682
|
||||
bone.tail[:] = 0.0293, 0.1684, 0.1073
|
||||
bone.roll = 3.1416
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones[bones['thigh.L']]
|
||||
bones['shin.L'] = bone.name
|
||||
bone = arm.edit_bones.new('foot.L')
|
||||
bone.head[:] = 0.0293, 0.1684, 0.1073
|
||||
bone.tail[:] = 0.0293, 0.1530, 0.0167
|
||||
bone.roll = 3.1416
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones[bones['shin.L']]
|
||||
bones['foot.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_toe.L')
|
||||
bone.head[:] = 0.0293, 0.1530, 0.0167
|
||||
bone.tail[:] = 0.0293, 0.1224, 0.0167
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones[bones['foot.L']]
|
||||
bones['r_toe.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_palm.001.L')
|
||||
bone.head[:] = 0.0220, 0.1457, 0.0123
|
||||
bone.tail[:] = 0.0215, 0.1401, 0.0123
|
||||
bone.roll = 0.0014
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones[bones['r_toe.L']]
|
||||
bones['r_palm.001.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_palm.002.L')
|
||||
bone.head[:] = 0.0297, 0.1458, 0.0123
|
||||
bone.tail[:] = 0.0311, 0.1393, 0.0123
|
||||
bone.roll = -0.0005
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones[bones['r_toe.L']]
|
||||
bones['r_palm.002.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_palm.003.L')
|
||||
bone.head[:] = 0.0363, 0.1473, 0.0123
|
||||
bone.tail[:] = 0.0376, 0.1407, 0.0123
|
||||
bone.roll = 0.0000
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones[bones['r_toe.L']]
|
||||
bones['r_palm.003.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_palm.004.L')
|
||||
bone.head[:] = 0.0449, 0.1501, 0.0123
|
||||
bone.tail[:] = 0.0466, 0.1479, 0.0123
|
||||
bone.roll = -0.0004
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones[bones['r_toe.L']]
|
||||
bones['r_palm.004.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_index.001.L')
|
||||
bone.head[:] = 0.0215, 0.1367, 0.0087
|
||||
bone.tail[:] = 0.0217, 0.1325, 0.0070
|
||||
bone.roll = -0.3427
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones[bones['r_palm.001.L']]
|
||||
bones['r_index.001.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_middle.001.L')
|
||||
bone.head[:] = 0.0311, 0.1358, 0.0117
|
||||
bone.tail[:] = 0.0324, 0.1297, 0.0092
|
||||
bone.roll = -1.0029
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones[bones['r_palm.002.L']]
|
||||
bones['r_middle.001.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_ring.001.L')
|
||||
bone.head[:] = 0.0376, 0.1372, 0.0117
|
||||
bone.tail[:] = 0.0389, 0.1311, 0.0092
|
||||
bone.roll = -1.0029
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones[bones['r_palm.003.L']]
|
||||
bones['r_ring.001.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_pinky.001.L')
|
||||
bone.head[:] = 0.0466, 0.1444, 0.0083
|
||||
bone.tail[:] = 0.0476, 0.1412, 0.0074
|
||||
bone.roll = -1.7551
|
||||
bone.use_connect = False
|
||||
bone.parent = arm.edit_bones[bones['r_palm.004.L']]
|
||||
bones['r_pinky.001.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_index.002.L')
|
||||
bone.head[:] = 0.0217, 0.1325, 0.0070
|
||||
bone.tail[:] = 0.0221, 0.1271, 0.0038
|
||||
bone.roll = -0.2465
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones[bones['r_index.001.L']]
|
||||
bones['r_index.002.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_middle.002.L')
|
||||
bone.head[:] = 0.0324, 0.1297, 0.0092
|
||||
bone.tail[:] = 0.0343, 0.1210, 0.0039
|
||||
bone.roll = -0.7479
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones[bones['r_middle.001.L']]
|
||||
bones['r_middle.002.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_ring.002.L')
|
||||
bone.head[:] = 0.0389, 0.1311, 0.0092
|
||||
bone.tail[:] = 0.0407, 0.1229, 0.0042
|
||||
bone.roll = -0.7479
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones[bones['r_ring.001.L']]
|
||||
bones['r_ring.002.L'] = bone.name
|
||||
bone = arm.edit_bones.new('r_pinky.002.L')
|
||||
bone.head[:] = 0.0476, 0.1412, 0.0074
|
||||
bone.tail[:] = 0.0494, 0.1351, 0.0032
|
||||
bone.roll = -0.8965
|
||||
bone.use_connect = True
|
||||
bone.parent = arm.edit_bones[bones['r_pinky.001.L']]
|
||||
bones['r_pinky.002.L'] = bone.name
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
bones = create_paw_sample(obj)
|
||||
pbone = obj.pose.bones[bones['thigh.L']]
|
||||
pbone.rigify_type = 'limbs.paw'
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
try:
|
||||
pbone.rigify_parameters.limb_type = "paw"
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
pbone.rigify_parameters.fk_layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
pbone.rigify_parameters.segments = 2
|
||||
except AttributeError:
|
||||
pass
|
||||
pbone = obj.pose.bones[bones['shin.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['foot.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['r_toe.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['r_palm.001.L']]
|
||||
pbone.rigify_type = 'limbs.super_palm'
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['r_palm.002.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['r_palm.003.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['r_palm.004.L']]
|
||||
pbone.rigify_type = 'limbs.super_palm'
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['r_index.001.L']]
|
||||
pbone.rigify_type = 'limbs.simple_tentacle'
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
try:
|
||||
pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
|
||||
except AttributeError:
|
||||
pass
|
||||
pbone = obj.pose.bones[bones['r_middle.001.L']]
|
||||
pbone.rigify_type = 'limbs.simple_tentacle'
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
try:
|
||||
pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
|
||||
except AttributeError:
|
||||
pass
|
||||
pbone = obj.pose.bones[bones['r_ring.001.L']]
|
||||
pbone.rigify_type = 'limbs.simple_tentacle'
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
try:
|
||||
pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
|
||||
except AttributeError:
|
||||
pass
|
||||
pbone = obj.pose.bones[bones['r_pinky.001.L']]
|
||||
pbone.rigify_type = 'limbs.simple_tentacle'
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
try:
|
||||
pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
|
||||
except AttributeError:
|
||||
pass
|
||||
pbone = obj.pose.bones[bones['r_index.002.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['r_middle.002.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['r_ring.002.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone = obj.pose.bones[bones['r_pinky.002.L']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
pbone.lock_rotation = (False, False, False)
|
||||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
for bone in arm.edit_bones:
|
||||
bone.select = False
|
||||
bone.select_head = False
|
||||
bone.select_tail = False
|
||||
for b in bones:
|
||||
bone = arm.edit_bones[bones[b]]
|
||||
bone.select = True
|
||||
bone.select_head = True
|
||||
bone.select_tail = True
|
||||
arm.edit_bones.active = bone
|
||||
|
||||
for eb in arm.edit_bones:
|
||||
if ('thigh' in eb.name) or ('shin' in eb.name) or ('foot' in eb.name) or ('toe' in eb.name):
|
||||
eb.layers = (False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
|
||||
else:
|
||||
eb.layers = (False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
|
||||
arm.layers = (False, False, False, False, False, True, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
create_sample(bpy.context.active_object)
|
||||
pbone.rigify_type = 'limbs.rear_paw'
|
||||
return bones
|
||||
|
|
|
@ -100,7 +100,7 @@ class Rig(SimpleChainRig):
|
|||
self.bones.ctrl.fk += [self.make_tip_control_bone(orgs[-1], orgs[0])]
|
||||
|
||||
def make_control_bone(self, i, org):
|
||||
return self.copy_bone(org, make_derived_name(org, 'ctrl'), parent=False)
|
||||
return self.copy_bone(org, make_derived_name(org, 'ctrl'), inherit_scale=True)
|
||||
|
||||
def make_tip_control_bone(self, org, name_org):
|
||||
name = self.copy_bone(org, make_derived_name(name_org, 'ctrl'), parent=False)
|
||||
|
@ -219,7 +219,7 @@ class Rig(SimpleChainRig):
|
|||
self.bones.mch.bend = map_list(self.make_mch_bend_bone, self.bones.org)
|
||||
|
||||
def make_mch_bend_bone(self, org):
|
||||
return self.copy_bone(org, make_derived_name(org, 'mch', '_drv'), parent=False, scale=0.3)
|
||||
return self.copy_bone(org, make_derived_name(org, 'mch', '_drv'), inherit_scale=True, scale=0.3)
|
||||
|
||||
@stage.parent_bones
|
||||
def parent_mch_bend_chain(self):
|
||||
|
|
|
@ -121,7 +121,7 @@ def new_bone(obj, bone_name):
|
|||
raise MetarigError("Can't add new bone '%s' outside of edit mode" % bone_name)
|
||||
|
||||
|
||||
def copy_bone(obj, bone_name, assign_name='', *, parent=False, bbone=False, length=None, scale=None):
|
||||
def copy_bone(obj, bone_name, assign_name='', *, parent=False, inherit_scale=False, bbone=False, length=None, scale=None):
|
||||
""" Makes a copy of the given bone in the given armature object.
|
||||
Returns the resulting bone's name.
|
||||
"""
|
||||
|
@ -151,6 +151,8 @@ def copy_bone(obj, bone_name, assign_name='', *, parent=False, bbone=False, leng
|
|||
|
||||
edit_bone_2.use_inherit_rotation = edit_bone_1.use_inherit_rotation
|
||||
edit_bone_2.use_local_location = edit_bone_1.use_local_location
|
||||
|
||||
if parent or inherit_scale:
|
||||
edit_bone_2.inherit_scale = edit_bone_1.inherit_scale
|
||||
|
||||
if bbone:
|
||||
|
@ -385,9 +387,9 @@ class BoneUtilityMixin(object):
|
|||
self.register_new_bone(name)
|
||||
return name
|
||||
|
||||
def copy_bone(self, bone_name, new_name='', *, parent=False, bbone=False, length=None, scale=None):
|
||||
def copy_bone(self, bone_name, new_name='', *, parent=False, inherit_scale=False, bbone=False, length=None, scale=None):
|
||||
"""Copy the bone with the given name, returning the new name."""
|
||||
name = copy_bone(self.obj, bone_name, new_name, parent=parent, bbone=bbone, length=length, scale=scale)
|
||||
name = copy_bone(self.obj, bone_name, new_name, parent=parent, inherit_scale=inherit_scale, bbone=bbone, length=length, scale=scale)
|
||||
self.register_new_bone(name, bone_name)
|
||||
return name
|
||||
|
||||
|
@ -659,13 +661,15 @@ def align_bone_to_axis(obj, bone_name, axis, *, length=None, roll=0, flip=False)
|
|||
bone_e.roll = roll
|
||||
|
||||
|
||||
def set_bone_widget_transform(obj, bone_name, transform_bone, use_size=True, scale=1.0):
|
||||
def set_bone_widget_transform(obj, bone_name, transform_bone, use_size=True, scale=1.0, target_size=False):
|
||||
assert obj.mode != 'EDIT'
|
||||
|
||||
bone = obj.pose.bones[bone_name]
|
||||
|
||||
if transform_bone and transform_bone != bone_name:
|
||||
bone.custom_shape_transform = obj.pose.bones[transform_bone]
|
||||
bone.custom_shape_transform = bone2 = obj.pose.bones[transform_bone]
|
||||
if use_size and target_size:
|
||||
scale *= bone2.length / bone.length
|
||||
else:
|
||||
bone.custom_shape_transform = None
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ import importlib
|
|||
import importlib.util
|
||||
import os
|
||||
|
||||
from bpy.types import bpy_struct, bpy_prop_array, Constraint
|
||||
|
||||
RIG_DIR = "rigs" # Name of the directory where rig types are kept
|
||||
METARIG_DIR = "metarigs" # Name of the directory where metarigs are kept
|
||||
TEMPLATE_DIR = "ui_templates" # Name of the directory where ui templates are kept
|
||||
|
@ -147,6 +149,30 @@ def list_bone_names_depth_first_sorted(obj):
|
|||
return result_list
|
||||
|
||||
|
||||
def _get_property_value(obj, name):
|
||||
value = getattr(obj, name, None)
|
||||
if isinstance(value, bpy_prop_array):
|
||||
value = tuple(value)
|
||||
return value
|
||||
|
||||
def _generate_properties(lines, prefix, obj, base_class, *, defaults={}, objects={}):
|
||||
block_props = set(prop.identifier for prop in base_class.bl_rna.properties) - set(defaults.keys())
|
||||
|
||||
for prop in type(obj).bl_rna.properties:
|
||||
if prop.identifier not in block_props and not prop.is_readonly:
|
||||
cur_value = _get_property_value(obj, prop.identifier)
|
||||
|
||||
if prop.identifier in defaults:
|
||||
if cur_value == defaults[prop.identifier]:
|
||||
continue
|
||||
|
||||
if isinstance(cur_value, bpy_struct):
|
||||
if cur_value in objects:
|
||||
lines.append('%s.%s = %s' % (prefix, prop.identifier, objects[cur_value]))
|
||||
else:
|
||||
lines.append('%s.%s = %r' % (prefix, prop.identifier, cur_value))
|
||||
|
||||
|
||||
def write_metarig(obj, layers=False, func_name="create", groups=False):
|
||||
"""
|
||||
Write a metarig as a python script, this rig is to have all info needed for
|
||||
|
@ -211,6 +237,8 @@ def write_metarig(obj, layers=False, func_name="create", groups=False):
|
|||
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.inherit_scale != 'FULL':
|
||||
code.append(" bone.inherit_scale = %r" % str(bone.inherit_scale))
|
||||
if bone.parent:
|
||||
code.append(" bone.parent = arm.edit_bones[bones[%r]]" % bone.parent.name)
|
||||
code.append(" bones[%r] = bone.name" % bone.name)
|
||||
|
@ -243,6 +271,29 @@ def write_metarig(obj, layers=False, func_name="create", groups=False):
|
|||
code.append(" pbone.rigify_parameters.%s = %s" % (param_name, str(param)))
|
||||
code.append(" except AttributeError:")
|
||||
code.append(" pass")
|
||||
# Constraints
|
||||
for con in pbone.constraints:
|
||||
code.append(" con = pbone.constraints.new(%r)" % (con.type))
|
||||
code.append(" con.name = %r" % (con.name))
|
||||
# Add target first because of target_space handling
|
||||
if con.type == 'ARMATURE':
|
||||
for tgt in con.targets:
|
||||
code.append(" tgt = con.targets.new()")
|
||||
code.append(" tgt.target = obj")
|
||||
code.append(" tgt.subtarget = %r" % (tgt.subtarget))
|
||||
code.append(" tgt.weight = %.3f" % (tgt.weight))
|
||||
elif getattr(con, 'target', None) == obj:
|
||||
code.append(" con.target = obj")
|
||||
# Generic properties
|
||||
_generate_properties(
|
||||
code, " con", con, Constraint,
|
||||
defaults={
|
||||
'owner_space': 'WORLD', 'target_space': 'WORLD',
|
||||
'mute': False, 'influence': 1.0,
|
||||
'target': obj,
|
||||
},
|
||||
objects={obj: 'obj'},
|
||||
)
|
||||
|
||||
code.append("\n bpy.ops.object.mode_set(mode='EDIT')")
|
||||
code.append(" for bone in arm.edit_bones:")
|
||||
|
|
Loading…
Reference in New Issue