10 from .pymeshio import pmx
11 from .pymeshio.pmx import reader
14 def convert_coord(pos):
16 Left handed y-up to Right handed z-up
18 return (pos.x, pos.z, pos.y)
21 return bl.createVector(v.x, v.y, v.z)
23 def get_object_name(fmt, index, name):
27 len_list=[len(name[:i].encode('utf-8')) for i in range(1, len(name)+1, 1)]
29 prefix=fmt.format(index)
30 max_length=21-len(prefix)
31 for str_len in len_list:
32 if str_len>max_length:
35 name=prefix+name[:letter_count]
36 print("%s(%d)" % (name, letter_count))
39 def __import_joints(joints, rigidbodies):
40 print("create joints")
41 container=bl.object.createEmpty('Joints')
43 True, False, False, False, False, False, False, False, False, False,
44 False, False, False, False, False, False, False, False, False, False,
46 material=bl.material.create('joint')
47 material.diffuse_color=(1, 0, 0)
49 for i, c in enumerate(joints):
50 bpy.ops.mesh.primitive_uv_sphere_add(
54 location=(c.position.x, c.position.z, c.position.y),
57 meshObject=bl.object.getActive()
58 constraintMeshes.append(meshObject)
59 mesh=bl.object.getData(meshObject)
60 bl.mesh.addMaterial(mesh, material)
61 meshObject.name=get_object_name("j{0:02}:", i, c.name)
62 #meshObject.draw_transparent=True
63 #meshObject.draw_wire=True
64 meshObject.draw_type='SOLID'
66 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
68 meshObject[bl.CONSTRAINT_NAME]=c.name
69 meshObject[bl.CONSTRAINT_A]=rigidbodies[c.rigidbody_index_a].name
70 meshObject[bl.CONSTRAINT_B]=rigidbodies[c.rigidbody_index_b].name
71 meshObject[bl.CONSTRAINT_POS_MIN]=VtoV(c.translation_limit_min)
72 meshObject[bl.CONSTRAINT_POS_MAX]=VtoV(c.translation_limit_max)
73 meshObject[bl.CONSTRAINT_ROT_MIN]=VtoV(c.rotation_limit_min)
74 meshObject[bl.CONSTRAINT_ROT_MAX]=VtoV(c.rotation_limit_max)
75 meshObject[bl.CONSTRAINT_SPRING_POS]=VtoV(c.spring_constant_translation)
76 meshObject[bl.CONSTRAINT_SPRING_ROT]=VtoV(c.spring_constant_rotation)
78 for meshObject in reversed(constraintMeshes):
79 bl.object.makeParent(container, meshObject)
83 def __importRigidBodies(rigidbodies, bones):
84 print("create rigid bodies")
86 container=bl.object.createEmpty('RigidBodies')
88 True, False, False, False, False, False, False, False, False, False,
89 False, False, False, False, False, False, False, False, False, False,
91 material=bl.material.create('rigidBody')
93 for i, rigid in enumerate(rigidbodies):
94 if rigid.bone_index==-1:
98 bone=bones[rigid.bone_index]
99 pos=rigid.shape_position
100 size=rigid.shape_size
102 if rigid.shape_type==0:
103 bpy.ops.mesh.primitive_ico_sphere_add(
104 location=(pos.x, pos.z, pos.y),
107 bpy.ops.transform.resize(
108 value=(size.x, size.x, size.x))
109 elif rigid.shape_type==1:
110 bpy.ops.mesh.primitive_cube_add(
111 location=(pos.x, pos.z, pos.y),
114 bpy.ops.transform.resize(
115 value=(size.x, size.z, size.y))
116 elif rigid.shape_type==2:
117 bpy.ops.mesh.primitive_cylinder_add(
118 location=(pos.x, pos.z, pos.y),
121 bpy.ops.transform.resize(
122 value=(size.x, size.x, size.y))
126 meshObject=bl.object.getActive()
127 mesh=bl.object.getData(meshObject)
128 rigidMeshes.append(meshObject)
129 bl.mesh.addMaterial(mesh, material)
130 meshObject.name=get_object_name("r{0:02}:", i, rigid.name)
131 #meshObject.draw_transparent=True
132 #meshObject.draw_wire=True
133 meshObject.draw_type='WIRE'
134 rot=rigid.shape_rotation
135 meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
137 meshObject[bl.RIGID_NAME]=rigid.name
138 meshObject[bl.RIGID_SHAPE_TYPE]=rigid.shape_type
139 meshObject[bl.RIGID_PROCESS_TYPE]=rigid.mode
140 meshObject[bl.RIGID_BONE_NAME]=bone.name
141 meshObject[bl.RIGID_GROUP]=rigid.collision_group
142 meshObject[bl.RIGID_INTERSECTION_GROUP]=rigid.no_collision_group
143 meshObject[bl.RIGID_WEIGHT]=rigid.param.mass
144 meshObject[bl.RIGID_LINEAR_DAMPING]=rigid.param.linear_damping
145 meshObject[bl.RIGID_ANGULAR_DAMPING]=rigid.param.angular_damping
146 meshObject[bl.RIGID_RESTITUTION]=rigid.param.restitution
147 meshObject[bl.RIGID_FRICTION]=rigid.param.friction
149 for meshObject in reversed(rigidMeshes):
150 bl.object.makeParent(container, meshObject)
154 def __create_a_material(m, name, textures_and_images):
160 pymeshio.pmx.Material
164 list of (texture, image)
166 material = bl.material.create(name)
168 material.diffuse_shader='FRESNEL'
169 material.diffuse_color=[m.diffuse_color.r, m.diffuse_color.g, m.diffuse_color.b]
170 material.alpha=m.alpha
172 material.specular_shader='TOON'
173 material.specular_color=[m.specular_color.r, m.specular_color.g, m.specular_color.b]
174 material.specular_toon_size=int(m.specular_factor)
176 material.mirror_color=[m.ambient_color.r, m.ambient_color.g, m.ambient_color.b]
182 material.preview_render_type='FLAT'
183 material.use_transparency=True
185 if m.texture_index!=-1:
186 bl.material.addTexture(material, textures_and_images[m.texture_index][0])
189 def __create_armature(bones, display_slots):
195 list of pymeshio.pmx.Bone
197 armature, armature_object=bl.armature.create()
200 bl.armature.makeEditable(armature_object)
202 bone=bl.armature.createBone(armature, b.name)
204 bone.head=bl.createVector(*convert_coord(b.position))
205 if not b.getConnectionFlag():
206 bone.tail=bl.createVector(*convert_coord(b.position))
207 elif not b.getVisibleFlag():
208 bone.tail=bone.head+bl.createVector(0, 1, 0)
211 bl_bones=[create_bone(b) for b in bones]
214 for b, bone in zip(bones, bl_bones):
215 assert(b.name==bone.name)
216 if b.parent_index!=-1:
217 #print("%s -> %s" % (bones[b.parent_index].name, b.name))
218 parent_bone=bl_bones[b.parent_index]
219 bone.parent=parent_bone
220 if b.getConnectionFlag() and b.tail_index!=-1:
221 assert(b.tail_index!=0)
222 tail_bone=bl_bones[b.tail_index]
223 bone.tail=tail_bone.head
224 bl.bone.setConnected(tail_bone)
226 print("no parent %s" % b.name)
227 bl.armature.update(armature)
229 # create ik constraint
231 pose = bl.object.getPose(armature_object)
232 for b, bone in zip(bones, bl_bones):
235 assert(len(ik.link)<16)
236 p_bone=pose.bones[bones[ik.target_index].name]
238 constraint=bl.armature.createIkConstraint(
239 armature_object, p_bone, bone.name,
240 ik.link, ik.limit_radian, ik.loop)
241 bl.armature.makeEditable(armature_object)
242 bl.armature.update(armature)
246 pose = bl.object.getPose(armature_object)
247 for i, ds in enumerate(display_slots):
249 g=bl.object.createBoneGroup(armature_object, ds.name, "THEME%02d" % (i+1))
250 for t, index in ds.references:
252 name=bones[index].name
254 pose.bones[name].bone_group=g
255 except KeyError as e:
256 print("pose %s is not found" % name)
259 return armature_object
261 def _execute(filepath):
267 model=reader.read_from_file(filepath)
269 print("fail to load %s" % filepath)
273 # メッシュをまとめるエンプティオブジェクト
274 model_name=model.english_name
275 if len(model_name)==0:
276 model_name=os.path.basename(filepath)
277 root_object=bl.object.createEmpty(model_name)
278 root_object[bl.MMD_MB_NAME]=model.name
279 root_object[bl.MMD_MB_COMMENT]=model.comment
280 root_object[bl.MMD_COMMENT]=model.english_comment
283 armature_object=__create_armature(model.bones, model.display_slots)
285 bl.object.makeParent(root_object, armature_object)
288 texture_dir=os.path.dirname(filepath)
289 textures_and_images=[bl.texture.create(os.path.join(texture_dir, t))
290 for t in model.textures]
291 print(textures_and_images)
293 index_generator=(i for i in model.indices)
294 # 頂点配列。(Left handed y-up) to (Right handed z-up)
295 vertices=[convert_coord(pos)
296 for pos in (v.position for v in model.vertices)]
298 for i, m in enumerate(model.materials):
299 name=get_object_name("{0:02}:", i, m.name)
303 material=__create_a_material(m, name, textures_and_images)
308 # object名はutf-8で21byteまで
309 mesh, mesh_object=bl.mesh.create(name)
310 bl.mesh.addMaterial(mesh, material)
312 bl.object.deselectAll()
313 bl.object.activate(mesh_object)
314 bl.object.makeParent(root_object, mesh_object)
319 indices=[next(index_generator)
320 for _ in range(m.vertex_count)]
321 used_indices=set(indices)
322 bl.mesh.addGeometry(mesh, vertices,
323 [(indices[i], indices[i+1], indices[i+2])
324 for i in range(0, len(indices), 3)])
325 assert(len(model.vertices), len(mesh.vertices))
329 hasTexture=bl.material.hasTexture(material)
331 index_gen=(i for i in indices)
332 image=(textures_and_images.get[m.texture_index]
333 if m.texture_index in textures_and_images
335 for i, face in enumerate(mesh.faces):
336 bl.face.setMaterial(face, 0)
338 uv0=model.vertices[next(index_gen)].uv
339 uv1=model.vertices[next(index_gen)].uv
340 uv2=model.vertices[next(index_gen)].uv
341 bl.mesh.setFaceUV(mesh, i, face, [# fix uv
353 bl.modifier.addArmature(mesh_object, armature_object)
354 # set vertex attributes(normal, bone weights)
355 bl.mesh.useVertexUV(mesh)
356 for i, (v, mvert) in enumerate(zip(model.vertices, mesh.vertices)):
357 bl.vertex.setNormal(mvert, convert_coord(v.normal))
358 if isinstance(v.deform, pmx.Bdef1):
359 bl.object.assignVertexGroup(mesh_object,
360 model.bones[v.deform.index0].name, i, 1.0)
361 elif isinstance(v.deform, pmx.Bdef2):
362 bl.object.assignVertexGroup(mesh_object,
363 model.bones[v.deform.index0].name, i, v.deform.weight0)
364 bl.object.assignVertexGroup(mesh_object,
365 model.bones[v.deform.index1].name, i, 1.0-v.deform.weight0)
367 raise Exception("unknown deform: %s" % v.deform)
373 bl.object.pinShape(mesh_object, True)
375 baseShapeBlock=bl.object.addShapeKey(mesh_object, bl.BASE_SHAPE_NAME)
377 for m in model.morphs:
378 new_shape_key=bl.object.addShapeKey(mesh_object, m.name)
380 if isinstance(o, pmx.VertexMorphOffset):
381 bl.shapekey.assign(new_shape_key,
383 mesh.vertices[o.vertex_index].co+
384 bl.createVector(*convert_coord(o.position_offset)))
386 raise Exception("unknown morph type: %s" % o)
388 bl.object.setActivateShapeKey(mesh_object, 0)
390 #############################
391 # clean up not used vertices
393 #############################
394 bl.mesh.vertsDelete(mesh, [i for i in range(len(mesh.vertices))
395 if i not in used_indices])
397 # import rigid bodies
398 rigidbody_object=__importRigidBodies(model.rigidbodies, model.bones)
400 bl.object.makeParent(root_object, rigidbody_object)
403 joint_object=__import_joints(model.joints, model.rigidbodies)
405 bl.object.makeParent(root_object, joint_object)