4 Name: 'MikuMikuDance model (.pmd)...'
7 Tooltip: 'Import PMD file for MikuMikuDance.'
9 __author__= ["ousttrue"]
14 This script imports a pmd into Blender for editing.
16 20091126: first implement.
17 20091209: implement IK.
18 20091210: implement morph target.
19 20100305: use english name.
20 20100408: cleanup not used vertices.
21 20100416: fix fornt face. texture load fail safe. add progress.
22 20100506: C extension.
23 20100521: add shape_key group.
24 20100530: add invisilbe bone tail(armature layer 2).
25 20100608: integrate 2.4 and 2.5.
26 20100616: implement rigid body.
27 20100619: fix for various models.
28 20100623: fix constraint name.
29 20100626: refactoring.
31 20100703: implement bone group.
32 20100710: implement toon texture.
33 20100718: keep model name, comment.
34 20100724: update for Blender2.53.
35 20100731: add full python module.
36 20101005: update for Blender2.54.
37 20101228: update for Blender2.55.
38 20110429: update for Blender2.57b.
39 20110522: implement RigidBody and Constraint.
40 20110918: update for Blender2.59.
41 20111002: update for pymeshio-2.1.0
44 'category': 'Import/Export',
45 'name': 'Import: MikuMikuDance Model Format (.pmd)',
49 'location': 'File > Import',
50 'description': 'Import from the MikuMikuDance Model Format (.pmd)',
51 'warning': '', # used for warning icon and text in addons panel
52 'wiki_url': 'http://sourceforge.jp/projects/meshio/wiki/FrontPage',
53 'tracker_url': 'http://sourceforge.jp/ticket/newticket.php?group_id=5081',
57 ###############################################################################
59 ###############################################################################
64 from .pymeshio import pmd
65 from .pymeshio.pmd import reader
66 from .pymeshio import englishmap
77 def createPmdMaterial(m, index):
78 material = bpy.data.materials.new("Material")
80 material.diffuse_shader='FRESNEL'
81 material.diffuse_color=([m.diffuse_color.r, m.diffuse_color.g, m.diffuse_color.b])
82 material.alpha=m.alpha
84 material.specular_shader='TOON'
85 material.specular_color=([m.specular_color.r, m.specular_color.g, m.specular_color.b])
86 material.specular_toon_size=int(m.specular_factor)
88 material.mirror_color=([m.ambient_color.r, m.ambient_color.g, m.ambient_color.b])
90 material.subsurface_scattering.use=True if m.edge_flag==1 else False
92 material.name="m_%02d" % index
93 material.preview_render_type='FLAT'
94 material.use_transparency=True
97 def poseBoneLimit(n, b):
100 if n.startswith("knee_"):
105 b.use_ik_limit_x=True
108 elif n.startswith("ankle_"):
112 def setSphereMap(material, index, blend_type='MULTIPLY'):
113 slot=material.texture_slots[index]
114 slot.texture_coords='NORMAL'
115 slot.mapping='SPHERE'
116 slot.blend_type=blend_type
119 ###############################################################################
121 return bl.createVector(v.x, v.y, v.z)
124 def convert_coord(pos):
126 Left handed y-up to Right handed z-up
128 return (pos.x, pos.z, pos.y)
131 def to_radian(degree):
132 return math.pi * degree / 180
135 def get_bone_name(l, index):
137 return l.bones[0].name.decode('cp932')
139 if index < len(l.bones):
140 name=englishmap.getEnglishBoneName(l.bones[index].name.decode('cp932'))
143 return l.bones[index].name.decode('cp932')
144 print('invalid bone index', index)
145 return l.bones[0].name.decode('cp932')
148 def get_group_name(g):
149 group_name=englishmap.getEnglishBoneGroupName(g.decode('cp932').strip())
151 group_name=g.decode('cp932').strip()
155 def __importToonTextures(io, tex_dir):
156 mesh, meshObject=bl.mesh.create(bl.TOON_TEXTURE_OBJECT)
157 material=bl.material.create(bl.TOON_TEXTURE_OBJECT)
158 bl.mesh.addMaterial(mesh, material)
160 toon=io.toon_textures[i]
161 path=os.path.join(tex_dir, toon.decode('cp932'))
162 texture, image=bl.texture.create(path)
163 bl.material.addTexture(material, texture, False)
164 return meshObject, material
167 def __importShape(obj, l, vertex_map):
172 bl.object.pinShape(obj, True)
180 # create vertex group
181 bl.object.addVertexGroup(obj, bl.MMD_SHAPE_GROUP_NAME)
186 bl.object.assignVertexGroup(
187 obj, bl.MMD_SHAPE_GROUP_NAME, vertex_map[i], 0)
193 baseShapeBlock=bl.object.addShapeKey(obj, bl.BASE_SHAPE_NAME)
195 mesh=bl.object.getData(obj)
204 name=englishmap.getEnglishSkinName(s.name.decode('cp932'))
206 name=s.name.decode('cp932')
209 new_shape_key=bl.object.addShapeKey(obj, name)
211 for index, offset in zip(s.indices, s.pos_list):
213 base_index=base.indices[index]
214 except IndexError as msg:
217 print("invalid index %d/%d" % (index, len(base.indices)))
220 vertex_index=vertex_map[base_index]
221 bl.shapekey.assign(new_shape_key, vertex_index,
222 mesh.vertices[vertex_index].co+
223 bl.createVector(*convert_coord(offset)))
224 except KeyError as e:
225 print('base_index: %d' % base_index)
229 bl.object.setActivateShapeKey(obj, 0)
232 def __build(armature, b, p, parent):
233 name=englishmap.getEnglishBoneName(b.name.decode('cp932'))
235 name=b.name.decode('cp932')
237 bone=bl.armature.createBone(armature, name)
239 if parent and (b.tail_index==0 or b.type==6 or b.type==7 or b.type==9):
241 bone.head = bl.createVector(*convert_coord(b.pos))
242 bone.tail=bone.head+bl.createVector(0, 1, 0)
244 if bone.name=="center_t":
245 # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
246 parent.tail=parent.head+bl.createVector(0, 1, 0)
247 bone.head=parent.tail
248 bone.tail=bone.head+bl.createVector(0, 1, 0)
250 if parent.tail==bone.head:
253 print('diffurence with parent.tail and head', name)
256 bl.bone.setConnected(bone)
258 bl.bone.setLayerMask(bone, [0, 1])
261 bone.head = bl.createVector(*convert_coord(b.pos))
262 bone.tail = bl.createVector(*convert_coord(b.tail))
265 if parent.tail==bone.head:
266 bl.bone.setConnected(bone)
268 if bone.head==bone.tail:
269 bone.tail=bone.head+bl.createVector(0, 1, 0)
272 __build(armature, c, b, bone)
275 def __importArmature(l):
276 armature, armature_object=bl.armature.create()
279 bl.armature.makeEditable(armature_object)
282 __build(armature, b, None, None)
283 bl.armature.update(armature)
287 pose = bl.object.getPose(armature_object)
289 target=l.bones[ik.target]
290 name = englishmap.getEnglishBoneName(target.name.decode('cp932'))
292 name=target.name.decode('cp932')
293 p_bone = pose.bones[name]
295 print('not found', name)
297 if len(ik.children) >= 16:
298 print('over MAX_CHAINLEN', ik, len(ik.children))
300 effector_name=englishmap.getEnglishBoneName(
301 l.bones[ik.index].name.decode('cp932'))
302 if not effector_name:
303 effector_name=l.bones[ik.index].name.decode('cp932')
305 constraint=bl.armature.createIkConstraint(armature_object,
306 p_bone, effector_name,
307 ik.children, ik.weight, ik.iterations)
309 bl.armature.makeEditable(armature_object)
310 bl.armature.update(armature)
314 for i, g in enumerate(l.bone_group_list):
315 name=get_group_name(g.name)
316 bl.object.createBoneGroup(armature_object, name, "THEME%02d" % (i+1))
318 # assign bone to group
319 for b_index, g_index in l.bone_display_list:
322 bone_name=englishmap.getEnglishBoneName(b.name.decode('cp932'))
324 bone_name=b.name.decode('cp932')
326 g=l.bone_group_list[g_index-1]
327 group_name=get_group_name(g.name)
330 pose.bones[bone_name].bone_group=pose.bone_groups[group_name]
334 return armature_object
337 def __import16MaerialAndMesh(meshObject, l,
338 material_order, face_map, tex_dir, toon_material):
340 mesh=bl.object.getData(meshObject)
341 ############################################################
343 ############################################################
344 bl.progress_print('create materials')
350 for material_index in material_order:
352 m=l.materials[material_index]
353 mesh_material_map[material_index]=index
357 material=createPmdMaterial(m, material_index)
360 texture_name=m.texture_file.decode('cp932')
362 for i, t in enumerate(texture_name.split('*')):
364 texture=textureMap[t]
366 path=os.path.join(tex_dir, t)
367 texture, image=bl.texture.create(path)
368 textureMap[texture_name]=texture
369 imageMap[material_index]=image
370 texture_index=bl.material.addTexture(material, texture)
371 if t.endswith('sph'):
373 setSphereMap(material, texture_index)
374 elif t.endswith('spa'):
376 setSphereMap(material, texture_index, 'ADD')
379 toon_index=bl.material.addTexture(
381 bl.material.getTexture(
383 0 if m.toon_index==0xFF else m.toon_index
387 bl.mesh.addMaterial(mesh, material)
391 ############################################################
393 ############################################################
394 bl.progress_print('create vertices')
397 for v in l.each_vertex():
398 vertices.append(convert_coord(v.pos))
400 ############################################################
402 ############################################################
403 bl.progress_print('create faces')
406 mesh_face_materials=[]
409 for material_index in material_order:
410 face_offset=face_map[material_index]
411 m=l.materials[material_index]
412 material_faces=l.indices[face_offset:face_offset+m.vertex_count]
414 def degenerate(i0, i1, i2):
418 return i0==i1 or i1==i2 or i2==i0
420 for j in xrange(0, len(material_faces), 3):
422 i1=material_faces[j+1]
423 i2=material_faces[j+2]
425 triangle=[i2, i1, i0]
426 if degenerate(*triangle):
428 mesh_face_indices.append(triangle[0:3])
429 mesh_face_materials.append(material_index)
430 used_vertices.add(i0)
431 used_vertices.add(i1)
432 used_vertices.add(i2)
434 ############################################################
435 # create vertices & faces
436 ############################################################
437 bl.mesh.addGeometry(mesh, vertices, mesh_face_indices)
439 ############################################################
441 ############################################################
442 # create vertex group
444 for v in l.each_vertex():
445 vertex_groups[v.bone0]=True
446 vertex_groups[v.bone1]=True
447 for i in vertex_groups.keys():
448 bl.object.addVertexGroup(meshObject, get_bone_name(l, i))
451 bl.mesh.useVertexUV(mesh)
452 for i, v, mvert in zip(xrange(len(l.vertices)),
453 l.each_vertex(), mesh.vertices):
455 bl.vertex.setNormal(mvert, convert_coord(v.normal))
457 w1=float(v.weight0)/100.0
459 bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone0),
461 bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone1),
464 ############################################################
466 ############################################################
469 for i, (face, material_index) in enumerate(
470 zip(mesh.faces, mesh_face_materials)):
472 index=mesh_material_map[material_index]
473 except KeyError as message:
474 print(message, mesh_material_map, m)
476 bl.face.setMaterial(face, index)
477 material=mesh.materials[index]
479 if bl.material.hasTexture(material):
480 uv_array=[l.getUV(i) for i in bl.face.getIndices(face)]
481 bl.mesh.setFaceUV(mesh, i, face,
483 [(uv.x, 1.0-uv.y) for uv in uv_array],
484 imageMap.get(index, None))
487 bl.face.setSmooth(face, True)
491 ############################################################
492 # clean up not used vertices
493 ############################################################
494 bl.progress_print('clean up vertices not used')
497 for i, v in enumerate(l.each_vertex()):
498 if i in used_vertices:
499 vertex_map[i]=len(vertex_map)
501 remove_vertices.append(i)
503 bl.mesh.vertsDelete(mesh, remove_vertices)
505 bl.progress_print('%s created' % mesh.name)
509 def __importMaterialAndMesh(io, tex_dir, toon_material):
511 @param l[in] mmd.PMDLoader
514 ############################################################
515 # shpaeキーで使われるマテリアル優先的に前に並べる
516 ############################################################
517 # shapeキーで使われる頂点インデックスを集める
518 shape_key_used_vertices=set()
529 for index in base.indices:
530 shape_key_used_vertices.add(index)
532 # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
533 def isMaterialUsedInShape(offset, m):
534 for i in xrange(offset, offset+m.vertex_count):
535 if io.indices[i] in shape_key_used_vertices:
538 material_with_shape=set()
540 # 各マテリアルの開始頂点インデックスを記録する
543 for i, m in enumerate(io.materials):
544 face_map[i]=face_count
545 if isMaterialUsedInShape(face_count, m):
546 material_with_shape.add(i)
547 face_count+=m.vertex_count
549 # shapeキーで使われる頂点のあるマテリアル
550 material_with_shape=list(material_with_shape)
551 material_with_shape.sort()
553 # shapeキーに使われていないマテリアル
554 material_without_shape=[]
555 for i in range(len(io.materials)):
556 if not i in material_with_shape:
557 material_without_shape.append(i)
560 def __splitList(l, length):
561 for i in range(0, len(l), length):
564 def __importMeshAndShape(material16, name):
565 mesh, meshObject=bl.mesh.create(name)
568 bl.object.deselectAll()
569 bl.object.activate(meshObject)
571 # shapeキーで使われる順に並べなおしたマテリアル16個分の
573 vertex_map=__import16MaerialAndMesh(
574 meshObject, io, material16, face_map, tex_dir, toon_material)
577 __importShape(meshObject, io, vertex_map)
582 mesh_objects=[__importMeshAndShape(material16, 'with_shape')
583 for material16 in __splitList(material_with_shape, 16)]
585 mesh_objects+=[__importMeshAndShape(material16, 'mesh')
586 for material16 in __splitList(material_without_shape, 16)]
591 def __importConstraints(io):
592 print("create constraint")
593 container=bl.object.createEmpty('Constraints')
595 True, False, False, False, False, False, False, False, False, False,
596 False, False, False, False, False, False, False, False, False, False,
598 material=bl.material.create('constraint')
599 material.diffuse_color=(1, 0, 0)
601 for i, c in enumerate(io.joints):
602 bpy.ops.mesh.primitive_uv_sphere_add(
606 location=(c.position.x, c.position.z, c.position.y),
609 meshObject=bl.object.getActive()
610 constraintMeshes.append(meshObject)
611 mesh=bl.object.getData(meshObject)
612 bl.mesh.addMaterial(mesh, material)
613 meshObject.name='c_%03d' % i
614 #meshObject.draw_transparent=True
615 #meshObject.draw_wire=True
616 meshObject.draw_type='SOLID'
618 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
620 meshObject[bl.CONSTRAINT_NAME]=c.name.decode('cp932')
621 meshObject[bl.CONSTRAINT_A]=io.rigidbodies[c.rigidbody_index_a].name.decode('cp932')
622 meshObject[bl.CONSTRAINT_B]=io.rigidbodies[c.rigidbody_index_b].name.decode('cp932')
623 meshObject[bl.CONSTRAINT_POS_MIN]=VtoV(c.translation_limit_min)
624 meshObject[bl.CONSTRAINT_POS_MAX]=VtoV(c.translation_limit_max)
625 meshObject[bl.CONSTRAINT_ROT_MIN]=VtoV(c.rotation_limit_min)
626 meshObject[bl.CONSTRAINT_ROT_MAX]=VtoV(c.rotation_limit_max)
627 meshObject[bl.CONSTRAINT_SPRING_POS]=VtoV(c.spring_constant_translation)
628 meshObject[bl.CONSTRAINT_SPRING_ROT]=VtoV(c.spring_constant_rotation)
630 for meshObject in reversed(constraintMeshes):
631 bl.object.makeParent(container, meshObject)
636 def __importRigidBodies(io):
637 print("create rigid bodies")
639 container=bl.object.createEmpty('RigidBodies')
641 True, False, False, False, False, False, False, False, False, False,
642 False, False, False, False, False, False, False, False, False, False,
644 material=bl.material.create('rigidBody')
646 for i, rigid in enumerate(io.rigidbodies):
647 if rigid.bone_index==0xFFFF:
651 bone=io.bones[rigid.bone_index]
652 pos=bone.pos+rigid.shape_position
654 if rigid.shape_type==pmd.SHAPE_SPHERE:
655 bpy.ops.mesh.primitive_ico_sphere_add(
656 location=(pos.x, pos.z, pos.y),
659 bpy.ops.transform.resize(
660 value=rigid.shape_size.to_a())
661 elif rigid.shape_type==pmd.SHAPE_BOX:
662 bpy.ops.mesh.primitive_cube_add(
663 location=(pos.x, pos.z, pos.y),
666 bpy.ops.transform.resize(
667 value=rigid.shape_size.to_a())
668 elif rigid.shape_type==pmd.SHAPE_CAPSULE:
669 bpy.ops.mesh.primitive_cylinder_add(
670 location=(pos.x, pos.z, pos.y),
673 bpy.ops.transform.resize(
674 value=rigid.shape_size.to_a())
678 meshObject=bl.object.getActive()
679 mesh=bl.object.getData(meshObject)
680 rigidMeshes.append(meshObject)
681 bl.mesh.addMaterial(mesh, material)
682 meshObject.name='r_%03d' % i
683 meshObject[bl.RIGID_NAME]=rigid.name.decode('cp932')
684 #meshObject.draw_transparent=True
685 #meshObject.draw_wire=True
686 meshObject.draw_type='WIRE'
687 rot=rigid.shape_rotation
688 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
691 meshObject[bl.RIGID_SHAPE_TYPE]=rigid.shape_type
692 meshObject[bl.RIGID_PROCESS_TYPE]=rigid.mode
694 bone_name = englishmap.getEnglishBoneName(bone.name.decode('cp932'))
696 bone_name=bone.name.decode('cp932')
697 meshObject[bl.RIGID_BONE_NAME]=bone_name
699 meshObject[bl.RIGID_GROUP]=rigid.collision_group
700 meshObject[bl.RIGID_INTERSECTION_GROUP]=rigid.no_collision_group
701 meshObject[bl.RIGID_WEIGHT]=rigid.mass
702 meshObject[bl.RIGID_LINEAR_DAMPING]=rigid.linear_damping
703 meshObject[bl.RIGID_ANGULAR_DAMPING]=rigid.angular_damping
704 meshObject[bl.RIGID_RESTITUTION]=rigid.restitution
705 meshObject[bl.RIGID_FRICTION]=rigid.friction
707 for meshObject in reversed(rigidMeshes):
708 bl.object.makeParent(container, meshObject)
713 def _execute(filepath=""):
715 load pmd file to context.
719 bl.progress_set('load %s' % filepath, 0.0)
721 model=reader.read_from_file(filepath)
723 bl.message("fail to load %s" % filepath)
725 bl.progress_set('loaded', 0.1)
728 model_name=model.english_name.decode('cp932')
729 if len(model_name)==0:
730 model_name=model.name.decode('cp932')
731 root=bl.object.createEmpty(model_name)
732 root[bl.MMD_MB_NAME]=model.name.decode('cp932')
733 root[bl.MMD_MB_COMMENT]=model.comment.decode('cp932')
734 root[bl.MMD_COMMENT]=model.english_comment.decode('cp932')
737 tex_dir=os.path.dirname(filepath)
738 toonTextures, toonMaterial=__importToonTextures(model, tex_dir)
739 bl.object.makeParent(root, toonTextures)
742 mesh_objects=__importMaterialAndMesh(model, tex_dir, toonMaterial)
743 for o in mesh_objects:
744 bl.object.makeParent(root, o)
747 armature_object=__importArmature(model)
749 bl.object.makeParent(root, armature_object)
750 armature = bl.object.getData(armature_object)
752 # add armature modifier
753 for o in mesh_objects:
754 bl.modifier.addArmature(o, armature_object)
757 for n, b in bl.object.getPose(armature_object).bones.items():
760 # import rigid bodies
761 rigidBodies=__importRigidBodies(model)
763 bl.object.makeParent(root, rigidBodies)
766 constraints=__importConstraints(model)
768 bl.object.makeParent(root, constraints)
770 bl.object.activate(root)