Beispiel #1
0
    def __createEditBones(self, obj, pmx_bones):
        """ create EditBones from pmx file data.
        @return the list of bone names which can be accessed by the bone index of pmx data.
        """
        editBoneTable = []
        nameTable = []
        dependency_cycle_ik_bones = []
        for i, p_bone in enumerate(pmx_bones):
            if p_bone.isIK:
                if p_bone.target != -1:
                    t = pmx_bones[p_bone.target]
                    if p_bone.parent == t.parent:
                        dependency_cycle_ik_bones.append(i)

        with bpyutils.edit_object(obj) as data:
            for i in pmx_bones:
                bone = data.edit_bones.new(name=i.name)
                loc = mathutils.Vector(
                    i.location) * self.__scale * self.TO_BLE_MATRIX
                bone.head = loc
                editBoneTable.append(bone)
                nameTable.append(bone.name)

            for i, (b_bone, m_bone) in enumerate(zip(editBoneTable,
                                                     pmx_bones)):
                if m_bone.parent != -1:
                    if i not in dependency_cycle_ik_bones:
                        b_bone.parent = editBoneTable[m_bone.parent]
                    else:
                        b_bone.parent = editBoneTable[m_bone.parent].parent

            for b_bone, m_bone in zip(editBoneTable, pmx_bones):
                if isinstance(m_bone.displayConnection, int):
                    if m_bone.displayConnection != -1:
                        b_bone.tail = editBoneTable[
                            m_bone.displayConnection].head
                    else:
                        b_bone.tail = b_bone.head
                else:
                    loc = mathutils.Vector(
                        m_bone.displayConnection
                    ) * self.TO_BLE_MATRIX * self.__scale
                    b_bone.tail = b_bone.head + loc

            for b_bone, m_bone in zip(editBoneTable, pmx_bones):
                if isinstance(m_bone.displayConnection, int)\
                        and m_bone.displayConnection >= 0\
                        and not m_bone.isMovable:
                    t = editBoneTable[m_bone.displayConnection]
                    if t.parent is not None and t.parent == b_bone:
                        t.use_connect = True

            for b_bone in editBoneTable:
                # Set the length of too short bones to 1 because Blender delete them.
                if b_bone.length < 0.001:
                    loc = mathutils.Vector([0, 0, 1]) * self.__scale
                    b_bone.tail = b_bone.head + loc

        return nameTable
Beispiel #2
0
    def __createEditBones(self, obj, pmx_bones):
        """ create EditBones from pmx file data.
        @return the list of bone names which can be accessed by the bone index of pmx data.
        """
        editBoneTable = []
        nameTable = []
        dependency_cycle_ik_bones = []
        for i, p_bone in enumerate(pmx_bones):
            if p_bone.isIK:
                if p_bone.target != -1:
                    t = pmx_bones[p_bone.target]
                    if p_bone.parent == t.parent:
                        dependency_cycle_ik_bones.append(i)

        with bpyutils.edit_object(obj) as data:
            for i in pmx_bones:
                bone = data.edit_bones.new(name=i.name)
                loc = mathutils.Vector(i.location) * self.__scale * self.TO_BLE_MATRIX
                bone.head = loc
                editBoneTable.append(bone)
                nameTable.append(bone.name)

            for i, (b_bone, m_bone) in enumerate(zip(editBoneTable, pmx_bones)):
                if m_bone.parent != -1:
                    if i not in dependency_cycle_ik_bones:
                        b_bone.parent = editBoneTable[m_bone.parent]
                    else:
                        b_bone.parent = editBoneTable[m_bone.parent].parent

            for b_bone, m_bone in zip(editBoneTable, pmx_bones):
                if isinstance(m_bone.displayConnection, int):
                    if m_bone.displayConnection != -1:
                        b_bone.tail = editBoneTable[m_bone.displayConnection].head
                    else:
                        b_bone.tail = b_bone.head
                else:
                    loc = mathutils.Vector(m_bone.displayConnection) * self.TO_BLE_MATRIX * self.__scale
                    b_bone.tail = b_bone.head + loc

            for b_bone in editBoneTable:
                # Set the length of too short bones to 1 because Blender delete them.
                if b_bone.length  < 0.001:
                    loc = mathutils.Vector([0, 0, 1]) * self.__scale
                    b_bone.tail = b_bone.head + loc

            for b_bone, m_bone in zip(editBoneTable, pmx_bones):
                if isinstance(m_bone.displayConnection, int)\
                        and m_bone.displayConnection >= 0\
                        and not m_bone.isMovable:
                    t = editBoneTable[m_bone.displayConnection]
                    if t.parent is not None and t.parent == b_bone:
                        t.use_connect = True

        return nameTable
Beispiel #3
0
 def apply_auto_bone_roll(cls, armature):
     bone_names = []
     for b in armature.pose.bones:
         if (not b.is_mmd_shadow_bone and not b.mmd_bone.enabled_local_axes
                 and cls.has_auto_local_axis(b.mmd_bone.name_j)):
             bone_names.append(b.name)
     with bpyutils.edit_object(armature) as data:
         for bone in data.edit_bones:
             if bone.name not in bone_names:
                 select = False
                 continue
             cls.update_auto_bone_roll(bone)
             bone.select = True
Beispiel #4
0
    def apply_bone_fixed_axis(cls, armature):
        bone_map = {}
        for b in armature.pose.bones:
            if b.is_mmd_shadow_bone or not b.mmd_bone.enabled_fixed_axis:
                continue
            mmd_bone = b.mmd_bone
            parent_tip = b.parent and not b.parent.is_mmd_shadow_bone and b.parent.mmd_bone.is_tip
            bone_map[b.name] = (mmd_bone.fixed_axis.normalized(),
                                mmd_bone.is_tip, parent_tip)

        force_align = True
        with bpyutils.edit_object(armature) as data:
            for bone in data.edit_bones:
                if bone.name not in bone_map:
                    bone.select = False
                    continue
                fixed_axis, is_tip, parent_tip = bone_map[bone.name]
                if fixed_axis.length:
                    axes = [bone.x_axis, bone.y_axis, bone.z_axis]
                    direction = fixed_axis.normalized().xzy
                    idx, val = max([(i, direction.dot(v))
                                    for i, v in enumerate(axes)],
                                   key=lambda x: abs(x[1]))
                    idx_1, idx_2 = (idx + 1) % 3, (idx + 2) % 3
                    axes[idx] = -direction if val < 0 else direction
                    axes[idx_2] = axes[idx].cross(axes[idx_1])
                    axes[idx_1] = axes[idx_2].cross(axes[idx])
                    if parent_tip and bone.use_connect:
                        bone.use_connect = False
                        bone.head = bone.parent.head
                    if force_align:
                        tail = bone.head + axes[1].normalized() * bone.length
                        if is_tip or (tail - bone.tail).length > 1e-4:
                            for c in bone.children:
                                if c.use_connect:
                                    c.use_connect = False
                                    if is_tip:
                                        c.head = bone.head
                        bone.tail = tail
                    bone.align_roll(axes[2])
                    bone_map[bone.name] = tuple(i != idx for i in range(3))
                else:
                    bone_map[bone.name] = (True, True, True)
                bone.select = True

        for bone_name, locks in bone_map.items():
            b = armature.pose.bones[bone_name]
            b.lock_location = (True, True, True)
            b.lock_ik_x, b.lock_ik_y, b.lock_ik_z = b.lock_rotation = locks
Beispiel #5
0
    def create(name,
               name_e='',
               scale=1,
               obj_name=None,
               armature=None,
               add_root_bone=False):
        scene = SceneOp(bpy.context)
        if obj_name is None:
            obj_name = name

        root = bpy.data.objects.new(name=obj_name, object_data=None)
        root.mmd_type = 'ROOT'
        root.mmd_root.name = name
        root.mmd_root.name_e = name_e
        root.empty_draw_size = scale / 0.2
        scene.link_object(root)

        armObj = armature
        if armObj:
            m = armObj.matrix_world
            armObj.parent_type = 'OBJECT'
            armObj.parent = root
            #armObj.matrix_world = m
            root.matrix_world = m
            armObj.matrix_local.identity()
        else:
            arm = bpy.data.armatures.new(name=obj_name)
            #arm.draw_type = 'STICK'
            armObj = bpy.data.objects.new(name=obj_name + '_arm',
                                          object_data=arm)
            armObj.parent = root
            scene.link_object(armObj)
        armObj.lock_rotation = armObj.lock_location = armObj.lock_scale = [
            True, True, True
        ]
        armObj.show_x_ray = True
        armObj.draw_type = 'WIRE'

        if add_root_bone:
            bone_name = u'全ての親'
            with bpyutils.edit_object(armObj) as data:
                bone = data.edit_bones.new(name=bone_name)
                bone.head = [0.0, 0.0, 0.0]
                bone.tail = [0.0, 0.0, root.empty_draw_size]
            armObj.pose.bones[bone_name].mmd_bone.name_j = bone_name
            armObj.pose.bones[bone_name].mmd_bone.name_e = 'Root'

        bpyutils.select_object(root)
        return Model(root)
    def execute(self, context):
        rig = mmd_model.Model.create('New MMD Model', 'New MMD Model', self.scale)
        arm = rig.armature()
        with bpyutils.edit_object(arm) as data:
            bone = data.edit_bones.new(name=u'全ての親')
            bone.head = [0.0, 0.0, 0.0]
            bone.tail = [0.0, 0.0, 1.0*self.scale]
        mmd_root = rig.rootObject().mmd_root
        frame_root = mmd_root.display_item_frames.add()
        frame_root.name = 'Root'
        frame_root.is_special = True
        frame_facial = mmd_root.display_item_frames.add()
        frame_facial.name = u'表情'
        frame_facial.is_special = True

        return {'FINISHED'}
Beispiel #7
0
    def apply_bone_local_axes(cls, armature):
        bone_map = {}
        for b in armature.pose.bones:
            if b.is_mmd_shadow_bone or not b.mmd_bone.enabled_local_axes:
                continue
            mmd_bone = b.mmd_bone
            bone_map[b.name] = (mmd_bone.local_axis_x, mmd_bone.local_axis_z)

        with bpyutils.edit_object(armature) as data:
            for bone in data.edit_bones:
                if bone.name not in bone_map:
                    bone.select = False
                    continue
                local_axis_x, local_axis_z = bone_map[bone.name]
                cls.update_bone_roll(bone, local_axis_x, local_axis_z)
                bone.select = True
    def __get_at_shadow_bone(self, bone_name, invert=False):
        arm = self.__bone.id_data
        mmd_shadow_bone_type = 'ADDITIONAL_TRANSFORM'
        if invert:
            mmd_shadow_bone_type += '_INVERT'

        shadow_bone = self.__get_shadow_bone(bone_name, mmd_shadow_bone_type)
        if shadow_bone:
            return shadow_bone
        with bpyutils.edit_object(arm) as data:
            src_bone = data.edit_bones[bone_name]
            shadow_bone = data.edit_bones.new(name='%s.shadow' % (bone_name))
            shadow_bone.head = mathutils.Vector([0, 0, 0])
            shadow_bone.tail = src_bone.tail - src_bone.head
            shadow_bone.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)
            shadow_bone_name = shadow_bone.name

        shadow_p_bone = arm.pose.bones[shadow_bone_name]
        shadow_p_bone.is_mmd_shadow_bone = True
        shadow_p_bone.mmd_shadow_bone_type = mmd_shadow_bone_type

        c = shadow_p_bone.constraints.new('COPY_ROTATION')
        c.target = arm
        c.subtarget = bone_name
        c.target_space = 'LOCAL'
        c.owner_space = 'LOCAL'
        if invert:
            c.invert_x = True
            c.invert_y = True
            c.invert_z = True

        c = shadow_p_bone.constraints.new('COPY_LOCATION')
        c.target = arm
        c.subtarget = bone_name
        c.target_space = 'LOCAL'
        c.owner_space = 'LOCAL'
        if invert:
            c.invert_x = True
            c.invert_y = True
            c.invert_z = True

        return shadow_p_bone
Beispiel #9
0
    def __get_at_shadow_bone(self, bone_name, invert=False):
        arm = self.__bone.id_data
        mmd_shadow_bone_type = 'ADDITIONAL_TRANSFORM'
        if invert:
            mmd_shadow_bone_type += '_INVERT'

        shadow_bone = self.__get_shadow_bone(bone_name, mmd_shadow_bone_type)
        if shadow_bone:
            return shadow_bone
        with bpyutils.edit_object(arm) as data:
            src_bone = data.edit_bones[bone_name]
            shadow_bone = data.edit_bones.new(name='%s.shadow'%(bone_name))
            shadow_bone.head = mathutils.Vector([0, 0, 0])
            shadow_bone.tail = src_bone.tail - src_bone.head
            shadow_bone.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)
            shadow_bone_name = shadow_bone.name

        shadow_p_bone = arm.pose.bones[shadow_bone_name]
        shadow_p_bone.is_mmd_shadow_bone = True
        shadow_p_bone.mmd_shadow_bone_type = mmd_shadow_bone_type

        c = shadow_p_bone.constraints.new('COPY_ROTATION')
        c.target = arm
        c.subtarget = bone_name
        c.target_space = 'LOCAL'
        c.owner_space = 'LOCAL'
        if invert:
            c.invert_x = True
            c.invert_y = True
            c.invert_z = True

        c = shadow_p_bone.constraints.new('COPY_LOCATION')
        c.target = arm
        c.subtarget = bone_name
        c.target_space = 'LOCAL'
        c.owner_space = 'LOCAL'
        if invert:
            c.invert_x = True
            c.invert_y = True
            c.invert_z = True

        return shadow_p_bone
    def execute(self, context):
        rig = mmd_model.Model.create('New MMD Model', 'New MMD Model',
                                     self.scale)
        arm = rig.armature()
        with bpyutils.edit_object(arm) as data:
            bone = data.edit_bones.new(name=u'全ての親')
            bone.head = [0.0, 0.0, 0.0]
            bone.tail = [0.0, 0.0, 1.0 * self.scale]
        mmd_root = rig.rootObject().mmd_root
        frame_root = mmd_root.display_item_frames.add()
        frame_root.name = 'Root'
        frame_root.is_special = True
        frame_facial = mmd_root.display_item_frames.add()
        frame_facial.name = u'表情'
        frame_facial.is_special = True

        return {'FINISHED'}
Beispiel #11
0
    def create_ik_constraint(self, bone, ik_target, threshold=0.1):
        """ create IK constraint

        If the distance of the ik_target head and the bone tail is greater than threashold,
        then a dummy ik target bone is created.

         Args:
             bone: A pose bone to add a IK constraint
             id_target: A pose bone for IK target
             threshold: Threshold of creating a dummy bone

         Returns:
             The bpy.types.KinematicConstraint object created. It is set target
             and subtarget options.

        """
        ik_target_name = ik_target.name
        if 0 and (ik_target.head - bone.tail).length > threshold:
            logging.debug('*** create a ik_target_dummy of bone %s',
                          ik_target.name)
            with bpyutils.edit_object(self.__arm) as data:
                dummy_target = data.edit_bones.new(name=ik_target.name +
                                                   '.ik_target_dummy')
                dummy_target.head = bone.tail
                dummy_target.tail = dummy_target.head + mathutils.Vector(
                    [0, 0, 1])
                dummy_target.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)
                dummy_target.parent = data.edit_bones[ik_target.name]
                ik_target_name = dummy_target.name
            dummy_ik_target = self.__arm.pose.bones[ik_target_name]
            dummy_ik_target.is_mmd_shadow_bone = True
            dummy_ik_target.mmd_shadow_bone_type = 'IK_TARGET'

        ik_const = bone.constraints.new('IK')
        ik_const.target = self.__arm
        ik_const.subtarget = ik_target_name
        return ik_const
Beispiel #12
0
    def create_ik_constraint(self, bone, ik_target, threshold=0.1):
        """ create IK constraint

        If the distance of the ik_target head and the bone tail is greater than threashold,
        then a dummy ik target bone is created.

         Args:
             bone: A pose bone to add a IK constraint
             id_target: A pose bone for IK target
             threshold: Threshold of creating a dummy bone

         Returns:
             The bpy.types.KinematicConstraint object created. It is set target
             and subtarget options.

        """
        ik_target_name = ik_target.name
        print((ik_target.head - bone.tail).length)
        if (ik_target.head - bone.tail).length > threshold:
            with bpyutils.edit_object(self.__arm) as data:
                dummy_target = data.edit_bones.new(name=ik_target.name + '.ik_target_dummy')
                dummy_target.head = bone.tail
                dummy_target.tail = dummy_target.head + mathutils.Vector([0, 0, 1])
                dummy_target.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
                )
                dummy_target.parent = data.edit_bones[ik_target.name]
                ik_target_name = dummy_target.name
            dummy_ik_target = self.__arm.pose.bones[ik_target_name]
            dummy_ik_target.is_mmd_shadow_bone = True
            dummy_ik_target.mmd_shadow_bone_type = 'IK_TARGET'

        ik_const = bone.constraints.new('IK')
        ik_const.target = self.__arm
        ik_const.subtarget = ik_target_name
        return ik_const
Beispiel #13
0
    def __exportBones(self):
        """ Export bones.
        Returns:
            A dictionary to map Blender bone names to bone indices of the pmx.model instance.
        """
        arm = self.__armature
        boneMap = {}
        pmx_bones = []
        pose_bones = arm.pose.bones
        world_mat = arm.matrix_world
        r = {}

        # sort by a depth of bones.
        t = []
        for i in pose_bones:
            t.append((i, self.__countBoneDepth(i)))

        sorted_bones = sorted(pose_bones, key=self.__countBoneDepth)

        with bpyutils.edit_object(arm) as data:
            for p_bone in sorted_bones:
                bone = data.edit_bones[p_bone.name]
                if p_bone.is_mmd_shadow_bone:
                    continue
                pmx_bone = pmx.Bone()
                if p_bone.mmd_bone.name_j != '':
                    pmx_bone.name = p_bone.mmd_bone.name_j
                else:
                    pmx_bone.name = bone.name

                mmd_bone = p_bone.mmd_bone
                if mmd_bone.additional_transform_bone_id != -1:
                    fnBone = FnBone.from_bone_id(
                        arm, mmd_bone.additional_transform_bone_id)
                    pmx_bone.additionalTransform = (
                        fnBone.pose_bone,
                        mmd_bone.additional_transform_influence)
                pmx_bone.hasAdditionalRotate = mmd_bone.has_additional_rotation
                pmx_bone.hasAdditionalLocation = mmd_bone.has_additional_location

                pmx_bone.name_e = p_bone.mmd_bone.name_e or ''
                pmx_bone.location = world_mat @ mathutils.Vector(
                    bone.head) * self.__scale @ self.TO_PMX_MATRIX
                pmx_bone.parent = bone.parent
                pmx_bone.visible = mmd_bone.is_visible
                pmx_bone.isMovable = not all(p_bone.lock_location)
                pmx_bone.isRotatable = not all(p_bone.lock_rotation)
                pmx_bones.append(pmx_bone)
                self.__bone_name_table.append(p_bone.name)
                boneMap[bone] = pmx_bone
                r[bone.name] = len(pmx_bones) - 1

                if p_bone.mmd_bone.is_tip:
                    pmx_bone.displayConnection = -1
                elif p_bone.mmd_bone.use_tail_location:
                    tail_loc = world_mat @ mathutils.Vector(
                        bone.tail) * self.__scale @ self.TO_PMX_MATRIX
                    pmx_bone.displayConnection = tail_loc - pmx_bone.location
                else:
                    for child in bone.children:
                        if child.use_connect:
                            pmx_bone.displayConnection = child
                            break
                    #if not pmx_bone.displayConnection: #I think this wasn't working properly
                    #pmx_bone.displayConnection = bone.tail - bone.head

                #add fixed and local axes
                if mmd_bone.enabled_fixed_axis:
                    pmx_bone.axis = mmd_bone.fixed_axis

                if mmd_bone.enabled_local_axes:
                    pmx_bone.localCoordinate = pmx.Coordinate(
                        mmd_bone.local_axis_x, mmd_bone.local_axis_z)

            for idx, i in enumerate(pmx_bones):
                if i.parent is not None:
                    i.parent = pmx_bones.index(boneMap[i.parent])
                    logging.debug('the parent of %s:%s: %s', idx, i.name,
                                  i.parent)
                if isinstance(i.displayConnection, pmx.Bone):
                    i.displayConnection = pmx_bones.index(i.displayConnection)
                elif isinstance(i.displayConnection, bpy.types.EditBone):
                    i.displayConnection = pmx_bones.index(
                        boneMap[i.displayConnection])

                if i.additionalTransform is not None:
                    b, influ = i.additionalTransform
                    i.additionalTransform = (r[b.name], influ)

            self.__model.bones = pmx_bones
        return r
Beispiel #14
0
    def __createEditBones(self, obj, pmx_bones):
        """ create EditBones from pmx file data.
        @return the list of bone names which can be accessed by the bone index of pmx data.
        """
        editBoneTable = []
        nameTable = []
        specialTipBones = []
        dependency_cycle_ik_bones = []
        #for i, p_bone in enumerate(pmx_bones):
        #    if p_bone.isIK:
        #        if p_bone.target != -1:
        #            t = pmx_bones[p_bone.target]
        #            if p_bone.parent == t.parent:
        #                dependency_cycle_ik_bones.append(i)

        with bpyutils.edit_object(obj) as data:
            for i in pmx_bones:
                bone = data.edit_bones.new(name=i.name)
                loc = Vector(i.location).xzy * self.__scale
                bone.head = loc
                editBoneTable.append(bone)
                nameTable.append(bone.name)

            for i, (b_bone, m_bone) in enumerate(zip(editBoneTable, pmx_bones)):
                if m_bone.parent != -1:
                    if i not in dependency_cycle_ik_bones:
                        b_bone.parent = editBoneTable[m_bone.parent]
                    else:
                        b_bone.parent = editBoneTable[m_bone.parent].parent

            for b_bone, m_bone in zip(editBoneTable, pmx_bones):
                if isinstance(m_bone.displayConnection, int):
                    if m_bone.displayConnection != -1:
                        b_bone.tail = editBoneTable[m_bone.displayConnection].head
                    else:
                        b_bone.tail = b_bone.head
                else:
                    loc = Vector(m_bone.displayConnection).xzy * self.__scale
                    b_bone.tail = b_bone.head + loc

            for b_bone, m_bone in zip(editBoneTable, pmx_bones):
                if m_bone.isIK and m_bone.target != -1:
                    logging.debug(' - checking IK links of %s', b_bone.name)
                    b_target = editBoneTable[m_bone.target]
                    for i in range(len(m_bone.ik_links)):
                        b_bone_link = editBoneTable[m_bone.ik_links[i].target]
                        if self.__fix_IK_links or b_bone_link.length < 0.001:
                            b_bone_tail = b_target if i == 0 else editBoneTable[m_bone.ik_links[i-1].target]
                            loc = b_bone_tail.head - b_bone_link.head
                            if loc.length < 0.001:
                                logging.warning('   ** unsolved IK link %s **', b_bone_link.name)
                            elif b_bone_tail.parent != b_bone_link:
                                logging.warning('   ** skipped IK link %s **', b_bone_link.name)
                            elif (b_bone_link.tail - b_bone_tail.head).length > 1e-4:
                                logging.debug('   * fix IK link %s', b_bone_link.name)
                                b_bone_link.tail = b_bone_link.head + loc

            for b_bone, m_bone in zip(editBoneTable, pmx_bones):
                # Set the length of too short bones to 1 because Blender delete them.
                if b_bone.length < 0.001:
                    if not self.__apply_bone_fixed_axis and m_bone.axis is not None:
                        fixed_axis = Vector(m_bone.axis)
                        if fixed_axis.length:
                            b_bone.tail = b_bone.head + fixed_axis.xzy.normalized() * self.__scale
                        else:
                            b_bone.tail = b_bone.head + Vector((0, 0, 1)) * self.__scale
                    else:
                        b_bone.tail = b_bone.head + Vector((0, 0, 1)) * self.__scale
                    if m_bone.displayConnection != -1 and m_bone.displayConnection != [0.0, 0.0, 0.0]:
                        logging.debug(' * special tip bone %s, display %s', b_bone.name, str(m_bone.displayConnection))
                        specialTipBones.append(b_bone.name)

            for b_bone, m_bone in zip(editBoneTable, pmx_bones):
                if m_bone.localCoordinate is not None:
                    FnBone.update_bone_roll(b_bone, m_bone.localCoordinate.x_axis, m_bone.localCoordinate.z_axis)
                elif FnBone.has_auto_local_axis(m_bone.name):
                    FnBone.update_auto_bone_roll(b_bone)

            for b_bone, m_bone in zip(editBoneTable, pmx_bones):
                if isinstance(m_bone.displayConnection, int) and m_bone.displayConnection >= 0:
                    t = editBoneTable[m_bone.displayConnection]
                    if t.parent is None or t.parent != b_bone:
                        logging.warning(' * disconnected: %s (%d)<> %s', b_bone.name, len(b_bone.children), t.name)
                        continue
                    if pmx_bones[m_bone.displayConnection].isMovable:
                        logging.warning(' * disconnected: %s (%d)-> %s', b_bone.name, len(b_bone.children), t.name)
                        continue
                    if (b_bone.tail - t.head).length > 1e-4:
                        logging.warning(' * disconnected: %s (%d)=> %s', b_bone.name, len(b_bone.children), t.name)
                        continue
                    t.use_connect = True

        return nameTable, specialTipBones
Beispiel #15
0
    def __exportBones(self):
        """ Export bones.
        Returns:
            A dictionary to map Blender bone names to bone indices of the pmx.model instance.
        """
        arm = self.__armature
        boneMap = {}
        pmx_bones = []
        pose_bones = arm.pose.bones
        world_mat = arm.matrix_world
        r = {}

        # sort by a depth of bones.
        t = []
        for i in pose_bones:
            t.append((i, self.__countBoneDepth(i)))

        sorted_bones = sorted(pose_bones, key=self.__countBoneDepth)

        with bpyutils.edit_object(arm) as data:
            for p_bone in sorted_bones:
                bone = data.edit_bones[p_bone.name]
                if p_bone.is_mmd_shadow_bone:
                    continue
                pmx_bone = pmx.Bone()
                if p_bone.mmd_bone.name_j != '':
                    pmx_bone.name = p_bone.mmd_bone.name_j
                else:
                    pmx_bone.name = bone.name

                mmd_bone = p_bone.mmd_bone
                if mmd_bone.additional_transform_bone_id != -1:
                    fnBone = FnBone.from_bone_id(arm, mmd_bone.additional_transform_bone_id)
                    pmx_bone.additionalTransform = (fnBone.pose_bone, mmd_bone.additional_transform_influence)
                pmx_bone.hasAdditionalRotate = mmd_bone.has_additional_rotation
                pmx_bone.hasAdditionalLocation = mmd_bone.has_additional_location

                pmx_bone.name_e = p_bone.mmd_bone.name_e or ''
                pmx_bone.location = world_mat * mathutils.Vector(bone.head) * self.__scale * self.TO_PMX_MATRIX
                pmx_bone.parent = bone.parent
                pmx_bone.visible = mmd_bone.is_visible
                pmx_bone.isMovable = not all(p_bone.lock_location)
                pmx_bone.isRotatable = not all(p_bone.lock_rotation)
                pmx_bones.append(pmx_bone)
                self.__bone_name_table.append(p_bone.name)
                boneMap[bone] = pmx_bone
                r[bone.name] = len(pmx_bones) - 1

                if p_bone.mmd_bone.is_tip:
                    pmx_bone.displayConnection = -1
                elif p_bone.mmd_bone.use_tail_location:
                    tail_loc = world_mat * mathutils.Vector(bone.tail) * self.__scale * self.TO_PMX_MATRIX
                    pmx_bone.displayConnection = tail_loc - pmx_bone.location
                else:
                    for child in bone.children:
                        if child.use_connect:
                            pmx_bone.displayConnection = child
                            break
                    #if not pmx_bone.displayConnection: #I think this wasn't working properly
                        #pmx_bone.displayConnection = bone.tail - bone.head

                #add fixed and local axes
                if mmd_bone.enabled_fixed_axis:
                    pmx_bone.axis = mmd_bone.fixed_axis

                if mmd_bone.enabled_local_axes:
                    pmx_bone.localCoordinate = pmx.Coordinate(
                        mmd_bone.local_axis_x, mmd_bone.local_axis_z)

            for idx, i in enumerate(pmx_bones):
                if i.parent is not None:
                    i.parent = pmx_bones.index(boneMap[i.parent])
                    logging.debug('the parent of %s:%s: %s', idx, i.name, i.parent)
                if isinstance(i.displayConnection, pmx.Bone):
                    i.displayConnection = pmx_bones.index(i.displayConnection)
                elif isinstance(i.displayConnection, bpy.types.EditBone):
                    i.displayConnection = pmx_bones.index(boneMap[i.displayConnection])

                if i.additionalTransform is not None:
                    b, influ = i.additionalTransform
                    i.additionalTransform = (r[b.name], influ)

            self.__model.bones = pmx_bones
        return r
Beispiel #16
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=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
            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.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