예제 #1
0
    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)
예제 #2
0
    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)
예제 #3
0
    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
예제 #4
0
    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