OSDN Git Service

7493bd0808eee602fbf7f5a54718ec5c7fad4ddd
[meshio/pymeshio.git] / blender26-meshio / export_pmx.py
1 # coding: utf-8
2
3 import io
4 from . import bl
5 from . import oneskinmesh
6 from .pymeshio import pmx
7 from .pymeshio import common
8 from .pymeshio.pmx import writer
9
10
11 def create_pmx(ex):
12     model=pmx.Model()
13     model.name=ex.name
14     model.comment=ex.comment
15
16     def get_deform(b0, b1, weight):
17         print(b0, b1, weight)
18         if b0==-1:
19             return pmx.Bdef1(b1, weight)
20         elif b1==-1:
21             return pmx.Bdef1(b0, weight)
22         else:
23             return pmx.Bdef2(b0, b1, weight)
24
25     model.vertices=[pmx.Vertex(
26         # convert right-handed z-up to left-handed y-up
27         common.Vector3(pos[0], pos[2], pos[1]), 
28         # convert right-handed z-up to left-handed y-up
29         common.Vector3(attribute.nx, attribute.nz, attribute.ny),
30         # reverse vertical
31         common.Vector2(attribute.u, 1.0-attribute.v),
32         get_deform(ex.skeleton.indexByName(b0), ex.skeleton.indexByName(b1), weight),
33         # edge flag, 0: enable edge, 1: not edge
34         1.0 
35         )
36         for pos, attribute, b0, b1, weight in ex.oneSkinMesh.vertexArray.zip()]
37
38     # bones
39     boneNameMap={}
40     for i, b in enumerate(self.skeleton.bones):
41
42         # name
43         boneNameMap[b.name]=i
44         v=englishmap.getUnicodeBoneName(b.name)
45         if not v:
46             v=[b.name, b.name]
47         assert(v)
48         bone=pmx.Bone(v[1])
49         bone.english_name=b.name
50
51         if len(v)>=3:
52             # has type
53             if v[2]==5:
54                 b.ik_index=self.skeleton.indexByName('eyes')
55             bone.type=v[2]
56         else:
57             bone.type=b.type
58
59         bone.parent_index=b.parent_index
60         bone.tail_index=b.tail_index
61         bone.ik_index=b.ik_index
62
63         # convert right-handed z-up to left-handed y-up
64         bone.pos.x=b.pos[0] if not near(b.pos[0], 0) else 0
65         bone.pos.y=b.pos[2] if not near(b.pos[2], 0) else 0
66         bone.pos.z=b.pos[1] if not near(b.pos[1], 0) else 0
67         
68         model.bones.append(bone)
69     return model
70
71     # IK
72     for ik in self.skeleton.ik_list:
73         solver=pmd.IK()
74         solver.index=self.skeleton.getIndex(ik.target)
75         solver.target=self.skeleton.getIndex(ik.effector)
76         solver.length=ik.length
77         b=self.skeleton.bones[ik.effector.parent_index]
78         for i in range(solver.length):
79             solver.children.append(self.skeleton.getIndex(b))
80             b=self.skeleton.bones[b.parent_index]
81         solver.iterations=ik.iterations
82         solver.weight=ik.weight
83         model.ik_list.append(solver)
84
85     # 面とマテリアル
86     vertexCount=self.oneSkinMesh.getVertexCount()
87     for material_name, indices in self.oneSkinMesh.vertexArray.each():
88         #print('material:', material_name)
89         try:
90             m=bl.material.get(material_name)
91         except KeyError as e:
92             m=DefaultMatrial()
93         def get_texture_name(texture):
94             pos=texture.replace("\\", "/").rfind("/")
95             if pos==-1:
96                 return texture
97             else:
98                 return texture[pos+1:]
99         textures=[get_texture_name(path)
100             for path in bl.material.eachEnalbeTexturePath(m)]
101         print(textures)
102         # マテリアル
103         model.materials.append(pmd.Material(
104                 # diffuse_color
105                 common.RGB(m.diffuse_color[0], m.diffuse_color[1], m.diffuse_color[2]),
106                 m.alpha,
107                 # specular_factor
108                 0 if m.specular_toon_size<1e-5 else m.specular_hardness*10,
109                 # specular_color
110                 common.RGB(m.specular_color[0], m.specular_color[1], m.specular_color[2]),
111                 # ambient_color
112                 common.RGB(m.mirror_color[0], m.mirror_color[1], m.mirror_color[2]),
113                 # flag
114                 1 if m.subsurface_scattering.use else 0,
115                 # toon
116                 0,
117                 # vertex_count
118                 len(indices),
119                 # texture
120                 ('*'.join(textures) if len(textures)>0 else "").encode('cp932')
121                 ))
122         # 面
123         for i in indices:
124             assert(i<vertexCount)
125         for i in range(0, len(indices), 3):
126             # reverse triangle
127             model.indices.append(indices[i])
128             model.indices.append(indices[i+1])
129             model.indices.append(indices[i+2])
130
131     # 表情
132     for i, m in enumerate(self.oneSkinMesh.morphList):
133         v=englishmap.getUnicodeSkinName(m.name)
134         if not v:
135             v=[m.name, m.name, 0]
136         assert(v)
137         # morph
138         morph=pmd.Morph(v[1].encode("cp932"))
139         morph.english_name=m.name.encode("cp932")
140         m.type=v[2]
141         morph.type=v[2]
142         for index, offset in m.offsets:
143             # convert right-handed z-up to left-handed y-up
144             morph.append(index, offset[0], offset[2], offset[1])
145         morph.vertex_count=len(m.offsets)
146
147     # 表情枠
148     # type==0はbase
149     for i, m in enumerate(self.oneSkinMesh.morphList):
150         if m.type==3:
151             model.morph_indices.append(i)
152     for i, m in enumerate(self.oneSkinMesh.morphList):
153         if m.type==2:
154             model.morph_indices.append(i)
155     for i, m in enumerate(self.oneSkinMesh.morphList):
156         if m.type==1:
157             model.morph_indices.append(i)
158     for i, m in enumerate(self.oneSkinMesh.morphList):
159         if m.type==4:
160             model.morph_indices.append(i)
161
162     # ボーングループ
163     for g in self.skeleton.bone_groups:
164         name=englishmap.getUnicodeBoneGroupName(g[0])
165         if not name:
166             name=g[0]
167         englishName=g[0]
168
169         model.bone_group_list.append(pmd.BoneGroup(
170                 (name+'\n').encode('cp932'),
171                 (englishName+'\n').encode('cp932')
172                 ))
173
174     # ボーングループメンバー
175     for i, b in enumerate(self.skeleton.bones):
176         if i==0:
177            continue
178         if b.type in [6, 7]:
179            continue
180         model.bone_display_list.append((i, self.skeleton.getBoneGroup(b)))
181
182     # English
183     model.english_name=self.englishName.encode('cp932')
184     model.english_comment=self.englishComment.encode('cp932')
185
186     # toon
187     toonMeshObject=None
188     for o in bl.object.each():
189         try:
190             if o.name.startswith(bl.TOON_TEXTURE_OBJECT):
191                 toonMeshObject=o
192         except:
193             p(o.name)
194         break
195     if toonMeshObject:
196         toonMesh=bl.object.getData(toonMeshObject)
197         toonMaterial=bl.mesh.getMaterial(toonMesh, 0)
198         for i in range(10):
199             t=bl.material.getTexture(toonMaterial, i)
200             if t:
201                 model.toon_textures[i]=("%s" % t.name).encode('cp932')
202             else:
203                 model.toon_textures[i]=("toon%02d.bmp" % (i+1)).encode('cp932')
204     else:
205         for i in range(10):
206             model.toon_textures[i]=("toon%02d.bmp" % (i+1)).encode('cp932')
207
208     # rigid body
209     rigidNameMap={}
210     for i, obj in enumerate(self.oneSkinMesh.rigidbodies):
211         name=obj[bl.RIGID_NAME] if bl.RIGID_NAME in obj else obj.name
212         print(name)
213         rigidNameMap[name]=i
214         boneIndex=boneNameMap[obj[bl.RIGID_BONE_NAME]]
215         if boneIndex==0:
216             boneIndex=-1
217             bone=self.skeleton.bones[0]
218         else:
219             bone=self.skeleton.bones[boneIndex]
220         if obj[bl.RIGID_SHAPE_TYPE]==0:
221             shape_type=pmd.SHAPE_SPHERE
222             shape_size=common.Vector3(obj.scale[0], 0, 0)
223         elif obj[bl.RIGID_SHAPE_TYPE]==1:
224             shape_type=pmd.SHAPE_BOX
225             shape_size=common.Vector3(obj.scale[0], obj.scale[1], obj.scale[2])
226         elif obj[bl.RIGID_SHAPE_TYPE]==2:
227             shape_type=pmd.SHAPE_CAPSULE
228             shape_size=common.Vector3(obj.scale[0], obj.scale[2], 0)
229         rigidBody=pmd.RigidBody(
230                 name.encode('cp932'), 
231                 collision_group=obj[bl.RIGID_GROUP],
232                 no_collision_group=obj[bl.RIGID_INTERSECTION_GROUP],
233                 bone_index=boneIndex,
234                 shape_position=common.Vector3(
235                     obj.location.x-bone.pos[0],
236                     obj.location.z-bone.pos[2],
237                     obj.location.y-bone.pos[1]),
238                 shape_rotation=common.Vector3(
239                     -obj.rotation_euler[0],
240                     -obj.rotation_euler[2],
241                     -obj.rotation_euler[1]),
242                 shape_type=shape_type,
243                 shape_size=shape_size,
244                 mass=obj[bl.RIGID_WEIGHT],
245                 linear_damping=obj[bl.RIGID_LINEAR_DAMPING],
246                 angular_damping=obj[bl.RIGID_ANGULAR_DAMPING],
247                 restitution=obj[bl.RIGID_RESTITUTION],
248                 friction=obj[bl.RIGID_FRICTION],
249                 mode=obj[bl.RIGID_PROCESS_TYPE]
250                 )
251         model.rigidbodies.append(rigidBody)
252
253     # constraint
254     model.joints=[pmd.Joint(
255         name=obj[bl.CONSTRAINT_NAME].encode('cp932'),
256         rigidbody_index_a=rigidNameMap[obj[bl.CONSTRAINT_A]],
257         rigidbody_index_b=rigidNameMap[obj[bl.CONSTRAINT_B]],
258         position=common.Vector3(
259             obj.location[0], 
260             obj.location[2], 
261             obj.location[1]),
262         rotation=common.Vector3(
263             -obj.rotation_euler[0], 
264             -obj.rotation_euler[2], 
265             -obj.rotation_euler[1]),
266         translation_limit_min=common.Vector3(
267             obj[bl.CONSTRAINT_POS_MIN][0],
268             obj[bl.CONSTRAINT_POS_MIN][1],
269             obj[bl.CONSTRAINT_POS_MIN][2]
270             ),
271         translation_limit_max=common.Vector3(
272             obj[bl.CONSTRAINT_POS_MAX][0],
273             obj[bl.CONSTRAINT_POS_MAX][1],
274             obj[bl.CONSTRAINT_POS_MAX][2]
275             ),
276         rotation_limit_min=common.Vector3(
277             obj[bl.CONSTRAINT_ROT_MIN][0],
278             obj[bl.CONSTRAINT_ROT_MIN][1],
279             obj[bl.CONSTRAINT_ROT_MIN][2]),
280         rotation_limit_max=common.Vector3(
281             obj[bl.CONSTRAINT_ROT_MAX][0],
282             obj[bl.CONSTRAINT_ROT_MAX][1],
283             obj[bl.CONSTRAINT_ROT_MAX][2]),
284         spring_constant_translation=common.Vector3(
285             obj[bl.CONSTRAINT_SPRING_POS][0],
286             obj[bl.CONSTRAINT_SPRING_POS][1],
287             obj[bl.CONSTRAINT_SPRING_POS][2]),
288         spring_constant_rotation=common.Vector3(
289             obj[bl.CONSTRAINT_SPRING_ROT][0],
290             obj[bl.CONSTRAINT_SPRING_ROT][1],
291             obj[bl.CONSTRAINT_SPRING_ROT][2])
292         )
293         for obj in self.oneSkinMesh.constraints]
294
295     # 書き込み
296     bl.message('write: %s' % path)
297     return writer.write(io.open(path, 'wb'), model)
298
299
300 def _execute(filepath):
301     active=bl.object.getActive()
302     if not active:
303         print("abort. no active object.")
304         return
305
306     exporter=oneskinmesh.Exporter()
307     exporter.setup()
308
309     model=create_pmx(exporter)
310     bl.object.activate(active)
311     with io.open(filepath, 'wb') as f:
312         writer.write(f, model)
313     return {'FINISHED'}
314