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)
125 bl.meshAssignVertexGroup(
126 obj, MMD_SHAPE_GROUP_NAME, vertex_map[i], 0)
132 baseShapeBlock=bl.objectAddShapeKey(obj, BASE_SHAPE_NAME)
134 mesh=bl.objectGetData(obj)
138 for s in l.morph_list:
143 name=englishmap.getEnglishSkinName(s.getName())
149 for index, offset in zip(s.indices, s.pos_list):
151 vertex_index=vertex_map[base.indices[index]]
152 v=mesh.verts[vertex_index].co
153 offset=convert_coord(offset)
157 except IndexError as msg:
159 print(index, len(base.indices), len(vertex_map))
160 print(len(mesh.verts))
161 print(base.indices[index])
165 #print 'this mesh not has shape vertices'
168 # create shapekey block
169 new_shape_key=bl.objectAddShapeKey(obj, name)
171 # copy vertex to shape key
175 for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
183 new_shape_key=bl.objectAddShapeKey(obj, name)
185 for index, offset in zip(s.indices, s.pos_list):
187 vertex_index=base.indices[index]
188 bl.shapeKeyAssign(new_shape_key, vertex_index,
189 mesh.verts[vertex_index].co+
190 bl.createVector(*convert_coord(offset)))
191 except IndexError as msg:
193 print(index, len(base.indices), len(vertex_map))
194 print(len(mesh.verts))
195 print(base.indices[index])
199 #print 'this mesh not has shape vertices'
203 bl.objectActivateShapeKey(obj, 0)
206 def __build(armature, b, p, parent):
207 name=englishmap.getEnglishBoneName(b.getName())
209 name=b.getName().encode(bl.INTERNAL_ENCODING)
211 bone=bl.createArmatureBone(armature, name)
215 assert(b.type==6 or b.type==7)
216 bone.head = bl.createVector(*convert_coord(b.pos))
217 bone.tail=bone.head+bl.createVector(0, 1, 0)
220 if bone.name=="center_t":
221 # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
222 parent.tail=parent.head+bl.createVector(0, 1, 0)
223 bone.head=parent.tail
224 bone.tail=bone.head+bl.createVector(0, 1, 0)
226 assert(parent.tail==bone.head)
227 bl.boneSetConnected(bone)
229 bl.boneLayerMask(bone, [0, 1])
231 bone.head = bl.createVector(*convert_coord(b.pos))
232 bone.tail = bl.createVector(*convert_coord(b.tail))
235 if parent.tail==bone.head:
236 bl.boneSetConnected(bone)
238 if bone.head==bone.tail:
239 bone.tail=bone.head+bl.createVector(0, 1, 0)
242 __build(armature, c, b, bone)
245 def __importArmature(scene, l):
247 armature, armature_object=bl.createArmature(scene)
248 bl.armatureMakeEditable(scene, armature_object)
251 __build(armature, b, None, None)
252 bl.armatureUpdate(armature)
256 pose = bl.objectGetPose(armature_object)
258 target=l.bones[ik.target]
259 name = englishmap.getEnglishBoneName(target.getName())
260 p_bone = pose.bones[name]
262 print('not found', name)
264 if len(ik.children) >= 16:
265 print('over MAX_CHAINLEN', ik, len(ik.children))
267 effector_name=englishmap.getEnglishBoneName(
268 l.bones[ik.index].getName())
269 if not effector_name:
270 effector_name=l.bones[ik.index].getName()
272 constraint=bl.createIkConstraint(armature_object,
273 p_bone, effector_name, ik)
275 bl.armatureMakeEditable(scene, armature_object)
276 bl.armatureUpdate(armature)
279 return armature_object
282 def __import16MaerialAndMesh(meshObject, l,
283 material_order, face_map, tex_dir):
285 mesh=bl.objectGetData(meshObject)
286 ############################################################
288 ############################################################
289 progress_print('create materials')
295 for material_index in material_order:
297 m=l.materials[material_index]
298 mesh_material_map[material_index]=index
302 material=bl.createPmdMaterial(m)
304 texture_name=m.getTexture()
305 #tex_file=re.compile('\*.*.spa$').sub('', m.getTexture())
306 #tex_path = os.path.join(tex_dir, tex_file).encode(
307 # bl.INTERNAL_ENCODING)
309 if texture_name in textureMap:
310 texture=textureMap[texture_name]
313 texture, image=bl.createTexture(
314 os.path.join(tex_dir, texture_name))
315 textureMap[texture_name]=texture
316 imageMap[material_index]=image
319 bl.materialAddTexture(material, texture)
320 bl.meshAddMaterial(mesh, material)
323 ############################################################
325 ############################################################
326 progress_print('create vertices')
330 for v in l.each_vertex():
331 vertices.append(convert_coord(v.pos))
333 for v in l.each_vertex():
334 vertices.extend(convert_coord(v.pos))
336 ############################################################
338 ############################################################
339 progress_print('create faces')
342 mesh_face_materials=[]
345 for material_index in material_order:
346 face_offset=face_map[material_index]
347 m=l.materials[material_index]
348 material_faces=l.indices[face_offset:face_offset+m.vertex_count]
350 def degenerate(i0, i1, i2):
354 return i0==i1 or i1==i2 or i2==i0
356 for j in xrange(0, len(material_faces), 3):
358 i1=material_faces[j+1]
359 i2=material_faces[j+2]
361 triangle=[i2, i0, i1]
363 triangle=[i0, i1, i2]
364 if degenerate(*triangle):
367 mesh_face_indices.append(triangle[0:3])
369 mesh_face_indices.extend(
370 [triangle[0], triangle[1], triangle[2], 0])
371 mesh_face_materials.append(material_index)
372 used_vertices.add(i0)
373 used_vertices.add(i1)
374 used_vertices.add(i2)
376 ############################################################
377 # create vertices & faces
378 ############################################################
379 bl.meshCreateVerteicesAndFaces(mesh, vertices, mesh_face_indices)
381 ############################################################
383 ############################################################
384 # create vertex group
386 for v in l.each_vertex():
387 vertex_groups[v.bone0]=True
388 vertex_groups[v.bone1]=True
389 for i in vertex_groups.keys():
390 bl.meshAddVertexGroup(meshObject, get_bone_name(l, i))
393 bl.meshUseVertexUv(mesh)
394 for i, v, mvert in zip(xrange(len(l.vertices)),
395 l.each_vertex(), mesh.verts):
397 bl.vertexSetNormal(mvert, convert_coord(v.normal))
398 bl.vertexSetUv(mvert, convert_uv(v.uv))
400 w1=float(v.weight0)/100.0
402 bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone0),
404 bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone1),
407 ############################################################
409 ############################################################
414 for face, material_index in zip(mesh.faces, mesh_face_materials):
416 index=mesh_material_map[material_index]
417 except KeyError as message:
418 print(message, mesh_material_map, m)
421 material=mesh.materials[index]
422 texture=material.getTextures()[0]
425 face.image=texture.tex.image
426 texture.tex.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
428 face.verts[0].uvco, face.verts[1].uvco, face.verts[2].uvco]
434 for face, uv_face, material_index in zip(mesh.faces,
435 mesh.uv_textures[0].data,
439 index=mesh_material_map[material_index]
440 except KeyError as message:
441 print(message, mesh_material_map, m)
443 face.material_index=index
444 material=mesh.materials[index]
446 if material.texture_slots[0]:
447 uv=l.getUV(face.verts[0])
448 uv_face.uv1=[uv.x, 1.0-uv.y]
450 uv=l.getUV(face.verts[1])
451 uv_face.uv2=[uv.x, 1.0-uv.y]
453 uv=l.getUV(face.verts[2])
454 uv_face.uv3=[uv.x, 1.0-uv.y]
455 if face.material_index in imageMap:
456 uv_face.image=imageMap[face.material_index]
463 ############################################################
464 # clean up not used vertices
465 ############################################################
466 progress_print('clean up vertices not used')
469 for i, v in enumerate(l.each_vertex()):
470 if i in used_vertices:
471 vertex_map[i]=len(vertex_map)
473 remove_vertices.append(i)
475 bl.meshVertsDelete(mesh, remove_vertices)
477 progress_print('%s created' % mesh.name)
481 def __importMesh(scene, io, tex_dir):
483 @param l[in] mmd.PMDLoader
486 ############################################################
487 # shpaeキーで使われるマテリアル優先的に前に並べる
488 ############################################################
489 # shapeキーで使われる頂点インデックスを集める
490 shape_key_used_vertices=set()
491 if len(io.morph_list)>0:
494 for s in io.morph_list:
501 for index in base.indices:
502 shape_key_used_vertices.add(index)
504 # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
505 def isMaterialUsedInShape(offset, m):
506 for i in xrange(offset, offset+m.vertex_count):
507 if io.indices[i] in shape_key_used_vertices:
510 # shapeキーで使われるマテリアルを記録する
511 shape_key_materials=set()
512 # 各マテリアルの開始頂点インデックスを記録する
515 for i, m in enumerate(io.materials):
516 face_map[i]=face_count
517 if isMaterialUsedInShape(face_count, m):
518 shape_key_materials.add(i)
519 face_count+=m.vertex_count
522 material_order=list(shape_key_materials)
524 # shapeキーに使われていないマテリアルを後ろに追加
525 for i in range(len(io.materials)):
526 if not i in material_order:
527 material_order.append(i)
529 # マテリアル16個ごとに分割したメッシュを作成する
532 while material_offset<len(io.materials):
533 mesh, meshObject=bl.createMesh(scene, 'mesh')
535 #meshObject.layers = [1]
536 mesh_objects.append(meshObject)
539 bl.objectDeselectAll()
540 bl.objectActivate(scene, meshObject)
542 # shapeキーで使われる順に並べなおしたマテリアル16個分の
544 vertex_map=__import16MaerialAndMesh(
546 material_order[material_offset:material_offset+16],
553 __importShape(meshObject, io, vertex_map)
564 def __execute(filename, scene):
566 load pmd file to context.
569 progress_set('load %s' % filename, 0.0)
572 if not io.read(filename):
573 print("fail to load %s" % filename)
575 progress_set('loaded %s' % filename, 0.1)
578 root=bl.createEmptyObject(scene,
579 io.english_name if len(io.english_name)>0 else io.getName().encode(bl.INTERNAL_ENCODING))
582 mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
583 for o in mesh_objects:
584 bl.objectMakeParent(root, o)
587 armature_object=__importArmature(scene, io)
589 bl.objectMakeParent(root, armature_object)
590 armature = bl.objectGetData(armature_object)
592 # add armature modifier
593 for o in mesh_objects:
594 bl.objectAddArmatureModifier(o, armature_object)
597 for n, b in bl.objectGetPose(armature_object).bones.items():
598 bl.poseBoneLimit(n, b)
601 bl.objectSelect(root)
602 for o in mesh_objects:
604 bl.objectSelect(armature_object)
609 def execute_24(filename):
613 filename=filename.decode(bl.INTERNAL_ENCODING)
614 print(bl.INTERNAL_ENCODING, bl.FS_ENCODING)
617 mode_edit = Blender.Window.EditMode()
619 Blender.Window.EditMode(0)
621 progress_start('pmd_import')
622 scene = bpy.data.scenes.active
623 __execute(filename, scene)
629 Blender.Window.EditMode(1)
630 Blender.Window.RedrawAll()
632 Blender.Window.FileSelector(
635 Blender.sys.makename(ext='.pmd'))
639 def execute_25(*args):
640 progress_start('pmd_import')
645 class IMPORT_OT_pmd(bpy.types.Operator):
646 bl_idname = "import_scene.pmd"
647 bl_label = 'Import PMD'
649 # List of operator properties, the attributes will be assigned
650 # to the class instance from the operator settings before calling.
652 path = StringProperty(
654 description="File path used for importing the PMD file",
655 maxlen= 1024, default= "")
656 filename = StringProperty(
658 description="Name of the file.")
659 directory = StringProperty(
661 description="Directory of the file.")
663 def execute(self, context):
664 execute_25(self.properties.path, context.scene)
667 def invoke(self, context, event):
669 wm.add_fileselect(self)
670 return 'RUNNING_MODAL'
673 def menu_func(self, context):
674 self.layout.operator(IMPORT_OT_pmd.bl_idname,
675 text="MikuMikuDance model (.pmd)")
678 bpy.types.register(IMPORT_OT_pmd)
679 bpy.types.INFO_MT_file_import.append(menu_func)
682 bpy.types.unregister(IMPORT_OT_pmd)
683 bpy.types.INFO_MT_file_import.remove(menu_func)
685 if __name__=="__main__":