OSDN Git Service

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