OSDN Git Service

fix bone connection.
[meshio/meshio.git] / swig / blender / pmd_import.py
1 #!BPY
2 # coding:utf-8
3 """
4  Name: 'MikuMikuDance model (.pmd)...'
5  Blender: 248
6  Group: 'Import'
7  Tooltip: 'Import PMD file for MikuMikuDance.'
8 """
9 __author__= ["ousttrue"]
10 __version__= "1.2"
11 __url__=()
12 __bpydoc__="""
13 pmd Importer
14
15 This script imports a pmd into Blender for editing.
16
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.
32 1.7 20100703: implement bone group.
33 """
34
35 MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
36 BASE_SHAPE_NAME='Basis'
37 RIGID_SHAPE_TYPE='rigid_shape_type'
38 RIGID_PROCESS_TYPE='rigid_process_type'
39 RIGID_BONE_NAME='rigid_bone_name'
40 #RIGID_LOCATION='rigid_loation'
41 RIGID_GROUP='ribid_group'
42 RIGID_INTERSECTION_GROUP='rigid_intersection_group'
43 RIGID_WEIGHT='rigid_weight'
44 RIGID_LINEAR_DAMPING='rigid_linear_damping'
45 RIGID_ANGULAR_DAMPING='rigid_angular_damping'
46 RIGID_RESTITUTION='rigid_restitution'
47 RIGID_FRICTION='rigid_friction'
48 CONSTRAINT_NAME='constraint_name'
49 CONSTRAINT_A='const_a'
50 CONSTRAINT_B='const_b'
51 CONSTRAINT_POS_MIN='const_pos_min'
52 CONSTRAINT_POS_MAX='const_pos_max'
53 CONSTRAINT_ROT_MIN='const_rot_min'
54 CONSTRAINT_ROT_MAX='const_rot_max'
55 CONSTRAINT_SPRING_POS='const_spring_pos'
56 CONSTRAINT_SPRING_ROT='const_spring_rot'
57
58
59 ###############################################################################
60 # import
61 ###############################################################################
62 import os
63 import sys
64 import math
65
66 # C extension
67 from meshio import pmd, englishmap
68
69 def isBlender24():
70     return sys.version_info[0]<3
71
72 if isBlender24():
73     # for 2.4
74     import Blender
75     from Blender import Mathutils
76     import bpy
77
78     # wrapper
79     import bl24 as bl
80
81     def createPmdMaterial(m, index):
82         material=Blender.Material.New()
83         #material.setRef(1)
84         #material.diffuseSize = 3.14/2
85         #material.setDiffuseSmooth(0)
86         #material.setSpecSize(0)
87         #material.setSpec(0)
88         # shader
89         # diffuse
90         material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
91         material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
92         material.setAlpha(m.diffuse.a)
93         # specular
94         material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
95         material.setSpec(m.shinness*0.1)
96         material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
97         # ambient
98         material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
99         # flag
100         material.enableSSS=True if m.flag==1 else False
101         # name
102         material.name="m_%02d" % index
103         return material
104
105     def poseBoneLimit(n, b):
106         if n.endswith("_t"):
107             return
108         if n.startswith("knee_"):
109             b.lockYRot=True
110             b.lockZRot=True
111             b.limitX=True
112             b.limitMin=[0, 0, 0]
113             b.limitMax=[180, 0, 0]
114         elif n.startswith("ankle_"):
115             b.lockYRot=True
116
117     def setSphereMap(material, index, blende_type=None):
118         pass
119
120 else:
121     # for 2.5
122     import bpy
123     from bpy.props import *
124     import mathutils
125
126     # wrapper
127     import bl25 as bl
128
129     xrange=range
130
131     def createPmdMaterial(m, index):
132         material = bpy.data.materials.new("Material")
133         # diffuse
134         material.diffuse_shader='FRESNEL'
135         material.diffuse_color=([m.diffuse.r, m.diffuse.g, m.diffuse.b])
136         material.alpha=m.diffuse.a
137         # specular
138         material.specular_shader='TOON'
139         material.specular_color=([m.specular.r, m.specular.g, m.specular.b])
140         material.specular_toon_size=int(m.shinness)
141         # ambient
142         material.mirror_color=([m.ambient.r, m.ambient.g, m.ambient.b])
143         # flag
144         material.subsurface_scattering.enabled=True if m.flag==1 else False
145         # other
146         material.name="m_%02d" % index
147         material.preview_render_type='FLAT'
148         material.transparency=True
149         return material
150
151     def poseBoneLimit(n, b):
152         if n.endswith("_t"):
153             return
154         if n.startswith("knee_"):
155             b.ik_dof_y=False
156             b.ik_dof_z=False
157             b.ik_dof_x=True
158             b.ik_limit_x=True
159             b.ik_min_x=0
160             b.ik_max_x=180
161         elif n.startswith("ankle_"):
162             #b.ik_dof_y=False
163             pass
164
165     def setSphereMap(material, index, blend_type=None):
166         slot=material.texture_slots[index]
167         slot.texture_coordinates='REFLECTION'
168         slot.mapping='SPHERE'
169         if blend_type:
170             slot.blend_type=blend_type
171
172
173 ###############################################################################
174 def VtoV(v):
175     return bl.createVector(v.x, v.y, v.z)
176
177 def convert_coord(pos):
178     """
179     Left handed y-up to Right handed z-up
180     """
181     return (pos.x, pos.z, pos.y)
182
183
184 def to_radian(degree):
185     return math.pi * degree / 180
186
187
188 def get_bone_name(l, index):
189     if index==0xFFFF:
190         return l.bones[0].getName()
191
192     if index < len(l.bones):
193         name=englishmap.getEnglishBoneName(l.bones[index].getName())
194         if name:
195             return name
196         return l.bones[index].getName()
197     print('invalid bone index', index)
198     return l.bones[0].getName()
199
200 def __importShape(obj, l, vertex_map):
201     if len(l.morph_list)==0:
202         return
203
204     # set shape_key pin
205     bl.object.pinShape(obj, True)
206
207     # find base 
208     base=None
209     for s in l.morph_list:
210         if s.type==0:
211             base=s
212
213             # create vertex group
214             bl.object.addVertexGroup(obj, MMD_SHAPE_GROUP_NAME)
215             hasShape=False
216             for i in s.indices:
217                 if i in vertex_map:
218                     hasShape=True
219                     bl.object.assignVertexGroup(
220                             obj, MMD_SHAPE_GROUP_NAME, vertex_map[i], 0)
221             if not hasShape:
222                 return
223     assert(base)
224
225     # create base key
226     baseShapeBlock=bl.object.addShapeKey(obj, BASE_SHAPE_NAME)
227     # mesh
228     mesh=bl.object.getData(obj)
229     mesh.update()
230
231     # each skin
232     for s in l.morph_list:
233         if s.type==0:
234             continue
235
236         # name
237         name=englishmap.getEnglishSkinName(s.getName())
238         if not name:
239             name=s.getName()
240
241         if isBlender24():
242             # 24
243             for index, offset in zip(s.indices, s.pos_list):
244                 try:
245                     vertex_index=vertex_map[base.indices[index]]
246                     v=mesh.verts[vertex_index].co
247                     offset=convert_coord(offset)
248                     v[0]+=offset[0]
249                     v[1]+=offset[1]
250                     v[2]+=offset[2]
251                 except IndexError as msg:
252                     print(msg)
253                     print(index, len(base.indices), len(vertex_map))
254                     print(len(mesh.verts))
255                     print(base.indices[index])
256                     print(vertex_index)
257                     break
258                 except KeyError:
259                     #print 'this mesh not has shape vertices'
260                     break
261
262             # create shapekey block
263             new_shape_key=bl.object.addShapeKey(obj, name)
264
265             # copy vertex to shape key
266             mesh.update()
267             
268             # restore
269             for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
270                 mv.co[0] = v[0]
271                 mv.co[1] = v[1]
272                 mv.co[2] = v[2]
273             mesh.update()
274
275         else:
276             # 25
277             new_shape_key=bl.object.addShapeKey(obj, name)
278
279             for index, offset in zip(s.indices, s.pos_list):
280                 try:
281                     vertex_index=vertex_map[base.indices[index]]
282                     bl.shapekey.assign(new_shape_key, vertex_index,
283                             mesh.verts[vertex_index].co+
284                             bl.createVector(*convert_coord(offset)))
285                 except IndexError as msg:
286                     print(msg)
287                     print(index, len(base.indices), len(vertex_map))
288                     print(len(mesh.verts))
289                     print(base.indices[index])
290                     print(vertex_index)
291                     break
292                 except KeyError:
293                     #print 'this mesh not has shape vertices'
294                     break
295
296     # select base shape
297     bl.object.setActivateShapeKey(obj, 0)
298
299
300 def __build(armature, b, p, parent):
301     name=englishmap.getEnglishBoneName(b.getName())
302     if not name:
303         name=b.getName()
304
305     bone=bl.armature.createBone(armature, name)
306
307     if parent and (b.tail_index==0 or b.type==6 or b.type==7 or b.type==9):
308         bone.head = bl.createVector(*convert_coord(b.pos))
309         bone.tail=bone.head+bl.createVector(0, 1, 0)
310         bone.parent=parent
311         if bone.name=="center_t":
312             # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
313             parent.tail=parent.head+bl.createVector(0, 1, 0)
314             bone.head=parent.tail
315             bone.tail=bone.head+bl.createVector(0, 1, 0)
316         else:
317             if parent.tail==bone.head:
318                 pass
319             else:
320                 print('diffurence with parent.tail and head', name)
321
322         if b.type!=9:
323             bl.bone.setConnected(bone)
324         # armature layer 2
325         bl.bone.setLayerMask(bone, [0, 1])
326     else:
327         # 通常ボーン
328         bone.head = bl.createVector(*convert_coord(b.pos))
329         bone.tail = bl.createVector(*convert_coord(b.tail))
330         if parent:
331             bone.parent=parent
332             if parent.tail==bone.head:
333                 bl.bone.setConnected(bone)
334
335     if bone.head==bone.tail:
336         bone.tail=bone.head+bl.createVector(0, 1, 0)
337
338     for c in b.children:
339         __build(armature, c, b, bone)
340
341
342 def __importArmature(scene, l):
343     armature, armature_object=bl.armature.create()
344
345     # build bone
346     bl.armature.makeEditable(armature_object)
347     for b in l.bones:
348         if not b.parent:
349             __build(armature, b, None, None)
350     bl.armature.update(armature)
351     bl.enterObjectMode()
352
353     # IK constraint
354     pose = bl.object.getPose(armature_object)
355     for ik in l.ik_list:
356         target=l.bones[ik.target]
357         name = englishmap.getEnglishBoneName(target.getName())
358         if not name:
359             name=target.getName()
360         p_bone = pose.bones[name]
361         if not p_bone:
362             print('not found', name)
363             continue
364         if len(ik.children) >= 16:
365             print('over MAX_CHAINLEN', ik, len(ik.children))
366             continue
367         effector_name=englishmap.getEnglishBoneName(
368                 l.bones[ik.index].getName())
369         if not effector_name:
370             effector_name=l.bones[ik.index].getName()
371
372         constraint=bl.armature.createIkConstraint(armature_object, 
373                 p_bone, effector_name, ik)
374
375     bl.armature.makeEditable(armature_object)
376     bl.armature.update(armature)
377     bl.enterObjectMode()
378
379     if isBlender24():
380         pass
381     else:
382         # create bone group
383         for i, g in enumerate(l.bone_group_list):
384             name=englishmap.getEnglishBoneGroupName(g.getName().strip())
385             if not name:
386                 name=g.getName()
387             bl.object.createBoneGroup(armature_object, name, "THEME%02d" % (i+1))
388
389         # assign bone to group
390         for b_index, g_index in l.bone_display_list:
391             # bone
392             b=l.bones[b_index]
393             bone_name=englishmap.getEnglishBoneName(b.getName())
394             if not bone_name:
395                 bone_name=b.getName()
396             # group
397             g=l.bone_group_list[g_index-1]
398             group_name=englishmap.getEnglishBoneGroupName(g.getName().strip())
399             if not group_name:
400                 group_name=g.getName()
401
402             # assign
403             pose.bones[bone_name].bone_group=pose.bone_groups[group_name]
404
405         bl.enterObjectMode()
406
407     return armature_object
408         
409
410 def __import16MaerialAndMesh(meshObject, l, 
411         material_order, face_map, tex_dir):
412
413     mesh=bl.object.getData(meshObject)
414     ############################################################
415     # material
416     ############################################################
417     bl.progress_print('create materials')
418     mesh_material_map={}
419     textureMap={}
420     imageMap={}
421     index=0
422
423     for material_index in material_order:
424         try:
425             m=l.materials[material_index]
426             mesh_material_map[material_index]=index
427         except KeyError:
428             break
429
430         material=createPmdMaterial(m, material_index)
431
432         texture_name=m.getTexture()
433         if texture_name!='':
434             for i, t in enumerate(texture_name.split('*')):
435                 if t in textureMap:
436                     texture=textureMap[t]
437                 else:
438                     path=os.path.join(tex_dir, t)
439                     texture, image=bl.texture.create(path)
440                     textureMap[texture_name]=texture
441                     imageMap[material_index]=image
442                 bl.material.addTexture(material, texture)
443                 if t.endswith('sph'):
444                     # sphere map
445                     setSphereMap(material, i)
446                 elif t.endswith('spa'):
447                     # sphere map
448                     setSphereMap(material, i, 'ADD')
449
450         bl.mesh.addMaterial(mesh, material)
451         index+=1
452
453     ############################################################
454     # vertex
455     ############################################################
456     bl.progress_print('create vertices')
457     # create vertices
458     vertices=[]
459     for v in l.each_vertex():
460         vertices.append(convert_coord(v.pos))
461
462     ############################################################
463     # face
464     ############################################################
465     bl.progress_print('create faces')
466     # create faces
467     mesh_face_indices=[]
468     mesh_face_materials=[]
469     used_vertices=set()
470
471     for material_index in material_order:
472         face_offset=face_map[material_index]
473         m=l.materials[material_index]
474         material_faces=l.indices[face_offset:face_offset+m.vertex_count]
475
476         def degenerate(i0, i1, i2):
477             """
478             縮退しているか?
479             """
480             return i0==i1 or i1==i2 or i2==i0
481
482         for j in xrange(0, len(material_faces), 3):
483             i0=material_faces[j]
484             i1=material_faces[j+1]
485             i2=material_faces[j+2]
486             # flip
487             triangle=[i2, i1, i0]
488             if degenerate(*triangle):
489                 continue
490             mesh_face_indices.append(triangle[0:3])
491             mesh_face_materials.append(material_index)
492             used_vertices.add(i0)
493             used_vertices.add(i1)
494             used_vertices.add(i2)
495
496     ############################################################
497     # create vertices & faces
498     ############################################################
499     bl.mesh.addGeometry(mesh, vertices, mesh_face_indices)
500
501     ############################################################
502     # vertex bone weight
503     ############################################################
504     # create vertex group
505     vertex_groups={}
506     for v in l.each_vertex():
507         vertex_groups[v.bone0]=True
508         vertex_groups[v.bone1]=True
509     for i in vertex_groups.keys():
510         bl.object.addVertexGroup(meshObject, get_bone_name(l, i))
511
512     # vertex params
513     bl.mesh.useVertexUV(mesh)
514     for i, v, mvert in zip(xrange(len(l.vertices)), 
515         l.each_vertex(), mesh.verts):
516         # normal, uv
517         bl.vertex.setNormal(mvert, convert_coord(v.normal))
518         # bone weight
519         w1=float(v.weight0)/100.0
520         w2=1.0-w1
521         bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone0),
522             i,  w1)
523         bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone1),
524             i,  w2)
525
526     ############################################################
527     # face params
528     ############################################################
529     used_map={}
530     bl.mesh.addUV(mesh)
531     for i, (face, material_index) in enumerate(
532             zip(mesh.faces, mesh_face_materials)):
533         try:
534             index=mesh_material_map[material_index]
535         except KeyError as message:
536             print(message, mesh_material_map, m)
537             assert(False)
538         bl.face.setMaterial(face, index)
539         material=mesh.materials[index]
540         used_map[index]=True
541         if bl.material.hasTexture(material):
542             uv_array=[l.getUV(i) for i in bl.face.getIndices(face)]
543             bl.mesh.setFaceUV(mesh, i, face, 
544                     # fix uv
545                     [(uv.x, 1.0-uv.y) for uv in uv_array], 
546                     imageMap.get(index, None))
547
548         # set smooth
549         face.smooth = 1
550
551     mesh.update()
552
553     ############################################################
554     # clean up not used vertices
555     ############################################################
556     bl.progress_print('clean up vertices not used')
557     remove_vertices=[]
558     vertex_map={}
559     for i, v in enumerate(l.each_vertex()):
560         if i in used_vertices:
561             vertex_map[i]=len(vertex_map)
562         else:
563             remove_vertices.append(i)
564
565     bl.mesh.vertsDelete(mesh, remove_vertices)
566
567     bl.progress_print('%s created' % mesh.name)
568     return vertex_map
569
570
571 def __importMesh(scene, io, tex_dir):
572     """
573     @param l[in] mmd.PMDLoader
574     @param filename[in]
575     """
576     ############################################################
577     # shpaeキーで使われるマテリアル優先的に前に並べる
578     ############################################################
579     # shapeキーで使われる頂点インデックスを集める
580     shape_key_used_vertices=set()
581     if len(io.morph_list)>0:
582         # base 
583         base=None
584         for s in io.morph_list:
585             if s.type!=0:
586                 continue
587             base=s
588             break
589         assert(base)
590
591         for index in base.indices:
592             shape_key_used_vertices.add(index)
593
594     # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
595     def isMaterialUsedInShape(offset, m):
596         for i in xrange(offset, offset+m.vertex_count): 
597             if io.indices[i] in shape_key_used_vertices:
598                 return True
599
600     material_with_shape=set()
601
602     # 各マテリアルの開始頂点インデックスを記録する
603     face_map={}
604     face_count=0
605     for i, m in enumerate(io.materials):
606         face_map[i]=face_count
607         if isMaterialUsedInShape(face_count, m):
608             material_with_shape.add(i)
609         face_count+=m.vertex_count
610
611     # shapeキーで使われる頂点のあるマテリアル
612     material_with_shape=list(material_with_shape)
613     material_with_shape.sort()
614
615     # shapeキーに使われていないマテリアル
616     material_without_shape=[]
617     for i in range(len(io.materials)):
618         if not i in material_with_shape:
619             material_without_shape.append(i)
620
621     # メッシュの生成
622     def __splitList(l, length):
623         for i in range(0, len(l), length):
624             yield l[i:i+length]
625
626     def __importMeshAndShape(material16, name):
627         mesh, meshObject=bl.mesh.create(name)
628
629         # activate object
630         bl.object.deselectAll()
631         bl.object.activate(meshObject)
632
633         # shapeキーで使われる順に並べなおしたマテリアル16個分の
634         # メッシュを作成する
635         vertex_map=__import16MaerialAndMesh(
636                 meshObject, io, material16, face_map, tex_dir)
637
638         # crete shape key
639         __importShape(meshObject, io, vertex_map)
640
641         mesh.update()
642         return meshObject
643
644     mesh_objects=[__importMeshAndShape(material16, 'with_shape')
645         for material16 in __splitList(material_with_shape, 16)]
646     
647     mesh_objects+=[__importMeshAndShape(material16, 'mesh')
648         for material16 in __splitList(material_without_shape, 16)]
649  
650     return mesh_objects
651
652
653 def __importConstraints(scene, io):
654     if isBlender24():
655         return
656     print("create constraint")
657     container=bl.object.createEmpty('Constraints')
658     layer=[
659             True, False, False, False, False, False, False, False,
660             False, 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             ]
664     material=bl.material.create('constraint')
665     material.diffuse_color=(1, 0, 0)
666     constraintMeshes=[]
667     for i, c in enumerate(io.constraints):
668         bpy.ops.mesh.primitive_uv_sphere_add(
669                 segments=8,
670                 rings=4,
671                 size=0.1,
672                 location=(c.pos.x, c.pos.z, c.pos.y),
673                 layer=layer
674                 )
675         meshObject=scene.objects.active
676         constraintMeshes.append(meshObject)
677         mesh=bl.object.getData(meshObject)
678         bl.mesh.addMaterial(mesh, material)
679         meshObject.name='c_%d' % i
680         #meshObject.draw_transparent=True
681         #meshObject.draw_wire=True
682         meshObject.max_draw_type='SOLID'
683         rot=c.rot
684         meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
685
686         meshObject[CONSTRAINT_NAME]=c.getName()
687         meshObject[CONSTRAINT_A]=io.rigidbodies[c.rigidA].getName()
688         meshObject[CONSTRAINT_B]=io.rigidbodies[c.rigidB].getName()
689         meshObject[CONSTRAINT_POS_MIN]=VtoV(c.constraintPosMin)
690         meshObject[CONSTRAINT_POS_MAX]=VtoV(c.constraintPosMax)
691         meshObject[CONSTRAINT_ROT_MIN]=VtoV(c.constraintRotMin)
692         meshObject[CONSTRAINT_ROT_MAX]=VtoV(c.constraintRotMax)
693         meshObject[CONSTRAINT_SPRING_POS]=VtoV(c.springPos)
694         meshObject[CONSTRAINT_SPRING_ROT]=VtoV(c.springRot)
695
696     for meshObject in reversed(constraintMeshes):
697         bl.object.makeParent(container, meshObject)
698
699     return container
700
701
702 def __importRigidBodies(scene, io):
703     if isBlender24():
704         return
705     print("create rigid bodies")
706
707     container=bl.object.createEmpty('RigidBodies')
708     layer=[
709             True, False, False, False, False, False, False, False,
710             False, False, False, False, False, False, False, False,
711             False, False, False, False, False, False, False, False,
712             False, False, False, False, False, False, False, False,
713             ]
714     material=bl.material.create('rigidBody')
715     rigidMeshes=[]
716     for rigid in io.rigidbodies:
717         if rigid.boneIndex==0xFFFF:
718             # no reference bone
719             bone=io.bones[0]
720         else:
721             bone=io.bones[rigid.boneIndex]
722         pos=bone.pos+rigid.position
723
724         if rigid.shapeType==pmd.SHAPE_SPHERE:
725             bpy.ops.mesh.primitive_ico_sphere_add(
726                     location=(pos.x, pos.z, pos.y),
727                     layer=layer
728                     )
729             bpy.ops.transform.resize(
730                     value=(rigid.w, rigid.w, rigid.w))
731         elif rigid.shapeType==pmd.SHAPE_BOX:
732             bpy.ops.mesh.primitive_cube_add(
733                     location=(pos.x, pos.z, pos.y),
734                     layer=layer
735                     )
736             bpy.ops.transform.resize(
737                     value=(rigid.w, rigid.d, rigid.h))
738         elif rigid.shapeType==pmd.SHAPE_CAPSULE:
739             bpy.ops.mesh.primitive_tube_add(
740                     location=(pos.x, pos.z, pos.y),
741                     layer=layer
742                     )
743             bpy.ops.transform.resize(
744                     value=(rigid.w, rigid.w, rigid.h))
745         else:
746             assert(False)
747
748         meshObject=scene.objects.active
749         mesh=bl.object.getData(meshObject)
750         rigidMeshes.append(meshObject)
751         bl.mesh.addMaterial(mesh, material)
752         meshObject.name=rigid.getName()
753         #meshObject.draw_transparent=True
754         #meshObject.draw_wire=True
755         meshObject.max_draw_type='WIRE'
756         rot=rigid.rotation
757         meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
758
759         # custom properties
760         meshObject[RIGID_SHAPE_TYPE]=rigid.shapeType
761         meshObject[RIGID_PROCESS_TYPE]=rigid.processType
762
763         bone_name = englishmap.getEnglishBoneName(bone.getName())
764         if not bone_name:
765             bone_name=bone.getName()
766         meshObject[RIGID_BONE_NAME]=bone_name
767
768         meshObject[RIGID_GROUP]=rigid.group
769         meshObject[RIGID_INTERSECTION_GROUP]=rigid.target
770         meshObject[RIGID_WEIGHT]=rigid.weight
771         meshObject[RIGID_LINEAR_DAMPING]=rigid.linearDamping
772         meshObject[RIGID_ANGULAR_DAMPING]=rigid.angularDamping
773         meshObject[RIGID_RESTITUTION]=rigid.restitution
774         meshObject[RIGID_FRICTION]=rigid.friction
775
776     for meshObject in reversed(rigidMeshes):
777         bl.object.makeParent(container, meshObject)
778
779     return container
780
781
782 def __execute(filename, scene):
783     """
784     load pmd file to context.
785     """
786            
787     # load pmd
788     bl.progress_set('load %s' % filename, 0.0)
789
790     io=pmd.IO()
791     if not io.read(filename):
792         bl.message("fail to load %s" % filename)
793         return
794     bl.progress_set('loaded %s' % filename, 0.1)
795
796     # create root object
797     model_name=io.getEnglishName()
798     if len(model_name)==0:
799         model_name=io.getName()
800     root=bl.object.createEmpty(model_name)
801
802     # import mesh
803     mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
804     for o in mesh_objects:
805         bl.object.makeParent(root, o)
806
807     # import armature
808     armature_object=__importArmature(scene, io)
809     if armature_object:
810         bl.object.makeParent(root, armature_object)
811         armature = bl.object.getData(armature_object) 
812
813         # add armature modifier
814         for o in mesh_objects:
815             bl.modifier.addArmature(o, armature_object)
816
817         # Limitation
818         for n, b in bl.object.getPose(armature_object).bones.items():
819             poseBoneLimit(n, b)
820
821     # import rigid bodies
822     rigidBodies=__importRigidBodies(scene, io)
823     if rigidBodies:
824         bl.object.makeParent(root, rigidBodies)
825
826     # import constraints
827     constraints=__importConstraints(scene, io)
828     if constraints:
829         bl.object.makeParent(root, constraints)
830
831     bl.object.activate(root)
832
833
834 if isBlender24():
835     # for 2.4
836     def execute_24(filename):
837         scene=bpy.data.scenes.active
838         bl.initialize('pmd_import', scene)
839         __execute(
840                 filename.decode(bl.INTERNAL_ENCODING), 
841                 scene)
842         bl.finalize()
843
844     Blender.Window.FileSelector(
845             execute_24, 
846             'Import PMD file', 
847             Blender.sys.makename(ext='.pmd'))
848
849 else:
850     # for 2.5
851     def execute_25(filename, scene):
852         bl.initialize('pmd_import', scene)
853         __execute(filename, scene)
854         bl.finalize()
855
856     # import operator
857     class IMPORT_OT_pmd(bpy.types.Operator):
858         bl_idname = "import_scene.pmd"
859         bl_label = 'Import PMD'
860
861         # List of operator properties, the attributes will be assigned
862         # to the class instance from the operator settings before calling.
863
864         path = StringProperty(
865                 name="File Path", 
866                 description="File path used for importing the PMD file", 
867                 maxlen= 1024, default= "")
868         filename = StringProperty(
869                 name="File Name", 
870                 description="Name of the file.")
871         directory = StringProperty(
872                 name="Directory", 
873                 description="Directory of the file.")
874
875         def execute(self, context):
876             execute_25(self.properties.path, context.scene)
877             return 'FINISHED'
878
879         def invoke(self, context, event):
880             wm = context.manager
881             wm.add_fileselect(self)
882             return 'RUNNING_MODAL'
883
884     # register menu
885     def menu_func(self, context): 
886         self.layout.operator(IMPORT_OT_pmd.bl_idname, 
887                 text="MikuMikuDance model (.pmd)")
888
889     def register():
890         bpy.types.register(IMPORT_OT_pmd)
891         bpy.types.INFO_MT_file_import.append(menu_func)
892
893     def unregister():
894         bpy.types.unregister(IMPORT_OT_pmd)
895         bpy.types.INFO_MT_file_import.remove(menu_func)
896
897     if __name__=="__main__":
898         register()
899