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 or b.type==9)
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])
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 bl.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 bl.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 bl.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 bl.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 bl.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 __importConstraints(scene, io):
566 print("create constrains")
567 container=bl.createEmptyObject(scene, 'Constraints')
569 True, 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,
572 False, False, False, False, False, False, False, False,
574 material=bl.createMaterial('constraint')
575 material.diffuse_color=(1, 0, 0)
577 for c in io.constraints:
578 bpy.ops.mesh.primitive_uv_sphere_add(
582 location=(c.pos.x, c.pos.z, c.pos.y),
585 meshObject=scene.objects.active
586 constraintMeshes.append(meshObject)
587 mesh=bl.objectGetData(meshObject)
588 bl.meshAddMaterial(mesh, material)
589 meshObject.name='c'+c.getName()
590 #meshObject.draw_transparent=True
591 #meshObject.draw_wire=True
592 meshObject.max_draw_type='SOLID'
594 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
596 meshObject[CONSTRAINT_A]=io.rigidbodies[c.rigidA].getName()
597 meshObject[CONSTRAINT_B]=io.rigidbodies[c.rigidB].getName()
598 meshObject[CONSTRAINT_POS_MIN]=bl.VtoV(c.constraintPosMin)
599 meshObject[CONSTRAINT_POS_MAX]=bl.VtoV(c.constraintPosMax)
600 meshObject[CONSTRAINT_ROT_MIN]=bl.VtoV(c.constraintRotMin)
601 meshObject[CONSTRAINT_ROT_MAX]=bl.VtoV(c.constraintRotMax)
602 meshObject[CONSTRAINT_SPRING_POS]=bl.VtoV(c.springPos)
603 meshObject[CONSTRAINT_SPRING_ROT]=bl.VtoV(c.springRot)
605 for meshObject in reversed(constraintMeshes):
606 bl.objectMakeParent(container, meshObject)
611 def __importRigidBodies(scene, io):
614 print("create rigid bodies")
616 container=bl.createEmptyObject(scene, 'RigidBodies')
618 True, 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,
621 False, False, False, False, False, False, False, False,
623 material=bl.createMaterial('rigidBody')
625 for rigid in io.rigidbodies:
626 if rigid.boneIndex==0xFFFF:
630 bone=io.bones[rigid.boneIndex]
631 pos=bone.pos+rigid.position
633 if rigid.shapeType==pmd.SHAPE_SPHERE:
634 bpy.ops.mesh.primitive_ico_sphere_add(
635 location=(pos.x, pos.z, pos.y),
638 bpy.ops.transform.resize(
639 value=(rigid.w, rigid.w, rigid.w))
640 elif rigid.shapeType==pmd.SHAPE_BOX:
641 bpy.ops.mesh.primitive_cube_add(
642 location=(pos.x, pos.z, pos.y),
645 bpy.ops.transform.resize(
646 value=(rigid.w, rigid.d, rigid.h))
647 elif rigid.shapeType==pmd.SHAPE_CAPSULE:
648 bpy.ops.mesh.primitive_tube_add(
649 location=(pos.x, pos.z, pos.y),
652 bpy.ops.transform.resize(
653 value=(rigid.w, rigid.w, rigid.h))
657 meshObject=scene.objects.active
658 mesh=bl.objectGetData(meshObject)
659 rigidMeshes.append(meshObject)
660 bl.meshAddMaterial(mesh, material)
661 meshObject.name=rigid.getName()
662 #meshObject.draw_transparent=True
663 #meshObject.draw_wire=True
664 meshObject.max_draw_type='WIRE'
666 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
669 meshObject[RIGID_SHAPE_TYPE]=rigid.shapeType
670 meshObject[RIGID_PROCESS_TYPE]=rigid.processType
672 bone_name = englishmap.getEnglishBoneName(bone.getName())
674 bone_name=bone.getName()
675 meshObject[RIGID_BONE_NAME]=bone_name
677 #meshObject[RIGID_LOCATION]=bl.VtoV(rigid.location)
678 meshObject[RIGID_GROUP]=rigid.group
679 meshObject[RIGID_INTERSECTION_GROUP]=rigid.target
680 meshObject[RIGID_WEIGHT]=rigid.weight
681 meshObject[RIGID_LINEAR_DAMPING]=rigid.linearDamping
682 meshObject[RIGID_ANGULAR_DAMPING]=rigid.angularDamping
683 meshObject[RIGID_RESTITUTION]=rigid.restitution
684 meshObject[RIGID_FRICTION]=rigid.friction
686 for meshObject in reversed(rigidMeshes):
687 bl.objectMakeParent(container, meshObject)
692 def __execute(filename, scene):
694 load pmd file to context.
696 bl.progress_start('pmd_import')
699 bl.progress_set('load %s' % filename, 0.0)
702 if not io.read(filename):
703 print("fail to load %s" % filename)
705 bl.progress_set('loaded %s' % filename, 0.1)
708 model_name=io.getEnglishName()
709 if len(model_name)==0:
710 model_name=io.getName()
711 root=bl.createEmptyObject(scene, model_name)
714 mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
715 for o in mesh_objects:
716 bl.objectMakeParent(root, o)
719 armature_object=__importArmature(scene, io)
721 bl.objectMakeParent(root, armature_object)
722 armature = bl.objectGetData(armature_object)
724 # add armature modifier
725 for o in mesh_objects:
726 bl.objectAddArmatureModifier(o, armature_object)
729 for n, b in bl.objectGetPose(armature_object).bones.items():
730 bl.poseBoneLimit(n, b)
732 # import rigid bodies
733 rigidBodies=__importRigidBodies(scene, io)
735 bl.objectMakeParent(root, rigidBodies)
738 constraints=__importConstraints(scene, io)
740 bl.objectMakeParent(root, constraints)
742 bl.objectActivate(scene, root)
747 def execute_24(filename):
751 filename=filename.decode(bl.INTERNAL_ENCODING)
752 print(bl.INTERNAL_ENCODING, bl.FS_ENCODING)
755 mode_edit = Blender.Window.EditMode()
757 Blender.Window.EditMode(0)
759 scene = bpy.data.scenes.active
760 __execute(filename, scene)
765 Blender.Window.EditMode(1)
766 Blender.Window.RedrawAll()
768 Blender.Window.FileSelector(
771 Blender.sys.makename(ext='.pmd'))
775 def execute_25(*args):
779 class IMPORT_OT_pmd(bpy.types.Operator):
780 bl_idname = "import_scene.pmd"
781 bl_label = 'Import PMD'
783 # List of operator properties, the attributes will be assigned
784 # to the class instance from the operator settings before calling.
786 path = StringProperty(
788 description="File path used for importing the PMD file",
789 maxlen= 1024, default= "")
790 filename = StringProperty(
792 description="Name of the file.")
793 directory = StringProperty(
795 description="Directory of the file.")
797 def execute(self, context):
798 execute_25(self.properties.path, context.scene)
801 def invoke(self, context, event):
803 wm.add_fileselect(self)
804 return 'RUNNING_MODAL'
807 def menu_func(self, context):
808 self.layout.operator(IMPORT_OT_pmd.bl_idname,
809 text="MikuMikuDance model (.pmd)")
812 bpy.types.register(IMPORT_OT_pmd)
813 bpy.types.INFO_MT_file_import.append(menu_func)
816 bpy.types.unregister(IMPORT_OT_pmd)
817 bpy.types.INFO_MT_file_import.remove(menu_func)
819 if __name__=="__main__":