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.
31 1.6 20100629: sphere map.
34 MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
35 BASE_SHAPE_NAME='Basis'
36 RIGID_SHAPE_TYPE='rigid_shape_type'
37 RIGID_PROCESS_TYPE='rigid_process_type'
38 RIGID_BONE_NAME='rigid_bone_name'
39 #RIGID_LOCATION='rigid_loation'
40 RIGID_GROUP='ribid_group'
41 RIGID_INTERSECTION_GROUP='rigid_intersection_group'
42 RIGID_WEIGHT='rigid_weight'
43 RIGID_LINEAR_DAMPING='rigid_linear_damping'
44 RIGID_ANGULAR_DAMPING='rigid_angular_damping'
45 RIGID_RESTITUTION='rigid_restitution'
46 RIGID_FRICTION='rigid_friction'
47 CONSTRAINT_NAME='constraint_name'
48 CONSTRAINT_A='const_a'
49 CONSTRAINT_B='const_b'
50 CONSTRAINT_POS_MIN='const_pos_min'
51 CONSTRAINT_POS_MAX='const_pos_max'
52 CONSTRAINT_ROT_MIN='const_rot_min'
53 CONSTRAINT_ROT_MAX='const_rot_max'
54 CONSTRAINT_SPRING_POS='const_spring_pos'
55 CONSTRAINT_SPRING_ROT='const_spring_rot'
58 ###############################################################################
60 ###############################################################################
66 from meshio import pmd, englishmap
69 return sys.version_info[0]<3
74 from Blender import Mathutils
80 def createPmdMaterial(m, index):
81 material=Blender.Material.New()
83 #material.diffuseSize = 3.14/2
84 #material.setDiffuseSmooth(0)
85 #material.setSpecSize(0)
89 material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
90 material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
91 material.setAlpha(m.diffuse.a)
93 material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
94 material.setSpec(m.shinness*0.1)
95 material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
97 material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
99 material.enableSSS=True if m.flag==1 else False
101 material.name="m_%02d" % index
104 def poseBoneLimit(n, b):
107 if n.startswith("knee_"):
112 b.limitMax=[180, 0, 0]
113 elif n.startswith("ankle_"):
116 def setSphereMap(material, index, blende_type=None):
122 from bpy.props import *
130 def createPmdMaterial(m, index):
131 material = bpy.data.materials.new("Material")
133 material.diffuse_shader='FRESNEL'
134 material.diffuse_color=([m.diffuse.r, m.diffuse.g, m.diffuse.b])
135 material.alpha=m.diffuse.a
137 material.specular_shader='TOON'
138 material.specular_color=([m.specular.r, m.specular.g, m.specular.b])
139 material.specular_toon_size=int(m.shinness)
141 material.mirror_color=([m.ambient.r, m.ambient.g, m.ambient.b])
143 material.subsurface_scattering.enabled=True if m.flag==1 else False
145 material.name="m_%02d" % index
146 material.preview_render_type='FLAT'
147 material.transparency=True
150 def poseBoneLimit(n, b):
153 if n.startswith("knee_"):
160 elif n.startswith("ankle_"):
164 def setSphereMap(material, index, blend_type=None):
165 slot=material.texture_slots[index]
166 slot.texture_coordinates='REFLECTION'
167 slot.mapping='SPHERE'
169 slot.blend_type=blend_type
172 ###############################################################################
174 return bl.createVector(v.x, v.y, v.z)
176 def convert_coord(pos):
178 Left handed y-up to Right handed z-up
180 return (pos.x, pos.z, pos.y)
183 def to_radian(degree):
184 return math.pi * degree / 180
187 def get_bone_name(l, index):
189 return l.bones[0].getName()
191 if index < len(l.bones):
192 name=englishmap.getEnglishBoneName(l.bones[index].getName())
195 return l.bones[index].getName()
196 print('invalid bone index', index)
197 return l.bones[0].getName()
199 def __importShape(obj, l, vertex_map):
200 if len(l.morph_list)==0:
204 bl.object.pinShape(obj, True)
208 for s in l.morph_list:
212 # create vertex group
213 bl.object.addVertexGroup(obj, MMD_SHAPE_GROUP_NAME)
218 bl.object.assignVertexGroup(
219 obj, MMD_SHAPE_GROUP_NAME, vertex_map[i], 0)
225 baseShapeBlock=bl.object.addShapeKey(obj, BASE_SHAPE_NAME)
227 mesh=bl.object.getData(obj)
231 for s in l.morph_list:
236 name=englishmap.getEnglishSkinName(s.getName())
242 for index, offset in zip(s.indices, s.pos_list):
244 vertex_index=vertex_map[base.indices[index]]
245 v=mesh.verts[vertex_index].co
246 offset=convert_coord(offset)
250 except IndexError as msg:
252 print(index, len(base.indices), len(vertex_map))
253 print(len(mesh.verts))
254 print(base.indices[index])
258 #print 'this mesh not has shape vertices'
261 # create shapekey block
262 new_shape_key=bl.object.addShapeKey(obj, name)
264 # copy vertex to shape key
268 for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
276 new_shape_key=bl.object.addShapeKey(obj, name)
278 for index, offset in zip(s.indices, s.pos_list):
280 vertex_index=vertex_map[base.indices[index]]
281 bl.shapekey.assign(new_shape_key, vertex_index,
282 mesh.verts[vertex_index].co+
283 bl.createVector(*convert_coord(offset)))
284 except IndexError as msg:
286 print(index, len(base.indices), len(vertex_map))
287 print(len(mesh.verts))
288 print(base.indices[index])
292 #print 'this mesh not has shape vertices'
296 bl.object.setActivateShapeKey(obj, 0)
299 def __build(armature, b, p, parent):
300 name=englishmap.getEnglishBoneName(b.getName())
304 bone=bl.armature.createBone(armature, name)
306 if parent and (b.tail_index==0 or b.type==6 or b.type==7 or b.type==9):
307 bone.head = bl.createVector(*convert_coord(b.pos))
308 bone.tail=bone.head+bl.createVector(0, 1, 0)
310 if bone.name=="center_t":
311 # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
312 parent.tail=parent.head+bl.createVector(0, 1, 0)
313 bone.head=parent.tail
314 bone.tail=bone.head+bl.createVector(0, 1, 0)
316 if parent.tail==bone.head:
319 print('diffurence with parent.tail and head', name)
321 bl.bone.setConnected(bone)
323 bl.bone.setLayerMask(bone, [0, 1])
326 bone.head = bl.createVector(*convert_coord(b.pos))
327 bone.tail = bl.createVector(*convert_coord(b.tail))
330 if parent.tail==bone.head:
331 bl.bone.setConnected(bone)
333 if bone.head==bone.tail:
334 bone.tail=bone.head+bl.createVector(0, 1, 0)
337 __build(armature, c, b, bone)
340 def __importArmature(scene, l):
342 armature, armature_object=bl.armature.create()
343 bl.armature.makeEditable(armature_object)
346 __build(armature, b, None, None)
347 bl.armature.update(armature)
351 pose = bl.object.getPose(armature_object)
353 target=l.bones[ik.target]
354 name = englishmap.getEnglishBoneName(target.getName())
356 name=target.getName()
357 p_bone = pose.bones[name]
359 print('not found', name)
361 if len(ik.children) >= 16:
362 print('over MAX_CHAINLEN', ik, len(ik.children))
364 effector_name=englishmap.getEnglishBoneName(
365 l.bones[ik.index].getName())
366 if not effector_name:
367 effector_name=l.bones[ik.index].getName()
369 constraint=bl.armature.createIkConstraint(armature_object,
370 p_bone, effector_name, ik)
372 bl.armature.makeEditable(armature_object)
373 bl.armature.update(armature)
376 return armature_object
379 def __import16MaerialAndMesh(meshObject, l,
380 material_order, face_map, tex_dir):
382 mesh=bl.object.getData(meshObject)
383 ############################################################
385 ############################################################
386 bl.progress_print('create materials')
392 for material_index in material_order:
394 m=l.materials[material_index]
395 mesh_material_map[material_index]=index
399 material=createPmdMaterial(m, material_index)
401 texture_name=m.getTexture()
403 for i, t in enumerate(texture_name.split('*')):
405 texture=textureMap[t]
407 path=os.path.join(tex_dir, t)
408 texture, image=bl.texture.create(path)
409 textureMap[texture_name]=texture
410 imageMap[material_index]=image
411 bl.material.addTexture(material, texture)
412 if t.endswith('sph'):
414 setSphereMap(material, i)
415 elif t.endswith('spa'):
417 setSphereMap(material, i, 'ADD')
419 bl.mesh.addMaterial(mesh, material)
422 ############################################################
424 ############################################################
425 bl.progress_print('create vertices')
428 for v in l.each_vertex():
429 vertices.append(convert_coord(v.pos))
431 ############################################################
433 ############################################################
434 bl.progress_print('create faces')
437 mesh_face_materials=[]
440 for material_index in material_order:
441 face_offset=face_map[material_index]
442 m=l.materials[material_index]
443 material_faces=l.indices[face_offset:face_offset+m.vertex_count]
445 def degenerate(i0, i1, i2):
449 return i0==i1 or i1==i2 or i2==i0
451 for j in xrange(0, len(material_faces), 3):
453 i1=material_faces[j+1]
454 i2=material_faces[j+2]
456 triangle=[i2, i1, i0]
457 if degenerate(*triangle):
459 mesh_face_indices.append(triangle[0:3])
460 mesh_face_materials.append(material_index)
461 used_vertices.add(i0)
462 used_vertices.add(i1)
463 used_vertices.add(i2)
465 ############################################################
466 # create vertices & faces
467 ############################################################
468 bl.mesh.addGeometry(mesh, vertices, mesh_face_indices)
470 ############################################################
472 ############################################################
473 # create vertex group
475 for v in l.each_vertex():
476 vertex_groups[v.bone0]=True
477 vertex_groups[v.bone1]=True
478 for i in vertex_groups.keys():
479 bl.object.addVertexGroup(meshObject, get_bone_name(l, i))
482 bl.mesh.useVertexUV(mesh)
483 for i, v, mvert in zip(xrange(len(l.vertices)),
484 l.each_vertex(), mesh.verts):
486 bl.vertex.setNormal(mvert, convert_coord(v.normal))
488 w1=float(v.weight0)/100.0
490 bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone0),
492 bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone1),
495 ############################################################
497 ############################################################
500 for i, (face, material_index) in enumerate(
501 zip(mesh.faces, mesh_face_materials)):
503 index=mesh_material_map[material_index]
504 except KeyError as message:
505 print(message, mesh_material_map, m)
507 bl.face.setMaterial(face, index)
508 material=mesh.materials[index]
510 if bl.material.hasTexture(material):
511 uv_array=[l.getUV(i) for i in bl.face.getIndices(face)]
512 bl.mesh.setFaceUV(mesh, i, face,
514 [(uv.x, 1.0-uv.y) for uv in uv_array],
515 imageMap.get(index, None))
522 ############################################################
523 # clean up not used vertices
524 ############################################################
525 bl.progress_print('clean up vertices not used')
528 for i, v in enumerate(l.each_vertex()):
529 if i in used_vertices:
530 vertex_map[i]=len(vertex_map)
532 remove_vertices.append(i)
534 bl.mesh.vertsDelete(mesh, remove_vertices)
536 bl.progress_print('%s created' % mesh.name)
540 def __importMesh(scene, io, tex_dir):
542 @param l[in] mmd.PMDLoader
545 ############################################################
546 # shpaeキーで使われるマテリアル優先的に前に並べる
547 ############################################################
548 # shapeキーで使われる頂点インデックスを集める
549 shape_key_used_vertices=set()
550 if len(io.morph_list)>0:
553 for s in io.morph_list:
560 for index in base.indices:
561 shape_key_used_vertices.add(index)
563 # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
564 def isMaterialUsedInShape(offset, m):
565 for i in xrange(offset, offset+m.vertex_count):
566 if io.indices[i] in shape_key_used_vertices:
569 material_with_shape=set()
571 # 各マテリアルの開始頂点インデックスを記録する
574 for i, m in enumerate(io.materials):
575 face_map[i]=face_count
576 if isMaterialUsedInShape(face_count, m):
577 material_with_shape.add(i)
578 face_count+=m.vertex_count
580 # shapeキーで使われる頂点のあるマテリアル
581 material_with_shape=list(material_with_shape)
582 material_with_shape.sort()
584 # shapeキーに使われていないマテリアル
585 material_without_shape=[]
586 for i in range(len(io.materials)):
587 if not i in material_with_shape:
588 material_without_shape.append(i)
591 def __splitList(l, length):
592 for i in range(0, len(l), length):
595 def __importMeshAndShape(material16, name):
596 mesh, meshObject=bl.mesh.create(name)
599 bl.object.deselectAll()
600 bl.object.activate(meshObject)
602 # shapeキーで使われる順に並べなおしたマテリアル16個分の
604 vertex_map=__import16MaerialAndMesh(
605 meshObject, io, material16, face_map, tex_dir)
608 __importShape(meshObject, io, vertex_map)
613 mesh_objects=[__importMeshAndShape(material16, 'with_shape')
614 for material16 in __splitList(material_with_shape, 16)]
616 mesh_objects+=[__importMeshAndShape(material16, 'mesh')
617 for material16 in __splitList(material_without_shape, 16)]
622 def __importConstraints(scene, io):
625 print("create constraint")
626 container=bl.object.createEmpty('Constraints')
628 True, 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,
631 False, False, False, False, False, False, False, False,
633 material=bl.material.create('constraint')
634 material.diffuse_color=(1, 0, 0)
636 for i, c in enumerate(io.constraints):
637 bpy.ops.mesh.primitive_uv_sphere_add(
641 location=(c.pos.x, c.pos.z, c.pos.y),
644 meshObject=scene.objects.active
645 constraintMeshes.append(meshObject)
646 mesh=bl.object.getData(meshObject)
647 bl.mesh.addMaterial(mesh, material)
648 meshObject.name='c_%d' % i
649 #meshObject.draw_transparent=True
650 #meshObject.draw_wire=True
651 meshObject.max_draw_type='SOLID'
653 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
655 meshObject[CONSTRAINT_NAME]=c.getName()
656 meshObject[CONSTRAINT_A]=io.rigidbodies[c.rigidA].getName()
657 meshObject[CONSTRAINT_B]=io.rigidbodies[c.rigidB].getName()
658 meshObject[CONSTRAINT_POS_MIN]=VtoV(c.constraintPosMin)
659 meshObject[CONSTRAINT_POS_MAX]=VtoV(c.constraintPosMax)
660 meshObject[CONSTRAINT_ROT_MIN]=VtoV(c.constraintRotMin)
661 meshObject[CONSTRAINT_ROT_MAX]=VtoV(c.constraintRotMax)
662 meshObject[CONSTRAINT_SPRING_POS]=VtoV(c.springPos)
663 meshObject[CONSTRAINT_SPRING_ROT]=VtoV(c.springRot)
665 for meshObject in reversed(constraintMeshes):
666 bl.object.makeParent(container, meshObject)
671 def __importRigidBodies(scene, io):
674 print("create rigid bodies")
676 container=bl.object.createEmpty('RigidBodies')
678 True, 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,
681 False, False, False, False, False, False, False, False,
683 material=bl.material.create('rigidBody')
685 for rigid in io.rigidbodies:
686 if rigid.boneIndex==0xFFFF:
690 bone=io.bones[rigid.boneIndex]
691 pos=bone.pos+rigid.position
693 if rigid.shapeType==pmd.SHAPE_SPHERE:
694 bpy.ops.mesh.primitive_ico_sphere_add(
695 location=(pos.x, pos.z, pos.y),
698 bpy.ops.transform.resize(
699 value=(rigid.w, rigid.w, rigid.w))
700 elif rigid.shapeType==pmd.SHAPE_BOX:
701 bpy.ops.mesh.primitive_cube_add(
702 location=(pos.x, pos.z, pos.y),
705 bpy.ops.transform.resize(
706 value=(rigid.w, rigid.d, rigid.h))
707 elif rigid.shapeType==pmd.SHAPE_CAPSULE:
708 bpy.ops.mesh.primitive_tube_add(
709 location=(pos.x, pos.z, pos.y),
712 bpy.ops.transform.resize(
713 value=(rigid.w, rigid.w, rigid.h))
717 meshObject=scene.objects.active
718 mesh=bl.object.getData(meshObject)
719 rigidMeshes.append(meshObject)
720 bl.mesh.addMaterial(mesh, material)
721 meshObject.name=rigid.getName()
722 #meshObject.draw_transparent=True
723 #meshObject.draw_wire=True
724 meshObject.max_draw_type='WIRE'
726 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
729 meshObject[RIGID_SHAPE_TYPE]=rigid.shapeType
730 meshObject[RIGID_PROCESS_TYPE]=rigid.processType
732 bone_name = englishmap.getEnglishBoneName(bone.getName())
734 bone_name=bone.getName()
735 meshObject[RIGID_BONE_NAME]=bone_name
737 meshObject[RIGID_GROUP]=rigid.group
738 meshObject[RIGID_INTERSECTION_GROUP]=rigid.target
739 meshObject[RIGID_WEIGHT]=rigid.weight
740 meshObject[RIGID_LINEAR_DAMPING]=rigid.linearDamping
741 meshObject[RIGID_ANGULAR_DAMPING]=rigid.angularDamping
742 meshObject[RIGID_RESTITUTION]=rigid.restitution
743 meshObject[RIGID_FRICTION]=rigid.friction
745 for meshObject in reversed(rigidMeshes):
746 bl.object.makeParent(container, meshObject)
751 def __execute(filename, scene):
753 load pmd file to context.
757 bl.progress_set('load %s' % filename, 0.0)
760 if not io.read(filename):
761 bl.message("fail to load %s" % filename)
763 bl.progress_set('loaded %s' % filename, 0.1)
766 model_name=io.getEnglishName()
767 if len(model_name)==0:
768 model_name=io.getName()
769 root=bl.object.createEmpty(model_name)
772 mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
773 for o in mesh_objects:
774 bl.object.makeParent(root, o)
777 armature_object=__importArmature(scene, io)
779 bl.object.makeParent(root, armature_object)
780 armature = bl.object.getData(armature_object)
782 # add armature modifier
783 for o in mesh_objects:
784 bl.modifier.addArmature(o, armature_object)
787 for n, b in bl.object.getPose(armature_object).bones.items():
790 # import rigid bodies
791 rigidBodies=__importRigidBodies(scene, io)
793 bl.object.makeParent(root, rigidBodies)
796 constraints=__importConstraints(scene, io)
798 bl.object.makeParent(root, constraints)
800 bl.object.activate(root)
805 def execute_24(filename):
806 scene=bpy.data.scenes.active
807 bl.initialize('pmd_import', scene)
809 filename.decode(bl.INTERNAL_ENCODING),
813 Blender.Window.FileSelector(
816 Blender.sys.makename(ext='.pmd'))
820 def execute_25(filename, scene):
821 bl.initialize('pmd_import', scene)
822 __execute(filename, scene)
826 class IMPORT_OT_pmd(bpy.types.Operator):
827 bl_idname = "import_scene.pmd"
828 bl_label = 'Import PMD'
830 # List of operator properties, the attributes will be assigned
831 # to the class instance from the operator settings before calling.
833 path = StringProperty(
835 description="File path used for importing the PMD file",
836 maxlen= 1024, default= "")
837 filename = StringProperty(
839 description="Name of the file.")
840 directory = StringProperty(
842 description="Directory of the file.")
844 def execute(self, context):
845 execute_25(self.properties.path, context.scene)
848 def invoke(self, context, event):
850 wm.add_fileselect(self)
851 return 'RUNNING_MODAL'
854 def menu_func(self, context):
855 self.layout.operator(IMPORT_OT_pmd.bl_idname,
856 text="MikuMikuDance model (.pmd)")
859 bpy.types.register(IMPORT_OT_pmd)
860 bpy.types.INFO_MT_file_import.append(menu_func)
863 bpy.types.unregister(IMPORT_OT_pmd)
864 bpy.types.INFO_MT_file_import.remove(menu_func)
866 if __name__=="__main__":