OSDN Git Service

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