OSDN Git Service

implement vertex attributes and face attributes.
[meshio/pymeshio.git] / blender26-meshio / import_pmx.py
1 # coding: utf-8
2 """
3 PMXモデルをインポートする。
4
5 1マテリアル、1オブジェクトで作成する。
6 """
7 import os
8 from . import bl
9 from .pymeshio import pmx
10 from .pymeshio.pmx import reader
11
12
13 def convert_coord(pos):
14     """
15     Left handed y-up to Right handed z-up
16     """
17     return (pos.x, pos.z, pos.y)
18
19 def __create_a_material(m, name, textures_and_images):
20     """
21     materialを作成する
22
23     :Params:
24         m
25             pymeshio.pmx.Material
26         name
27             material name
28         textures_and_images
29             list of (texture, image)
30     """
31     material = bl.material.create(name)
32     # diffuse
33     material.diffuse_shader='FRESNEL'
34     material.diffuse_color=[m.diffuse_color.r, m.diffuse_color.g, m.diffuse_color.b]
35     material.alpha=m.alpha
36     # specular
37     material.specular_shader='TOON'
38     material.specular_color=[m.specular_color.r, m.specular_color.g, m.specular_color.b]
39     material.specular_toon_size=int(m.specular_factor)
40     # ambient
41     material.mirror_color=[m.ambient_color.r, m.ambient_color.g, m.ambient_color.b]
42     # todo
43     # flag
44     # edge_color
45     # edge_size
46     # other
47     material.preview_render_type='FLAT'
48     material.use_transparency=True
49     # texture
50     if m.texture_index!=-1:
51         bl.material.addTexture(material, textures_and_images[m.texture_index][0])
52     return material
53
54 def __create_armature(bones, display_slots):
55     """
56     armatureを作成する
57
58     :Params:
59         bones
60             list of pymeshio.pmx.Bone
61     """
62     armature, armature_object=bl.armature.create()
63
64     # create bones
65     bl.armature.makeEditable(armature_object)
66     def create_bone(b):
67         bone=bl.armature.createBone(armature, b.name)
68         # bone position
69         bone.head=bl.createVector(*convert_coord(b.position))
70         if not b.getConnectionFlag():
71             bone.tail=bl.createVector(*convert_coord(b.position))
72         elif not b.getVisibleFlag():
73             bone.tail=bone.head+bl.createVector(0, 1, 0)
74
75         return bone
76     bl_bones=[create_bone(b) for b in bones]
77
78     # build skeleton
79     for b, bone in zip(bones, bl_bones):
80         assert(b.name==bone.name)
81         if b.parent_index!=-1:
82             print("%s -> %s" % (bones[b.parent_index].name, b.name))
83             parent_bone=bl_bones[b.parent_index]
84             bone.parent=parent_bone
85             if b.getConnectionFlag() and b.tail_index!=-1:
86                 assert(b.tail_index!=0)
87                 tail_bone=bl_bones[b.tail_index]
88                 bone.tail=tail_bone.head
89                 bl.bone.setConnected(tail_bone)
90         else:
91             print("no parent %s" % b.name)
92     bl.armature.update(armature)
93
94     # create ik constraint
95     bl.enterObjectMode()
96     pose = bl.object.getPose(armature_object)
97     for b, bone in zip(bones, bl_bones):
98         if b.getIkFlag():
99             ik=b.ik
100             assert(len(ik.link)<16)
101             p_bone=pose.bones[bones[ik.target_index].name]
102             assert(p_bone)
103             constraint=bl.armature.createIkConstraint(
104                     armature_object, p_bone, bone.name,
105                     ik.link, ik.limit_radian, ik.loop)
106     bl.armature.makeEditable(armature_object)
107     bl.armature.update(armature)
108
109     # create bone group
110     bl.enterObjectMode()
111     pose = bl.object.getPose(armature_object)
112     for i, ds in enumerate(display_slots):
113         print(ds)
114         g=bl.object.createBoneGroup(armature_object, ds.name, "THEME%02d" % (i+1))
115         for t, index in ds.references:
116             if t==0:
117                 name=bones[index].name
118                 try:
119                     pose.bones[name].bone_group=g
120                 except KeyError as e:
121                     print("pose %s is not found" % name)
122
123     bl.enterObjectMode()
124     return armature_object
125
126 def _execute(filepath):
127     """
128     importerr 本体
129     """
130     bl.progress_set('load %s' % filepath, 0.0)
131     print(filepath)
132
133     model=reader.read_from_file(filepath)
134     if not model:
135         print("fail to load %s" % filepath)
136         return
137     print(model)
138     bl.progress_set('loaded', 0.1)
139
140     # メッシュをまとめるエンプティオブジェクト
141     model_name=model.english_name
142     if len(model_name)==0:
143         model_name=os.path.basename(filepath)
144     root_object=bl.object.createEmpty(model_name)
145     root_object[bl.MMD_MB_NAME]=model.name
146     root_object[bl.MMD_MB_COMMENT]=model.comment
147     root_object[bl.MMD_COMMENT]=model.english_comment
148
149     # armatureを作る
150     armature_object=__create_armature(model.bones, model.display_slots)
151     if armature_object:
152         bl.object.makeParent(root_object, armature_object)
153
154     # テクスチャを作る
155     texture_dir=os.path.dirname(filepath)
156     textures_and_images=[bl.texture.create(os.path.join(texture_dir, t))
157             for t in model.textures]
158     print(textures_and_images)
159
160     index_generator=(i for i in model.indices)
161     # 頂点配列。(Left handed y-up) to (Right handed z-up)
162     vertices=[convert_coord(pos)
163             for pos in (v.position for v in model.vertices)]
164
165     # マテリアル毎にメッシュを作成する
166     for i, m in enumerate(model.materials):
167         print(m.name)
168         # material作成
169         material=__create_a_material(m, m.name, textures_and_images)
170         # object名はutf-8で21byteまで
171         mesh, mesh_object=bl.mesh.create("object:{0:02}".format(i))
172         bl.mesh.addMaterial(mesh, material)
173         # activate object
174         bl.object.deselectAll()
175         bl.object.activate(mesh_object)
176         bl.object.makeParent(root_object, mesh_object)
177         # vertices & faces
178         indices=[next(index_generator)
179                     for _ in range(m.vertex_count)]
180         bl.mesh.addGeometry(mesh, vertices,
181                 [(indices[i], indices[i+1], indices[i+2])
182                     for i in range(0, len(indices), 3)])
183         assert(len(model.vertices), len(mesh.vertices))
184
185         # assign material
186         bl.mesh.addUV(mesh)
187         hasTexture=bl.material.hasTexture(material)
188         if hasTexture:
189             index_gen=(i for i in indices)
190             image=(textures_and_images.get[m.texture_index] 
191                     if m.texture_index in textures_and_images
192                     else None)
193         for i, face in enumerate(mesh.faces):
194             bl.face.setMaterial(face, 0)
195             if hasTexture:
196                 uv0=model.vertices[next(index_gen)].uv
197                 uv1=model.vertices[next(index_gen)].uv
198                 uv2=model.vertices[next(index_gen)].uv
199                 bl.mesh.setFaceUV(mesh, i, face, [# fix uv
200                     (uv0.x, 1.0-uv0.y),
201                     (uv1.x, 1.0-uv1.y),
202                     (uv2.x, 1.0-uv2.y)
203                     ],
204                     image)
205
206         if armature_object:
207             # armature modifirer
208             bl.modifier.addArmature(mesh_object, armature_object)
209             # set vertex attributes(normal, bone weights)
210             bl.mesh.useVertexUV(mesh)
211             for i, (v,  mvert) in enumerate(zip(model.vertices, mesh.vertices)):
212                 bl.vertex.setNormal(mvert, convert_coord(v.normal))
213                 if isinstance(v.deform, pmx.Bdef1):
214                     bl.object.assignVertexGroup(mesh_object,
215                             model.bones[v.deform.index0].name, i, 1.0)
216                 elif isinstance(v.deform, pmx.Bdef2):
217                     bl.object.assignVertexGroup(mesh_object,
218                             model.bones[v.deform.index0].name, i, v.deform.weight0)
219                     bl.object.assignVertexGroup(mesh_object,
220                             model.bones[v.deform.index1].name, i, 1.0-v.deform.weight0)
221                 else:
222                     raise Exception("unknown deform: %s" % v.deform)
223
224     return {'FINISHED'}
225