def _setAdditionalTransformBone(prop, value): arm = prop.id_data prop['is_additional_transform_dirty'] = True if value not in arm.pose.bones.keys(): prop['additional_transform_bone_id'] = -1 return pose_bone = arm.pose.bones[value] bone = FnBone(pose_bone) prop['additional_transform_bone_id'] = bone.bone_id
def _getAdditionalTransformBone(prop): arm = prop.id_data bone_id = prop.get('additional_transform_bone_id', -1) if bone_id < 0: return '' fnBone = FnBone.from_bone_id(arm, bone_id) if not fnBone: return '' return fnBone.pose_bone.name
def _set_bone(prop, value): root = prop.id_data fnModel = FnModel(root) arm = fnModel.armature() if value not in arm.pose.bones.keys(): prop['bone_id'] = -1 return pose_bone = arm.pose.bones[value] fnBone = FnBone(pose_bone) prop['bone_id'] = fnBone.bone_id
def _get_bone(prop): bone_id = prop.get('bone_id', -1) if bone_id < 0: return '' root = prop.id_data fnModel = FnModel(root) arm = fnModel.armature() fnBone = FnBone.from_bone_id(arm, bone_id) if not fnBone: return '' return fnBone.pose_bone.name
def execute(self, context): arm = context.active_object if not arm or arm.type != 'ARMATURE': self.report({'ERROR'}, 'Active object is not an armature object') return {'CANCELLED'} if self.type == 'APPLY': FnBone.apply_bone_local_axes(arm) FnBone.apply_additional_transformation(arm) else: FnBone.load_bone_local_axes(arm, enable=(self.type == 'LOAD')) return {'FINISHED'}
def applyAdditionalTransformConstraints(self, force=False): arm = self.armature() fnBone = FnBone() for bone in arm.pose.bones[:]: fnBone.pose_bone = bone fnBone.apply_additional_transformation()
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 execute(self, **args): if 'pmx' in args: self.__model = args['pmx'] else: self.__model = pmx.load(args['filepath']) self.__fixRepeatedMorphName() types = args.get('types', set()) clean_model = args.get('clean_model', False) remove_doubles = args.get('remove_doubles', False) self.__scale = args.get('scale', 1.0) self.__use_mipmap = args.get('use_mipmap', True) self.__sph_blend_factor = args.get('sph_blend_factor', 1.0) self.__spa_blend_factor = args.get('spa_blend_factor', 1.0) self.__fix_IK_links = args.get('fix_IK_links', False) self.__apply_bone_fixed_axis = args.get('apply_bone_fixed_axis', False) self.__translator = args.get('translator', None) logging.info('****************************************') logging.info(' mmd_tools.import_pmx module') logging.info('----------------------------------------') logging.info(' Start to load model data form a pmx file') logging.info(' by the mmd_tools.pmx modlue.') logging.info('') start_time = time.time() self.__createObjects() if 'MESH' in types: if clean_model: _PMXCleaner.clean(self.__model, 'MORPHS' not in types) if remove_doubles: self.__vertex_map = _PMXCleaner.remove_doubles(self.__model, 'MORPHS' not in types) self.__createMeshObject() self.__importVertices() self.__importMaterials() self.__importFaces() self.__meshObj.data.update() self.__assignCustomNormals() self.__storeVerticesSDEF() if 'ARMATURE' in types: # for tracking bone order if 'MESH' not in types: self.__createMeshObject() self.__importVertexGroup() self.__importBones() if args.get('rename_LR_bones', False): use_underscore = args.get('use_underscore', False) self.__renameLRBones(use_underscore) if self.__translator: self.__translateBoneNames() if self.__apply_bone_fixed_axis: FnBone.apply_bone_fixed_axis(self.__armObj) FnBone.apply_additional_transformation(self.__armObj) if 'PHYSICS' in types: self.__importRigids() self.__importJoints() if 'DISPLAY' in types: self.__importDisplayFrames() else: self.__rig.initialDisplayFrames() if 'MORPHS' in types: self.__importGroupMorphs() self.__importVertexMorphs() self.__importBoneMorphs() self.__importMaterialMorphs() self.__importUVMorphs() if self.__meshObj: self.__addArmatureModifier(self.__meshObj, self.__armObj) #bpy.context.scene.gravity[2] = -9.81 * 10 * self.__scale root = self.__root if 'ARMATURE' in types: root.mmd_root.show_armature = True if 'MESH' in types: root.mmd_root.show_meshes = True self.__targetScene.active_object = root root.select = True logging.info(' Finished importing the model in %f seconds.', time.time() - start_time) logging.info('----------------------------------------') logging.info(' mmd_tools.import_pmx module') logging.info('****************************************')
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 _updateMMDBoneAdditionalTransform(prop, context): prop['is_additional_transform_dirty'] = True p_bone = context.active_pose_bone if p_bone and p_bone.mmd_bone.as_pointer() == prop.as_pointer(): FnBone.apply_additional_transformation(prop.id_data)
def _updateAdditionalTransformInfluence(prop, context): p_bone = context.active_pose_bone if p_bone and p_bone.mmd_bone.as_pointer() == prop.as_pointer(): FnBone(p_bone).update_additional_transform_influence() else: prop['is_additional_transform_dirty'] = True
def execute(self, context): arm = context.active_object FnBone.apply_auto_bone_roll(arm) return {'FINISHED'}