OSDN Git Service

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