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'
30 BASE_SHAPE_NAME='Basis'
33 ###############################################################################
35 ###############################################################################
42 from meshio import pmd, englishmap
45 return sys.version_info[0]<3
50 from Blender import Mathutils
58 from bpy.props import *
66 ###############################################################################
68 ###############################################################################
69 def progress_start(base):
71 progressBar=bl.ProgressBar(base)
73 def progress_finish():
77 def progress_print(message, progress=0.05):
79 progressBar.advance(message, progress)
81 def progress_set(message, progress):
83 progressBar.set(message, progress)
86 ###############################################################################
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 to_radian(degree):
99 return math.pi * degree / 180
102 def get_bone_name(l, index):
103 name=englishmap.getEnglishBoneName(l.bones[index].getName())
104 return name if name else l.bones[index].getName()
106 def __importShape(obj, l, vertex_map):
107 if len(l.morph_list)==0:
111 bl.objectPinShape(obj)
115 for s in l.morph_list:
119 # create vertex group
120 bl.meshAddVertexGroup(obj, MMD_SHAPE_GROUP_NAME)
126 bl.meshAssignVertexGroup(
127 obj, MMD_SHAPE_GROUP_NAME, vertex_map[i], 0)
130 bl.meshAssignVertexGroup(
131 obj, MMD_SHAPE_GROUP_NAME, i, 0)
137 baseShapeBlock=bl.objectAddShapeKey(obj, BASE_SHAPE_NAME)
139 mesh=bl.objectGetData(obj)
143 for s in l.morph_list:
148 name=englishmap.getEnglishSkinName(s.getName())
154 for index, offset in zip(s.indices, s.pos_list):
156 vertex_index=vertex_map[base.indices[index]]
157 v=mesh.verts[vertex_index].co
158 offset=convert_coord(offset)
162 except IndexError as msg:
164 print(index, len(base.indices), len(vertex_map))
165 print(len(mesh.verts))
166 print(base.indices[index])
170 #print 'this mesh not has shape vertices'
173 # create shapekey block
174 new_shape_key=bl.objectAddShapeKey(obj, name)
176 # copy vertex to shape key
180 for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
188 new_shape_key=bl.objectAddShapeKey(obj, name)
190 for index, offset in zip(s.indices, s.pos_list):
192 vertex_index=base.indices[index]
193 bl.shapeKeyAssign(new_shape_key, vertex_index,
194 mesh.verts[vertex_index].co+
195 bl.createVector(*convert_coord(offset)))
196 except IndexError as msg:
198 print(index, len(base.indices), len(vertex_map))
199 print(len(mesh.verts))
200 print(base.indices[index])
204 #print 'this mesh not has shape vertices'
208 bl.objectActivateShapeKey(obj, 0)
211 def __build(armature, b, p, parent):
212 name=englishmap.getEnglishBoneName(b.getName())
216 bone=bl.createArmatureBone(armature, name)
220 assert(b.type==6 or b.type==7)
221 bone.head = bl.createVector(*convert_coord(b.pos))
222 bone.tail=bone.head+bl.createVector(0, 1, 0)
225 if bone.name=="center_t":
226 # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
227 parent.tail=parent.head+bl.createVector(0, 1, 0)
228 bone.head=parent.tail
229 bone.tail=bone.head+bl.createVector(0, 1, 0)
231 assert(parent.tail==bone.head)
232 bl.boneSetConnected(bone)
234 bl.boneLayerMask(bone, [0, 1])
236 bone.head = bl.createVector(*convert_coord(b.pos))
237 bone.tail = bl.createVector(*convert_coord(b.tail))
240 if parent.tail==bone.head:
241 bl.boneSetConnected(bone)
243 if bone.head==bone.tail:
244 bone.tail=bone.head+bl.createVector(0, 1, 0)
247 __build(armature, c, b, bone)
250 def __importArmature(scene, l):
252 armature, armature_object=bl.createArmature(scene)
253 bl.armatureMakeEditable(scene, armature_object)
256 __build(armature, b, None, None)
257 bl.armatureUpdate(armature)
261 pose = bl.objectGetPose(armature_object)
263 target=l.bones[ik.target]
264 name = englishmap.getEnglishBoneName(target.getName())
266 name=target.getName()
267 p_bone = pose.bones[name]
269 print('not found', name)
271 if len(ik.children) >= 16:
272 print('over MAX_CHAINLEN', ik, len(ik.children))
274 effector_name=englishmap.getEnglishBoneName(
275 l.bones[ik.index].getName())
276 if not effector_name:
277 effector_name=l.bones[ik.index].getName()
279 constraint=bl.createIkConstraint(armature_object,
280 p_bone, effector_name, ik)
282 bl.armatureMakeEditable(scene, armature_object)
283 bl.armatureUpdate(armature)
286 return armature_object
289 def __import16MaerialAndMesh(meshObject, l,
290 material_order, face_map, tex_dir):
292 mesh=bl.objectGetData(meshObject)
293 ############################################################
295 ############################################################
296 progress_print('create materials')
302 for material_index in material_order:
304 m=l.materials[material_index]
305 mesh_material_map[material_index]=index
309 material=bl.createPmdMaterial(m)
311 texture_name=m.getTexture()
313 if texture_name in textureMap:
314 texture=textureMap[texture_name]
317 texture, image=bl.createTexture(
318 os.path.join(tex_dir, texture_name))
319 textureMap[texture_name]=texture
320 imageMap[material_index]=image
323 bl.materialAddTexture(material, texture)
324 bl.meshAddMaterial(mesh, material)
327 ############################################################
329 ############################################################
330 progress_print('create vertices')
334 for v in l.each_vertex():
335 vertices.append(convert_coord(v.pos))
337 for v in l.each_vertex():
338 vertices.extend(convert_coord(v.pos))
340 ############################################################
342 ############################################################
343 progress_print('create faces')
346 mesh_face_materials=[]
349 for material_index in material_order:
350 face_offset=face_map[material_index]
351 m=l.materials[material_index]
352 material_faces=l.indices[face_offset:face_offset+m.vertex_count]
354 def degenerate(i0, i1, i2):
358 return i0==i1 or i1==i2 or i2==i0
360 for j in xrange(0, len(material_faces), 3):
362 i1=material_faces[j+1]
363 i2=material_faces[j+2]
365 triangle=[i2, i0, i1]
367 triangle=[i0, i1, i2]
368 if degenerate(*triangle):
371 mesh_face_indices.append(triangle[0:3])
373 mesh_face_indices.extend(
374 [triangle[0], triangle[1], triangle[2], 0])
375 mesh_face_materials.append(material_index)
376 used_vertices.add(i0)
377 used_vertices.add(i1)
378 used_vertices.add(i2)
380 ############################################################
381 # create vertices & faces
382 ############################################################
383 bl.meshCreateVerteicesAndFaces(mesh, vertices, mesh_face_indices)
385 ############################################################
387 ############################################################
388 # create vertex group
390 for v in l.each_vertex():
391 vertex_groups[v.bone0]=True
392 vertex_groups[v.bone1]=True
393 for i in vertex_groups.keys():
394 bl.meshAddVertexGroup(meshObject, get_bone_name(l, i))
397 bl.meshUseVertexUv(mesh)
398 for i, v, mvert in zip(xrange(len(l.vertices)),
399 l.each_vertex(), mesh.verts):
401 bl.vertexSetNormal(mvert, convert_coord(v.normal))
402 bl.vertexSetUv(mvert, convert_uv(v.uv))
404 w1=float(v.weight0)/100.0
406 bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone0),
408 bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone1),
411 ############################################################
413 ############################################################
418 for face, material_index in zip(mesh.faces, mesh_face_materials):
420 index=mesh_material_map[material_index]
421 except KeyError as message:
422 print(message, mesh_material_map, m)
425 material=mesh.materials[index]
426 texture=material.getTextures()[0]
429 face.image=texture.tex.image
430 texture.tex.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
432 face.verts[0].uvco, face.verts[1].uvco, face.verts[2].uvco]
438 for face, uv_face, material_index in zip(mesh.faces,
439 mesh.uv_textures[0].data,
443 index=mesh_material_map[material_index]
444 except KeyError as message:
445 print(message, mesh_material_map, m)
447 face.material_index=index
448 material=mesh.materials[index]
450 if material.texture_slots[0]:
451 uv=l.getUV(face.verts[0])
452 uv_face.uv1=[uv.x, 1.0-uv.y]
454 uv=l.getUV(face.verts[1])
455 uv_face.uv2=[uv.x, 1.0-uv.y]
457 uv=l.getUV(face.verts[2])
458 uv_face.uv3=[uv.x, 1.0-uv.y]
459 if face.material_index in imageMap:
460 uv_face.image=imageMap[face.material_index]
467 ############################################################
468 # clean up not used vertices
469 ############################################################
470 progress_print('clean up vertices not used')
473 for i, v in enumerate(l.each_vertex()):
474 if i in used_vertices:
475 vertex_map[i]=len(vertex_map)
477 remove_vertices.append(i)
479 bl.meshVertsDelete(mesh, remove_vertices)
481 progress_print('%s created' % mesh.name)
485 def __importMesh(scene, io, tex_dir):
487 @param l[in] mmd.PMDLoader
490 ############################################################
491 # shpaeキーで使われるマテリアル優先的に前に並べる
492 ############################################################
493 # shapeキーで使われる頂点インデックスを集める
494 shape_key_used_vertices=set()
495 if len(io.morph_list)>0:
498 for s in io.morph_list:
505 for index in base.indices:
506 shape_key_used_vertices.add(index)
508 # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
509 def isMaterialUsedInShape(offset, m):
510 for i in xrange(offset, offset+m.vertex_count):
511 if io.indices[i] in shape_key_used_vertices:
514 # shapeキーで使われるマテリアルを記録する
515 shape_key_materials=set()
516 # 各マテリアルの開始頂点インデックスを記録する
519 for i, m in enumerate(io.materials):
520 face_map[i]=face_count
521 if isMaterialUsedInShape(face_count, m):
522 shape_key_materials.add(i)
523 face_count+=m.vertex_count
526 material_order=list(shape_key_materials)
528 # shapeキーに使われていないマテリアルを後ろに追加
529 for i in range(len(io.materials)):
530 if not i in material_order:
531 material_order.append(i)
533 # マテリアル16個ごとに分割したメッシュを作成する
536 while material_offset<len(io.materials):
537 mesh, meshObject=bl.createMesh(scene, 'mesh')
539 #meshObject.layers = [1]
540 mesh_objects.append(meshObject)
543 bl.objectDeselectAll()
544 bl.objectActivate(scene, meshObject)
546 # shapeキーで使われる順に並べなおしたマテリアル16個分の
548 vertex_map=__import16MaerialAndMesh(
550 material_order[material_offset:material_offset+16],
557 __importShape(meshObject, io, vertex_map)
568 def __execute(filename, scene):
570 load pmd file to context.
573 progress_set('load %s' % filename, 0.0)
576 if not io.read(filename):
577 print("fail to load %s" % filename)
579 progress_set('loaded %s' % filename, 0.1)
582 model_name=io.getEnglishName()
583 if len(model_name)==0:
584 model_name=io.getName()
585 root=bl.createEmptyObject(scene, model_name)
588 mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
589 for o in mesh_objects:
590 bl.objectMakeParent(root, o)
593 armature_object=__importArmature(scene, io)
595 bl.objectMakeParent(root, armature_object)
596 armature = bl.objectGetData(armature_object)
598 # add armature modifier
599 for o in mesh_objects:
600 bl.objectAddArmatureModifier(o, armature_object)
603 for n, b in bl.objectGetPose(armature_object).bones.items():
604 bl.poseBoneLimit(n, b)
607 bl.objectSelect(root)
608 for o in mesh_objects:
610 bl.objectSelect(armature_object)
615 def execute_24(filename):
619 filename=filename.decode(bl.INTERNAL_ENCODING)
620 print(bl.INTERNAL_ENCODING, bl.FS_ENCODING)
623 mode_edit = Blender.Window.EditMode()
625 Blender.Window.EditMode(0)
627 progress_start('pmd_import')
628 scene = bpy.data.scenes.active
629 __execute(filename, scene)
635 Blender.Window.EditMode(1)
636 Blender.Window.RedrawAll()
638 Blender.Window.FileSelector(
641 Blender.sys.makename(ext='.pmd'))
645 def execute_25(*args):
646 progress_start('pmd_import')
651 class IMPORT_OT_pmd(bpy.types.Operator):
652 bl_idname = "import_scene.pmd"
653 bl_label = 'Import PMD'
655 # List of operator properties, the attributes will be assigned
656 # to the class instance from the operator settings before calling.
658 path = StringProperty(
660 description="File path used for importing the PMD file",
661 maxlen= 1024, default= "")
662 filename = StringProperty(
664 description="Name of the file.")
665 directory = StringProperty(
667 description="Directory of the file.")
669 def execute(self, context):
670 execute_25(self.properties.path, context.scene)
673 def invoke(self, context, event):
675 wm.add_fileselect(self)
676 return 'RUNNING_MODAL'
679 def menu_func(self, context):
680 self.layout.operator(IMPORT_OT_pmd.bl_idname,
681 text="MikuMikuDance model (.pmd)")
684 bpy.types.register(IMPORT_OT_pmd)
685 bpy.types.INFO_MT_file_import.append(menu_func)
688 bpy.types.unregister(IMPORT_OT_pmd)
689 bpy.types.INFO_MT_file_import.remove(menu_func)
691 if __name__=="__main__":