4 Name: 'MikuMikuDance model (.pmd)...'
7 Tooltip: 'Import PMD file for MikuMikuDance.'
9 __author__= ["ousttrue"]
15 This script imports a pmd into Blender for editing.
17 0.1: 20091126: first implement.
18 0.2: 20091209: implement IK.
19 0.3: 20091210: implement morph target.
20 0.4: 20100305: use english name.
21 0.5: 20100408: cleanup not used vertices.
22 0.6: 20100416: fix fornt face. texture load fail safe. add progress.
23 0.7: 20100506: C extension.
24 0.8: 20100521: add shape_key group.
25 1.0: 20100530: add invisilbe bone tail(armature layer 2).
26 1.1: 20100608: integrate 2.4 and 2.5.
29 MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
32 ###############################################################################
34 ###############################################################################
41 from meshio import pmd, englishmap
44 return sys.version_info[0]<3
49 from Blender import Mathutils
57 from bpy.props import *
65 ###############################################################################
67 ###############################################################################
68 def progress_start(base):
70 progressBar=bl.ProgressBar(base)
72 def progress_finish():
76 def progress_print(message, progress=0.05):
78 progressBar.advance(message, progress)
80 def progress_set(message, progress):
82 progressBar.set(message, progress)
87 def convert_coord(pos):
89 Left handed y-up to Right handed z-up
91 return (pos.x, pos.z, pos.y)
95 return (uv.x, 1.0 - uv.y)
98 def get_bone_name(l, index):
99 name=englishmap.getEnglishBoneName(l.bones[index].getName())
100 return name if name else l.bones[index].getName().encode(bl.INTERNAL_ENCODING)
103 class Builder(object):
107 def build(self, armature, bones):
110 self.__build(armature, b, None, None)
113 def __build(self, armature, b, p, parent):
114 name=englishmap.getEnglishBoneName(b.getName())
116 name=b.getName().encode(bl.INTERNAL_ENCODING)
119 bone=Blender.Armature.Editbone()
121 armature.bones[name]=bone
125 assert(b.type==6 or b.type==7)
126 bone.head = Mathutils.Vector(*convert_coord(b.pos))
127 bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
130 if bone.name=="center_t":
131 # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
132 parent.tail=parent.head+Mathutils.Vector(0, 1, 0)
133 bone.head=parent.tail
134 bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
136 assert(parent.tail==bone.head)
137 bone.options=[Blender.Armature.CONNECTED]
139 bone.layerMask = (1<<1)
141 bone.head = Mathutils.Vector(*convert_coord(b.pos))
142 bone.tail = Mathutils.Vector(*convert_coord(b.tail))
145 if parent.tail==bone.head:
146 bone.options=[Blender.Armature.CONNECTED]
148 if bone.head==bone.tail:
149 bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
152 self.__build(armature, c, b, bone)
155 def importArmature(scene, l):
157 armature = Blender.Armature.New()
159 armature_object = scene.objects.new(armature)
161 act = Blender.Armature.NLA.NewAction()
162 act.setActive(armature_object)
164 armature_object.drawMode = (
165 armature_object.drawMode | Blender.Object.DrawModes.XRAY)
167 armature.drawType = Blender.Armature.OCTAHEDRON
168 armature.drawNames=True
169 armature.envelopes = False
170 armature.vertexGroups = True
171 armature.mirrorEdit = True
174 armature.makeEditable()
176 ############################################################
178 ############################################################
180 builder.build(armature, l.bones)
182 ############################################################
184 ############################################################
185 pose = armature_object.getPose()
186 cSetting = Blender.Constraint.Settings
188 # IKtarget->parent(=IK).name
189 target=l.bones[ik.target]
190 name = englishmap.getEnglishBoneName(target.getName())
191 p_bone = pose.bones[name]
193 print('not found', name)
195 if len(ik.children) >= 16:
196 print('over MAX_CHAINLEN', ik, len(ik.children))
199 ik_solver = p_bone.constraints.append(Blender.Constraint.Type.IKSOLVER)
200 ik_solver[cSetting.CHAINLEN]=len(ik.children)
201 ik_solver[cSetting.TARGET]=armature_object
202 ik_solver[cSetting.USETIP]=False
204 effector_name=englishmap.getEnglishBoneName(
205 l.bones[ik.index].getName())
206 if not effector_name:
207 effector_name=l.bones[ik.index].getName()
209 ik_solver[cSetting.BONE]=effector_name
210 #ik_solver.influence=ik.weight
211 # not used. place folder when export.
212 ik_solver[cSetting.ROTWEIGHT]=ik.weight
213 ik_solver[cSetting.ITERATIONS]=ik.iterations * 10
215 armature.makeEditable()
218 return armature_object
221 def importShape(obj, l, vertex_map):
222 if len(l.morph_list)==0:
225 mesh=obj.getData(mesh=True)
229 for s in l.morph_list:
233 # create vertex group
234 mesh.addVertGroup(MMD_SHAPE_GROUP_NAME)
240 indices.append(vertex_map[i])
241 mesh.assignVertsToGroup(MMD_SHAPE_GROUP_NAME, indices, 0,
242 Blender.Mesh.AssignModes.ADD)
248 assert(len(mesh.key.blocks)==1)
250 baseShapeBlock=mesh.key.blocks[baseShapeIndex]
251 baseShapeBlock.name='Basis'
252 obj.activeShape=baseShapeIndex
259 for s in l.morph_list:
260 if s.name==base.name:
263 for index, offset in zip(s.indices, s.pos_list):
265 vertex_index=vertex_map[base.indices[index]]
266 v=mesh.verts[vertex_index].co
267 offset=convert_coord(offset)
271 except IndexErrora as msg:
273 print(index, len(base.indices), len(vertex_map))
274 print(len(mesh.verts))
275 print(base.indices[index])
279 #print 'this mesh not has shape vertices'
283 name=englishmap.getEnglishSkinName(s.getName())
285 name=s.getName().encode(bl.INTERNAL_ENCODING)
288 # create shapekey block
290 shapeIndex=len(mesh.key.blocks)-1
291 keyBlock=mesh.key.blocks[shapeIndex]
294 # copy vertex to shape key
298 for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
305 obj.activeShape=baseShapeIndex
309 def to_radian(degree):
310 return math.pi * degree / 180
313 def convert_coord(pos):
315 Left handed y-up to Right handed z-up
317 return (pos.x, pos.z, pos.y)
321 return (uv.x, 1.0 - uv.y)
324 def getBoneName(bone):
325 name = englishmap.getEnglishBoneName(bone.getName())
326 return name if name else bone.getName()
329 def get_bone_name(l, index):
330 name=englishmap.getEnglishBoneName(l.bones[index].getName())
331 return name if name else l.bones[index].getName()
334 def create_texture(directory, texture_name):
335 texture=bpy.data.textures.new(texture_name)
337 texture=texture.recast_type()
338 texturePath=os.path.join(directory, texture_name)
339 print('create_texture', texturePath)
340 image=bpy.data.images.load(texturePath)
342 texture.mipmap = True
343 texture.interpolation = True
344 texture.use_alpha = True
348 def build_bone(armature, b, parent=None):
353 bone = armature.edit_bones.new(name if name else b.getName())
355 bone.head = mathutils.Vector(convert_coord(b.pos))
357 bone.connected=True if parent.tail==bone.head else False
358 bone.tail = mathutils.Vector(convert_coord(b.tail))
359 if bone.head==bone.tail:
360 bone.tail=bone.head-mathutils.Vector((0, 1, 0))
361 elif b.__class__ is pmd.BONE_IK:
362 bone.head = mathutils.Vector(convert_coord(b.pos))
363 bone.tail = mathutils.Vector(convert_coord(b.tail))
366 tail=mathutils.Vector(convert_coord(b.pos))
368 bone.head = tail-mathutils.Vector((0, 1, 0))
370 for child in b.children:
371 build_bone(armature, child, bone)
374 def importArmature(scene, l):
376 armature = bpy.data.armatures.new('Armature')
378 armature_object=bpy.data.objects.new('Armature', armature)
379 scene.objects.link(armature_object)
380 armature_object.x_ray=True
381 armature.draw_names=True
384 armature.drawtype='OCTAHEDRAL'
385 armature.deform_envelope=False
386 armature.deform_vertexgroups=True
387 armature.x_axis_mirror=True
390 #act = Blender.Armature.NLA.NewAction()
391 #act.setActive(armature_object)
393 # select only armature object and set edit mode
394 scene.objects.active=armature_object
395 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
396 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
401 build_bone(armature, b)
403 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
404 bpy.ops.object.select_all(action='DESELECT')
406 ############################################################
408 ############################################################
409 pose = armature_object.pose
411 effector=l.bones[ik.target]
412 parent=l.bones[effector.parent_index]
413 name=getBoneName(parent)
414 p_bone = pose.bones[name]
416 print('not found', name)
418 if len(ik.children) >= 16:
419 print('over MAX_CHAINLEN', ik, len(ik.children))
422 ik_const = p_bone.constraints.new('IK')
423 ik_const.chain_length=len(ik.children)
424 ik_const.target=armature_object
425 ik_const.subtarget=getBoneName(l.bones[ik.index])
427 rot_const = p_bone.constraints.new('LIMIT_ROTATION')
428 rot_const.influence = ik.weight
429 rot_const.owner_space = 'LOCAL'
430 rot_const.use_limit_x=True
431 rot_const.use_limit_z=True
432 rot_const.minimum_x=to_radian(ik.iterations)
433 rot_const.maximum_x=to_radian(180)
434 rot_const.minimum_z=to_radian(180 - ik.iterations)
435 rot_const.maximum_z=to_radian(0)
437 return armature_object
440 def importShape(meshObject, l, vertex_map):
441 if len(l.morph_list)==0:
446 for s in l.morph_list:
454 baseblock=meshObject.add_shape_key("Basis")
460 for s in l.morph_list:
461 if s.getName()==base.name:
466 #for v, base_pos in zip(mesh.verts, baseblock.data):
471 name=englishmap.getEnglishSkinName(s.getName())
474 new_shape_key=meshObject.add_shape_key(name)
475 #new_shape_key.value=1.0
478 for i, offset in zip(s.indices, s.pos_list):
480 vertex_index=base.indices[i]
481 new_shape_key.data[vertex_index].co=[p+o for p, o in zip(
482 mesh.verts[vertex_index].co, convert_coord(offset))]
483 except IndexError as msg:
484 print(IndexError, msg)
485 print(i, len(base.indices))
486 print(vertex_index, len(mesh.verts))
487 print(base.indices[i])
490 #print 'this mesh not has shape vertices'
494 #icu=ipo.addCurve(name)
495 #icu.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
496 #icu.append( (0.0, 0.0) )
499 def __import16MaerialAndMesh(meshObject, l,
500 material_order, face_map, tex_dir):
502 mesh=bl.objectGetData(meshObject)
503 ############################################################
505 ############################################################
506 progress_print('create materials')
512 for material_index in material_order:
514 m=l.materials[material_index]
515 mesh_material_map[material_index]=index
519 material=bl.createPmdMaterial(m)
521 texture_name=m.getTexture()
522 #tex_file=re.compile('\*.*.spa$').sub('', m.getTexture())
523 #tex_path = os.path.join(tex_dir, tex_file).encode(
524 # bl.INTERNAL_ENCODING)
526 if texture_name in textureMap:
527 texture=textureMap[texture_name]
530 texture, image=bl.createTexture(
531 os.path.join(tex_dir, texture_name))
532 textureMap[texture_name]=texture
533 imageMap[material_index]=image
536 bl.materialAddTexture(material, texture)
537 bl.meshAddMaterial(mesh, material)
540 ############################################################
542 ############################################################
543 progress_print('create vertices')
547 for v in l.each_vertex():
548 vertices.append(convert_coord(v.pos))
550 for v in l.each_vertex():
551 vertices.extend(convert_coord(v.pos))
553 ############################################################
555 ############################################################
556 progress_print('create faces')
559 mesh_face_materials=[]
562 for material_index in material_order:
563 face_offset=face_map[material_index]
564 m=l.materials[material_index]
565 material_faces=l.indices[face_offset:face_offset+m.vertex_count]
567 def degenerate(i0, i1, i2):
571 return i0==i1 or i1==i2 or i2==i0
573 for j in xrange(0, len(material_faces), 3):
575 i1=material_faces[j+1]
576 i2=material_faces[j+2]
578 triangle=[i2, i0, i1]
580 triangle=[i0, i1, i2]
581 if degenerate(*triangle):
584 mesh_face_indices.append(triangle[0:3])
586 mesh_face_indices.extend(
587 [triangle[0], triangle[1], triangle[2], 0])
588 mesh_face_materials.append(material_index)
589 used_vertices.add(i0)
590 used_vertices.add(i1)
591 used_vertices.add(i2)
593 ############################################################
594 # create vertices & faces
595 ############################################################
596 bl.meshCreateVerteicesAndFaces(mesh, vertices, mesh_face_indices)
598 ############################################################
600 ############################################################
601 # create vertex group
603 for v in l.each_vertex():
604 vertex_groups[v.bone0]=True
605 vertex_groups[v.bone1]=True
606 for i in vertex_groups.keys():
607 bl.meshAddVertexGroup(meshObject, get_bone_name(l, i))
610 bl.meshUseVertexUv(mesh)
611 for i, v, mvert in zip(xrange(len(l.vertices)),
612 l.each_vertex(), mesh.verts):
614 bl.vertexSetNormal(mvert, convert_coord(v.normal))
615 bl.vertexSetUv(mvert, convert_uv(v.uv))
617 w1=float(v.weight0)/100.0
619 bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone0),
621 bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone1),
624 ############################################################
626 ############################################################
631 for face, material_index in zip(mesh.faces, mesh_face_materials):
633 index=mesh_material_map[material_index]
634 except KeyError as message:
635 print(message, mesh_material_map, m)
638 material=mesh.materials[index]
639 texture=material.getTextures()[0]
642 face.image=texture.tex.image
643 texture.tex.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
645 face.verts[0].uvco, face.verts[1].uvco, face.verts[2].uvco]
651 for face, uv_face, material_index in zip(mesh.faces,
652 mesh.uv_textures[0].data,
656 index=mesh_material_map[material_index]
657 except KeyError as message:
658 print(message, mesh_material_map, m)
660 face.material_index=index
661 material=mesh.materials[index]
663 if material.texture_slots[0]:
664 uv=l.getUV(face.verts[0])
665 uv_face.uv1=[uv.x, 1.0-uv.y]
667 uv=l.getUV(face.verts[1])
668 uv_face.uv2=[uv.x, 1.0-uv.y]
670 uv=l.getUV(face.verts[2])
671 uv_face.uv3=[uv.x, 1.0-uv.y]
672 if face.material_index in imageMap:
673 uv_face.image=imageMap[face.material_index]
680 ############################################################
681 # clean up not used vertices
682 ############################################################
683 progress_print('clean up vertices not used')
686 for i, v in enumerate(l.each_vertex()):
687 if i in used_vertices:
688 vertex_map[i]=len(vertex_map)
690 remove_vertices.append(i)
692 bl.meshVertsDelete(mesh, remove_vertices)
694 progress_print('%s created' % mesh.name)
698 def __importMesh(scene, io, tex_dir):
700 @param l[in] mmd.PMDLoader
703 ############################################################
704 # shpaeキーで使われるマテリアル優先的に前に並べる
705 ############################################################
706 # shapeキーで使われる頂点インデックスを集める
707 shape_key_used_vertices=set()
708 if len(io.morph_list)>0:
711 for s in io.morph_list:
718 for index in base.indices:
719 shape_key_used_vertices.add(index)
721 # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
722 def isMaterialUsedInShape(offset, m):
723 for i in xrange(offset, offset+m.vertex_count):
724 if io.indices[i] in shape_key_used_vertices:
727 # shapeキーで使われるマテリアルを記録する
728 shape_key_materials=set()
729 # 各マテリアルの開始頂点インデックスを記録する
732 for i, m in enumerate(io.materials):
733 face_map[i]=face_count
734 if isMaterialUsedInShape(face_count, m):
735 shape_key_materials.add(i)
736 face_count+=m.vertex_count
739 material_order=list(shape_key_materials)
741 # shapeキーに使われていないマテリアルを後ろに追加
742 for i in range(len(io.materials)):
743 if not i in material_order:
744 material_order.append(i)
746 # マテリアル16個ごとに分割したメッシュを作成する
749 while material_offset<len(io.materials):
750 mesh, meshObject=bl.createMesh(scene, 'mesh')
752 #meshObject.layers = [1]
753 mesh_objects.append(meshObject)
756 bl.objectDeselectAll()
757 bl.objectActivate(scene, meshObject)
759 # shapeキーで使われる順に並べなおしたマテリアル16個分の
761 vertex_map=__import16MaerialAndMesh(
763 material_order[material_offset:material_offset+16],
770 importShape(meshObject, io, vertex_map)
780 def __execute(filename, scene):
782 load pmd file to context.
785 progress_set('load %s' % filename, 0.0)
788 if not io.read(filename):
789 print("fail to load %s" % filename)
791 progress_set('loaded %s' % filename, 0.1)
794 root=bl.createEmptyObject(scene,
795 io.english_name if len(io.english_name)>0 else io.getName().encode(bl.INTERNAL_ENCODING))
798 mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
799 for o in mesh_objects:
800 bl.objectMakeParent(root, o)
803 armature_object=importArmature(scene, io)
805 bl.objectMakeParent(root, armature_object)
806 armature = bl.objectGetData(armature_object)
808 # add armature modifier
809 for o in mesh_objects:
810 bl.objectAddArmatureModifier(o, armature_object)
813 for n, b in bl.objectGetPose(armature_object).bones.items():
814 bl.poseBoneLimit(n, b)
817 bl.objectSelect(root)
818 for o in mesh_objects:
820 bl.objectSelect(armature_object)
825 def execute_24(filename):
829 filename=filename.decode(bl.INTERNAL_ENCODING)
830 print(bl.INTERNAL_ENCODING, bl.FS_ENCODING)
833 mode_edit = Blender.Window.EditMode()
835 Blender.Window.EditMode(0)
837 progress_start('pmd_import')
838 scene = bpy.data.scenes.active
839 __execute(filename, scene)
845 Blender.Window.EditMode(1)
846 Blender.Window.RedrawAll()
848 Blender.Window.FileSelector(
851 Blender.sys.makename(ext='.pmd'))
855 def execute_25(*args):
856 progress_start('pmd_import')
861 class IMPORT_OT_pmd(bpy.types.Operator):
862 bl_idname = "import_scene.pmd"
863 bl_label = 'Import PMD'
865 # List of operator properties, the attributes will be assigned
866 # to the class instance from the operator settings before calling.
868 path = StringProperty(
870 description="File path used for importing the PMD file",
871 maxlen= 1024, default= "")
872 filename = StringProperty(
874 description="Name of the file.")
875 directory = StringProperty(
877 description="Directory of the file.")
879 def execute(self, context):
880 execute_25(self.properties.path, context.scene)
883 def invoke(self, context, event):
885 wm.add_fileselect(self)
886 return 'RUNNING_MODAL'
889 def menu_func(self, context):
890 self.layout.operator(IMPORT_OT_pmd.bl_idname,
891 text="MikuMikuDance model (.pmd)")
894 bpy.types.register(IMPORT_OT_pmd)
895 bpy.types.INFO_MT_file_import.append(menu_func)
898 bpy.types.unregister(IMPORT_OT_pmd)
899 bpy.types.INFO_MT_file_import.remove(menu_func)
901 if __name__=="__main__":