OSDN Git Service

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