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.
27 1.2: 20100616: implement rigid body.
28 1.3: 20100619: fix for various models.
29 1.4: 20100623: fix constraint name.
30 1.5: 20100626: refactoring.
33 MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
34 BASE_SHAPE_NAME='Basis'
35 RIGID_SHAPE_TYPE='rigid_shape_type'
36 RIGID_PROCESS_TYPE='rigid_process_type'
37 RIGID_BONE_NAME='rigid_bone_name'
38 #RIGID_LOCATION='rigid_loation'
39 RIGID_GROUP='ribid_group'
40 RIGID_INTERSECTION_GROUP='rigid_intersection_group'
41 RIGID_WEIGHT='rigid_weight'
42 RIGID_LINEAR_DAMPING='rigid_linear_damping'
43 RIGID_ANGULAR_DAMPING='rigid_angular_damping'
44 RIGID_RESTITUTION='rigid_restitution'
45 RIGID_FRICTION='rigid_friction'
46 CONSTRAINT_NAME='constraint_name'
47 CONSTRAINT_A='const_a'
48 CONSTRAINT_B='const_b'
49 CONSTRAINT_POS_MIN='const_pos_min'
50 CONSTRAINT_POS_MAX='const_pos_max'
51 CONSTRAINT_ROT_MIN='const_rot_min'
52 CONSTRAINT_ROT_MAX='const_rot_max'
53 CONSTRAINT_SPRING_POS='const_spring_pos'
54 CONSTRAINT_SPRING_ROT='const_spring_rot'
57 ###############################################################################
59 ###############################################################################
65 from meshio import pmd, englishmap
68 return sys.version_info[0]<3
73 from Blender import Mathutils
79 def createPmdMaterial(m, index):
80 material=Blender.Material.New()
82 #material.diffuseSize = 3.14/2
83 #material.setDiffuseSmooth(0)
84 #material.setSpecSize(0)
88 material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
89 material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
90 material.setAlpha(m.diffuse.a)
92 material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
93 material.setSpec(m.shinness*0.1)
94 material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
96 material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
98 material.enableSSS=True if m.flag==1 else False
100 material.name="m_%02d" % index
103 def poseBoneLimit(n, b):
106 if n.startswith("knee_"):
111 b.limitMax=[180, 0, 0]
112 elif n.startswith("ankle_"):
115 def setSphereMap(material, index, blende_type=None):
121 from bpy.props import *
129 def createPmdMaterial(m, index):
130 material = bpy.data.materials.new("Material")
132 material.diffuse_shader='FRESNEL'
133 material.diffuse_color=([m.diffuse.r, m.diffuse.g, m.diffuse.b])
134 material.alpha=m.diffuse.a
136 material.specular_shader='TOON'
137 material.specular_color=([m.specular.r, m.specular.g, m.specular.b])
138 material.specular_toon_size=int(m.shinness)
140 material.mirror_color=([m.ambient.r, m.ambient.g, m.ambient.b])
142 material.subsurface_scattering.enabled=True if m.flag==1 else False
144 material.name="m_%02d" % index
145 material.preview_render_type='FLAT'
146 material.transparency=True
149 def poseBoneLimit(n, b):
152 if n.startswith("knee_"):
159 elif n.startswith("ankle_"):
163 def setSphereMap(material, index, blend_type=None):
164 slot=material.texture_slots[index]
165 slot.texture_coordinates='REFLECTION'
166 slot.mapping='SPHERE'
168 slot.blend_type=blend_type
171 ###############################################################################
173 return bl.createVector(v.x, v.y, v.z)
175 def convert_coord(pos):
177 Left handed y-up to Right handed z-up
179 return (pos.x, pos.z, pos.y)
182 def to_radian(degree):
183 return math.pi * degree / 180
186 def get_bone_name(l, index):
188 return l.bones[0].getName()
190 if index < len(l.bones):
191 name=englishmap.getEnglishBoneName(l.bones[index].getName())
194 return l.bones[index].getName()
195 print('invalid bone index', index)
196 return l.bones[0].getName()
198 def __importShape(obj, l, vertex_map):
199 if len(l.morph_list)==0:
203 bl.object.pinShape(obj, True)
207 for s in l.morph_list:
211 # create vertex group
212 bl.object.addVertexGroup(obj, MMD_SHAPE_GROUP_NAME)
217 bl.object.assignVertexGroup(
218 obj, MMD_SHAPE_GROUP_NAME, vertex_map[i], 0)
224 baseShapeBlock=bl.object.addShapeKey(obj, BASE_SHAPE_NAME)
226 mesh=bl.object.getData(obj)
230 for s in l.morph_list:
235 name=englishmap.getEnglishSkinName(s.getName())
241 for index, offset in zip(s.indices, s.pos_list):
243 vertex_index=vertex_map[base.indices[index]]
244 v=mesh.verts[vertex_index].co
245 offset=convert_coord(offset)
249 except IndexError as msg:
251 print(index, len(base.indices), len(vertex_map))
252 print(len(mesh.verts))
253 print(base.indices[index])
257 #print 'this mesh not has shape vertices'
260 # create shapekey block
261 new_shape_key=bl.object.addShapeKey(obj, name)
263 # copy vertex to shape key
267 for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
275 new_shape_key=bl.object.addShapeKey(obj, name)
277 for index, offset in zip(s.indices, s.pos_list):
279 vertex_index=vertex_map[base.indices[index]]
280 bl.shapekey.assign(new_shape_key, vertex_index,
281 mesh.verts[vertex_index].co+
282 bl.createVector(*convert_coord(offset)))
283 except IndexError as msg:
285 print(index, len(base.indices), len(vertex_map))
286 print(len(mesh.verts))
287 print(base.indices[index])
291 #print 'this mesh not has shape vertices'
295 bl.object.setActivateShapeKey(obj, 0)
298 def __build(armature, b, p, parent):
299 name=englishmap.getEnglishBoneName(b.getName())
303 bone=bl.armature.createBone(armature, name)
305 if parent and (b.tail_index==0 or b.type==6 or b.type==7 or b.type==9):
306 bone.head = bl.createVector(*convert_coord(b.pos))
307 bone.tail=bone.head+bl.createVector(0, 1, 0)
309 if bone.name=="center_t":
310 # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
311 parent.tail=parent.head+bl.createVector(0, 1, 0)
312 bone.head=parent.tail
313 bone.tail=bone.head+bl.createVector(0, 1, 0)
315 if parent.tail==bone.head:
318 print('diffurence with parent.tail and head', name)
320 bl.bone.setConnected(bone)
322 bl.bone.setLayerMask(bone, [0, 1])
325 bone.head = bl.createVector(*convert_coord(b.pos))
326 bone.tail = bl.createVector(*convert_coord(b.tail))
329 if parent.tail==bone.head:
330 bl.bone.setConnected(bone)
332 if bone.head==bone.tail:
333 bone.tail=bone.head+bl.createVector(0, 1, 0)
336 __build(armature, c, b, bone)
339 def __importArmature(scene, l):
341 armature, armature_object=bl.armature.create()
342 bl.armature.makeEditable(armature_object)
345 __build(armature, b, None, None)
346 bl.armature.update(armature)
350 pose = bl.object.getPose(armature_object)
352 target=l.bones[ik.target]
353 name = englishmap.getEnglishBoneName(target.getName())
355 name=target.getName()
356 p_bone = pose.bones[name]
358 print('not found', name)
360 if len(ik.children) >= 16:
361 print('over MAX_CHAINLEN', ik, len(ik.children))
363 effector_name=englishmap.getEnglishBoneName(
364 l.bones[ik.index].getName())
365 if not effector_name:
366 effector_name=l.bones[ik.index].getName()
368 constraint=bl.armature.createIkConstraint(armature_object,
369 p_bone, effector_name, ik)
371 bl.armature.makeEditable(armature_object)
372 bl.armature.update(armature)
375 return armature_object
378 def __import16MaerialAndMesh(meshObject, l,
379 material_order, face_map, tex_dir):
381 mesh=bl.object.getData(meshObject)
382 ############################################################
384 ############################################################
385 bl.progress_print('create materials')
391 for material_index in material_order:
393 m=l.materials[material_index]
394 mesh_material_map[material_index]=index
398 material=createPmdMaterial(m, material_index)
400 texture_name=m.getTexture()
402 for i, t in enumerate(texture_name.split('*')):
404 texture=textureMap[t]
406 path=os.path.join(tex_dir, t)
407 texture, image=bl.texture.create(path)
408 textureMap[texture_name]=texture
409 imageMap[material_index]=image
410 bl.material.addTexture(material, texture)
411 if t.endswith('sph'):
413 setSphereMap(material, i)
414 elif t.endswith('spa'):
416 setSphereMap(material, i, 'ADD')
418 bl.mesh.addMaterial(mesh, material)
421 ############################################################
423 ############################################################
424 bl.progress_print('create vertices')
427 for v in l.each_vertex():
428 vertices.append(convert_coord(v.pos))
430 ############################################################
432 ############################################################
433 bl.progress_print('create faces')
436 mesh_face_materials=[]
439 for material_index in material_order:
440 face_offset=face_map[material_index]
441 m=l.materials[material_index]
442 material_faces=l.indices[face_offset:face_offset+m.vertex_count]
444 def degenerate(i0, i1, i2):
448 return i0==i1 or i1==i2 or i2==i0
450 for j in xrange(0, len(material_faces), 3):
452 i1=material_faces[j+1]
453 i2=material_faces[j+2]
455 triangle=[i2, i1, i0]
456 if degenerate(*triangle):
458 mesh_face_indices.append(triangle[0:3])
459 mesh_face_materials.append(material_index)
460 used_vertices.add(i0)
461 used_vertices.add(i1)
462 used_vertices.add(i2)
464 ############################################################
465 # create vertices & faces
466 ############################################################
467 bl.mesh.addGeometry(mesh, vertices, mesh_face_indices)
469 ############################################################
471 ############################################################
472 # create vertex group
474 for v in l.each_vertex():
475 vertex_groups[v.bone0]=True
476 vertex_groups[v.bone1]=True
477 for i in vertex_groups.keys():
478 bl.object.addVertexGroup(meshObject, get_bone_name(l, i))
481 bl.mesh.useVertexUV(mesh)
482 for i, v, mvert in zip(xrange(len(l.vertices)),
483 l.each_vertex(), mesh.verts):
485 bl.vertex.setNormal(mvert, convert_coord(v.normal))
487 w1=float(v.weight0)/100.0
489 bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone0),
491 bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone1),
494 ############################################################
496 ############################################################
499 for i, (face, material_index) in enumerate(
500 zip(mesh.faces, mesh_face_materials)):
502 index=mesh_material_map[material_index]
503 except KeyError as message:
504 print(message, mesh_material_map, m)
506 bl.face.setMaterial(face, index)
507 material=mesh.materials[index]
509 if bl.material.hasTexture(material):
510 uv_array=[l.getUV(i) for i in bl.face.getIndices(face)]
511 bl.mesh.setFaceUV(mesh, i, face,
513 [(uv.x, 1.0-uv.y) for uv in uv_array],
514 imageMap.get(index, None))
521 ############################################################
522 # clean up not used vertices
523 ############################################################
524 bl.progress_print('clean up vertices not used')
527 for i, v in enumerate(l.each_vertex()):
528 if i in used_vertices:
529 vertex_map[i]=len(vertex_map)
531 remove_vertices.append(i)
533 bl.mesh.vertsDelete(mesh, remove_vertices)
535 bl.progress_print('%s created' % mesh.name)
539 def __importMesh(scene, io, tex_dir):
541 @param l[in] mmd.PMDLoader
544 ############################################################
545 # shpaeキーで使われるマテリアル優先的に前に並べる
546 ############################################################
547 # shapeキーで使われる頂点インデックスを集める
548 shape_key_used_vertices=set()
549 if len(io.morph_list)>0:
552 for s in io.morph_list:
559 for index in base.indices:
560 shape_key_used_vertices.add(index)
562 # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
563 def isMaterialUsedInShape(offset, m):
564 for i in xrange(offset, offset+m.vertex_count):
565 if io.indices[i] in shape_key_used_vertices:
568 material_with_shape=set()
570 # 各マテリアルの開始頂点インデックスを記録する
573 for i, m in enumerate(io.materials):
574 face_map[i]=face_count
575 if isMaterialUsedInShape(face_count, m):
576 material_with_shape.add(i)
577 face_count+=m.vertex_count
579 # shapeキーで使われる頂点のあるマテリアル
580 material_with_shape=list(material_with_shape)
581 material_with_shape.sort()
583 # shapeキーに使われていないマテリアル
584 material_without_shape=[]
585 for i in range(len(io.materials)):
586 if not i in material_with_shape:
587 material_without_shape.append(i)
590 def __splitList(l, length):
591 for i in range(0, len(l), length):
594 def __importMeshAndShape(material16, name):
595 mesh, meshObject=bl.mesh.create(name)
598 bl.object.deselectAll()
599 bl.object.activate(meshObject)
601 # shapeキーで使われる順に並べなおしたマテリアル16個分の
603 vertex_map=__import16MaerialAndMesh(
604 meshObject, io, material16, face_map, tex_dir)
607 __importShape(meshObject, io, vertex_map)
612 mesh_objects=[__importMeshAndShape(material16, 'with_shape')
613 for material16 in __splitList(material_with_shape, 16)]
615 mesh_objects+=[__importMeshAndShape(material16, 'mesh')
616 for material16 in __splitList(material_without_shape, 16)]
621 def __importConstraints(scene, io):
624 print("create constraint")
625 container=bl.object.createEmpty('Constraints')
627 True, False, False, False, False, False, False, False,
628 False, False, False, False, False, False, False, False,
629 False, False, False, False, False, False, False, False,
630 False, False, False, False, False, False, False, False,
632 material=bl.material.create('constraint')
633 material.diffuse_color=(1, 0, 0)
635 for i, c in enumerate(io.constraints):
636 bpy.ops.mesh.primitive_uv_sphere_add(
640 location=(c.pos.x, c.pos.z, c.pos.y),
643 meshObject=scene.objects.active
644 constraintMeshes.append(meshObject)
645 mesh=bl.object.getData(meshObject)
646 bl.mesh.addMaterial(mesh, material)
647 meshObject.name='c_%d' % i
648 #meshObject.draw_transparent=True
649 #meshObject.draw_wire=True
650 meshObject.max_draw_type='SOLID'
652 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
654 meshObject[CONSTRAINT_NAME]=c.getName()
655 meshObject[CONSTRAINT_A]=io.rigidbodies[c.rigidA].getName()
656 meshObject[CONSTRAINT_B]=io.rigidbodies[c.rigidB].getName()
657 meshObject[CONSTRAINT_POS_MIN]=VtoV(c.constraintPosMin)
658 meshObject[CONSTRAINT_POS_MAX]=VtoV(c.constraintPosMax)
659 meshObject[CONSTRAINT_ROT_MIN]=VtoV(c.constraintRotMin)
660 meshObject[CONSTRAINT_ROT_MAX]=VtoV(c.constraintRotMax)
661 meshObject[CONSTRAINT_SPRING_POS]=VtoV(c.springPos)
662 meshObject[CONSTRAINT_SPRING_ROT]=VtoV(c.springRot)
664 for meshObject in reversed(constraintMeshes):
665 bl.object.makeParent(container, meshObject)
670 def __importRigidBodies(scene, io):
673 print("create rigid bodies")
675 container=bl.object.createEmpty('RigidBodies')
677 True, False, False, False, False, False, False, False,
678 False, False, False, False, False, False, False, False,
679 False, False, False, False, False, False, False, False,
680 False, False, False, False, False, False, False, False,
682 material=bl.material.create('rigidBody')
684 for rigid in io.rigidbodies:
685 if rigid.boneIndex==0xFFFF:
689 bone=io.bones[rigid.boneIndex]
690 pos=bone.pos+rigid.position
692 if rigid.shapeType==pmd.SHAPE_SPHERE:
693 bpy.ops.mesh.primitive_ico_sphere_add(
694 location=(pos.x, pos.z, pos.y),
697 bpy.ops.transform.resize(
698 value=(rigid.w, rigid.w, rigid.w))
699 elif rigid.shapeType==pmd.SHAPE_BOX:
700 bpy.ops.mesh.primitive_cube_add(
701 location=(pos.x, pos.z, pos.y),
704 bpy.ops.transform.resize(
705 value=(rigid.w, rigid.d, rigid.h))
706 elif rigid.shapeType==pmd.SHAPE_CAPSULE:
707 bpy.ops.mesh.primitive_tube_add(
708 location=(pos.x, pos.z, pos.y),
711 bpy.ops.transform.resize(
712 value=(rigid.w, rigid.w, rigid.h))
716 meshObject=scene.objects.active
717 mesh=bl.object.getData(meshObject)
718 rigidMeshes.append(meshObject)
719 bl.mesh.addMaterial(mesh, material)
720 meshObject.name=rigid.getName()
721 #meshObject.draw_transparent=True
722 #meshObject.draw_wire=True
723 meshObject.max_draw_type='WIRE'
725 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
728 meshObject[RIGID_SHAPE_TYPE]=rigid.shapeType
729 meshObject[RIGID_PROCESS_TYPE]=rigid.processType
731 bone_name = englishmap.getEnglishBoneName(bone.getName())
733 bone_name=bone.getName()
734 meshObject[RIGID_BONE_NAME]=bone_name
736 meshObject[RIGID_GROUP]=rigid.group
737 meshObject[RIGID_INTERSECTION_GROUP]=rigid.target
738 meshObject[RIGID_WEIGHT]=rigid.weight
739 meshObject[RIGID_LINEAR_DAMPING]=rigid.linearDamping
740 meshObject[RIGID_ANGULAR_DAMPING]=rigid.angularDamping
741 meshObject[RIGID_RESTITUTION]=rigid.restitution
742 meshObject[RIGID_FRICTION]=rigid.friction
744 for meshObject in reversed(rigidMeshes):
745 bl.object.makeParent(container, meshObject)
750 def __execute(filename, scene):
752 load pmd file to context.
756 bl.progress_set('load %s' % filename, 0.0)
759 if not io.read(filename):
760 bl.message("fail to load %s" % filename)
762 bl.progress_set('loaded %s' % filename, 0.1)
765 model_name=io.getEnglishName()
766 if len(model_name)==0:
767 model_name=io.getName()
768 root=bl.object.createEmpty(model_name)
771 mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
772 for o in mesh_objects:
773 bl.object.makeParent(root, o)
776 armature_object=__importArmature(scene, io)
778 bl.object.makeParent(root, armature_object)
779 armature = bl.object.getData(armature_object)
781 # add armature modifier
782 for o in mesh_objects:
783 bl.modifier.addArmature(o, armature_object)
786 for n, b in bl.object.getPose(armature_object).bones.items():
789 # import rigid bodies
790 rigidBodies=__importRigidBodies(scene, io)
792 bl.object.makeParent(root, rigidBodies)
795 constraints=__importConstraints(scene, io)
797 bl.object.makeParent(root, constraints)
799 bl.object.activate(root)
804 def execute_24(filename):
805 scene=bpy.data.scenes.active
806 bl.initialize('pmd_import', scene)
808 filename.decode(bl.INTERNAL_ENCODING),
812 Blender.Window.FileSelector(
815 Blender.sys.makename(ext='.pmd'))
819 def execute_25(filename, scene):
820 bl.initialize('pmd_import', scene)
821 __execute(filename, scene)
825 class IMPORT_OT_pmd(bpy.types.Operator):
826 bl_idname = "import_scene.pmd"
827 bl_label = 'Import PMD'
829 # List of operator properties, the attributes will be assigned
830 # to the class instance from the operator settings before calling.
832 path = StringProperty(
834 description="File path used for importing the PMD file",
835 maxlen= 1024, default= "")
836 filename = StringProperty(
838 description="Name of the file.")
839 directory = StringProperty(
841 description="Directory of the file.")
843 def execute(self, context):
844 execute_25(self.properties.path, context.scene)
847 def invoke(self, context, event):
849 wm.add_fileselect(self)
850 return 'RUNNING_MODAL'
853 def menu_func(self, context):
854 self.layout.operator(IMPORT_OT_pmd.bl_idname,
855 text="MikuMikuDance model (.pmd)")
858 bpy.types.register(IMPORT_OT_pmd)
859 bpy.types.INFO_MT_file_import.append(menu_func)
862 bpy.types.unregister(IMPORT_OT_pmd)
863 bpy.types.INFO_MT_file_import.remove(menu_func)
865 if __name__=="__main__":