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())
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())
261 name=target.getName()
262 p_bone = pose.bones[name]
264 print('not found', name)
266 if len(ik.children) >= 16:
267 print('over MAX_CHAINLEN', ik, len(ik.children))
269 effector_name=englishmap.getEnglishBoneName(
270 l.bones[ik.index].getName())
271 if not effector_name:
272 effector_name=l.bones[ik.index].getName()
274 constraint=bl.createIkConstraint(armature_object,
275 p_bone, effector_name, ik)
277 bl.armatureMakeEditable(scene, armature_object)
278 bl.armatureUpdate(armature)
281 return armature_object
284 def __import16MaerialAndMesh(meshObject, l,
285 material_order, face_map, tex_dir):
287 mesh=bl.objectGetData(meshObject)
288 ############################################################
290 ############################################################
291 progress_print('create materials')
297 for material_index in material_order:
299 m=l.materials[material_index]
300 mesh_material_map[material_index]=index
304 material=bl.createPmdMaterial(m)
306 texture_name=m.getTexture()
308 if texture_name in textureMap:
309 texture=textureMap[texture_name]
312 texture, image=bl.createTexture(
313 os.path.join(tex_dir, texture_name))
314 textureMap[texture_name]=texture
315 imageMap[material_index]=image
318 bl.materialAddTexture(material, texture)
319 bl.meshAddMaterial(mesh, material)
322 ############################################################
324 ############################################################
325 progress_print('create vertices')
329 for v in l.each_vertex():
330 vertices.append(convert_coord(v.pos))
332 for v in l.each_vertex():
333 vertices.extend(convert_coord(v.pos))
335 ############################################################
337 ############################################################
338 progress_print('create faces')
341 mesh_face_materials=[]
344 for material_index in material_order:
345 face_offset=face_map[material_index]
346 m=l.materials[material_index]
347 material_faces=l.indices[face_offset:face_offset+m.vertex_count]
349 def degenerate(i0, i1, i2):
353 return i0==i1 or i1==i2 or i2==i0
355 for j in xrange(0, len(material_faces), 3):
357 i1=material_faces[j+1]
358 i2=material_faces[j+2]
360 triangle=[i2, i0, i1]
362 triangle=[i0, i1, i2]
363 if degenerate(*triangle):
366 mesh_face_indices.append(triangle[0:3])
368 mesh_face_indices.extend(
369 [triangle[0], triangle[1], triangle[2], 0])
370 mesh_face_materials.append(material_index)
371 used_vertices.add(i0)
372 used_vertices.add(i1)
373 used_vertices.add(i2)
375 ############################################################
376 # create vertices & faces
377 ############################################################
378 bl.meshCreateVerteicesAndFaces(mesh, vertices, mesh_face_indices)
380 ############################################################
382 ############################################################
383 # create vertex group
385 for v in l.each_vertex():
386 vertex_groups[v.bone0]=True
387 vertex_groups[v.bone1]=True
388 for i in vertex_groups.keys():
389 bl.meshAddVertexGroup(meshObject, get_bone_name(l, i))
392 bl.meshUseVertexUv(mesh)
393 for i, v, mvert in zip(xrange(len(l.vertices)),
394 l.each_vertex(), mesh.verts):
396 bl.vertexSetNormal(mvert, convert_coord(v.normal))
397 bl.vertexSetUv(mvert, convert_uv(v.uv))
399 w1=float(v.weight0)/100.0
401 bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone0),
403 bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone1),
406 ############################################################
408 ############################################################
413 for face, material_index in zip(mesh.faces, mesh_face_materials):
415 index=mesh_material_map[material_index]
416 except KeyError as message:
417 print(message, mesh_material_map, m)
420 material=mesh.materials[index]
421 texture=material.getTextures()[0]
424 face.image=texture.tex.image
425 texture.tex.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
427 face.verts[0].uvco, face.verts[1].uvco, face.verts[2].uvco]
433 for face, uv_face, material_index in zip(mesh.faces,
434 mesh.uv_textures[0].data,
438 index=mesh_material_map[material_index]
439 except KeyError as message:
440 print(message, mesh_material_map, m)
442 face.material_index=index
443 material=mesh.materials[index]
445 if material.texture_slots[0]:
446 uv=l.getUV(face.verts[0])
447 uv_face.uv1=[uv.x, 1.0-uv.y]
449 uv=l.getUV(face.verts[1])
450 uv_face.uv2=[uv.x, 1.0-uv.y]
452 uv=l.getUV(face.verts[2])
453 uv_face.uv3=[uv.x, 1.0-uv.y]
454 if face.material_index in imageMap:
455 uv_face.image=imageMap[face.material_index]
462 ############################################################
463 # clean up not used vertices
464 ############################################################
465 progress_print('clean up vertices not used')
468 for i, v in enumerate(l.each_vertex()):
469 if i in used_vertices:
470 vertex_map[i]=len(vertex_map)
472 remove_vertices.append(i)
474 bl.meshVertsDelete(mesh, remove_vertices)
476 progress_print('%s created' % mesh.name)
480 def __importMesh(scene, io, tex_dir):
482 @param l[in] mmd.PMDLoader
485 ############################################################
486 # shpaeキーで使われるマテリアル優先的に前に並べる
487 ############################################################
488 # shapeキーで使われる頂点インデックスを集める
489 shape_key_used_vertices=set()
490 if len(io.morph_list)>0:
493 for s in io.morph_list:
500 for index in base.indices:
501 shape_key_used_vertices.add(index)
503 # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
504 def isMaterialUsedInShape(offset, m):
505 for i in xrange(offset, offset+m.vertex_count):
506 if io.indices[i] in shape_key_used_vertices:
509 # shapeキーで使われるマテリアルを記録する
510 shape_key_materials=set()
511 # 各マテリアルの開始頂点インデックスを記録する
514 for i, m in enumerate(io.materials):
515 face_map[i]=face_count
516 if isMaterialUsedInShape(face_count, m):
517 shape_key_materials.add(i)
518 face_count+=m.vertex_count
521 material_order=list(shape_key_materials)
523 # shapeキーに使われていないマテリアルを後ろに追加
524 for i in range(len(io.materials)):
525 if not i in material_order:
526 material_order.append(i)
528 # マテリアル16個ごとに分割したメッシュを作成する
531 while material_offset<len(io.materials):
532 mesh, meshObject=bl.createMesh(scene, 'mesh')
534 #meshObject.layers = [1]
535 mesh_objects.append(meshObject)
538 bl.objectDeselectAll()
539 bl.objectActivate(scene, meshObject)
541 # shapeキーで使われる順に並べなおしたマテリアル16個分の
543 vertex_map=__import16MaerialAndMesh(
545 material_order[material_offset:material_offset+16],
552 __importShape(meshObject, io, vertex_map)
563 def __execute(filename, scene):
565 load pmd file to context.
568 progress_set('load %s' % filename, 0.0)
571 if not io.read(filename):
572 print("fail to load %s" % filename)
574 progress_set('loaded %s' % filename, 0.1)
577 model_name=io.getEnglishName()
578 if len(model_name)==0:
579 model_name=io.getName()
580 root=bl.createEmptyObject(scene, model_name)
583 mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
584 for o in mesh_objects:
585 bl.objectMakeParent(root, o)
588 armature_object=__importArmature(scene, io)
590 bl.objectMakeParent(root, armature_object)
591 armature = bl.objectGetData(armature_object)
593 # add armature modifier
594 for o in mesh_objects:
595 bl.objectAddArmatureModifier(o, armature_object)
598 for n, b in bl.objectGetPose(armature_object).bones.items():
599 bl.poseBoneLimit(n, b)
602 bl.objectSelect(root)
603 for o in mesh_objects:
605 bl.objectSelect(armature_object)
610 def execute_24(filename):
614 filename=filename.decode(bl.INTERNAL_ENCODING)
615 print(bl.INTERNAL_ENCODING, bl.FS_ENCODING)
618 mode_edit = Blender.Window.EditMode()
620 Blender.Window.EditMode(0)
622 progress_start('pmd_import')
623 scene = bpy.data.scenes.active
624 __execute(filename, scene)
630 Blender.Window.EditMode(1)
631 Blender.Window.RedrawAll()
633 Blender.Window.FileSelector(
636 Blender.sys.makename(ext='.pmd'))
640 def execute_25(*args):
641 progress_start('pmd_import')
646 class IMPORT_OT_pmd(bpy.types.Operator):
647 bl_idname = "import_scene.pmd"
648 bl_label = 'Import PMD'
650 # List of operator properties, the attributes will be assigned
651 # to the class instance from the operator settings before calling.
653 path = StringProperty(
655 description="File path used for importing the PMD file",
656 maxlen= 1024, default= "")
657 filename = StringProperty(
659 description="Name of the file.")
660 directory = StringProperty(
662 description="Directory of the file.")
664 def execute(self, context):
665 execute_25(self.properties.path, context.scene)
668 def invoke(self, context, event):
670 wm.add_fileselect(self)
671 return 'RUNNING_MODAL'
674 def menu_func(self, context):
675 self.layout.operator(IMPORT_OT_pmd.bl_idname,
676 text="MikuMikuDance model (.pmd)")
679 bpy.types.register(IMPORT_OT_pmd)
680 bpy.types.INFO_MT_file_import.append(menu_func)
683 bpy.types.unregister(IMPORT_OT_pmd)
684 bpy.types.INFO_MT_file_import.remove(menu_func)
686 if __name__=="__main__":