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