OSDN Git Service

implementing export_pmx...
[meshio/pymeshio.git] / blender26-meshio / export_pmx.py
1 # coding: utf-8
2
3 import io
4 from . import bl
5 from . import exporter
6 from .pymeshio import pmx
7 from .pymeshio import common
8 from .pymeshio.pmx import writer
9
10
11 def near(x, y, EPSILON=1e-5):
12     d=x-y
13     return d>=-EPSILON and d<=EPSILON
14
15
16 def create_pmx(ex):
17     model=pmx.Model()
18
19     o=ex.root.o
20     model.english_name=o.name
21     model.name=o[bl.MMD_MB_NAME] if bl.MMD_MB_NAME in o else 'Blenderエクスポート'
22     model.comment=o[bl.MMD_MB_COMMENT] if bl.MMD_MB_COMMENT in o else 'Blnderエクスポート\n'
23     model.english_comment=o[bl.MMD_COMMENT] if bl.MMD_COMMENT in o else 'blender export\n'
24
25     def get_deform(b0, b1, weight):
26         if b0==-1:
27             return pmx.Bdef1(b1, weight)
28         elif b1==-1:
29             return pmx.Bdef1(b0, weight)
30         else:
31             return pmx.Bdef2(b0, b1, weight)
32
33     model.vertices=[pmx.Vertex(
34         # convert right-handed z-up to left-handed y-up
35         common.Vector3(pos[0], pos[2], pos[1]), 
36         # convert right-handed z-up to left-handed y-up
37         common.Vector3(attribute.nx, attribute.nz, attribute.ny),
38         # reverse vertical
39         common.Vector2(attribute.u, 1.0-attribute.v),
40         get_deform(ex.skeleton.indexByName(b0), ex.skeleton.indexByName(b1), weight),
41         # edge flag, 0: enable edge, 1: not edge
42         1.0 
43         )
44         for pos, attribute, b0, b1, weight in ex.oneSkinMesh.vertexArray.zip()]
45
46     '''
47     # IK
48     for ik in self.skeleton.ik_list:
49         solver=pmd.IK()
50         solver.index=self.skeleton.getIndex(ik.target)
51         solver.target=self.skeleton.getIndex(ik.effector)
52         solver.length=ik.length
53         b=self.skeleton.bones[ik.effector.parent_index]
54         for i in range(solver.length):
55             solver.children.append(self.skeleton.getIndex(b))
56             b=self.skeleton.bones[b.parent_index]
57         solver.iterations=ik.iterations
58         solver.weight=ik.weight
59         model.ik_list.append(solver)
60     '''
61     def create_bone(b):
62         return pmx.Bone(
63             name=b.name,
64             english_name=b.name,
65             # convert right-handed z-up to left-handed y-up
66             position=common.Vector3(
67                 b.pos[0] if not near(b.pos[0], 0) else 0,
68                 b.pos[2] if not near(b.pos[2], 0) else 0,
69                 b.pos[1] if not near(b.pos[1], 0) else 0
70                 ),
71             parent_index=b.parent_index,
72             layer=0,
73             flag=0,
74             tail_position=None,
75             tail_index=b.tail_index,
76             effect_index=-1,
77             effect_factor=0.0,
78             fixed_axis=None,
79             local_x_vector=None,
80             local_z_vector=None,
81             external_key=-1,
82             ik=None
83                 )
84     model.bones=[create_bone(b)
85             for b in ex.skeleton.bones]
86
87     textures=set()
88     def get_texture_name(texture):
89         pos=texture.replace("\\", "/").rfind("/")
90         if pos==-1:
91             return texture
92         else:
93             return texture[pos+1:]
94     for m in ex.oneSkinMesh.vertexArray.indexArrays.keys():
95         for path in bl.material.eachEnalbeTexturePath(bl.material.get(m)):
96             textures.add(get_texture_name(path))
97     model.textures=list(textures)
98
99     # 面とマテリアル
100     vertexCount=ex.oneSkinMesh.getVertexCount()
101     for material_name, indices in ex.oneSkinMesh.vertexArray.each():
102         #print('material:', material_name)
103         try:
104             m=bl.material.get(material_name)
105         except KeyError as e:
106             m=DefaultMatrial()
107         # マテリアル
108         model.materials.append(pmx.Material(
109                 name=m.name,
110                 english_name='',
111                 diffuse_color=common.RGB(m.diffuse_color[0], m.diffuse_color[1], m.diffuse_color[2]),
112                 alpha=m.alpha,
113                 specular_factor=0 if m.specular_toon_size<1e-5 else m.specular_hardness*10,
114                 specular_color=common.RGB(m.specular_color[0], m.specular_color[1], m.specular_color[2]),
115                 ambient_color=common.RGB(m.mirror_color[0], m.mirror_color[1], m.mirror_color[2]),
116                 flag=1 if m.subsurface_scattering.use else 0,
117                 edge_color=common.RGBA(0, 0, 0, 1),
118                 edge_size=1.0,
119                 texture_index=0,
120                 sphere_texture_index=0,
121                 sphere_mode=0,
122                 toon_sharing_flag=0,
123                 toon_texture_index=0,
124                 comment='',
125                 vertex_count=len(indices)
126                 ))
127         # 面
128         for i in indices:
129             assert(i<vertexCount)
130         for i in range(0, len(indices), 3):
131             # reverse triangle
132             model.indices.append(indices[i+2])
133             model.indices.append(indices[i+1])
134             model.indices.append(indices[i])
135
136     # 表情
137     for i, m in enumerate(ex.oneSkinMesh.morphList):
138         morph=pmx.Morph(
139                 name=m.name,
140                 english_name='',
141                 panel=0,
142                 morph_type=1,
143                 )
144         morph.offsets=[pmx.VertexMorphOffset(
145             index, 
146             common.Vector3(offset[0], offset[2], offset[1])
147             )
148             for index, offset in m.offsets]
149
150
151     # ボーングループ
152     model.display_slots=[pmx.DisplaySlot(
153         name=name,
154         english_name='',
155         special_flag=0,
156         )
157         for name, members in ex.skeleton.bone_groups]
158
159     # rigid body
160     boneNameMap={}
161     for i, b in enumerate(ex.skeleton.bones):
162         boneNameMap[b.name]=i
163     rigidNameMap={}
164     for i, obj in enumerate(ex.oneSkinMesh.rigidbodies):
165         name=obj[bl.RIGID_NAME] if bl.RIGID_NAME in obj else obj.name
166         print(name)
167         rigidNameMap[name]=i
168         boneIndex=boneNameMap[obj[bl.RIGID_BONE_NAME]]
169         if boneIndex==0:
170             boneIndex=-1
171             bone=ex.skeleton.bones[0]
172         else:
173             bone=ex.skeleton.bones[boneIndex]
174         if obj[bl.RIGID_SHAPE_TYPE]==0:
175             shape_type=0
176             shape_size=common.Vector3(obj.scale[0], 0, 0)
177         elif obj[bl.RIGID_SHAPE_TYPE]==1:
178             shape_type=1
179             shape_size=common.Vector3(obj.scale[0], obj.scale[1], obj.scale[2])
180         elif obj[bl.RIGID_SHAPE_TYPE]==2:
181             shape_type=2
182             shape_size=common.Vector3(obj.scale[0], obj.scale[2], 0)
183         rigidBody=pmx.RigidBody(
184                 name=name, 
185                 english_name='',
186                 collision_group=obj[bl.RIGID_GROUP],
187                 no_collision_group=obj[bl.RIGID_INTERSECTION_GROUP],
188                 bone_index=boneIndex,
189                 shape_position=common.Vector3(
190                     obj.location.x-bone.pos[0],
191                     obj.location.z-bone.pos[2],
192                     obj.location.y-bone.pos[1]),
193                 shape_rotation=common.Vector3(
194                     -obj.rotation_euler[0],
195                     -obj.rotation_euler[2],
196                     -obj.rotation_euler[1]),
197                 shape_type=shape_type,
198                 shape_size=shape_size,
199                 mass=obj[bl.RIGID_WEIGHT],
200                 linear_damping=obj[bl.RIGID_LINEAR_DAMPING],
201                 angular_damping=obj[bl.RIGID_ANGULAR_DAMPING],
202                 restitution=obj[bl.RIGID_RESTITUTION],
203                 friction=obj[bl.RIGID_FRICTION],
204                 mode=obj[bl.RIGID_PROCESS_TYPE]
205                 )
206         model.rigidbodies.append(rigidBody)
207
208     # joint
209     model.joints=[pmx.Joint(
210         name=obj[bl.CONSTRAINT_NAME],
211         english_name='',
212         joint_type=0,
213         rigidbody_index_a=rigidNameMap[obj[bl.CONSTRAINT_A]],
214         rigidbody_index_b=rigidNameMap[obj[bl.CONSTRAINT_B]],
215         position=common.Vector3(
216             obj.location[0], 
217             obj.location[2], 
218             obj.location[1]),
219         rotation=common.Vector3(
220             -obj.rotation_euler[0], 
221             -obj.rotation_euler[2], 
222             -obj.rotation_euler[1]),
223         translation_limit_min=common.Vector3(
224             obj[bl.CONSTRAINT_POS_MIN][0],
225             obj[bl.CONSTRAINT_POS_MIN][1],
226             obj[bl.CONSTRAINT_POS_MIN][2]
227             ),
228         translation_limit_max=common.Vector3(
229             obj[bl.CONSTRAINT_POS_MAX][0],
230             obj[bl.CONSTRAINT_POS_MAX][1],
231             obj[bl.CONSTRAINT_POS_MAX][2]
232             ),
233         rotation_limit_min=common.Vector3(
234             obj[bl.CONSTRAINT_ROT_MIN][0],
235             obj[bl.CONSTRAINT_ROT_MIN][1],
236             obj[bl.CONSTRAINT_ROT_MIN][2]),
237         rotation_limit_max=common.Vector3(
238             obj[bl.CONSTRAINT_ROT_MAX][0],
239             obj[bl.CONSTRAINT_ROT_MAX][1],
240             obj[bl.CONSTRAINT_ROT_MAX][2]),
241         spring_constant_translation=common.Vector3(
242             obj[bl.CONSTRAINT_SPRING_POS][0],
243             obj[bl.CONSTRAINT_SPRING_POS][1],
244             obj[bl.CONSTRAINT_SPRING_POS][2]),
245         spring_constant_rotation=common.Vector3(
246             obj[bl.CONSTRAINT_SPRING_ROT][0],
247             obj[bl.CONSTRAINT_SPRING_ROT][1],
248             obj[bl.CONSTRAINT_SPRING_ROT][2])
249         )
250         for obj in ex.oneSkinMesh.constraints]
251
252     return model
253
254
255 def _execute(filepath):
256     active=bl.object.getActive()
257     if not active:
258         print("abort. no active object.")
259         return
260
261     ex=exporter.Exporter()
262     ex.setup()
263
264     model=create_pmx(ex)
265     bl.object.activate(active)
266     with io.open(filepath, 'wb') as f:
267         writer.write(f, model)
268     return {'FINISHED'}
269