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
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
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
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
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'}
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
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'}
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
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
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
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
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
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