OSDN Git Service

3f7220a3a782325100aae800f140dd78688bb400
[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.1"
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 """
28
29 MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
30
31
32 ###############################################################################
33 # import
34 ###############################################################################
35 import os
36 import sys
37 import re
38 import math
39
40 # C extension
41 from meshio import pmd, englishmap
42
43 def isBlender24():
44     return sys.version_info[0]<3
45
46 if isBlender24():
47     # for 2.4
48     import Blender
49     from Blender import Mathutils
50     import bpy
51
52     # wrapper
53     import bl24 as bl
54 else:
55     # for 2.5
56     import bpy
57     from bpy.props import *
58     import mathutils
59
60     # wrapper
61     import bl25 as bl
62
63
64 ###############################################################################
65 # progress bar
66 ###############################################################################
67 def progress_start(base):
68     global progressBar
69     progressBar=bl.ProgressBar(base)
70
71 def progress_finish():
72     global progressBar
73     progressBar.finish()
74
75 def progress_print(message, progress=0.05):
76     global progressBar
77     progressBar.advance(message, progress)
78
79 def progress_set(message, progress):
80     global progressBar
81     progressBar.set(message, progress)
82
83
84 if isBlender24():
85     # functions
86     def convert_coord(pos):
87         """
88         Left handed y-up to Right handed z-up
89         """
90         return (pos.x, pos.z, pos.y)
91
92
93     def convert_uv(uv):
94         return (uv.x, 1.0 - uv.y)
95
96
97     def get_bone_name(l, index):
98         name=englishmap.getEnglishBoneName(l.bones[index].getName())
99         return name if name else l.bones[index].getName().encode(bl.INTERNAL_ENCODING)
100
101
102     def createMaterial():
103         """
104         create default materil 
105         """
106         material=Blender.Material.New()
107         material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
108         material.setRef(1)
109         material.diffuseSize = 3.14/2
110         material.setDiffuseSmooth(0)
111         material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
112         material.setSpecSize(0)
113         material.setSpec(0)
114         return material
115
116
117     def importMesh(scene, l, tex_dir):
118         """
119         @param l[in] mmd.PMDLoader
120         @param filename[in]
121         """
122
123         ############################################################
124         # shpaeキーで使われるマテリアル優先的に前に並べる
125         ############################################################
126         # shapeキーで使われる頂点インデックスを集める
127         shape_key_used_vertices=set()
128         if len(l.morph_list)>0:
129             # base 
130             base=None
131             for s in l.morph_list:
132                 if s.type!=0:
133                     continue
134                 base=s
135                 break
136             assert(base)
137
138             for index in base.indices:
139                 shape_key_used_vertices.add(index)
140
141         # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
142         def isMaterialUsedInShape(offset, m):
143             for i in xrange(offset, offset+m.vertex_count): 
144                 if l.indices[i] in shape_key_used_vertices:
145                     return True
146
147         # shapeキーで使われるマテリアルを記録する
148         shape_key_materials=set()
149         # 各マテリアルの開始頂点インデックスを記録する
150         face_map={}
151         face_count=0
152         for i, m in enumerate(l.materials):
153             face_map[i]=face_count
154             if isMaterialUsedInShape(face_count, m):
155                 shape_key_materials.add(i)
156             face_count+=m.vertex_count
157
158         # list化
159         material_order=list(shape_key_materials)
160
161         # shapeキーに使われていないマテリアルを後ろに追加
162         for i in range(len(l.materials)):
163             if not i in material_order:
164                 material_order.append(i)
165
166         # マテリアル16個ごとに分割したメッシュを作成する
167         material_offset=0
168         mesh_objects=[]
169         while material_offset<len(l.materials):
170             # create mesh
171             mesh = Blender.Mesh.New()
172             mesh.vertexUV = 1
173             # create object
174             obj = scene.objects.new(mesh)
175             obj.layers = [1]
176             mesh_objects.append(obj)
177
178             # shapeキーで使われる順に並べなおしたマテリアル16個分の
179             # メッシュを作成する
180             vertex_map=import16MaerialAndMesh(
181                     mesh, l, 
182                     material_order[material_offset:material_offset+16], 
183                     face_map, tex_dir)
184
185             # crete shape key
186             importShape(obj, l, vertex_map)
187
188             mesh.update()
189             material_offset+=16
190
191         return mesh_objects
192
193
194     def import16MaerialAndMesh(mesh, l, material_order, face_map, tex_dir):
195         ############################################################
196         # material
197         ############################################################
198         progress_print('create materials')
199         mesh_material_map={}
200         materials=[]
201         index=0
202         for material_index in material_order:
203             try:
204                 m=l.materials[material_index]
205                 mesh_material_map[material_index]=index
206             except KeyError:
207                 break
208
209             material=createMaterial()
210             material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
211             material.setAlpha(m.diffuse.a)
212             material.setSpec(m.shinness*0.1)
213             material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
214             material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
215             material.enableSSS=True if m.flag==1 else False
216             # set texture
217             if m.getTexture()!='':
218                 tex_file=re.compile('\*.*.spa$').sub('', m.getTexture())
219                 tex_path = os.path.join(tex_dir, tex_file).encode(
220                         bl.INTERNAL_ENCODING)
221                 tex = Blender.Texture.New()
222                 tex.setType("Image")
223                 try:
224                     tex.image = Blender.Image.Load(tex_path)
225                     material.setTexture(0, tex)
226                     material.getTextures()[0].texco = Blender.Texture.TexCo.UV
227                 except IOError:
228                     print(material.name, "fail to load", tex_path)
229             materials.append(material)
230             # lookup table for assign
231             index+=1
232         mesh.materials=materials
233
234         ############################################################
235         # vertex
236         ############################################################
237         progress_print('create vertices')
238         # create vertices
239         vertex_groups={}
240         vertices=[]
241         for v in l.each_vertex():
242             vertices.append(convert_coord(v.pos))
243             vertex_groups[v.bone0]=True
244             vertex_groups[v.bone1]=True
245         mesh.verts.extend(vertices)
246
247         # create vertex group
248         for i in vertex_groups.keys():
249             mesh.addVertGroup(get_bone_name(l, i))
250
251         # vertex params
252         for i, v, mvert in zip(xrange(len(l.vertices)), l.each_vertex(), mesh.verts):
253             mvert.no=Mathutils.Vector(*convert_coord(v.normal))
254             mvert.uvco=convert_uv(v.uv)
255             w1=float(v.weight0)/100.0
256             w2=1.0-w1
257             mesh.assignVertsToGroup(get_bone_name(l, v.bone0), [i], w1, 
258                     Blender.Mesh.AssignModes.ADD)
259             mesh.assignVertsToGroup(get_bone_name(l, v.bone1), [i], w2, 
260                     Blender.Mesh.AssignModes.ADD)    
261
262         ############################################################
263         # face
264         ############################################################
265         progress_print('create faces')
266         # create faces
267         mesh_face_indices=[]
268         mesh_face_materials=[]
269         used_vertices=set()
270
271         def degenerate(i0, i1, i2):
272             return i0==i1 or i1==i2 or i2==i0
273
274         for material_index in material_order:
275             face_offset=face_map[material_index]
276             m=l.materials[material_index]
277             material_faces=l.indices[face_offset:face_offset+m.vertex_count]
278             for j in xrange(0, len(material_faces), 3):
279                 i0=material_faces[j]
280                 i1=material_faces[j+1]
281                 i2=material_faces[j+2]
282                 triangle=[i0, i1, i2]
283                 if degenerate(*triangle):
284                     continue
285                 mesh_face_indices.append(triangle)
286                 mesh_face_materials.append(material_index)
287                 used_vertices.add(i0)
288                 used_vertices.add(i1)
289                 used_vertices.add(i2)
290
291         mesh.faces.extend(mesh_face_indices, ignoreDups=True)
292
293         # face params
294         used_map={}
295         mesh.addUVLayer('NewUV')
296         for face, material_index in zip(mesh.faces, mesh_face_materials):
297             try:
298                 index=mesh_material_map[material_index]
299             except KeyError as message:
300                 print(message, mesh_material_map, m)
301                 assert(False)
302             face.mat=index
303             material=mesh.materials[index]
304             texture=material.getTextures()[0]
305             used_map[index]=True
306             if texture:
307                 face.image=texture.tex.image
308                 texture.tex.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
309                 face.uv=[face.verts[0].uvco, face.verts[1].uvco, face.verts[2].uvco]
310             # set smooth
311             face.smooth = 1
312         # flip
313         mesh.flipNormals()
314
315         ############################################################
316         # clean up not used vertices
317         ############################################################
318         progress_print('clean up vertices not used')
319         remove_vertices=[]
320         vertex_map={}
321         for i, v in enumerate(l.each_vertex()):
322             if i in used_vertices:
323                 vertex_map[i]=len(vertex_map)
324             else:
325                 remove_vertices.append(i)
326         mesh.verts.delete(remove_vertices)
327
328         progress_print('%s created' % mesh.name)
329         return vertex_map
330
331
332     class Builder(object):
333         def __init__(self):
334             self.boneMap={}
335
336         def build(self, armature, bones):
337             for b in bones:
338                 if not b.parent:
339                     self.__build(armature, b, None, None)
340             armature.update()
341
342         def __build(self, armature, b, p, parent):
343             name=englishmap.getEnglishBoneName(b.getName())
344             if not name:
345                 name=b.getName().encode(bl.INTERNAL_ENCODING)
346             self.boneMap[name]=b
347
348             bone=Blender.Armature.Editbone()
349             bone.name=name
350             armature.bones[name]=bone
351
352             if b.tail_index==0:
353                 # 先端
354                 assert(b.type==6 or b.type==7)
355                 bone.head = Mathutils.Vector(*convert_coord(b.pos))
356                 bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
357                 assert(parent)
358                 bone.parent=parent
359                 if bone.name=="center_t":
360                     # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
361                     parent.tail=parent.head+Mathutils.Vector(0, 1, 0)
362                     bone.head=parent.tail
363                     bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
364                 else:
365                     assert(parent.tail==bone.head)
366                 bone.options=[Blender.Armature.CONNECTED]
367                 # armature layer 2
368                 bone.layerMask = (1<<1)
369             else:
370                 bone.head = Mathutils.Vector(*convert_coord(b.pos))
371                 bone.tail = Mathutils.Vector(*convert_coord(b.tail))
372                 if parent:
373                     bone.parent=parent
374                     if parent.tail==bone.head:
375                         bone.options=[Blender.Armature.CONNECTED]
376
377             if bone.head==bone.tail:
378                 bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
379
380             for c in b.children:
381                 self.__build(armature, c, b, bone)
382
383
384     def importArmature(scene, l):
385         # create armature
386         armature = Blender.Armature.New()
387         # link to object
388         armature_object = scene.objects.new(armature)
389         # create action
390         act = Blender.Armature.NLA.NewAction()
391         act.setActive(armature_object)
392         # set XRAY
393         armature_object.drawMode = (
394                 armature_object.drawMode | Blender.Object.DrawModes.XRAY)
395         # armature settings
396         armature.drawType = Blender.Armature.OCTAHEDRON
397         armature.drawNames=True
398         armature.envelopes = False
399         armature.vertexGroups = True
400         armature.mirrorEdit = True
401
402         # create armature
403         armature.makeEditable()
404
405         ############################################################
406         # build bone
407         ############################################################
408         builder=Builder()
409         builder.build(armature, l.bones)
410
411         ############################################################
412         # IK
413         ############################################################
414         pose = armature_object.getPose()
415         cSetting = Blender.Constraint.Settings
416         for ik in l.ik_list:
417             # IKtarget->parent(=IK).name
418             target=l.bones[ik.target]
419             name = englishmap.getEnglishBoneName(target.getName())
420             p_bone = pose.bones[name]
421             if not p_bone:
422                 print('not found', name)
423                 continue
424             if len(ik.children) >= 16:
425                 print('over MAX_CHAINLEN', ik, len(ik.children))
426                 continue
427             # IK solver
428             ik_solver = p_bone.constraints.append(Blender.Constraint.Type.IKSOLVER)
429             ik_solver[cSetting.CHAINLEN]=len(ik.children)
430             ik_solver[cSetting.TARGET]=armature_object
431             ik_solver[cSetting.USETIP]=False
432
433             effector_name=englishmap.getEnglishBoneName(
434                     l.bones[ik.index].getName())
435             if not effector_name:
436                 effector_name=l.bones[ik.index].getName()
437
438             ik_solver[cSetting.BONE]=effector_name
439             #ik_solver.influence=ik.weight
440             # not used. place folder when export.
441             ik_solver[cSetting.ROTWEIGHT]=ik.weight
442             ik_solver[cSetting.ITERATIONS]=ik.iterations * 10
443
444         armature.makeEditable()
445         armature.update()
446
447         return armature_object
448         
449
450     def importShape(obj, l, vertex_map):
451         if len(l.morph_list)==0:
452             return
453         obj.pinShape=True
454         mesh=obj.getData(mesh=True)
455
456         # find base 
457         base=None
458         for s in l.morph_list:
459             if s.type==0:
460                 base=s
461
462                 # create vertex group
463                 mesh.addVertGroup(MMD_SHAPE_GROUP_NAME)
464                 indices=[]
465                 hasShape=False
466                 for i in s.indices:
467                     if i in vertex_map:
468                         hasShape=True
469                         indices.append(vertex_map[i])
470                 mesh.assignVertsToGroup(MMD_SHAPE_GROUP_NAME, indices, 0, 
471                         Blender.Mesh.AssignModes.ADD)
472                 if not hasShape:
473                     return
474
475                 # create base key
476                 mesh.insertKey()
477                 assert(len(mesh.key.blocks)==1)
478                 baseShapeIndex=0
479                 baseShapeBlock=mesh.key.blocks[baseShapeIndex]
480                 baseShapeBlock.name='Basis'
481                 obj.activeShape=baseShapeIndex
482                 mesh.update()
483                 break
484
485         assert(base)
486
487         # each skin
488         for s in l.morph_list:
489             if s.name==base.name:
490                 continue
491
492             for index, offset in zip(s.indices, s.pos_list):
493                 try:
494                     vertex_index=vertex_map[base.indices[index]]
495                     v=mesh.verts[vertex_index].co
496                     offset=convert_coord(offset)
497                     v[0]+=offset[0]
498                     v[1]+=offset[1]
499                     v[2]+=offset[2]
500                 except IndexErrora as msg:
501                     print(msg)
502                     print(index, len(base.indices), len(vertex_map))
503                     print(len(mesh.verts))
504                     print(base.indices[index])
505                     print(vertex_index)
506                     break
507                 except KeyError:
508                     #print 'this mesh not has shape vertices'
509                     break
510
511             # get skin name
512             name=englishmap.getEnglishSkinName(s.getName())
513             if not name:
514                 name=s.getName().encode(bl.INTERNAL_ENCODING)
515                 print(name)
516
517             # create shapekey block
518             mesh.insertKey()
519             shapeIndex=len(mesh.key.blocks)-1
520             keyBlock=mesh.key.blocks[shapeIndex]
521             keyBlock.name=name
522
523             # copy vertex to shape key
524             mesh.update()
525             
526             # restore
527             for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
528                 mv.co[0] = v[0]
529                 mv.co[1] = v[1]
530                 mv.co[2] = v[2]
531             mesh.update()
532
533         # select base shape
534         obj.activeShape=baseShapeIndex
535
536 else:
537     # for 2.5
538     def to_radian(degree):
539         return math.pi * degree / 180
540
541
542     def convert_coord(pos):
543         """
544         Left handed y-up to Right handed z-up
545         """
546         return (pos.x, pos.z, pos.y)
547
548
549     def convert_uv(uv):
550         return (uv.x, 1.0 - uv.y)
551
552
553     def getBoneName(bone):
554         name = englishmap.getEnglishBoneName(bone.getName())
555         return name if name else bone.getName()
556
557
558     def create_texture(directory, texture_name):
559         texture=bpy.data.textures.new(texture_name)
560         texture.type='IMAGE'
561         texture=texture.recast_type()
562         texturePath=os.path.join(directory, texture_name)
563         print('create_texture', texturePath)
564         image=bpy.data.images.load(texturePath)
565         texture.image=image
566         texture.mipmap = True
567         texture.interpolation = True
568         texture.use_alpha = True
569         return texture
570
571
572     def createMaterial():
573         """
574         create default materil 
575         """
576         material = bpy.data.materials.new("Material")
577         material.diffuse_shader='TOON'
578         material.specular_shader='TOON'
579         # temporary
580         material.emit=1.0
581         return material
582
583
584     def importMesh(scene, l, tex_dir):
585         """
586         @param l[in] mmd.PMDLoader
587         @param filename[in]
588         """
589
590         ############################################################
591         # shpaeキーで使われるマテリアル優先的に前に並べる
592         ############################################################
593         # shapeキーで使われる頂点インデックスを集める
594         shape_key_used_vertices=set()
595         if len(l.morph_list)>0:
596             # base 
597             base=None
598             for s in l.morph_list:
599                 if s.type!=0:
600                     continue
601                 base=s
602                 break
603             assert(base)
604
605             for index in base.indices:
606                 shape_key_used_vertices.add(index)
607
608         # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
609         def isMaterialUsedInShape(offset, m):
610             for i in range(offset, offset+m.vertex_count): 
611                 if l.indices[i] in shape_key_used_vertices:
612                     return True
613
614         # shapeキーで使われるマテリアルを記録する
615         shape_key_materials=set()
616         # 各マテリアルの開始頂点インデックスを記録する
617         face_map={}
618         face_count=0
619         for i, m in enumerate(l.materials):
620             face_map[i]=face_count
621             if isMaterialUsedInShape(face_count, m):
622                 shape_key_materials.add(i)
623             face_count+=m.vertex_count
624
625         # shapeキーで使われるマテリアルを前に並べるインデックスマップを作る
626         material_map={}
627         used_index=0
628         not_used_index=len(shape_key_materials)
629         for i, m in enumerate(l.materials):
630             if i in shape_key_materials:
631                 material_map[i]=used_index
632                 used_index+=1
633             else:
634                 material_map[i]=not_used_index
635                 not_used_index+=1
636
637         # マテリアル16個ごとに分割したメッシュを作成する
638         material_index=0
639         mesh_objects=[]
640         while material_index<len(l.materials):
641             # shapeキーで使われる順に並べなおしたマテリアル16個分の
642             # メッシュを作成する
643             meshObject, used_vertices=import16MaerialAndMesh(l, 
644                     material_index, material_map, face_map, tex_dir)
645             scene.objects.link(meshObject)
646             scene.update()
647             mesh_objects.append(meshObject)
648
649             # enter Edit Mode
650             bpy.ops.object.select_all(action='DESELECT')
651             meshObject.selected=True
652             scene.objects.active=meshObject
653             bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
654      
655             # crete shape key
656             importShape(meshObject, l)
657
658             ############################################################
659             # clean up not used vertices
660             ############################################################
661             #progress_print('clean up vertices not used')
662             vertex_map={}
663             mesh=meshObject.data
664             for i, v in enumerate(mesh.verts):
665                 if i in used_vertices:
666                     vertex_map[i]=len(vertex_map)
667                     v.selected=False
668                 else:
669                     v.selected=True
670                     assert(mesh.verts[i].selected)
671             bpy.ops.object.mode_set(mode='EDIT', toggle=False)
672             print("%d vertices selected" % mesh.total_vert_sel)
673             print("used %d/%d" % (len(vertex_map), len(mesh.verts)))
674             bpy.ops.mesh.delete(type='VERT')
675
676             ############################################################
677             # flip face
678             ############################################################
679             bpy.ops.mesh.select_all(action='SELECT')
680             bpy.ops.mesh.flip_normals()
681             bpy.ops.mesh.select_all(action='DESELECT')
682
683             # exit Edit Mode
684             bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
685
686             mesh.update()
687             material_index+=16
688
689         return mesh_objects
690
691
692     def import16MaerialAndMesh(l, 
693             material_offset, material_map, face_map, tex_dir):
694         # create mesh
695         mesh=bpy.data.meshes.new("Mesh")
696
697         # create object
698         meshObject= bpy.data.objects.new("Mesh", mesh)
699         meshObject.layers[0]=True
700
701         ############################################################
702         # material
703         ############################################################
704         #progress_print('create materials')
705         mesh_material_map={}
706         materials=[]
707         textureMap={}
708         imageMap={}
709         index=0
710         for i in range(material_offset, material_offset+16):
711             try:
712                 material_index=material_map[i]
713                 m=l.materials[material_index]
714                 mesh_material_map[material_index]=index
715             except KeyError:
716                 break
717
718             material=createMaterial()
719             material.diffuse_color=([m.diffuse.r, m.diffuse.g, m.diffuse.b])
720             material.alpha=m.diffuse.a
721             material.specular_hardness=int(m.shinness)
722             material.specular_color=([m.specular.r, m.specular.g, m.specular.b])
723             material.mirror_color=([m.ambient.r, m.ambient.g, m.ambient.b])
724             texture_name=m.getTexture()
725             if texture_name!='':
726                 if texture_name in textureMap:
727                     texture=textureMap[texture_name]
728                 else:
729                     texture=create_texture(tex_dir, texture_name)
730                     textureMap[texture_name]=texture
731                     imageMap[material_index]=texture.image
732                 #material.add_texture(texture, "UV", {"COLOR", "ALPHA"})
733                 material.add_texture(texture, "UV", "COLOR")
734
735             materials.append(material)
736             mesh.add_material(material)
737             # lookup table for assign
738             index+=1
739
740         ############################################################
741         # vertex
742         ############################################################
743         #progress_print('create vertices')
744         # create vertices
745         vertex_groups={}
746         unpackedVertices=[]
747         for v in l.each_vertex():
748             unpackedVertices.extend(
749                     convert_coord(v.pos))
750             vertex_groups[v.bone0]=True
751             vertex_groups[v.bone1]=True
752
753         ############################################################
754         # face
755         ############################################################
756         #progress_print('create faces')
757         # create faces
758         mesh_face_indices=[]
759         mesh_face_materials=[]
760         used_vertices=set()
761         for i in range(material_offset, material_offset+16):
762             try:
763                 material_index=material_map[i]
764             except KeyError:
765                 break
766             face_offset=face_map[material_index]
767             m=l.materials[material_index]
768             material_faces=l.indices[face_offset:face_offset+m.vertex_count]
769             for j in range(0, len(material_faces), 3):
770                 i0=material_faces[j]
771                 i1=material_faces[j+1]
772                 i2=material_faces[j+2]
773                 if i2==0:
774                     mesh_face_indices.extend([i2, i0, i1, 0])
775                 else:
776                     mesh_face_indices.extend([i0, i1, i2, 0])
777                 mesh_face_materials.append(material_index)
778                 used_vertices.add(i0)
779                 used_vertices.add(i1)
780                 used_vertices.add(i2)
781
782         ############################################################
783         # create vertices & faces
784         ############################################################
785         mesh.add_geometry(
786                 int(len(unpackedVertices)/3), 0, int(len(mesh_face_indices)/4))
787         mesh.verts.foreach_set("co", unpackedVertices)
788         mesh.faces.foreach_set("verts_raw", mesh_face_indices)
789         assert(len(l.vertices)==len(mesh.verts))
790
791         ############################################################
792         # face params
793         ############################################################
794         used_map={}
795         mesh.add_uv_texture()
796
797         for face, uv_face, material_index in zip(mesh.faces, 
798                 mesh.uv_textures[0].data,
799                 mesh_face_materials,
800                 ):
801             try:
802                 index=mesh_material_map[material_index]
803             except KeyError as message:
804                 print(message, mesh_material_map, m)
805                 assert(False)
806             face.material_index=index
807             material=mesh.materials[index]
808             used_map[index]=True
809             if material.texture_slots[0]:
810                 #texture=material.texture_slots[0].texture
811                 #face.image=texture.image
812                 #texture.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
813                 uv=l.getUV(face.verts[0])
814                 uv_face.uv1=[uv.x, 1.0-uv.y]
815
816                 uv=l.getUV(face.verts[1])
817                 uv_face.uv2=[uv.x, 1.0-uv.y]
818
819                 uv=l.getUV(face.verts[2])
820                 uv_face.uv3=[uv.x, 1.0-uv.y]
821             if face.material_index in imageMap:
822                 uv_face.image=imageMap[face.material_index]
823                 uv_face.tex=True
824
825             # set smooth
826             face.smooth = 1
827
828         ############################################################
829         # vertex weight
830         ############################################################
831         # create vertex group
832         for i in vertex_groups.keys():
833             meshObject.add_vertex_group(getBoneName(l.bones[i]))
834
835         # vertex params
836         for i, v, mvert in zip(range(len(l.vertices)), 
837                 l.each_vertex(), mesh.verts):
838             mvert.normal=mathutils.Vector(convert_coord(v.normal))
839             #mvert.uvco=convert_uv(v.uv)
840             w1=float(v.weight0)/100.0
841             w2=1.0-w1
842
843             meshObject.add_vertex_to_group(i, 
844                     meshObject.vertex_groups[getBoneName(l.bones[v.bone0])], w1, 'ADD')
845             meshObject.add_vertex_to_group(i, 
846                     meshObject.vertex_groups[getBoneName(l.bones[v.bone1])], w2, 'ADD')
847         mesh.update()
848
849         #progress_print('%s created' % mesh.name)
850         return meshObject, used_vertices
851
852
853     def build_bone(armature, b, parent=None):
854         if b.tail_index==0:
855             return
856
857         name=getBoneName(b)
858         bone = armature.edit_bones.new(name if name else b.getName())
859         if parent:
860             bone.head = mathutils.Vector(convert_coord(b.pos))
861             bone.parent=parent
862             bone.connected=True if parent.tail==bone.head else False
863             bone.tail = mathutils.Vector(convert_coord(b.tail))
864             if bone.head==bone.tail:
865                 bone.tail=bone.head-mathutils.Vector((0, 1, 0))
866         elif b.__class__ is pmd.BONE_IK:
867             bone.head = mathutils.Vector(convert_coord(b.pos))
868             bone.tail = mathutils.Vector(convert_coord(b.tail))
869         else:
870             # center
871             tail=mathutils.Vector(convert_coord(b.pos))
872             bone.tail = tail
873             bone.head = tail-mathutils.Vector((0, 1, 0))
874
875         for child in b.children:
876             build_bone(armature, child, bone)
877
878
879     def importArmature(scene, l):
880         # create armature
881         armature = bpy.data.armatures.new('Armature')
882         # link to object
883         armature_object=bpy.data.objects.new('Armature', armature)
884         scene.objects.link(armature_object)
885         armature_object.x_ray=True
886         armature.draw_names=True
887
888         # armature settings
889         armature.drawtype='OCTAHEDRAL'
890         armature.deform_envelope=False
891         armature.deform_vertexgroups=True
892         armature.x_axis_mirror=True
893
894         # create action
895         #act = Blender.Armature.NLA.NewAction()
896         #act.setActive(armature_object)
897
898         # select only armature object and set edit mode
899         scene.objects.active=armature_object
900         bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
901         bpy.ops.object.mode_set(mode='EDIT', toggle=False)
902
903         # create armature
904         for b in l.bones:
905             if not b.parent:
906                 build_bone(armature, b)
907
908         bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
909         bpy.ops.object.select_all(action='DESELECT')
910
911         ############################################################
912         # IK
913         ############################################################
914         pose = armature_object.pose
915         for ik in l.ik_list:
916             effector=l.bones[ik.target]
917             parent=l.bones[effector.parent_index]
918             name=getBoneName(parent)
919             p_bone = pose.bones[name]
920             if not p_bone:
921                 print('not found', name)
922                 continue
923             if len(ik.children) >= 16:
924                 print('over MAX_CHAINLEN', ik, len(ik.children))
925                 continue
926             # IK
927             ik_const = p_bone.constraints.new('IK')
928             ik_const.chain_length=len(ik.children)
929             ik_const.target=armature_object
930             ik_const.subtarget=getBoneName(l.bones[ik.index])
931             # ROT
932             rot_const = p_bone.constraints.new('LIMIT_ROTATION')
933             rot_const.influence = ik.weight
934             rot_const.owner_space = 'LOCAL'
935             rot_const.use_limit_x=True
936             rot_const.use_limit_z=True
937             rot_const.minimum_x=to_radian(ik.iterations)
938             rot_const.maximum_x=to_radian(180)
939             rot_const.minimum_z=to_radian(180 - ik.iterations)
940             rot_const.maximum_z=to_radian(0)
941
942         return armature_object
943         
944
945     def importShape(meshObject, l):
946         if len(l.morph_list)==0:
947             return
948
949         # base 
950         base=None
951         for s in l.morph_list:
952             if s.type!=0:
953                 continue
954             base=s
955             break
956         assert(base)
957
958         # create base key
959         baseblock=meshObject.add_shape_key("Basis")
960
961         # mesh
962         mesh=meshObject.data
963
964         # each skin
965         for s in l.morph_list:
966             if s.getName()==base.name:
967                 # skip base
968                 continue
969
970             # restore
971             #for v, base_pos in zip(mesh.verts, baseblock.data):
972             #    v.co=base_pos.co
973             #mesh.update()
974
975             # name
976             name=englishmap.getEnglishSkinName(s.getName())
977             if not name:
978                 name=s.getName()
979             new_shape_key=meshObject.add_shape_key(name)
980             #new_shape_key.value=1.0
981
982             # morph
983             for i, offset in zip(s.indices, s.pos_list):
984                 try:
985                     vertex_index=base.indices[i]
986                     new_shape_key.data[vertex_index].co=[p+o for p, o in zip(
987                         mesh.verts[vertex_index].co, convert_coord(offset))]
988                 except IndexError as msg:
989                     print(IndexError, msg)
990                     print(i, len(base.indices))
991                     print(vertex_index, len(mesh.verts))
992                     print(base.indices[i])
993                     break
994                 except KeyError:
995                     #print 'this mesh not has shape vertices'
996                     break
997             
998             # set ipo curve
999             #icu=ipo.addCurve(name)
1000             #icu.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
1001             #icu.append( (0.0, 0.0) )
1002
1003    
1004 def __execute(filename, scene):
1005     """
1006     load pmd file to context.
1007     """
1008     # load pmd
1009     progress_set('load %s' % filename, 0.0)
1010
1011     io=pmd.IO()
1012     if not io.read(filename):
1013         print("fail to load %s" % filename)
1014         return
1015     progress_set('loaded %s' % filename, 0.1)
1016
1017     # create root object
1018     root=bl.createEmptyObject(scene, 
1019             io.english_name if len(io.english_name)>0 else io.getName().encode(bl.INTERNAL_ENCODING))
1020
1021     # import mesh
1022     mesh_objects=importMesh(scene, io, os.path.dirname(filename))
1023     for o in mesh_objects:
1024         bl.objectMakeParent(root, o)
1025
1026     # import armature
1027     armature_object=importArmature(scene, io)
1028     if armature_object:
1029         bl.objectMakeParent(root, armature_object)
1030         armature = bl.objectGetData(armature_object) 
1031
1032         # add armature modifier
1033         for o in mesh_objects:
1034             bl.objectAddArmatureModifier(o, armature_object)
1035
1036         # Limitation
1037         for n, b in bl.objectGetPose(armature_object).bones.items():
1038             bl.poseBoneLimit(n, b)
1039
1040     # select objects
1041     bl.objectSelect(root)
1042     for o in mesh_objects:
1043         bl.objectSelect(o)
1044     bl.objectSelect(armature_object)
1045  
1046
1047 if isBlender24():
1048     # for 2.4
1049     def execute_24(filename):
1050         """
1051         @param filename
1052         """
1053         filename=filename.decode(bl.INTERNAL_ENCODING)
1054         print(bl.INTERNAL_ENCODING, bl.FS_ENCODING)
1055
1056         # set object mode
1057         mode_edit = Blender.Window.EditMode() 
1058         if mode_edit: 
1059             Blender.Window.EditMode(0)
1060             
1061         progress_start('pmd_import')
1062         scene = bpy.data.scenes.active
1063         __execute(filename, scene)
1064         scene.update(0)
1065         progress_finish()
1066
1067         # restore edit mode
1068         if mode_edit: 
1069             Blender.Window.EditMode(1)
1070         Blender.Window.RedrawAll()
1071
1072     Blender.Window.FileSelector(
1073             execute_24, 
1074             'Import PMD file', 
1075             Blender.sys.makename(ext='.pmd'))
1076
1077 else:
1078     # for 2.5
1079     def execute_25(*args):
1080         progress_start('pmd_import')
1081         __execute(*args)
1082         progress_finish()
1083
1084     # import operator
1085     class IMPORT_OT_pmd(bpy.types.Operator):
1086         bl_idname = "import_scene.pmd"
1087         bl_label = 'Import PMD'
1088
1089         # List of operator properties, the attributes will be assigned
1090         # to the class instance from the operator settings before calling.
1091
1092         path = StringProperty(
1093                 name="File Path", 
1094                 description="File path used for importing the PMD file", 
1095                 maxlen= 1024, default= "")
1096         filename = StringProperty(
1097                 name="File Name", 
1098                 description="Name of the file.")
1099         directory = StringProperty(
1100                 name="Directory", 
1101                 description="Directory of the file.")
1102
1103         def execute(self, context):
1104             execute_25(self.properties.path, context.scene)
1105             return 'FINISHED'
1106
1107         def invoke(self, context, event):
1108             wm = context.manager
1109             wm.add_fileselect(self)
1110             return 'RUNNING_MODAL'
1111
1112     # register menu
1113     def menu_func(self, context): 
1114         self.layout.operator(IMPORT_OT_pmd.bl_idname, 
1115                 text="MikuMikuDance model (.pmd)")
1116
1117     def register():
1118         bpy.types.register(IMPORT_OT_pmd)
1119         bpy.types.INFO_MT_file_import.append(menu_func)
1120
1121     def unregister():
1122         bpy.types.unregister(IMPORT_OT_pmd)
1123         bpy.types.INFO_MT_file_import.remove(menu_func)
1124
1125     if __name__=="__main__":
1126         register()
1127