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.
30 MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
31 BASE_SHAPE_NAME='Basis'
32 RIGID_SHAPE_TYPE='rigid_shape_type'
33 RIGID_PROCESS_TYPE='rigid_process_type'
34 RIGID_BONE_NAME='rigid_bone_name'
35 #RIGID_LOCATION='rigid_loation'
36 RIGID_GROUP='ribid_group'
37 RIGID_INTERSECTION_GROUP='rigid_intersection_group'
38 RIGID_WEIGHT='rigid_weight'
39 RIGID_LINEAR_DAMPING='rigid_linear_damping'
40 RIGID_ANGULAR_DAMPING='rigid_angular_damping'
41 RIGID_RESTITUTION='rigid_restitution'
42 RIGID_FRICTION='rigid_friction'
43 CONSTRAINT_A='const_a'
44 CONSTRAINT_B='const_b'
45 CONSTRAINT_POS_MIN='const_pos_min'
46 CONSTRAINT_POS_MAX='const_pos_max'
47 CONSTRAINT_ROT_MIN='const_rot_min'
48 CONSTRAINT_ROT_MAX='const_rot_max'
49 CONSTRAINT_SPRING_POS='const_spring_pos'
50 CONSTRAINT_SPRING_ROT='const_spring_rot'
53 ###############################################################################
55 ###############################################################################
61 from meshio import pmd, englishmap
64 return sys.version_info[0]<3
69 from Blender import Mathutils
77 from bpy.props import *
85 ###############################################################################
86 def convert_coord(pos):
88 Left handed y-up to Right handed z-up
90 return (pos.x, pos.z, pos.y)
94 return (uv.x, 1.0 - uv.y)
97 def to_radian(degree):
98 return math.pi * degree / 180
101 def get_bone_name(l, index):
102 name=englishmap.getEnglishBoneName(l.bones[index].getName())
103 return name if name else l.bones[index].getName()
105 def __importShape(obj, l, vertex_map):
106 if len(l.morph_list)==0:
110 bl.objectPinShape(obj)
114 for s in l.morph_list:
118 # create vertex group
119 bl.meshAddVertexGroup(obj, MMD_SHAPE_GROUP_NAME)
124 bl.meshAssignVertexGroup(
125 obj, MMD_SHAPE_GROUP_NAME, vertex_map[i], 0)
131 baseShapeBlock=bl.objectAddShapeKey(obj, BASE_SHAPE_NAME)
133 mesh=bl.objectGetData(obj)
137 for s in l.morph_list:
142 name=englishmap.getEnglishSkinName(s.getName())
148 for index, offset in zip(s.indices, s.pos_list):
150 vertex_index=vertex_map[base.indices[index]]
151 v=mesh.verts[vertex_index].co
152 offset=convert_coord(offset)
156 except IndexError as msg:
158 print(index, len(base.indices), len(vertex_map))
159 print(len(mesh.verts))
160 print(base.indices[index])
164 #print 'this mesh not has shape vertices'
167 # create shapekey block
168 new_shape_key=bl.objectAddShapeKey(obj, name)
170 # copy vertex to shape key
174 for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
182 new_shape_key=bl.objectAddShapeKey(obj, name)
184 for index, offset in zip(s.indices, s.pos_list):
186 vertex_index=vertex_map[base.indices[index]]
187 bl.shapeKeyAssign(new_shape_key, vertex_index,
188 mesh.verts[vertex_index].co+
189 bl.createVector(*convert_coord(offset)))
190 except IndexError as msg:
192 print(index, len(base.indices), len(vertex_map))
193 print(len(mesh.verts))
194 print(base.indices[index])
198 #print 'this mesh not has shape vertices'
202 bl.objectActivateShapeKey(obj, 0)
205 def __build(armature, b, p, parent):
206 name=englishmap.getEnglishBoneName(b.getName())
210 bone=bl.createArmatureBone(armature, name)
214 assert(b.type==6 or b.type==7)
215 bone.head = bl.createVector(*convert_coord(b.pos))
216 bone.tail=bone.head+bl.createVector(0, 1, 0)
219 if bone.name=="center_t":
220 # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
221 parent.tail=parent.head+bl.createVector(0, 1, 0)
222 bone.head=parent.tail
223 bone.tail=bone.head+bl.createVector(0, 1, 0)
225 assert(parent.tail==bone.head)
226 bl.boneSetConnected(bone)
228 bl.boneLayerMask(bone, [0, 1])
230 bone.head = bl.createVector(*convert_coord(b.pos))
231 bone.tail = bl.createVector(*convert_coord(b.tail))
234 if parent.tail==bone.head:
235 bl.boneSetConnected(bone)
237 if bone.head==bone.tail:
238 bone.tail=bone.head+bl.createVector(0, 1, 0)
241 __build(armature, c, b, bone)
244 def __importArmature(scene, l):
246 armature, armature_object=bl.createArmature(scene)
247 bl.armatureMakeEditable(scene, armature_object)
250 __build(armature, b, None, None)
251 bl.armatureUpdate(armature)
255 pose = bl.objectGetPose(armature_object)
257 target=l.bones[ik.target]
258 name = englishmap.getEnglishBoneName(target.getName())
260 name=target.getName()
261 p_bone = pose.bones[name]
263 print('not found', name)
265 if len(ik.children) >= 16:
266 print('over MAX_CHAINLEN', ik, len(ik.children))
268 effector_name=englishmap.getEnglishBoneName(
269 l.bones[ik.index].getName())
270 if not effector_name:
271 effector_name=l.bones[ik.index].getName()
273 constraint=bl.createIkConstraint(armature_object,
274 p_bone, effector_name, ik)
276 bl.armatureMakeEditable(scene, armature_object)
277 bl.armatureUpdate(armature)
280 return armature_object
283 def __import16MaerialAndMesh(meshObject, l,
284 material_order, face_map, tex_dir):
286 mesh=bl.objectGetData(meshObject)
287 ############################################################
289 ############################################################
290 bl.progress_print('create materials')
296 for material_index in material_order:
298 m=l.materials[material_index]
299 mesh_material_map[material_index]=index
303 material=bl.createPmdMaterial(m)
305 texture_name=m.getTexture()
307 if texture_name in textureMap:
308 texture=textureMap[texture_name]
311 texture, image=bl.createTexture(
312 os.path.join(tex_dir, texture_name))
313 textureMap[texture_name]=texture
314 imageMap[material_index]=image
317 bl.materialAddTexture(material, texture)
318 bl.meshAddMaterial(mesh, material)
321 ############################################################
323 ############################################################
324 bl.progress_print('create vertices')
328 for v in l.each_vertex():
329 vertices.append(convert_coord(v.pos))
331 for v in l.each_vertex():
332 vertices.extend(convert_coord(v.pos))
334 ############################################################
336 ############################################################
337 bl.progress_print('create faces')
340 mesh_face_materials=[]
343 for material_index in material_order:
344 face_offset=face_map[material_index]
345 m=l.materials[material_index]
346 material_faces=l.indices[face_offset:face_offset+m.vertex_count]
348 def degenerate(i0, i1, i2):
352 return i0==i1 or i1==i2 or i2==i0
354 for j in xrange(0, len(material_faces), 3):
356 i1=material_faces[j+1]
357 i2=material_faces[j+2]
359 triangle=[i2, i0, i1]
361 triangle=[i0, i1, i2]
362 if degenerate(*triangle):
365 mesh_face_indices.append(triangle[0:3])
367 mesh_face_indices.extend(
368 [triangle[0], triangle[1], triangle[2], 0])
369 mesh_face_materials.append(material_index)
370 used_vertices.add(i0)
371 used_vertices.add(i1)
372 used_vertices.add(i2)
374 ############################################################
375 # create vertices & faces
376 ############################################################
377 bl.meshCreateVerteicesAndFaces(mesh, vertices, mesh_face_indices)
379 ############################################################
381 ############################################################
382 # create vertex group
384 for v in l.each_vertex():
385 vertex_groups[v.bone0]=True
386 vertex_groups[v.bone1]=True
387 for i in vertex_groups.keys():
388 bl.meshAddVertexGroup(meshObject, get_bone_name(l, i))
391 bl.meshUseVertexUv(mesh)
392 for i, v, mvert in zip(xrange(len(l.vertices)),
393 l.each_vertex(), mesh.verts):
395 bl.vertexSetNormal(mvert, convert_coord(v.normal))
396 bl.vertexSetUv(mvert, convert_uv(v.uv))
398 w1=float(v.weight0)/100.0
400 bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone0),
402 bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone1),
405 ############################################################
407 ############################################################
412 for face, material_index in zip(mesh.faces, mesh_face_materials):
414 index=mesh_material_map[material_index]
415 except KeyError as message:
416 print(message, mesh_material_map, m)
419 material=mesh.materials[index]
420 texture=material.getTextures()[0]
423 face.image=texture.tex.image
424 texture.tex.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
426 face.verts[0].uvco, face.verts[1].uvco, face.verts[2].uvco]
432 for face, uv_face, material_index in zip(mesh.faces,
433 mesh.uv_textures[0].data,
437 index=mesh_material_map[material_index]
438 except KeyError as message:
439 print(message, mesh_material_map, m)
441 face.material_index=index
442 material=mesh.materials[index]
444 if material.texture_slots[0]:
445 uv=l.getUV(face.verts[0])
446 uv_face.uv1=[uv.x, 1.0-uv.y]
448 uv=l.getUV(face.verts[1])
449 uv_face.uv2=[uv.x, 1.0-uv.y]
451 uv=l.getUV(face.verts[2])
452 uv_face.uv3=[uv.x, 1.0-uv.y]
453 if face.material_index in imageMap:
454 uv_face.image=imageMap[face.material_index]
461 ############################################################
462 # clean up not used vertices
463 ############################################################
464 bl.progress_print('clean up vertices not used')
467 for i, v in enumerate(l.each_vertex()):
468 if i in used_vertices:
469 vertex_map[i]=len(vertex_map)
471 remove_vertices.append(i)
473 bl.meshVertsDelete(mesh, remove_vertices)
475 bl.progress_print('%s created' % mesh.name)
479 def __importMesh(scene, io, tex_dir):
481 @param l[in] mmd.PMDLoader
484 ############################################################
485 # shpaeキーで使われるマテリアル優先的に前に並べる
486 ############################################################
487 # shapeキーで使われる頂点インデックスを集める
488 shape_key_used_vertices=set()
489 if len(io.morph_list)>0:
492 for s in io.morph_list:
499 for index in base.indices:
500 shape_key_used_vertices.add(index)
502 # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
503 def isMaterialUsedInShape(offset, m):
504 for i in xrange(offset, offset+m.vertex_count):
505 if io.indices[i] in shape_key_used_vertices:
508 # shapeキーで使われるマテリアルを記録する
509 shape_key_materials=set()
510 # 各マテリアルの開始頂点インデックスを記録する
513 for i, m in enumerate(io.materials):
514 face_map[i]=face_count
515 if isMaterialUsedInShape(face_count, m):
516 shape_key_materials.add(i)
517 face_count+=m.vertex_count
520 material_order=list(shape_key_materials)
522 # shapeキーに使われていないマテリアルを後ろに追加
523 for i in range(len(io.materials)):
524 if not i in material_order:
525 material_order.append(i)
527 # マテリアル16個ごとに分割したメッシュを作成する
530 while material_offset<len(io.materials):
531 mesh, meshObject=bl.createMesh(scene, 'mesh')
533 #meshObject.layers = [1]
534 mesh_objects.append(meshObject)
537 bl.objectDeselectAll()
538 bl.objectActivate(scene, meshObject)
540 # shapeキーで使われる順に並べなおしたマテリアル16個分の
542 vertex_map=__import16MaerialAndMesh(
544 material_order[material_offset:material_offset+16],
551 __importShape(meshObject, io, vertex_map)
562 def __importConstraints(scene, io):
565 print("create constrains")
566 container=bl.createEmptyObject(scene, 'Constraints')
568 True, False, False, False, False, False, False, False,
569 False, False, False, False, False, False, False, False,
570 False, False, False, False, False, False, False, False,
571 False, False, False, False, False, False, False, False,
573 material=bl.createMaterial('constraint')
574 material.diffuse_color=(1, 0, 0)
576 for c in io.constraints:
577 bpy.ops.mesh.primitive_uv_sphere_add(
581 location=(c.pos.x, c.pos.z, c.pos.y),
584 meshObject=scene.objects.active
585 constraintMeshes.append(meshObject)
586 mesh=bl.objectGetData(meshObject)
587 bl.meshAddMaterial(mesh, material)
588 meshObject.name='c'+c.getName()
589 #meshObject.draw_transparent=True
590 #meshObject.draw_wire=True
591 meshObject.max_draw_type='SOLID'
593 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
595 meshObject[CONSTRAINT_A]=io.rigidbodies[c.rigidA].getName()
596 meshObject[CONSTRAINT_B]=io.rigidbodies[c.rigidB].getName()
597 meshObject[CONSTRAINT_POS_MIN]=bl.VtoV(c.constraintPosMin)
598 meshObject[CONSTRAINT_POS_MAX]=bl.VtoV(c.constraintPosMax)
599 meshObject[CONSTRAINT_ROT_MIN]=bl.VtoV(c.constraintRotMin)
600 meshObject[CONSTRAINT_ROT_MAX]=bl.VtoV(c.constraintRotMax)
601 meshObject[CONSTRAINT_SPRING_POS]=bl.VtoV(c.springPos)
602 meshObject[CONSTRAINT_SPRING_ROT]=bl.VtoV(c.springRot)
604 for meshObject in reversed(constraintMeshes):
605 bl.objectMakeParent(container, meshObject)
610 def __importRigidBodies(scene, io):
613 print("create rigid bodies")
615 container=bl.createEmptyObject(scene, 'RigidBodies')
617 True, False, False, False, False, False, False, False,
618 False, False, False, False, False, False, False, False,
619 False, False, False, False, False, False, False, False,
620 False, False, False, False, False, False, False, False,
622 material=bl.createMaterial('rigidBody')
624 for rigid in io.rigidbodies:
625 if rigid.boneIndex==0xFFFF:
629 bone=io.bones[rigid.boneIndex]
630 pos=bone.pos+rigid.position
632 if rigid.shapeType==pmd.SHAPE_SPHERE:
633 bpy.ops.mesh.primitive_ico_sphere_add(
634 location=(pos.x, pos.z, pos.y),
637 bpy.ops.transform.resize(
638 value=(rigid.w, rigid.w, rigid.w))
639 elif rigid.shapeType==pmd.SHAPE_BOX:
640 bpy.ops.mesh.primitive_cube_add(
641 location=(pos.x, pos.z, pos.y),
644 bpy.ops.transform.resize(
645 value=(rigid.w, rigid.d, rigid.h))
646 elif rigid.shapeType==pmd.SHAPE_CAPSULE:
647 bpy.ops.mesh.primitive_tube_add(
648 location=(pos.x, pos.z, pos.y),
651 bpy.ops.transform.resize(
652 value=(rigid.w, rigid.w, rigid.h))
656 meshObject=scene.objects.active
657 mesh=bl.objectGetData(meshObject)
658 rigidMeshes.append(meshObject)
659 bl.meshAddMaterial(mesh, material)
660 meshObject.name=rigid.getName()
661 #meshObject.draw_transparent=True
662 #meshObject.draw_wire=True
663 meshObject.max_draw_type='WIRE'
665 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
668 meshObject[RIGID_SHAPE_TYPE]=rigid.shapeType
669 meshObject[RIGID_PROCESS_TYPE]=rigid.processType
671 bone_name = englishmap.getEnglishBoneName(bone.getName())
673 bone_name=bone.getName()
674 meshObject[RIGID_BONE_NAME]=bone_name
676 #meshObject[RIGID_LOCATION]=bl.VtoV(rigid.location)
677 meshObject[RIGID_GROUP]=rigid.group
678 meshObject[RIGID_INTERSECTION_GROUP]=rigid.target
679 meshObject[RIGID_WEIGHT]=rigid.weight
680 meshObject[RIGID_LINEAR_DAMPING]=rigid.linearDamping
681 meshObject[RIGID_ANGULAR_DAMPING]=rigid.angularDamping
682 meshObject[RIGID_RESTITUTION]=rigid.restitution
683 meshObject[RIGID_FRICTION]=rigid.friction
685 for meshObject in reversed(rigidMeshes):
686 bl.objectMakeParent(container, meshObject)
691 def __execute(filename, scene):
693 load pmd file to context.
695 bl.progress_start('pmd_import')
698 bl.progress_set('load %s' % filename, 0.0)
701 if not io.read(filename):
702 print("fail to load %s" % filename)
704 bl.progress_set('loaded %s' % filename, 0.1)
707 model_name=io.getEnglishName()
708 if len(model_name)==0:
709 model_name=io.getName()
710 root=bl.createEmptyObject(scene, model_name)
713 mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
714 for o in mesh_objects:
715 bl.objectMakeParent(root, o)
718 armature_object=__importArmature(scene, io)
720 bl.objectMakeParent(root, armature_object)
721 armature = bl.objectGetData(armature_object)
723 # add armature modifier
724 for o in mesh_objects:
725 bl.objectAddArmatureModifier(o, armature_object)
728 for n, b in bl.objectGetPose(armature_object).bones.items():
729 bl.poseBoneLimit(n, b)
731 # import rigid bodies
732 rigidBodies=__importRigidBodies(scene, io)
734 bl.objectMakeParent(root, rigidBodies)
737 constraints=__importConstraints(scene, io)
739 bl.objectMakeParent(root, constraints)
741 bl.objectActivate(scene, root)
746 def execute_24(filename):
750 filename=filename.decode(bl.INTERNAL_ENCODING)
751 print(bl.INTERNAL_ENCODING, bl.FS_ENCODING)
754 mode_edit = Blender.Window.EditMode()
756 Blender.Window.EditMode(0)
758 scene = bpy.data.scenes.active
759 __execute(filename, scene)
764 Blender.Window.EditMode(1)
765 Blender.Window.RedrawAll()
767 Blender.Window.FileSelector(
770 Blender.sys.makename(ext='.pmd'))
774 def execute_25(*args):
778 class IMPORT_OT_pmd(bpy.types.Operator):
779 bl_idname = "import_scene.pmd"
780 bl_label = 'Import PMD'
782 # List of operator properties, the attributes will be assigned
783 # to the class instance from the operator settings before calling.
785 path = StringProperty(
787 description="File path used for importing the PMD file",
788 maxlen= 1024, default= "")
789 filename = StringProperty(
791 description="Name of the file.")
792 directory = StringProperty(
794 description="Directory of the file.")
796 def execute(self, context):
797 execute_25(self.properties.path, context.scene)
800 def invoke(self, context, event):
802 wm.add_fileselect(self)
803 return 'RUNNING_MODAL'
806 def menu_func(self, context):
807 self.layout.operator(IMPORT_OT_pmd.bl_idname,
808 text="MikuMikuDance model (.pmd)")
811 bpy.types.register(IMPORT_OT_pmd)
812 bpy.types.INFO_MT_file_import.append(menu_func)
815 bpy.types.unregister(IMPORT_OT_pmd)
816 bpy.types.INFO_MT_file_import.remove(menu_func)
818 if __name__=="__main__":