4 Name: 'MikuMikuDance model (.pmd)...'
7 Tooltip: 'Export PMD file for MikuMikuDance.'
9 __author__= ["ousttrue"]
15 This script exports a pmd model.
17 20100318: first implementation.
18 20100519: refactoring. use C extension.
19 20100530: implement basic features.
20 20100612: integrate 2.4 and 2.5.
21 20100616: implement rigid body.
22 20100619: fix rigid body, bone weight.
23 20100626: refactoring.
25 20100710: toon texture & bone group.
26 20100711: separate vertex with normal or uv.
27 20100724: update for Blender2.53.
28 20100731: add full python module.
29 20101005: update for Blender2.54.
30 20101228: update for Blender2.55.
31 20110429: update for Blender2.57b.
32 20110522: implement RigidBody and Constraint.
33 20111002: update for pymeshio-2.1.0
38 from . import exporter
39 from .pymeshio import common
40 from .pymeshio import pmd
41 from .pymeshio import englishmap
42 from .pymeshio.pmd import writer
45 def near(x, y, EPSILON=1e-5):
47 return d>=-EPSILON and d<=EPSILON
51 return s.encode('cp932')
54 def write(self, path):
59 name=o[bl.MMD_MB_NAME] if bl.MMD_MB_NAME in o else 'Blenderエクスポート'
60 comment=o[bl.MMD_MB_COMMENT] if bl.MMD_MB_COMMENT in o else 'Blnderエクスポート\n'
61 englishComment=o[bl.MMD_COMMENT] if bl.MMD_COMMENT in o else 'blender export\n'
63 model.name=name.encode('cp932')
64 model.english_name=englishName.encode('cp932')
65 model.comment=comment.encode('cp932')
66 model.english_comment=englishComment.encode('cp932')
69 model.vertices=[pmd.Vertex(
70 # convert right-handed z-up to left-handed y-up
71 common.Vector3(pos[0], pos[2], pos[1]),
72 # convert right-handed z-up to left-handed y-up
73 common.Vector3(attribute.nx, attribute.nz, attribute.ny),
75 common.Vector2(attribute.u, 1.0-attribute.v),
76 self.skeleton.indexByName(b0),
77 self.skeleton.indexByName(b1),
79 # edge flag, 0: enable edge, 1: not edge
82 for pos, attribute, b0, b1, weight in self.oneSkinMesh.vertexArray.zip()]
85 vertexCount=self.oneSkinMesh.getVertexCount()
86 for material_name, indices in self.oneSkinMesh.vertexArray.each():
87 #print('material:', material_name)
89 m=bl.material.get(material_name)
92 def get_texture_name(texture):
93 pos=texture.replace("\\", "/").rfind("/")
97 return texture[pos+1:]
98 textures=[get_texture_name(path)
99 for path in bl.material.eachEnalbeTexturePath(m)]
102 model.materials.append(pmd.Material(
104 common.RGB(m.diffuse_color[0], m.diffuse_color[1], m.diffuse_color[2]),
107 0 if m.specular_toon_size<1e-5 else m.specular_hardness*10,
109 common.RGB(m.specular_color[0], m.specular_color[1], m.specular_color[2]),
111 common.RGB(m.mirror_color[0], m.mirror_color[1], m.mirror_color[2]),
113 1 if m.subsurface_scattering.use else 0,
119 ('*'.join(textures) if len(textures)>0 else "").encode('cp932')
123 assert(i<vertexCount)
124 for i in range(0, len(indices), 3):
126 model.indices.append(indices[i])
127 model.indices.append(indices[i+1])
128 model.indices.append(indices[i+2])
132 for i, b in enumerate(self.skeleton.bones):
135 boneNameMap[b.name]=i
136 v=englishmap.getUnicodeBoneName(b.name)
140 bone=pmd.Bone(v[1].encode('cp932'))
143 bone_english_name=toCP932(b.name)
144 if len(bone_english_name)>=20:
145 print(bone_english_name)
146 #assert(len(bone_english_name)<20)
147 bone.english_name=bone_english_name
152 b.ik_index=self.skeleton.indexByName('eyes')
157 bone.parent_index=b.parent_index
158 bone.tail_index=b.tail_index
159 bone.ik_index=b.ik_index
161 # convert right-handed z-up to left-handed y-up
162 bone.pos.x=b.pos[0] if not near(b.pos[0], 0) else 0
163 bone.pos.y=b.pos[2] if not near(b.pos[2], 0) else 0
164 bone.pos.z=b.pos[1] if not near(b.pos[1], 0) else 0
166 model.bones.append(bone)
169 for ik in self.skeleton.ik_list:
171 solver.index=self.skeleton.getIndex(ik.target)
172 solver.target=self.skeleton.getIndex(ik.effector)
173 solver.length=ik.length
174 b=self.skeleton.bones[ik.effector.parent_index]
175 for i in range(solver.length):
176 solver.children.append(self.skeleton.getIndex(b))
177 b=self.skeleton.bones[b.parent_index]
178 solver.iterations=ik.iterations
179 solver.weight=ik.weight
180 model.ik_list.append(solver)
183 for i, m in enumerate(self.oneSkinMesh.morphList):
184 v=englishmap.getUnicodeSkinName(m.name)
186 v=[m.name, m.name, 0]
189 morph=pmd.Morph(v[1].encode("cp932"))
190 morph.english_name=m.name.encode("cp932")
193 for index, offset in m.offsets:
194 # convert right-handed z-up to left-handed y-up
195 morph.append(index, offset[0], offset[2], offset[1])
196 morph.vertex_count=len(m.offsets)
200 for i, m in enumerate(self.oneSkinMesh.morphList):
202 model.morph_indices.append(i)
203 for i, m in enumerate(self.oneSkinMesh.morphList):
205 model.morph_indices.append(i)
206 for i, m in enumerate(self.oneSkinMesh.morphList):
208 model.morph_indices.append(i)
209 for i, m in enumerate(self.oneSkinMesh.morphList):
211 model.morph_indices.append(i)
214 for g in self.skeleton.bone_groups:
215 name=englishmap.getUnicodeBoneGroupName(g[0])
220 model.bone_group_list.append(pmd.BoneGroup(
221 (name+'\n').encode('cp932'),
222 (englishName+'\n').encode('cp932')
226 for i, b in enumerate(self.skeleton.bones):
231 model.bone_display_list.append((i, self.skeleton.getBoneGroup(b)))
235 for o in bl.object.each():
237 if o.name.startswith(bl.TOON_TEXTURE_OBJECT):
243 toonMesh=bl.object.getData(toonMeshObject)
244 toonMaterial=bl.mesh.getMaterial(toonMesh, 0)
246 t=bl.material.getTexture(toonMaterial, i)
248 model.toon_textures[i]=("%s" % t.name).encode('cp932')
250 model.toon_textures[i]=("toon%02d.bmp" % (i+1)).encode('cp932')
253 model.toon_textures[i]=("toon%02d.bmp" % (i+1)).encode('cp932')
257 for i, obj in enumerate(self.oneSkinMesh.rigidbodies):
258 name=obj[bl.RIGID_NAME] if bl.RIGID_NAME in obj else obj.name
261 boneIndex=boneNameMap[obj[bl.RIGID_BONE_NAME]]
264 bone=self.skeleton.bones[0]
266 bone=self.skeleton.bones[boneIndex]
267 if obj[bl.RIGID_SHAPE_TYPE]==0:
268 shape_type=pmd.SHAPE_SPHERE
269 shape_size=common.Vector3(obj.scale[0], 0, 0)
270 elif obj[bl.RIGID_SHAPE_TYPE]==1:
271 shape_type=pmd.SHAPE_BOX
272 shape_size=common.Vector3(obj.scale[0], obj.scale[1], obj.scale[2])
273 elif obj[bl.RIGID_SHAPE_TYPE]==2:
274 shape_type=pmd.SHAPE_CAPSULE
275 shape_size=common.Vector3(obj.scale[0], obj.scale[2], 0)
276 rigidBody=pmd.RigidBody(
277 name.encode('cp932'),
278 collision_group=obj[bl.RIGID_GROUP],
279 no_collision_group=obj[bl.RIGID_INTERSECTION_GROUP],
280 bone_index=boneIndex,
281 shape_position=common.Vector3(
282 obj.location.x-bone.pos[0],
283 obj.location.z-bone.pos[2],
284 obj.location.y-bone.pos[1]),
285 shape_rotation=common.Vector3(
286 -obj.rotation_euler[0],
287 -obj.rotation_euler[2],
288 -obj.rotation_euler[1]),
289 shape_type=shape_type,
290 shape_size=shape_size,
291 mass=obj[bl.RIGID_WEIGHT],
292 linear_damping=obj[bl.RIGID_LINEAR_DAMPING],
293 angular_damping=obj[bl.RIGID_ANGULAR_DAMPING],
294 restitution=obj[bl.RIGID_RESTITUTION],
295 friction=obj[bl.RIGID_FRICTION],
296 mode=obj[bl.RIGID_PROCESS_TYPE]
298 model.rigidbodies.append(rigidBody)
301 model.joints=[pmd.Joint(
302 name=obj[bl.CONSTRAINT_NAME].encode('cp932'),
303 rigidbody_index_a=rigidNameMap[obj[bl.CONSTRAINT_A]],
304 rigidbody_index_b=rigidNameMap[obj[bl.CONSTRAINT_B]],
305 position=common.Vector3(
309 rotation=common.Vector3(
310 -obj.rotation_euler[0],
311 -obj.rotation_euler[2],
312 -obj.rotation_euler[1]),
313 translation_limit_min=common.Vector3(
314 obj[bl.CONSTRAINT_POS_MIN][0],
315 obj[bl.CONSTRAINT_POS_MIN][1],
316 obj[bl.CONSTRAINT_POS_MIN][2]
318 translation_limit_max=common.Vector3(
319 obj[bl.CONSTRAINT_POS_MAX][0],
320 obj[bl.CONSTRAINT_POS_MAX][1],
321 obj[bl.CONSTRAINT_POS_MAX][2]
323 rotation_limit_min=common.Vector3(
324 obj[bl.CONSTRAINT_ROT_MIN][0],
325 obj[bl.CONSTRAINT_ROT_MIN][1],
326 obj[bl.CONSTRAINT_ROT_MIN][2]),
327 rotation_limit_max=common.Vector3(
328 obj[bl.CONSTRAINT_ROT_MAX][0],
329 obj[bl.CONSTRAINT_ROT_MAX][1],
330 obj[bl.CONSTRAINT_ROT_MAX][2]),
331 spring_constant_translation=common.Vector3(
332 obj[bl.CONSTRAINT_SPRING_POS][0],
333 obj[bl.CONSTRAINT_SPRING_POS][1],
334 obj[bl.CONSTRAINT_SPRING_POS][2]),
335 spring_constant_rotation=common.Vector3(
336 obj[bl.CONSTRAINT_SPRING_ROT][0],
337 obj[bl.CONSTRAINT_SPRING_ROT][1],
338 obj[bl.CONSTRAINT_SPRING_ROT][2])
340 for obj in self.oneSkinMesh.constraints]
342 bl.message('write: %s' % path)
343 with io.open(path, 'wb') as f:
344 return writer.write(f, model)
347 def _execute(filepath=''):
348 active=bl.object.getActive()
350 print("abort. no active object.")
353 ex=exporter.Exporter()
358 bl.object.activate(active)