OSDN Git Service

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