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

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormeta-androcto <meta.androcto1@gmail.com>2017-07-12 04:05:13 +0300
committermeta-androcto <meta.androcto1@gmail.com>2017-07-12 04:05:13 +0300
commit8a3e171dabe636e089ed1f7beb2c09a101ab2afb (patch)
treec040c71cb094d8383345de66c8ac714232ba7edc /object_skinify.py
parent4e25de776a09e9d6bb6ccac9e935c32ea0952d95 (diff)
skinify rig: fixes for rigify by Karab44
Diffstat (limited to 'object_skinify.py')
-rw-r--r--object_skinify.py382
1 files changed, 223 insertions, 159 deletions
diff --git a/object_skinify.py b/object_skinify.py
index 92e2a8ed..c62466f2 100644
--- a/object_skinify.py
+++ b/object_skinify.py
@@ -19,8 +19,8 @@
bl_info = {
"name": "Skinify Rig",
"author": "Albert Makac (karab44)",
- "version": (0, 8, 9),
- "blender": (2, 7, 8),
+ "version": (0, 9, 0),
+ "blender": (2, 7, 9),
"location": "Properties > Bone > Skinify Rig (visible on pose mode only)",
"description": "Creates a mesh object from selected bones",
"warning": "",
@@ -104,23 +104,47 @@ pitchipoy_data = \
rigify_data = horse_data, shark_data, bird_data, cat_data, biped_data, human_data, \
wolf_data, quadruped_data, human_legacy_data, pitchipoy_data
-
-class Rig_type(Enum):
- HORSE = 0
- SHARK = 1
- BIRD = 2
- CAT = 3
- BIPED = 4
- HUMAN = 5
- WOLF = 6
- QUAD = 7
- LEGACY = 8
- PITCHIPOY = 9
- OTHER = 10
-
-
-rig_type = Rig_type.OTHER
-
+#Skin.rig_type.ENUM
+#Skin.junction_dict['bname'].data[0] idx, data[1] idx +1, data[2] thicnkess
+#NOTE each fragment contains section information about adequate bone junctions idx and idx + 1 and these vertices' ids share common thickness
+class Skin(object):
+
+ class Rig_type(Enum):
+ HORSE = 0
+ SHARK = 1
+ BIRD = 2
+ CAT = 3
+ BIPED = 4
+ HUMAN = 5
+ WOLF = 6
+ QUAD = 7
+ LEGACY = 8
+ PITCHIPOY = 9
+ OTHER = 10
+
+ def __init__(self, rig_type):
+ self.rig_type = rig_type
+ self.junctions_dict = dict()
+
+
+ def fragment_create(self, bname, idx = None, thickness = 0.0):
+ data = []
+ data.insert(0, idx)
+
+ if idx != None:
+ data.insert(1, idx + 1)
+ else:
+ data.insert(1, None)
+
+ self.junctions_dict[bname] = data
+ self.junctions_dict[bname].append(thickness)
+
+ #for the sake of code clarity
+ def fragment_update(self, bname, idx = None, thickness = 0.0):
+ self.fragment_create(bname, idx, thickness)
+
+
+rig_type = Skin.Rig_type.OTHER
# initialize properties
def init_props():
@@ -139,26 +163,9 @@ def init_props():
scn.sub_level = 1
-# selects vertices
-def select_vertices(mesh_obj, idx):
- bpy.context.scene.objects.active = mesh_obj
- mode = mesh_obj.mode
- bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.mesh.select_all(action='DESELECT')
- bpy.ops.object.mode_set(mode='OBJECT')
-
- for i in idx:
- mesh_obj.data.vertices[i].select = True
-
- selectedVerts = [v.index for v in mesh_obj.data.vertices if v.select]
-
- bpy.ops.object.mode_set(mode=mode)
- return selectedVerts
-
-
def identify_rig():
if 'rigify_layers' not in bpy.context.object.data:
- return Rig_type.OTHER # non recognized
+ return Skin.Rig_type.OTHER # non recognized
LEGACY_LAYERS_SIZE = 28
layers = bpy.context.object.data['rigify_layers']
@@ -175,35 +182,33 @@ def identify_rig():
elif (props['row'] != rig[index][0]) or (props['group_prop'] != rig[index][1]):
break
- # SUCCESS if reach the end
+ # SUCCESS if reaches the end
if index == len(layers) - 1:
- return Rig_type(type)
+ return Skin.Rig_type(type)
index = index + 1
- return Rig_type.OTHER
-
+ return Skin.Rig_type.OTHER
-def prepare_ignore_list(rig_type, bones):
- # detect the head, face, hands, breast, heels or other exceptionary bones to exclusion or customization
+#prepares customizable ignore and thickness lists
+# edit these lists to suits your taste
+def prepare_lists(rig_type, finger_thickness):
+
+
+ # EXAMPLE IGNORE LIST
+ # detect the head, face, hands, breast, heels or other exceptionary bones for exclusion or customization
common_ignore_list = ['eye', 'heel', 'breast', 'root']
-
- # edit these lists to suits your taste
-
horse_ignore_list = ['chest', 'belly', 'pelvis', 'jaw', 'nose', 'skull', 'ear.']
-
shark_ignore_list = ['jaw']
-
bird_ignore_list = [
'face', 'pelvis', 'nose', 'lip', 'jaw', 'chin', 'ear.', 'brow',
'lid', 'forehead', 'temple', 'cheek', 'teeth', 'tongue', 'beak'
]
cat_ignore_list = [
- 'face', 'belly' 'pelvis.C', 'nose', 'lip', 'jaw', 'chin', 'ear.', 'brow',
+ 'face', 'belly', 'pelvis.C', 'nose', 'lip', 'jaw', 'chin', 'ear.', 'brow',
'lid', 'forehead', 'temple', 'cheek', 'teeth', 'tongue'
]
biped_ignore_list = ['pelvis']
-
human_ignore_list = [
'face', 'pelvis', 'nose', 'lip', 'jaw', 'chin', 'ear.', 'brow',
'lid', 'forehead', 'temple', 'cheek', 'teeth', 'tongue'
@@ -217,84 +222,119 @@ def prepare_ignore_list(rig_type, bones):
'lid', 'forehead', 'temple', 'cheek', 'teeth', 'tongue'
]
rigify_legacy_ignore_list = []
-
pitchipoy_ignore_list = [
'face', 'pelvis', 'nose', 'lip', 'jaw', 'chin', 'ear.', 'brow',
'lid', 'forehead', 'temple', 'cheek', 'teeth', 'tongue'
]
-
other_ignore_list = []
-
+
+ # EXAMPLE THICKNESS
+ # feel free to modify and customize the list by adding elements followed by comma common_thickness_dict = {"hand": common_finger_thickness, "head": common_head_thickness}
+ common_finger_thickness = finger_thickness
+ common_thickness_dict = {"hand": common_finger_thickness}
+ horse_thickness_dict = {}
+ shark_thickness_dict = {}
+ bird_thickness_dict = {}
+ cat_thickness_dict = {}
+ face_thickness = 0.20
+ biped_thickness_dict = {}
+ human_thickness_dict = {"face": face_thickness}
+ wolf_thickness_dict = {}
+ quad_thickness_dict = {}
+ rigify_legacy_thickness_dict = {}
+ pitchipoy_thickness_dict = {"face": face_thickness}
+ other_thickness_dict = {}
+
+
+ #combine lists depending on rig type
ignore_list = common_ignore_list
-
- if rig_type == Rig_type.HORSE:
+ thickness_dict = common_thickness_dict
+ if rig_type == Skin.Rig_type.HORSE:
ignore_list = ignore_list + horse_ignore_list
+ thickness_dict.update(horse_thickness_dict)
print("RIDER OF THE APOCALYPSE")
- elif rig_type == Rig_type.SHARK:
+ elif rig_type == Skin.Rig_type.SHARK:
ignore_list = ignore_list + shark_ignore_list
+ thickness_dict.update(shark_thickness_dict)
print("DEADLY JAWS")
- elif rig_type == Rig_type.BIRD:
+ elif rig_type == Skin.Rig_type.BIRD:
ignore_list = ignore_list + bird_ignore_list
+ thickness_dict.update(bird_thickness_dict)
print("WINGS OF LIBERTY")
- elif rig_type == Rig_type.CAT:
+ elif rig_type == Skin.Rig_type.CAT:
ignore_list = ignore_list + cat_ignore_list
+ thickness_dict.update(cat_thickness_dict)
print("MEOW")
- elif rig_type == Rig_type.BIPED:
- ignore_list = ignore_list + biped_ignore_list
+ elif rig_type == Skin.Rig_type.BIPED:
+ ignore_list = ignore_list + biped_ignore_list
+ thickness_dict.update(biped_thickness_dict)
print("HUMANOID")
- elif rig_type == Rig_type.HUMAN:
+ elif rig_type == Skin.Rig_type.HUMAN:
ignore_list = ignore_list + human_ignore_list
+ thickness_dict.update(human_thickness_dict)
print("JUST A HUMAN AFTER ALL")
- elif rig_type == Rig_type.WOLF:
+ elif rig_type == Skin.Rig_type.WOLF:
ignore_list = ignore_list + wolf_ignore_list
+ thickness_dict.update(wolf_thickness_dict)
print("WHITE FANG")
- elif rig_type == Rig_type.QUAD:
+ elif rig_type == Skin.Rig_type.QUAD:
ignore_list = ignore_list + quad_ignore_list
+ thickness_dict.update(quad_thickness_dict)
print("MYSTERIOUS CREATURE")
- elif rig_type == Rig_type.LEGACY:
+ elif rig_type == Skin.Rig_type.LEGACY:
ignore_list = ignore_list + rigify_legacy_ignore_list
+ thickness_dict.update(rigify_legacy_thickness_dict)
print("LEGACY RIGIFY")
- elif rig_type == Rig_type.PITCHIPOY:
+ elif rig_type == Skin.Rig_type.PITCHIPOY:
ignore_list = ignore_list + pitchipoy_ignore_list
+ thickness_dict.update(pitchipoy_thickness_dict)
print("PITCHIPOY")
- elif rig_type == Rig_type.OTHER:
+ elif rig_type == Skin.Rig_type.OTHER:
ignore_list = ignore_list + other_ignore_list
+ thickness_dict.update(other_thickness_dict)
print("rig non recognized...")
-
- return ignore_list
+
+ return ignore_list, thickness_dict
# generates edges from vertices used by skin modifier
def generate_edges(mesh, shape_object, bones, scale, connect_mesh=False, connect_parents=False,
- head_ornaments=False, generate_all=False):
+ head_ornaments=False, generate_all=False, thickness = 0.0, finger_thickness = 0.0):
"""
- This function adds vertices for all heads and tails
+ This function adds vertices for all bones' heads and tails
"""
- # scene preferences
-
- alternate_scale_list = []
-
+
me = mesh
verts = []
edges = []
idx = 0
- alternate_scale_idx_list = list()
-
+
rig_type = identify_rig()
- ignore_list = prepare_ignore_list(rig_type, bones)
-
+ skin = Skin(rig_type)
+
+ # prepare the list
+ ignore_list, thickness_dict = prepare_lists(skin.rig_type, finger_thickness)
+
+ #create default junctions for all bones
+ for b in bones:
+ # set default thickness to all new junctions
+ skin.fragment_create(bname = b.name, idx = None, thickness = thickness)
+
# edge generator loop
- for b in bones:
- # look for rig's hands and their childs
- if 'hand' in b.name.lower():
- # prepare the list
- for c in b.children_recursive:
- alternate_scale_list.append(c.name)
-
+ for b in bones:
+ # look for rig's specific bones and their childs and set individual thickness
+ for bname, thick in thickness_dict.items():
+
+ if bname.lower() in b.name.lower():
+ skin.fragment_update(bname = b.name, idx = None, thickness = thick)
+ for c in b.children_recursive:
+ #update junctions with specific thickness
+ skin.fragment_update(bname = c.name, idx = None, thickness = thick)
+
found = False
for i in ignore_list:
- if i in b.name.lower():
+ if i.lower() in b.name.lower():
found = True
break
@@ -309,10 +349,10 @@ def generate_edges(mesh, shape_object, bones, scale, connect_mesh=False, connect
if head_ornaments is False:
if b.parent is not None:
- if 'head' in b.parent.name.lower() and not rig_type == Rig_type.HUMAN:
+ if 'head' in b.parent.name.lower() and not rig_type == Skin.Rig_type.HUMAN:
continue
- if 'face' in b.parent.name.lower() and rig_type == Rig_type.HUMAN:
+ if 'face' in b.parent.name.lower() and rig_type == Skin.Rig_type.HUMAN:
continue
if connect_parents:
@@ -334,19 +374,22 @@ def generate_edges(mesh, shape_object, bones, scale, connect_mesh=False, connect
verts.append(vert1)
verts.append(vert2)
edges.append([idx, idx + 1])
-
- # also make list of edges made of gaps between the bones
- for a in alternate_scale_list:
- if b.name == a:
- alternate_scale_idx_list.append(idx)
- alternate_scale_idx_list.append(idx + 1)
+
+ # also make list of edges made of gaps between the bones
+ for bname, data in skin.junctions_dict.items():
+ if b.name == bname:
+ skin.fragment_update(b.name, idx, data[2])
+ break
+
+ # create new segment for new connections
+ skin.fragment_create(b.name + b.parent.name, idx, data[2])
idx = idx + 2
# for bvh free floating hips and hips correction for rigify and pitchipoy
if ((generate_all is False and 'hip' in b.name.lower()) or
- (generate_all is False and (b.name == 'hips' and rig_type == Rig_type.LEGACY) or
- (b.name == 'spine' and rig_type == Rig_type.PITCHIPOY) or (b.name == 'spine' and
- rig_type == Rig_type.HUMAN) or (b.name == 'spine' and rig_type == Rig_type.BIPED))):
+ (generate_all is False and (b.name == 'hips' and rig_type == Skin.Rig_type.LEGACY) or
+ (b.name == 'spine' and rig_type == Skin.Rig_type.PITCHIPOY) or (b.name == 'spine' and
+ rig_type == Skin.Rig_type.HUMAN) or (b.name == 'spine' and rig_type == Skin.Rig_type.BIPED))):
continue
vert1 = b.head
@@ -354,35 +397,49 @@ def generate_edges(mesh, shape_object, bones, scale, connect_mesh=False, connect
verts.append(vert1)
verts.append(vert2)
- edges.append([idx, idx + 1])
-
- for a in alternate_scale_list:
- if b.name == a:
- alternate_scale_idx_list.append(idx)
- alternate_scale_idx_list.append(idx + 1)
+ edges.append([idx, idx + 1])
+ #insert idx to junctions and update
+ for bname, data in skin.junctions_dict.items():
+ if b.name == bname:
+ skin.fragment_update(b.name, idx, data[2])
+
idx = idx + 2
-
+
# Create mesh from given verts, faces
me.from_pydata(verts, edges, [])
# Update mesh with new data
- me.update()
-
+ me.update()
# set object scale exact as armature's scale
shape_object.scale = scale
- return alternate_scale_idx_list, rig_type
+ return skin
+
+
+# selects vertices
+def select_vertices(mesh_obj, idx):
+ bpy.context.scene.objects.active = mesh_obj
+ mode = mesh_obj.mode
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.select_all(action='DESELECT')
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ for i in idx:
+ mesh_obj.data.vertices[i].select = True
+ selectedVerts = [v.index for v in mesh_obj.data.vertices if v.select]
-def generate_mesh(shape_object, size, thickness=0.8, finger_thickness=0.25, sub_level=1,
- connect_mesh=False, connect_parents=False, generate_all=False, apply_mod=True,
- alternate_scale_idx_list=[], rig_type=0, bones=[]):
+ bpy.ops.object.mode_set(mode=mode)
+ return selectedVerts
+
+
+def generate_mesh(shape_object, size, sub_level=1, connect_mesh=False, connect_parents=False, generate_all=False, apply_mod=True, skin = None, bones=[]):
"""
This function adds modifiers for generated edges
"""
total_bones_num = len(bpy.context.object.pose.bones.keys())
selected_bones_num = len(bones)
-
+
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
@@ -404,31 +461,30 @@ def generate_mesh(shape_object, size, thickness=0.8, finger_thickness=0.25, sub_
override['modifier'] = bpy.context.object.modifiers
break
- # calculate optimal thickness for defaults
+ # calculate optimal, normalized thickness for each segment
bpy.ops.object.skin_root_mark(override)
- bpy.ops.transform.skin_resize(override,
- value=(1 * thickness * (size / 10), 1 * thickness * (size / 10), 1 * thickness * (size / 10)),
- constraint_axis=(False, False, False), constraint_orientation='GLOBAL',
- mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH',
- proportional_size=1
- )
+
+ # select finger vertices and calculate optimal thickness for fingers to fix proportions
+ # by default set fingers thickness to 25 percent of body thickness
+ # make loose hands only for better topology
+
+ if len(skin.junctions_dict.keys()) > 0:
+ for bname, data in skin.junctions_dict.items():
+ if data[0] != None:
+ fragment_idx = list()
+ fragment_idx.append(data[0])
+ fragment_idx.append(data[1])
+ thickness = data[2]
+ select_vertices(shape_object, fragment_idx)
+ bpy.ops.transform.skin_resize(override,
+ value=(1 * thickness * (size / 10), 1 * thickness * (size / 10), 1 * thickness * (size / 10)),
+ constraint_axis=(False, False, False), constraint_orientation='GLOBAL',
+ mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH',
+ proportional_size=1
+ )
shape_object.modifiers["Skin"].use_smooth_shade = True
shape_object.modifiers["Skin"].use_x_symmetry = True
- # select finger vertices and calculate optimal thickness for fingers to fix proportions
- if len(alternate_scale_idx_list) > 0:
- select_vertices(shape_object, alternate_scale_idx_list)
-
- bpy.ops.object.skin_loose_mark_clear(override, action='MARK')
- # by default set fingers thickness to 25 percent of body thickness
- bpy.ops.transform.skin_resize(override,
- value=(finger_thickness, finger_thickness, finger_thickness),
- constraint_axis=(False, False, False), constraint_orientation='GLOBAL',
- mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH',
- proportional_size=1
- )
- # make loose hands only for better topology
-
# bpy.ops.mesh.select_all(action='DESELECT')
if connect_mesh:
@@ -436,19 +492,24 @@ def generate_mesh(shape_object, size, thickness=0.8, finger_thickness=0.25, sub_
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.remove_doubles()
-
- # fix rigify and pitchipoy hands topology
+
+
+ # fix rigify and pitchipoy hands topology
if connect_mesh and connect_parents and generate_all is False and \
- (rig_type == Rig_type.LEGACY or rig_type == Rig_type.PITCHIPOY or rig_type == Rig_type.HUMAN) and \
+ (skin.rig_type == Skin.Rig_type.LEGACY or skin.rig_type == Skin.Rig_type.PITCHIPOY or skin.rig_type == Skin.Rig_type.HUMAN) and \
selected_bones_num == total_bones_num:
# thickness will set palm vertex for both hands look pretty
corrective_thickness = 2.5
+
# left hand verts
merge_idx = []
- if rig_type == Rig_type.LEGACY:
- merge_idx = [7, 8, 13, 17, 22, 27]
- elif rig_type == Rig_type.PITCHIPOY or rig_type == Rig_type.HUMAN:
- merge_idx = [9, 14, 18, 23, 24, 29]
+
+ if skin.rig_type == Skin.Rig_type.LEGACY:
+ merge_idx = [8, 9, 14, 18, 23, 28]
+
+ elif skin.rig_type == Skin.Rig_type.PITCHIPOY or skin.rig_type == Skin.Rig_type.HUMAN:
+ merge_idx = [10, 11, 16, 20, 25, 30]
+
select_vertices(shape_object, merge_idx)
bpy.ops.mesh.merge(type='CENTER')
bpy.ops.transform.skin_resize(override,
@@ -459,12 +520,13 @@ def generate_mesh(shape_object, size, thickness=0.8, finger_thickness=0.25, sub_
)
bpy.ops.mesh.select_all(action='DESELECT')
- # right hand verts
- if rig_type == Rig_type.LEGACY:
- merge_idx = [30, 35, 39, 44, 45, 50]
- elif rig_type == Rig_type.PITCHIPOY or rig_type == Rig_type.HUMAN:
- merge_idx = [32, 37, 41, 46, 51, 52]
-
+ # right hand verts
+ if skin.rig_type == Skin.Rig_type.LEGACY:
+ merge_idx = [31, 32, 37, 41, 46, 51]
+
+ elif skin.rig_type == Skin.Rig_type.PITCHIPOY or skin.rig_type == Skin.Rig_type.HUMAN:
+ merge_idx = [33, 34, 39, 43, 48, 53]
+
select_vertices(shape_object, merge_idx)
bpy.ops.mesh.merge(type='CENTER')
bpy.ops.transform.skin_resize(override,
@@ -477,12 +539,14 @@ def generate_mesh(shape_object, size, thickness=0.8, finger_thickness=0.25, sub_
# making hands even more pretty
bpy.ops.mesh.select_all(action='DESELECT')
hands_idx = [] # left and right hand vertices
- if rig_type == Rig_type.LEGACY:
+ if skin.rig_type == Skin.Rig_type.LEGACY:
# hands_idx = [8, 33] # L and R
- hands_idx = [6, 29]
- elif rig_type == Rig_type.PITCHIPOY or rig_type == Rig_type.HUMAN:
+ hands_idx = [7, 30]
+
+ elif skin.rig_type == Skin.Rig_type.PITCHIPOY or skin.rig_type == Skin.Rig_type.HUMAN:
# hands_idx = [10, 35] # L and R
- hands_idx = [8, 31]
+ hands_idx = [9, 32]
+
select_vertices(shape_object, hands_idx)
# change the thickness to make hands look less blocky and more sexy
corrective_thickness = 0.7
@@ -497,9 +561,9 @@ def generate_mesh(shape_object, size, thickness=0.8, finger_thickness=0.25, sub_
# todo optionally take root from rig's hip tail or head depending on scenario
root_idx = []
- if rig_type == Rig_type.LEGACY and selected_bones_num == total_bones_num:
+ if skin.rig_type == Skin.Rig_type.LEGACY and selected_bones_num == total_bones_num:
root_idx = [59]
- elif (rig_type == Rig_type.PITCHIPOY or rig_type == Rig_type.HUMAN) and selected_bones_num == total_bones_num:
+ elif (skin.rig_type == Skin.Rig_type.PITCHIPOY or skin.rig_type == Skin.Rig_type.HUMAN) and selected_bones_num == total_bones_num:
root_idx = [56]
elif selected_bones_num == total_bones_num:
root_idx = [0]
@@ -578,15 +642,15 @@ def main(context):
# this way we fit mesh and bvh with armature modifier correctly
- alternate_scale_idx_list, rig_type = generate_edges(
- me, ob, bone_selection, scale, sknfy.connect_mesh,
- sknfy.connect_parents, sknfy.head_ornaments,
- sknfy.generate_all
- )
-
- generate_mesh(ob, size, sknfy.thickness, sknfy.finger_thickness, sknfy.sub_level,
+ skin = generate_edges(
+ me, ob, bone_selection, scale, sknfy.connect_mesh,
+ sknfy.connect_parents, sknfy.head_ornaments,
+ sknfy.generate_all, sknfy.thickness, sknfy.finger_thickness
+ )
+
+ generate_mesh(ob, size, sknfy.sub_level,
sknfy.connect_mesh, sknfy.connect_parents, sknfy.generate_all,
- sknfy.apply_mod, alternate_scale_idx_list, rig_type, bone_selection)
+ sknfy.apply_mod, skin, bone_selection)
# parent mesh with armature only if modifiers are applied
if sknfy.apply_mod and sknfy.parent_armature: