def __cleanup(self, names_in_use=None): names_in_use = names_in_use or {} rig = self.__rig for mesh in rig.meshes(): for kb in getattr(mesh.data.shape_keys, 'key_blocks', ()): if kb.name.startswith('mmd_bind') and kb.name not in names_in_use: kb.driver_remove('value') kb.relative_key.mute = False ObjectOp(mesh).shape_key_remove(kb) for m in mesh.modifiers: # uv morph if m.name.startswith('mmd_bind') and m.name not in names_in_use: mesh.modifiers.remove(m) from mmd_tools_local.core.shader import _MaterialMorph for m in rig.materials(): if m and m.node_tree: for n in sorted((x for x in m.node_tree.nodes if x.name.startswith('mmd_bind')), key=lambda x: -x.location[0]): _MaterialMorph.reset_morph_links(n) m.node_tree.nodes.remove(n) attributes = set(TransformConstraintOp.min_max_attributes('LOCATION', 'to')) attributes |= set(TransformConstraintOp.min_max_attributes('ROTATION', 'to')) for b in rig.armature().pose.bones: for c in b.constraints: if c.name.startswith('mmd_bind') and c.name[:-4] not in names_in_use: for attr in attributes: c.driver_remove(attr) b.constraints.remove(c)
def __cleanup(self, names_in_use=None): names_in_use = names_in_use or {} rig = self.__rig for mesh in rig.meshes(): for kb in getattr(mesh.data.shape_keys, 'key_blocks', ()): if kb.name.startswith( 'mmd_bind') and kb.name not in names_in_use: kb.driver_remove('value') kb.relative_key.mute = False ObjectOp(mesh).shape_key_remove(kb) for m in mesh.modifiers: # uv morph if m.name.startswith( 'mmd_bind') and m.name not in names_in_use: mesh.modifiers.remove(m) attributes = set( TransformConstraintOp.min_max_attributes('LOCATION', 'to')) attributes |= set( TransformConstraintOp.min_max_attributes('ROTATION', 'to')) for b in rig.armature().pose.bones: for c in b.constraints: if c.name.startswith( 'mmd_bind') and c.name[:-4] not in names_in_use: for attr in attributes: c.driver_remove(attr) b.constraints.remove(c)
def bind(self): rig = self.__rig root = rig.rootObject() armObj = rig.armature() mmd_root = root.mmd_root obj = self.create() arm = self.__dummy_armature(obj, create=True) morph_key_blocks = obj.data.shape_keys.key_blocks # data gathering group_map = {} shape_key_map = {} uv_morph_map = {} for mesh in rig.meshes(): mesh.show_only_shape_key = False key_blocks = getattr(mesh.data.shape_keys, 'key_blocks', ()) for kb in key_blocks: kb_name = kb.name if kb_name not in morph_key_blocks: continue name_bind = 'mmd_bind%s'%hash(morph_key_blocks[kb_name]) if name_bind not in key_blocks: mesh.shape_key_add(name=name_bind) kb_bind = key_blocks[name_bind] kb_bind.relative_key = kb kb_bind.slider_min = -10 kb_bind.slider_max = 10 data_path = 'data.shape_keys.key_blocks["%s"].value'%kb_name.replace('"', '\\"') groups = [] shape_key_map.setdefault(name_bind, []).append((kb_bind, data_path, groups)) group_map.setdefault(('vertex_morphs', kb_name), []).append(groups) uv_layers = [l.name for l in mesh.data.uv_layers if not l.name.startswith('_')] uv_layers += ['']*(5-len(uv_layers)) for vg, morph_name, axis in FnMorph.get_uv_morph_vertex_groups(mesh): morph = mmd_root.uv_morphs.get(morph_name, None) if morph is None or morph.data_type != 'VERTEX_GROUP': continue uv_layer = '_'+uv_layers[morph.uv_index] if axis[1] in 'ZW' else uv_layers[morph.uv_index] if uv_layer not in mesh.data.uv_layers: continue name_bind = 'mmd_bind%s'%hash(vg.name) uv_morph_map.setdefault(name_bind, ()) mod = mesh.modifiers.get(name_bind, None) or mesh.modifiers.new(name=name_bind, type='UV_WARP') mod.show_expanded = False mod.vertex_group = vg.name mod.axis_u, mod.axis_v = ('Y', 'X') if axis[1] in 'YW' else ('X', 'Y') mod.uv_layer = uv_layer name_bind = 'mmd_bind%s'%hash(morph_name) mod.object_from = mod.object_to = arm if axis[0] == '-': mod.bone_from, mod.bone_to = 'mmd_bind_ctrl_base', name_bind else: mod.bone_from, mod.bone_to = name_bind, 'mmd_bind_ctrl_base' bone_offset_map = {} with bpyutils.edit_object(arm) as data: edit_bones = data.edit_bones def __get_bone(name, layer, parent): b = edit_bones.get(name, None) or edit_bones.new(name=name) b.layers = [x == layer for x in range(len(b.layers))] b.head = (0, 0, 0) b.tail = (0, 0, 1) b.use_deform = False b.parent = parent return b for m in mmd_root.bone_morphs: data_path = 'data.shape_keys.key_blocks["%s"].value'%m.name.replace('"', '\\"') for d in m.data: if not d.bone: d.name = '' continue d.name = name_bind = 'mmd_bind%s'%hash(d) b = __get_bone(name_bind, 10, None) groups = [] bone_offset_map[name_bind] = (m.name, d, b.name, data_path, groups) group_map.setdefault(('bone_morphs', m.name), []).append(groups) ctrl_base = __get_bone('mmd_bind_ctrl_base', 11, None) for m in mmd_root.uv_morphs: morph_name = m.name.replace('"', '\\"') data_path = 'data.shape_keys.key_blocks["%s"].value'%morph_name scale_path = 'mmd_root.uv_morphs["%s"].vertex_group_scale'%morph_name name_bind = 'mmd_bind%s'%hash(m.name) b = __get_bone(name_bind, 11, ctrl_base) groups = [] uv_morph_map.setdefault(name_bind, []).append((b.name, data_path, scale_path, groups)) group_map.setdefault(('uv_morphs', m.name), []).append(groups) used_bone_names = bone_offset_map.keys()|uv_morph_map.keys() used_bone_names.add(ctrl_base.name) for b in edit_bones: # cleanup if b.name.startswith('mmd_bind') and b.name not in used_bone_names: edit_bones.remove(b) material_offset_map = {} for m in mmd_root.material_morphs: morph_name = m.name.replace('"', '\\"') data_path = 'data.shape_keys.key_blocks["%s"].value'%morph_name groups = [] group_map.setdefault(('material_morphs', m.name), []).append(groups) material_offset_map.setdefault('group_dict', {})[m.name] = (data_path, groups) for d in m.data: d.name = name_bind = 'mmd_bind%s'%hash(d) table = material_offset_map.setdefault(d.material_id, ([], [])) table[1 if d.offset_type == 'ADD' else 0].append((m.name, d, name_bind)) for m in mmd_root.group_morphs: if len(m.data) != len(set(m.data.keys())): print(' * Found duplicated morph data in Group Morph "%s"'%m.name) morph_name = m.name.replace('"', '\\"') morph_path = 'data.shape_keys.key_blocks["%s"].value'%morph_name for d in m.data: param = (morph_name, d.name.replace('"', '\\"')) factor_path = 'mmd_root.group_morphs["%s"].data["%s"].factor'%param for groups in group_map.get((d.morph_type, d.name), ()): groups.append((m.name, morph_path, factor_path)) self.__cleanup(shape_key_map.keys()|bone_offset_map.keys()|uv_morph_map.keys()) def __config_groups(variables, expression, groups): for g_name, morph_path, factor_path in groups: var = self.__add_single_prop(variables, obj, morph_path, 'g') fvar = self.__add_single_prop(variables, root, factor_path, 'w') expression = '%s+%s*%s'%(expression, var.name, fvar.name) return expression # vertex morphs for kb_bind, morph_data_path, groups in (i for l in shape_key_map.values() for i in l): driver, variables = self.__driver_variables(kb_bind, 'value') var = self.__add_single_prop(variables, obj, morph_data_path, 'v') driver.expression = '-(%s)'%__config_groups(variables, var.name, groups) kb_bind.relative_key.mute = True kb_bind.mute = False # bone morphs def __config_bone_morph(constraints, map_type, attributes, val, val_str): c_name = 'mmd_bind%s.%s'%(hash(data), map_type[:3]) c = TransformConstraintOp.create(constraints, c_name, map_type) TransformConstraintOp.update_min_max(c, val, None) c.show_expanded = False c.target = arm c.subtarget = bname for attr in attributes: driver, variables = self.__driver_variables(armObj, c.path_from_id(attr)) var = self.__add_single_prop(variables, obj, morph_data_path, 'b') expression = __config_groups(variables, var.name, groups) sign = '-' if attr.startswith('to_min') else '' driver.expression = '%s%s*(%s)'%(sign, val_str, expression) from math import pi attributes_rot = TransformConstraintOp.min_max_attributes('ROTATION', 'to') attributes_loc = TransformConstraintOp.min_max_attributes('LOCATION', 'to') for morph_name, data, bname, morph_data_path, groups in bone_offset_map.values(): b = arm.pose.bones[bname] b.location = data.location b.rotation_quaternion = data.rotation.__class__(*data.rotation.to_axis_angle()) # Fix for consistency b.is_mmd_shadow_bone = True b.mmd_shadow_bone_type = 'BIND' pb = armObj.pose.bones[data.bone] __config_bone_morph(pb.constraints, 'ROTATION', attributes_rot, pi, 'pi') __config_bone_morph(pb.constraints, 'LOCATION', attributes_loc, 100, '100') # uv morphs b = arm.pose.bones['mmd_bind_ctrl_base'] b.is_mmd_shadow_bone = True b.mmd_shadow_bone_type = 'BIND' for bname, data_path, scale_path, groups in (i for l in uv_morph_map.values() for i in l): b = arm.pose.bones[bname] b.is_mmd_shadow_bone = True b.mmd_shadow_bone_type = 'BIND' driver, variables = self.__driver_variables(b, 'location', index=0) var = self.__add_single_prop(variables, obj, data_path, 'u') fvar = self.__add_single_prop(variables, root, scale_path, 's') driver.expression = '(%s)*%s'%(__config_groups(variables, var.name, groups), fvar.name) # material morphs from mmd_tools_local.core.shader import _MaterialMorph group_dict = material_offset_map.get('group_dict', {}) def __config_material_morph(mat, morph_list): nodes = _MaterialMorph.setup_morph_nodes(mat, tuple(x[1] for x in morph_list)) for (morph_name, data, name_bind), node in zip(morph_list, nodes): node.label, node.name = morph_name, name_bind data_path, groups = group_dict[morph_name] driver, variables = self.__driver_variables(mat.node_tree, node.inputs[0].path_from_id('default_value')) var = self.__add_single_prop(variables, obj, data_path, 'm') driver.expression = '%s'%__config_groups(variables, var.name, groups) for mat in (m for m in rig.materials() if m and m.use_nodes and not m.name.startswith('mmd_')): mat_id = mat.mmd_material.material_id mul_all, add_all = material_offset_map.get(-1, ([], [])) mul_list, add_list = material_offset_map.get('' if mat_id < 0 else mat_id, ([], [])) morph_list = tuple(mul_all+mul_list+add_all+add_list) __config_material_morph(mat, morph_list) mat_edge = bpy.data.materials.get('mmd_edge.'+mat.name, None) if mat_edge: __config_material_morph(mat_edge, morph_list) morph_key_blocks[0].mute = False
def bind(self): #bpy.context.user_preferences.system.use_scripts_auto_execute = True rig = self.__rig root = rig.rootObject() armObj = rig.armature() mmd_root = root.mmd_root obj = self.create() arm = self.__dummy_armature(obj, create=True) morph_key_blocks = obj.data.shape_keys.key_blocks # data gathering group_map = {} shape_key_map = {} uv_morph_map = {} for mesh in rig.meshes(): mesh.show_only_shape_key = False key_blocks = getattr(mesh.data.shape_keys, 'key_blocks', ()) for kb in key_blocks: kb_name = kb.name if kb_name not in morph_key_blocks: continue name_bind = 'mmd_bind%s'%hash(morph_key_blocks[kb_name]) if name_bind not in key_blocks: mesh.shape_key_add(name_bind) kb_bind = key_blocks[name_bind] kb_bind.relative_key = kb kb_bind.slider_min = -10 kb_bind.slider_max = 10 data_path = 'data.shape_keys.key_blocks["%s"].value'%kb_name.replace('"', '\\"') groups = [] shape_key_map.setdefault(name_bind, []).append((kb_bind, data_path, groups)) group_map.setdefault(('vertex_morphs', kb_name), []).append(groups) uv_layers = [l.name for l in mesh.data.uv_layers if not l.name.startswith('_')] uv_layers += ['']*(5-len(uv_layers)) for vg, morph_name, axis in FnMorph.get_uv_morph_vertex_groups(mesh): morph = mmd_root.uv_morphs.get(morph_name, None) if morph is None or morph.data_type != 'VERTEX_GROUP': continue uv_layer = '_'+uv_layers[morph.uv_index] if axis[1] in 'ZW' else uv_layers[morph.uv_index] if uv_layer not in mesh.data.uv_layers: continue name_bind = 'mmd_bind%s'%hash(vg.name) uv_morph_map.setdefault(name_bind, ()) mod = mesh.modifiers.get(name_bind, None) or mesh.modifiers.new(name=name_bind, type='UV_WARP') mod.show_expanded = False mod.vertex_group = vg.name mod.axis_u, mod.axis_v = ('Y', 'X') if axis[1] in 'YW' else ('X', 'Y') mod.uv_layer = uv_layer name_bind = 'mmd_bind%s'%hash(morph_name) mod.object_from = mod.object_to = arm if axis[0] == '-': mod.bone_from, mod.bone_to = 'mmd_bind_ctrl_base', name_bind else: mod.bone_from, mod.bone_to = name_bind, 'mmd_bind_ctrl_base' bone_offset_map = {} with bpyutils.edit_object(arm) as data: edit_bones = data.edit_bones def __get_bone(name, layer, parent): b = edit_bones.get(name, None) or edit_bones.new(name=name) b.layers = [x == layer for x in range(len(b.layers))] b.head = (0, 0, 0) b.tail = (0, 0, 1) b.use_deform = False b.parent = parent return b for m in mmd_root.bone_morphs: data_path = 'data.shape_keys.key_blocks["%s"].value'%m.name.replace('"', '\\"') for d in m.data: if not d.bone: d.name = '' continue d.name = str(hash(d)) name_bind = 'mmd_bind%s'%hash(d) b = __get_bone(name_bind, 10, None) groups = [] bone_offset_map[name_bind] = (m.name, d, b.name, data_path, groups) group_map.setdefault(('bone_morphs', m.name), []).append(groups) ctrl_base = __get_bone('mmd_bind_ctrl_base', 11, None) for m in mmd_root.uv_morphs: morph_name = m.name.replace('"', '\\"') data_path = 'data.shape_keys.key_blocks["%s"].value'%morph_name scale_path = 'mmd_root.uv_morphs["%s"].vertex_group_scale'%morph_name name_bind = 'mmd_bind%s'%hash(m.name) b = __get_bone(name_bind, 11, ctrl_base) groups = [] uv_morph_map.setdefault(name_bind, []).append((b.name, data_path, scale_path, groups)) group_map.setdefault(('uv_morphs', m.name), []).append(groups) used_bone_names = bone_offset_map.keys()|uv_morph_map.keys() used_bone_names.add(ctrl_base.name) for b in edit_bones: # cleanup if b.name.startswith('mmd_bind') and b.name not in used_bone_names: edit_bones.remove(b) for m in mmd_root.group_morphs: for d in m.data: for groups in group_map.get((d.morph_type, d.name), ()): morph_name = m.name.replace('"', '\\"') param = (morph_name, d.name.replace('"', '\\"')) factor_path = 'mmd_root.group_morphs["%s"].data["%s"].factor'%param morph_path = 'data.shape_keys.key_blocks["%s"].value'%morph_name groups.append((m.name, morph_path, factor_path)) self.__cleanup(shape_key_map.keys()|bone_offset_map.keys()|uv_morph_map.keys()) def __config_groups(variables, expression, groups): for g_name, morph_path, factor_path in groups: var = self.__add_single_prop(variables, obj, morph_path, 'g') fvar = self.__add_single_prop(variables, root, factor_path, 'w') expression = '%s+%s*%s'%(expression, var.name, fvar.name) return expression # vertex morphs for kb_bind, morph_data_path, groups in (i for l in shape_key_map.values() for i in l): driver, variables = self.__driver_variables(kb_bind, 'value') var = self.__add_single_prop(variables, obj, morph_data_path, 'v') driver.expression = '-(%s)'%__config_groups(variables, var.name, groups) kb_bind.relative_key.mute = True kb_bind.mute = False # bone morphs def __config_bone_morph(constraints, map_type, attributes, val, val_str): c_name = 'mmd_bind%s.%s'%(hash(data), map_type[:3]) c = TransformConstraintOp.create(constraints, c_name, map_type) TransformConstraintOp.update_min_max(c, val, None) c.show_expanded = False c.target = arm c.subtarget = bname for attr in attributes: driver, variables = self.__driver_variables(armObj, c.path_from_id(attr)) var = self.__add_single_prop(variables, obj, morph_data_path, 'b') expression = __config_groups(variables, var.name, groups) sign = '-' if attr.startswith('to_min') else '' driver.expression = '%s%s*(%s)'%(sign, val_str, expression) from math import pi attributes_rot = TransformConstraintOp.min_max_attributes('ROTATION', 'to') attributes_loc = TransformConstraintOp.min_max_attributes('LOCATION', 'to') for morph_name, data, bname, morph_data_path, groups in bone_offset_map.values(): b = arm.pose.bones[bname] root_path = 'mmd_root.bone_morphs["%s"].data["%s"]'%(morph_name.replace('"', '\\"'), data.name) for i in range(3): data_path = '%s.location[%d]'%(root_path, i) driver, variables = self.__driver_variables(b, 'location', index=i) driver.expression = self.__add_single_prop(variables, root, data_path, 'L').name for i in range(4): data_path = '%s.rotation[%d]'%(root_path, i) driver, variables = self.__driver_variables(b, 'rotation_quaternion', index=i) driver.expression = self.__add_single_prop(variables, root, data_path, 'R').name b.is_mmd_shadow_bone = True b.mmd_shadow_bone_type = 'BIND' pb = armObj.pose.bones[data.bone] __config_bone_morph(pb.constraints, 'ROTATION', attributes_rot, pi, 'pi') __config_bone_morph(pb.constraints, 'LOCATION', attributes_loc, 100, '100') # uv morphs b = arm.pose.bones['mmd_bind_ctrl_base'] b.is_mmd_shadow_bone = True b.mmd_shadow_bone_type = 'BIND' for bname, data_path, scale_path, groups in (i for l in uv_morph_map.values() for i in l): b = arm.pose.bones[bname] b.is_mmd_shadow_bone = True b.mmd_shadow_bone_type = 'BIND' driver, variables = self.__driver_variables(b, 'location', index=0) var = self.__add_single_prop(variables, obj, data_path, 'u') fvar = self.__add_single_prop(variables, root, scale_path, 's') driver.expression = '(%s)*%s'%(__config_groups(variables, var.name, groups), fvar.name) #TODO material morphs if possible morph_key_blocks[0].mute = False