OSDN Git Service

implement pmd_import bone group.
[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         bl.bone.setConnected(bone)
323         # armature layer 2
324         bl.bone.setLayerMask(bone, [0, 1])
325     else:
326         # 通常ボーン
327         bone.head = bl.createVector(*convert_coord(b.pos))
328         bone.tail = bl.createVector(*convert_coord(b.tail))
329         if parent:
330             bone.parent=parent
331             if parent.tail==bone.head:
332                 bl.bone.setConnected(bone)
333
334     if bone.head==bone.tail:
335         bone.tail=bone.head+bl.createVector(0, 1, 0)
336
337     for c in b.children:
338         __build(armature, c, b, bone)
339
340
341 def __importArmature(scene, l):
342     armature, armature_object=bl.armature.create()
343
344     # build bone
345     bl.armature.makeEditable(armature_object)
346     for b in l.bones:
347         if not b.parent:
348             __build(armature, b, None, None)
349     bl.armature.update(armature)
350     bl.enterObjectMode()
351
352     # IK constraint
353     pose = bl.object.getPose(armature_object)
354     for ik in l.ik_list:
355         target=l.bones[ik.target]
356         name = englishmap.getEnglishBoneName(target.getName())
357         if not name:
358             name=target.getName()
359         p_bone = pose.bones[name]
360         if not p_bone:
361             print('not found', name)
362             continue
363         if len(ik.children) >= 16:
364             print('over MAX_CHAINLEN', ik, len(ik.children))
365             continue
366         effector_name=englishmap.getEnglishBoneName(
367                 l.bones[ik.index].getName())
368         if not effector_name:
369             effector_name=l.bones[ik.index].getName()
370
371         constraint=bl.armature.createIkConstraint(armature_object, 
372                 p_bone, effector_name, ik)
373
374     bl.armature.makeEditable(armature_object)
375     bl.armature.update(armature)
376     bl.enterObjectMode()
377
378     if isBlender24():
379         pass
380     else:
381         # create bone group
382         for i, g in enumerate(l.bone_group_list):
383             name=englishmap.getEnglishBoneGroupName(g.getName().strip())
384             if not name:
385                 name=g.getName()
386             bl.object.createBoneGroup(armature_object, name, "THEME%02d" % (i+1))
387
388         # assign bone to group
389         for b_index, g_index in l.bone_display_list:
390             # bone
391             b=l.bones[b_index]
392             bone_name=englishmap.getEnglishBoneName(b.getName())
393             if not bone_name:
394                 bone_name=b.getName()
395             # group
396             g=l.bone_group_list[g_index-1]
397             group_name=englishmap.getEnglishBoneGroupName(g.getName().strip())
398             if not group_name:
399                 group_name=g.getName()
400
401             # assign
402             pose.bones[bone_name].bone_group=pose.bone_groups[group_name]
403
404         bl.enterObjectMode()
405
406     return armature_object
407         
408
409 def __import16MaerialAndMesh(meshObject, l, 
410         material_order, face_map, tex_dir):
411
412     mesh=bl.object.getData(meshObject)
413     ############################################################
414     # material
415     ############################################################
416     bl.progress_print('create materials')
417     mesh_material_map={}
418     textureMap={}
419     imageMap={}
420     index=0
421
422     for material_index in material_order:
423         try:
424             m=l.materials[material_index]
425             mesh_material_map[material_index]=index
426         except KeyError:
427             break
428
429         material=createPmdMaterial(m, material_index)
430
431         texture_name=m.getTexture()
432         if texture_name!='':
433             for i, t in enumerate(texture_name.split('*')):
434                 if t in textureMap:
435                     texture=textureMap[t]
436                 else:
437                     path=os.path.join(tex_dir, t)
438                     texture, image=bl.texture.create(path)
439                     textureMap[texture_name]=texture
440                     imageMap[material_index]=image
441                 bl.material.addTexture(material, texture)
442                 if t.endswith('sph'):
443                     # sphere map
444                     setSphereMap(material, i)
445                 elif t.endswith('spa'):
446                     # sphere map
447                     setSphereMap(material, i, 'ADD')
448
449         bl.mesh.addMaterial(mesh, material)
450         index+=1
451
452     ############################################################
453     # vertex
454     ############################################################
455     bl.progress_print('create vertices')
456     # create vertices
457     vertices=[]
458     for v in l.each_vertex():
459         vertices.append(convert_coord(v.pos))
460
461     ############################################################
462     # face
463     ############################################################
464     bl.progress_print('create faces')
465     # create faces
466     mesh_face_indices=[]
467     mesh_face_materials=[]
468     used_vertices=set()
469
470     for material_index in material_order:
471         face_offset=face_map[material_index]
472         m=l.materials[material_index]
473         material_faces=l.indices[face_offset:face_offset+m.vertex_count]
474
475         def degenerate(i0, i1, i2):
476             """
477             縮退しているか?
478             """
479             return i0==i1 or i1==i2 or i2==i0
480
481         for j in xrange(0, len(material_faces), 3):
482             i0=material_faces[j]
483             i1=material_faces[j+1]
484             i2=material_faces[j+2]
485             # flip
486             triangle=[i2, i1, i0]
487             if degenerate(*triangle):
488                 continue
489             mesh_face_indices.append(triangle[0:3])
490             mesh_face_materials.append(material_index)
491             used_vertices.add(i0)
492             used_vertices.add(i1)
493             used_vertices.add(i2)
494
495     ############################################################
496     # create vertices & faces
497     ############################################################
498     bl.mesh.addGeometry(mesh, vertices, mesh_face_indices)
499
500     ############################################################
501     # vertex bone weight
502     ############################################################
503     # create vertex group
504     vertex_groups={}
505     for v in l.each_vertex():
506         vertex_groups[v.bone0]=True
507         vertex_groups[v.bone1]=True
508     for i in vertex_groups.keys():
509         bl.object.addVertexGroup(meshObject, get_bone_name(l, i))
510
511     # vertex params
512     bl.mesh.useVertexUV(mesh)
513     for i, v, mvert in zip(xrange(len(l.vertices)), 
514         l.each_vertex(), mesh.verts):
515         # normal, uv
516         bl.vertex.setNormal(mvert, convert_coord(v.normal))
517         # bone weight
518         w1=float(v.weight0)/100.0
519         w2=1.0-w1
520         bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone0),
521             i,  w1)
522         bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone1),
523             i,  w2)
524
525     ############################################################
526     # face params
527     ############################################################
528     used_map={}
529     bl.mesh.addUV(mesh)
530     for i, (face, material_index) in enumerate(
531             zip(mesh.faces, mesh_face_materials)):
532         try:
533             index=mesh_material_map[material_index]
534         except KeyError as message:
535             print(message, mesh_material_map, m)
536             assert(False)
537         bl.face.setMaterial(face, index)
538         material=mesh.materials[index]
539         used_map[index]=True
540         if bl.material.hasTexture(material):
541             uv_array=[l.getUV(i) for i in bl.face.getIndices(face)]
542             bl.mesh.setFaceUV(mesh, i, face, 
543                     # fix uv
544                     [(uv.x, 1.0-uv.y) for uv in uv_array], 
545                     imageMap.get(index, None))
546
547         # set smooth
548         face.smooth = 1
549
550     mesh.update()
551
552     ############################################################
553     # clean up not used vertices
554     ############################################################
555     bl.progress_print('clean up vertices not used')
556     remove_vertices=[]
557     vertex_map={}
558     for i, v in enumerate(l.each_vertex()):
559         if i in used_vertices:
560             vertex_map[i]=len(vertex_map)
561         else:
562             remove_vertices.append(i)
563
564     bl.mesh.vertsDelete(mesh, remove_vertices)
565
566     bl.progress_print('%s created' % mesh.name)
567     return vertex_map
568
569
570 def __importMesh(scene, io, tex_dir):
571     """
572     @param l[in] mmd.PMDLoader
573     @param filename[in]
574     """
575     ############################################################
576     # shpaeキーで使われるマテリアル優先的に前に並べる
577     ############################################################
578     # shapeキーで使われる頂点インデックスを集める
579     shape_key_used_vertices=set()
580     if len(io.morph_list)>0:
581         # base 
582         base=None
583         for s in io.morph_list:
584             if s.type!=0:
585                 continue
586             base=s
587             break
588         assert(base)
589
590         for index in base.indices:
591             shape_key_used_vertices.add(index)
592
593     # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
594     def isMaterialUsedInShape(offset, m):
595         for i in xrange(offset, offset+m.vertex_count): 
596             if io.indices[i] in shape_key_used_vertices:
597                 return True
598
599     material_with_shape=set()
600
601     # 各マテリアルの開始頂点インデックスを記録する
602     face_map={}
603     face_count=0
604     for i, m in enumerate(io.materials):
605         face_map[i]=face_count
606         if isMaterialUsedInShape(face_count, m):
607             material_with_shape.add(i)
608         face_count+=m.vertex_count
609
610     # shapeキーで使われる頂点のあるマテリアル
611     material_with_shape=list(material_with_shape)
612     material_with_shape.sort()
613
614     # shapeキーに使われていないマテリアル
615     material_without_shape=[]
616     for i in range(len(io.materials)):
617         if not i in material_with_shape:
618             material_without_shape.append(i)
619
620     # メッシュの生成
621     def __splitList(l, length):
622         for i in range(0, len(l), length):
623             yield l[i:i+length]
624
625     def __importMeshAndShape(material16, name):
626         mesh, meshObject=bl.mesh.create(name)
627
628         # activate object
629         bl.object.deselectAll()
630         bl.object.activate(meshObject)
631
632         # shapeキーで使われる順に並べなおしたマテリアル16個分の
633         # メッシュを作成する
634         vertex_map=__import16MaerialAndMesh(
635                 meshObject, io, material16, face_map, tex_dir)
636
637         # crete shape key
638         __importShape(meshObject, io, vertex_map)
639
640         mesh.update()
641         return meshObject
642
643     mesh_objects=[__importMeshAndShape(material16, 'with_shape')
644         for material16 in __splitList(material_with_shape, 16)]
645     
646     mesh_objects+=[__importMeshAndShape(material16, 'mesh')
647         for material16 in __splitList(material_without_shape, 16)]
648  
649     return mesh_objects
650
651
652 def __importConstraints(scene, io):
653     if isBlender24():
654         return
655     print("create constraint")
656     container=bl.object.createEmpty('Constraints')
657     layer=[
658             True, False, False, False, False, False, False, False,
659             False, 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             ]
663     material=bl.material.create('constraint')
664     material.diffuse_color=(1, 0, 0)
665     constraintMeshes=[]
666     for i, c in enumerate(io.constraints):
667         bpy.ops.mesh.primitive_uv_sphere_add(
668                 segments=8,
669                 rings=4,
670                 size=0.1,
671                 location=(c.pos.x, c.pos.z, c.pos.y),
672                 layer=layer
673                 )
674         meshObject=scene.objects.active
675         constraintMeshes.append(meshObject)
676         mesh=bl.object.getData(meshObject)
677         bl.mesh.addMaterial(mesh, material)
678         meshObject.name='c_%d' % i
679         #meshObject.draw_transparent=True
680         #meshObject.draw_wire=True
681         meshObject.max_draw_type='SOLID'
682         rot=c.rot
683         meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
684
685         meshObject[CONSTRAINT_NAME]=c.getName()
686         meshObject[CONSTRAINT_A]=io.rigidbodies[c.rigidA].getName()
687         meshObject[CONSTRAINT_B]=io.rigidbodies[c.rigidB].getName()
688         meshObject[CONSTRAINT_POS_MIN]=VtoV(c.constraintPosMin)
689         meshObject[CONSTRAINT_POS_MAX]=VtoV(c.constraintPosMax)
690         meshObject[CONSTRAINT_ROT_MIN]=VtoV(c.constraintRotMin)
691         meshObject[CONSTRAINT_ROT_MAX]=VtoV(c.constraintRotMax)
692         meshObject[CONSTRAINT_SPRING_POS]=VtoV(c.springPos)
693         meshObject[CONSTRAINT_SPRING_ROT]=VtoV(c.springRot)
694
695     for meshObject in reversed(constraintMeshes):
696         bl.object.makeParent(container, meshObject)
697
698     return container
699
700
701 def __importRigidBodies(scene, io):
702     if isBlender24():
703         return
704     print("create rigid bodies")
705
706     container=bl.object.createEmpty('RigidBodies')
707     layer=[
708             True, False, False, False, False, False, False, False,
709             False, 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             ]
713     material=bl.material.create('rigidBody')
714     rigidMeshes=[]
715     for rigid in io.rigidbodies:
716         if rigid.boneIndex==0xFFFF:
717             # no reference bone
718             bone=io.bones[0]
719         else:
720             bone=io.bones[rigid.boneIndex]
721         pos=bone.pos+rigid.position
722
723         if rigid.shapeType==pmd.SHAPE_SPHERE:
724             bpy.ops.mesh.primitive_ico_sphere_add(
725                     location=(pos.x, pos.z, pos.y),
726                     layer=layer
727                     )
728             bpy.ops.transform.resize(
729                     value=(rigid.w, rigid.w, rigid.w))
730         elif rigid.shapeType==pmd.SHAPE_BOX:
731             bpy.ops.mesh.primitive_cube_add(
732                     location=(pos.x, pos.z, pos.y),
733                     layer=layer
734                     )
735             bpy.ops.transform.resize(
736                     value=(rigid.w, rigid.d, rigid.h))
737         elif rigid.shapeType==pmd.SHAPE_CAPSULE:
738             bpy.ops.mesh.primitive_tube_add(
739                     location=(pos.x, pos.z, pos.y),
740                     layer=layer
741                     )
742             bpy.ops.transform.resize(
743                     value=(rigid.w, rigid.w, rigid.h))
744         else:
745             assert(False)
746
747         meshObject=scene.objects.active
748         mesh=bl.object.getData(meshObject)
749         rigidMeshes.append(meshObject)
750         bl.mesh.addMaterial(mesh, material)
751         meshObject.name=rigid.getName()
752         #meshObject.draw_transparent=True
753         #meshObject.draw_wire=True
754         meshObject.max_draw_type='WIRE'
755         rot=rigid.rotation
756         meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
757
758         # custom properties
759         meshObject[RIGID_SHAPE_TYPE]=rigid.shapeType
760         meshObject[RIGID_PROCESS_TYPE]=rigid.processType
761
762         bone_name = englishmap.getEnglishBoneName(bone.getName())
763         if not bone_name:
764             bone_name=bone.getName()
765         meshObject[RIGID_BONE_NAME]=bone_name
766
767         meshObject[RIGID_GROUP]=rigid.group
768         meshObject[RIGID_INTERSECTION_GROUP]=rigid.target
769         meshObject[RIGID_WEIGHT]=rigid.weight
770         meshObject[RIGID_LINEAR_DAMPING]=rigid.linearDamping
771         meshObject[RIGID_ANGULAR_DAMPING]=rigid.angularDamping
772         meshObject[RIGID_RESTITUTION]=rigid.restitution
773         meshObject[RIGID_FRICTION]=rigid.friction
774
775     for meshObject in reversed(rigidMeshes):
776         bl.object.makeParent(container, meshObject)
777
778     return container
779
780
781 def __execute(filename, scene):
782     """
783     load pmd file to context.
784     """
785            
786     # load pmd
787     bl.progress_set('load %s' % filename, 0.0)
788
789     io=pmd.IO()
790     if not io.read(filename):
791         bl.message("fail to load %s" % filename)
792         return
793     bl.progress_set('loaded %s' % filename, 0.1)
794
795     # create root object
796     model_name=io.getEnglishName()
797     if len(model_name)==0:
798         model_name=io.getName()
799     root=bl.object.createEmpty(model_name)
800
801     # import mesh
802     mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
803     for o in mesh_objects:
804         bl.object.makeParent(root, o)
805
806     # import armature
807     armature_object=__importArmature(scene, io)
808     if armature_object:
809         bl.object.makeParent(root, armature_object)
810         armature = bl.object.getData(armature_object) 
811
812         # add armature modifier
813         for o in mesh_objects:
814             bl.modifier.addArmature(o, armature_object)
815
816         # Limitation
817         for n, b in bl.object.getPose(armature_object).bones.items():
818             poseBoneLimit(n, b)
819
820     # import rigid bodies
821     rigidBodies=__importRigidBodies(scene, io)
822     if rigidBodies:
823         bl.object.makeParent(root, rigidBodies)
824
825     # import constraints
826     constraints=__importConstraints(scene, io)
827     if constraints:
828         bl.object.makeParent(root, constraints)
829
830     bl.object.activate(root)
831
832
833 if isBlender24():
834     # for 2.4
835     def execute_24(filename):
836         scene=bpy.data.scenes.active
837         bl.initialize('pmd_import', scene)
838         __execute(
839                 filename.decode(bl.INTERNAL_ENCODING), 
840                 scene)
841         bl.finalize()
842
843     Blender.Window.FileSelector(
844             execute_24, 
845             'Import PMD file', 
846             Blender.sys.makename(ext='.pmd'))
847
848 else:
849     # for 2.5
850     def execute_25(filename, scene):
851         bl.initialize('pmd_import', scene)
852         __execute(filename, scene)
853         bl.finalize()
854
855     # import operator
856     class IMPORT_OT_pmd(bpy.types.Operator):
857         bl_idname = "import_scene.pmd"
858         bl_label = 'Import PMD'
859
860         # List of operator properties, the attributes will be assigned
861         # to the class instance from the operator settings before calling.
862
863         path = StringProperty(
864                 name="File Path", 
865                 description="File path used for importing the PMD file", 
866                 maxlen= 1024, default= "")
867         filename = StringProperty(
868                 name="File Name", 
869                 description="Name of the file.")
870         directory = StringProperty(
871                 name="Directory", 
872                 description="Directory of the file.")
873
874         def execute(self, context):
875             execute_25(self.properties.path, context.scene)
876             return 'FINISHED'
877
878         def invoke(self, context, event):
879             wm = context.manager
880             wm.add_fileselect(self)
881             return 'RUNNING_MODAL'
882
883     # register menu
884     def menu_func(self, context): 
885         self.layout.operator(IMPORT_OT_pmd.bl_idname, 
886                 text="MikuMikuDance model (.pmd)")
887
888     def register():
889         bpy.types.register(IMPORT_OT_pmd)
890         bpy.types.INFO_MT_file_import.append(menu_func)
891
892     def unregister():
893         bpy.types.unregister(IMPORT_OT_pmd)
894         bpy.types.INFO_MT_file_import.remove(menu_func)
895
896     if __name__=="__main__":
897         register()
898