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_"):
118 from bpy.props import *
126 def createPmdMaterial(m, index):
127 material = bpy.data.materials.new("Material")
129 material.diffuse_shader='FRESNEL'
130 material.diffuse_color=([m.diffuse.r, m.diffuse.g, m.diffuse.b])
131 material.alpha=m.diffuse.a
133 material.specular_shader='TOON'
134 material.specular_color=([m.specular.r, m.specular.g, m.specular.b])
135 material.specular_toon_size=int(m.shinness)
137 material.mirror_color=([m.ambient.r, m.ambient.g, m.ambient.b])
139 material.subsurface_scattering.enabled=True if m.flag==1 else False
141 material.name="m_%02d" % index
142 material.preview_render_type='FLAT'
143 material.transparency=True
146 def poseBoneLimit(n, b):
149 if n.startswith("knee_"):
156 elif n.startswith("ankle_"):
161 ###############################################################################
163 return bl.createVector(v.x, v.y, v.z)
165 def convert_coord(pos):
167 Left handed y-up to Right handed z-up
169 return (pos.x, pos.z, pos.y)
173 return (uv.x, 1.0 - uv.y)
176 def to_radian(degree):
177 return math.pi * degree / 180
180 def get_bone_name(l, index):
182 return l.bones[0].getName()
184 if index < len(l.bones):
185 name=englishmap.getEnglishBoneName(l.bones[index].getName())
188 return l.bones[index].getName()
189 print('invalid bone index', index)
190 return l.bones[0].getName()
192 def __importShape(obj, l, vertex_map):
193 if len(l.morph_list)==0:
197 bl.object.pinShape(obj, True)
201 for s in l.morph_list:
205 # create vertex group
206 bl.object.addVertexGroup(obj, MMD_SHAPE_GROUP_NAME)
211 bl.object.assignVertexGroup(
212 obj, MMD_SHAPE_GROUP_NAME, vertex_map[i], 0)
218 baseShapeBlock=bl.object.addShapeKey(obj, BASE_SHAPE_NAME)
220 mesh=bl.object.getData(obj)
224 for s in l.morph_list:
229 name=englishmap.getEnglishSkinName(s.getName())
235 for index, offset in zip(s.indices, s.pos_list):
237 vertex_index=vertex_map[base.indices[index]]
238 v=mesh.verts[vertex_index].co
239 offset=convert_coord(offset)
243 except IndexError as msg:
245 print(index, len(base.indices), len(vertex_map))
246 print(len(mesh.verts))
247 print(base.indices[index])
251 #print 'this mesh not has shape vertices'
254 # create shapekey block
255 new_shape_key=bl.object.addShapeKey(obj, name)
257 # copy vertex to shape key
261 for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
269 new_shape_key=bl.object.addShapeKey(obj, name)
271 for index, offset in zip(s.indices, s.pos_list):
273 vertex_index=vertex_map[base.indices[index]]
274 bl.shapekey.assign(new_shape_key, vertex_index,
275 mesh.verts[vertex_index].co+
276 bl.createVector(*convert_coord(offset)))
277 except IndexError as msg:
279 print(index, len(base.indices), len(vertex_map))
280 print(len(mesh.verts))
281 print(base.indices[index])
285 #print 'this mesh not has shape vertices'
289 bl.object.setActivateShapeKey(obj, 0)
292 def __build(armature, b, p, parent):
293 name=englishmap.getEnglishBoneName(b.getName())
297 bone=bl.armature.createBone(armature, name)
299 if parent and (b.tail_index==0 or b.type==6 or b.type==7 or b.type==9):
300 bone.head = bl.createVector(*convert_coord(b.pos))
301 bone.tail=bone.head+bl.createVector(0, 1, 0)
303 if bone.name=="center_t":
304 # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
305 parent.tail=parent.head+bl.createVector(0, 1, 0)
306 bone.head=parent.tail
307 bone.tail=bone.head+bl.createVector(0, 1, 0)
309 if parent.tail==bone.head:
312 print('diffurence with parent.tail and head', name)
314 bl.bone.setConnected(bone)
316 bl.bone.setLayerMask(bone, [0, 1])
319 bone.head = bl.createVector(*convert_coord(b.pos))
320 bone.tail = bl.createVector(*convert_coord(b.tail))
323 if parent.tail==bone.head:
324 bl.bone.setConnected(bone)
326 if bone.head==bone.tail:
327 bone.tail=bone.head+bl.createVector(0, 1, 0)
330 __build(armature, c, b, bone)
333 def __importArmature(scene, l):
335 armature, armature_object=bl.armature.create()
336 bl.armature.makeEditable(armature_object)
339 __build(armature, b, None, None)
340 bl.armature.update(armature)
344 pose = bl.object.getPose(armature_object)
346 target=l.bones[ik.target]
347 name = englishmap.getEnglishBoneName(target.getName())
349 name=target.getName()
350 p_bone = pose.bones[name]
352 print('not found', name)
354 if len(ik.children) >= 16:
355 print('over MAX_CHAINLEN', ik, len(ik.children))
357 effector_name=englishmap.getEnglishBoneName(
358 l.bones[ik.index].getName())
359 if not effector_name:
360 effector_name=l.bones[ik.index].getName()
362 constraint=bl.armature.createIkConstraint(armature_object,
363 p_bone, effector_name, ik)
365 bl.armature.makeEditable(armature_object)
366 bl.armature.update(armature)
369 return armature_object
372 def __import16MaerialAndMesh(meshObject, l,
373 material_order, face_map, tex_dir):
375 mesh=bl.object.getData(meshObject)
376 ############################################################
378 ############################################################
379 bl.progress_print('create materials')
385 for material_index in material_order:
387 m=l.materials[material_index]
388 mesh_material_map[material_index]=index
392 material=createPmdMaterial(m, material_index)
394 texture_name=m.getTexture()
396 if texture_name in textureMap:
397 texture=textureMap[texture_name]
400 texture, image=bl.texture.create(
401 os.path.join(tex_dir, texture_name))
402 textureMap[texture_name]=texture
403 imageMap[material_index]=image
406 bl.material.addTexture(material, texture)
407 bl.mesh.addMaterial(mesh, material)
410 ############################################################
412 ############################################################
413 bl.progress_print('create vertices')
416 for v in l.each_vertex():
417 vertices.append(convert_coord(v.pos))
419 ############################################################
421 ############################################################
422 bl.progress_print('create faces')
425 mesh_face_materials=[]
428 for material_index in material_order:
429 face_offset=face_map[material_index]
430 m=l.materials[material_index]
431 material_faces=l.indices[face_offset:face_offset+m.vertex_count]
433 def degenerate(i0, i1, i2):
437 return i0==i1 or i1==i2 or i2==i0
439 for j in xrange(0, len(material_faces), 3):
441 i1=material_faces[j+1]
442 i2=material_faces[j+2]
444 triangle=[i2, i1, i0]
445 if degenerate(*triangle):
447 mesh_face_indices.append(triangle[0:3])
448 mesh_face_materials.append(material_index)
449 used_vertices.add(i0)
450 used_vertices.add(i1)
451 used_vertices.add(i2)
453 ############################################################
454 # create vertices & faces
455 ############################################################
456 bl.mesh.addGeometry(mesh, vertices, mesh_face_indices)
458 ############################################################
460 ############################################################
461 # create vertex group
463 for v in l.each_vertex():
464 vertex_groups[v.bone0]=True
465 vertex_groups[v.bone1]=True
466 for i in vertex_groups.keys():
467 bl.object.addVertexGroup(meshObject, get_bone_name(l, i))
470 bl.mesh.useVertexUV(mesh)
471 for i, v, mvert in zip(xrange(len(l.vertices)),
472 l.each_vertex(), mesh.verts):
474 bl.vertex.setNormal(mvert, convert_coord(v.normal))
476 w1=float(v.weight0)/100.0
478 bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone0),
480 bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone1),
483 ############################################################
485 ############################################################
488 for i, (face, material_index) in enumerate(
489 zip(mesh.faces, mesh_face_materials)):
491 index=mesh_material_map[material_index]
492 except KeyError as message:
493 print(message, mesh_material_map, m)
495 bl.face.setMaterial(face, index)
496 material=mesh.materials[index]
498 if bl.material.hasTexture(material):
499 uv_array=[l.getUV(i) for i in bl.face.getIndices(face)]
500 bl.mesh.setFaceUV(mesh, i, face,
502 [(uv.x, 1.0-uv.y) for uv in uv_array],
503 imageMap.get(index, None))
510 ############################################################
511 # clean up not used vertices
512 ############################################################
513 bl.progress_print('clean up vertices not used')
516 for i, v in enumerate(l.each_vertex()):
517 if i in used_vertices:
518 vertex_map[i]=len(vertex_map)
520 remove_vertices.append(i)
522 bl.mesh.vertsDelete(mesh, remove_vertices)
524 bl.progress_print('%s created' % mesh.name)
528 def __importMesh(scene, io, tex_dir):
530 @param l[in] mmd.PMDLoader
533 ############################################################
534 # shpaeキーで使われるマテリアル優先的に前に並べる
535 ############################################################
536 # shapeキーで使われる頂点インデックスを集める
537 shape_key_used_vertices=set()
538 if len(io.morph_list)>0:
541 for s in io.morph_list:
548 for index in base.indices:
549 shape_key_used_vertices.add(index)
551 # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
552 def isMaterialUsedInShape(offset, m):
553 for i in xrange(offset, offset+m.vertex_count):
554 if io.indices[i] in shape_key_used_vertices:
557 # shapeキーで使われるマテリアルを記録する
558 shape_key_materials=set()
559 # 各マテリアルの開始頂点インデックスを記録する
562 for i, m in enumerate(io.materials):
563 face_map[i]=face_count
564 if isMaterialUsedInShape(face_count, m):
565 shape_key_materials.add(i)
566 face_count+=m.vertex_count
569 material_order=list(shape_key_materials)
571 # shapeキーに使われていないマテリアルを後ろに追加
572 for i in range(len(io.materials)):
573 if not i in material_order:
574 material_order.append(i)
576 # マテリアル16個ごとに分割したメッシュを作成する
579 while material_offset<len(io.materials):
580 mesh, meshObject=bl.mesh.create('mesh')
582 mesh_objects.append(meshObject)
585 bl.object.deselectAll()
586 bl.object.activate(meshObject)
588 # shapeキーで使われる順に並べなおしたマテリアル16個分の
590 vertex_map=__import16MaerialAndMesh(
592 material_order[material_offset:material_offset+16],
596 __importShape(meshObject, io, vertex_map)
604 def __importConstraints(scene, io):
607 print("create constraint")
608 container=bl.object.createEmpty('Constraints')
610 True, False, False, False, False, False, False, False,
611 False, False, False, False, False, False, False, False,
612 False, False, False, False, False, False, False, False,
613 False, False, False, False, False, False, False, False,
615 material=bl.material.create('constraint')
616 material.diffuse_color=(1, 0, 0)
618 for i, c in enumerate(io.constraints):
619 bpy.ops.mesh.primitive_uv_sphere_add(
623 location=(c.pos.x, c.pos.z, c.pos.y),
626 meshObject=scene.objects.active
627 constraintMeshes.append(meshObject)
628 mesh=bl.object.getData(meshObject)
629 bl.mesh.addMaterial(mesh, material)
630 meshObject.name='c_%d' % i
631 #meshObject.draw_transparent=True
632 #meshObject.draw_wire=True
633 meshObject.max_draw_type='SOLID'
635 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
637 meshObject[CONSTRAINT_NAME]=c.getName()
638 meshObject[CONSTRAINT_A]=io.rigidbodies[c.rigidA].getName()
639 meshObject[CONSTRAINT_B]=io.rigidbodies[c.rigidB].getName()
640 meshObject[CONSTRAINT_POS_MIN]=VtoV(c.constraintPosMin)
641 meshObject[CONSTRAINT_POS_MAX]=VtoV(c.constraintPosMax)
642 meshObject[CONSTRAINT_ROT_MIN]=VtoV(c.constraintRotMin)
643 meshObject[CONSTRAINT_ROT_MAX]=VtoV(c.constraintRotMax)
644 meshObject[CONSTRAINT_SPRING_POS]=VtoV(c.springPos)
645 meshObject[CONSTRAINT_SPRING_ROT]=VtoV(c.springRot)
647 for meshObject in reversed(constraintMeshes):
648 bl.object.makeParent(container, meshObject)
653 def __importRigidBodies(scene, io):
656 print("create rigid bodies")
658 container=bl.object.createEmpty('RigidBodies')
660 True, False, False, False, False, False, False, False,
661 False, False, False, False, False, False, False, False,
662 False, False, False, False, False, False, False, False,
663 False, False, False, False, False, False, False, False,
665 material=bl.material.create('rigidBody')
667 for rigid in io.rigidbodies:
668 if rigid.boneIndex==0xFFFF:
672 bone=io.bones[rigid.boneIndex]
673 pos=bone.pos+rigid.position
675 if rigid.shapeType==pmd.SHAPE_SPHERE:
676 bpy.ops.mesh.primitive_ico_sphere_add(
677 location=(pos.x, pos.z, pos.y),
680 bpy.ops.transform.resize(
681 value=(rigid.w, rigid.w, rigid.w))
682 elif rigid.shapeType==pmd.SHAPE_BOX:
683 bpy.ops.mesh.primitive_cube_add(
684 location=(pos.x, pos.z, pos.y),
687 bpy.ops.transform.resize(
688 value=(rigid.w, rigid.d, rigid.h))
689 elif rigid.shapeType==pmd.SHAPE_CAPSULE:
690 bpy.ops.mesh.primitive_tube_add(
691 location=(pos.x, pos.z, pos.y),
694 bpy.ops.transform.resize(
695 value=(rigid.w, rigid.w, rigid.h))
699 meshObject=scene.objects.active
700 mesh=bl.object.getData(meshObject)
701 rigidMeshes.append(meshObject)
702 bl.mesh.addMaterial(mesh, material)
703 meshObject.name=rigid.getName()
704 #meshObject.draw_transparent=True
705 #meshObject.draw_wire=True
706 meshObject.max_draw_type='WIRE'
708 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
711 meshObject[RIGID_SHAPE_TYPE]=rigid.shapeType
712 meshObject[RIGID_PROCESS_TYPE]=rigid.processType
714 bone_name = englishmap.getEnglishBoneName(bone.getName())
716 bone_name=bone.getName()
717 meshObject[RIGID_BONE_NAME]=bone_name
719 meshObject[RIGID_GROUP]=rigid.group
720 meshObject[RIGID_INTERSECTION_GROUP]=rigid.target
721 meshObject[RIGID_WEIGHT]=rigid.weight
722 meshObject[RIGID_LINEAR_DAMPING]=rigid.linearDamping
723 meshObject[RIGID_ANGULAR_DAMPING]=rigid.angularDamping
724 meshObject[RIGID_RESTITUTION]=rigid.restitution
725 meshObject[RIGID_FRICTION]=rigid.friction
727 for meshObject in reversed(rigidMeshes):
728 bl.object.makeParent(container, meshObject)
733 def __execute(filename, scene):
735 load pmd file to context.
739 bl.progress_set('load %s' % filename, 0.0)
742 if not io.read(filename):
743 bl.message("fail to load %s" % filename)
745 bl.progress_set('loaded %s' % filename, 0.1)
748 model_name=io.getEnglishName()
749 if len(model_name)==0:
750 model_name=io.getName()
751 root=bl.object.createEmpty(model_name)
754 mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
755 for o in mesh_objects:
756 bl.object.makeParent(root, o)
759 armature_object=__importArmature(scene, io)
761 bl.object.makeParent(root, armature_object)
762 armature = bl.object.getData(armature_object)
764 # add armature modifier
765 for o in mesh_objects:
766 bl.modifier.addArmature(o, armature_object)
769 for n, b in bl.object.getPose(armature_object).bones.items():
772 # import rigid bodies
773 rigidBodies=__importRigidBodies(scene, io)
775 bl.object.makeParent(root, rigidBodies)
778 constraints=__importConstraints(scene, io)
780 bl.object.makeParent(root, constraints)
782 bl.object.activate(root)
787 def execute_24(filename):
788 scene=bpy.data.scenes.active
789 bl.initialize('pmd_import', scene)
791 filename.decode(bl.INTERNAL_ENCODING),
795 Blender.Window.FileSelector(
798 Blender.sys.makename(ext='.pmd'))
802 def execute_25(filename, scene):
803 bl.initialize('pmd_import', scene)
804 __execute(filename, scene)
808 class IMPORT_OT_pmd(bpy.types.Operator):
809 bl_idname = "import_scene.pmd"
810 bl_label = 'Import PMD'
812 # List of operator properties, the attributes will be assigned
813 # to the class instance from the operator settings before calling.
815 path = StringProperty(
817 description="File path used for importing the PMD file",
818 maxlen= 1024, default= "")
819 filename = StringProperty(
821 description="Name of the file.")
822 directory = StringProperty(
824 description="Directory of the file.")
826 def execute(self, context):
827 execute_25(self.properties.path, context.scene)
830 def invoke(self, context, event):
832 wm.add_fileselect(self)
833 return 'RUNNING_MODAL'
836 def menu_func(self, context):
837 self.layout.operator(IMPORT_OT_pmd.bl_idname,
838 text="MikuMikuDance model (.pmd)")
841 bpy.types.register(IMPORT_OT_pmd)
842 bpy.types.INFO_MT_file_import.append(menu_func)
845 bpy.types.unregister(IMPORT_OT_pmd)
846 bpy.types.INFO_MT_file_import.remove(menu_func)
848 if __name__=="__main__":