5 from Blender import Mathutils
11 FS_ENCODING=sys.getfilesystemencoding()
12 if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):
13 INTERNAL_ENCODING='utf-8'
15 INTERNAL_ENCODING=FS_ENCODING
18 ###############################################################################
20 ###############################################################################
22 def __init__(self, path, encoding):
23 self.io=open(path, "wb")
24 self.encoding=encoding
36 ###############################################################################
38 ###############################################################################
39 class ProgressBar(object):
40 def __init__(self, base):
41 print "#### %s ####" % base
43 self.start=Blender.sys.time()
44 self.set('<start>', 0)
46 def advance(self, message, progress):
47 self.progress+=float(progress)
50 def set(self, message, progress):
51 self.progress=float(progress)
54 def _print(self, message):
56 message="%s: %s" % (self.base, message)
57 if message.__class__ is unicode:
58 message=message.encode(FS_ENCODING)
59 Blender.Window.DrawProgressBar(self.progress, message)
63 message='finished in %.2f sec' % (Blender.sys.time()-self.start)
64 self.set(message, 1.0)
67 ###############################################################################
68 # for mqo mikoto bone.
69 ###############################################################################
70 class MikotoBone(object):
73 'iHead', 'iTail', 'iUp',
74 'vHead', 'vTail', 'vUp',
75 'parent', 'isFloating',
78 def __init__(self, face=None, vertices=None, materials=None):
86 self.name=materials[face.material_index].name.encode('utf-8')
97 sqNorm0=e01.getSqNorm()
98 sqNorm1=e12.getSqNorm()
99 sqNorm2=e20.getSqNorm()
135 self.vHead=vertices[self.iHead]
136 self.vTail=vertices[self.iTail]
137 self.vUp=vertices[self.iUp]
139 if self.name.endswith('[]'):
140 basename=self.name[0:-2]
143 self.name="%s_L" % basename
145 self.name="%s_R" % basename
148 def setParent(self, parent, floating=False):
152 parent.children.append(self)
154 def printTree(self, indent=''):
155 print("%s%s" % (indent, self.name))
156 for child in self.children:
157 child.printTree(indent+' ')
160 def build_armature(armature, mikotoBone, parent=None):
162 create a armature bone.
164 bone = Armature.Editbone()
165 bone.name = mikotoBone.name.encode('utf-8')
166 armature.bones[bone.name] = bone
168 bone.head = Mathutils.Vector(*mikotoBone.vHead.to_a())
169 bone.tail = Mathutils.Vector(*mikotoBone.vTail.to_a())
172 if mikotoBone.isFloating:
175 bone.options=[Armature.CONNECTED]
177 for child in mikotoBone.children:
178 build_armature(armature, child, bone)
181 def create_armature(scene, mqo):
186 for o in mqo.objects:
187 if o.name.startswith('bone'):
194 for f in boneObject.faces:
196 print("invalid index_count: %d" % f.index_count)
198 b=MikotoBone(f, boneObject.vertices, mqo.materials)
202 # build mikoto bone tree
204 mikotoRoot=MikotoBone()
206 for b in tailMap.values():
207 # each bone has unique parent or is root bone.
208 if b.iHead in tailMap:
209 b.setParent(tailMap[b.iHead])
212 for e in boneObject.edges:
213 if b.iHead==e.indices[0]:
215 if e.indices[1] in tailMap:
216 b.setParent(tailMap[e.indices[1]], True)
219 elif b.iHead==e.indices[1]:
221 if e.indices[0] in tailMap:
222 b.setParent(tailMap[e.indices[0]], True)
229 b.setParent(mikotoRoot, True)
231 if len(mikotoRoot.children)==0:
232 print("no root bone")
235 if len(mikotoRoot.children)==1:
237 mikotoRoot=mikotoRoot.children[0]
238 mikotoRoot.parent=None
240 mikotoRoot.vHead=Vector3(0, 10, 0)
241 mikotoRoot.vTail=Vector3(0, 0, 0)
246 armature = Armature.New()
248 armature_object = scene.objects.new(armature)
250 act = Armature.NLA.NewAction()
251 act.setActive(armature_object)
253 armature_object.drawMode |= Object.DrawModes.XRAY
255 armature.drawType = Armature.OCTAHEDRON
256 armature.envelopes = False
257 armature.vertexGroups = True
258 armature.mirrorEdit = True
259 armature.drawNames=True
262 armature.makeEditable()
263 build_armature(armature, mikotoRoot)
266 return armature_object
269 class TrianglePlane(object):
271 mikoto方式ボーンのアンカーウェイト計算用。
277 def __init__(self, v0, v1, v2):
282 def isInsideXY(self, p):
283 v0=Vector2(self.v0.x, self.v0.y)
284 v1=Vector2(self.v1.x, self.v1.y)
285 v2=Vector2(self.v2.x, self.v2.y)
289 c0=Vector2.cross(e01, p-v0)
290 c1=Vector2.cross(e12, p-v1)
291 c2=Vector2.cross(e20, p-v2)
292 if c0>=0 and c1>=0 and c2>=0:
294 if c0<=0 and c1<=0 and c2<=0:
297 def isInsideYZ(self, p):
298 v0=Vector2(self.v0.y, self.v0.z)
299 v1=Vector2(self.v1.y, self.v1.z)
300 v2=Vector2(self.v2.y, self.v2.z)
304 c0=Vector2.cross(e01, p-v0)
305 c1=Vector2.cross(e12, p-v1)
306 c2=Vector2.cross(e20, p-v2)
307 if c0>=0 and c1>=0 and c2>=0:
309 if c0<=0 and c1<=0 and c2<=0:
312 def isInsideZX(self, p):
313 v0=Vector2(self.v0.z, self.v0.x)
314 v1=Vector2(self.v1.z, self.v1.x)
315 v2=Vector2(self.v2.z, self.v2.x)
319 c0=Vector2.cross(e01, p-v0)
320 c1=Vector2.cross(e12, p-v1)
321 c2=Vector2.cross(e20, p-v2)
322 if c0>=0 and c1>=0 and c2>=0:
324 if c0<=0 and c1<=0 and c2<=0:
328 class MikotoAnchor(object):
339 def push(self, face, vertices):
340 if face.index_count==3:
341 self.triangles.append(TrianglePlane(
342 vertices[face.indices[0]],
343 vertices[face.indices[1]],
344 vertices[face.indices[2]]
346 elif face.index_count==4:
347 self.triangles.append(TrianglePlane(
348 vertices[face.indices[0]],
349 vertices[face.indices[1]],
350 vertices[face.indices[2]]
352 self.triangles.append(TrianglePlane(
353 vertices[face.indices[2]],
354 vertices[face.indices[3]],
355 vertices[face.indices[0]]
359 self.bbox=BoundingBox(vertices[face.indices[0]])
360 for i in face.indices:
361 self.bbox.expand(vertices[i])
364 def calcWeight(self, v):
365 if not self.bbox.isInside(v):
368 if self.anyXY(v.x, v.y) and self.anyYZ(v.y, v.z) and self.anyZX(v.z, v.x):
373 def anyXY(self, x, y):
374 for t in self.triangles:
375 if t.isInsideXY(Vector2(x, y)):
379 def anyYZ(self, y, z):
380 for t in self.triangles:
381 if t.isInsideYZ(Vector2(y, z)):
385 def anyZX(self, z, x):
386 for t in self.triangles:
387 if t.isInsideZX(Vector2(z, x)):
392 def create_bone_weight(scene, mqo, armature_object, objects):
394 create mikoto bone weight.
397 # setup mikoto anchors
398 for o in mqo.objects:
399 if o.name.startswith("anchor"):
401 name=mqo.materials[f.material_index].name
402 if name.endswith('[]'):
404 v=o.vertices[f.indices[0]]
408 if not name_L in anchorMap:
409 anchorMap[name_L]=MikotoAnchor()
410 anchorMap[name_L].push(f, o.vertices)
414 if not name_R in anchorMap:
415 anchorMap[name_R]=MikotoAnchor()
416 anchorMap[name_R].push(f, o.vertices)
420 if not name in anchorMap:
421 anchorMap[name]=MikotoAnchor()
422 anchorMap[name].push(f, o.vertices)
425 # add armature modifier
426 mod=o.modifiers.append(Modifier.Types.ARMATURE)
427 mod[Modifier.Settings.OBJECT] = armature_object
428 mod[Modifier.Settings.ENVELOPES] = False
430 # create vertex group
431 mesh=o.getData(mesh=True)
432 for name in anchorMap.keys():
433 mesh.addVertGroup(name)
436 # assing vertices to vertex group
438 mesh=o.getData(mesh=True)
439 for i, mvert in enumerate(mesh.verts):
441 for name, anchor in anchorMap.items():
442 weight=anchor.calcWeight(mvert.co)
444 mesh.assignVertsToGroup(
445 name, [i], weight, Mesh.AssignModes.ADD)
448 # debug orphan vertex
449 print('orphan', mvert)
452 ###############################################################################
453 def createEmptyObject(scene, name):
454 empty=scene.objects.new("Empty")
459 def createMqoMaterial(m):
460 material = Blender.Material.New(m.getName().encode(INTERNAL_ENCODING))
461 material.mode |= Blender.Material.Modes.SHADELESS
462 material.rgbCol = [m.color.r, m.color.g, m.color.b]
463 material.alpha = m.color.a
464 material.amb = m.ambient
465 material.spec = m.specular
466 material.hard = int(255 * m.power)
469 def createPmdMaterial(m):
470 material=Blender.Material.New()
471 material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
473 material.diffuseSize = 3.14/2
474 material.setDiffuseSmooth(0)
475 material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
476 material.setSpecSize(0)
478 material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
479 material.setAlpha(m.diffuse.a)
480 material.setSpec(m.shinness*0.1)
481 material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
482 material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
483 material.enableSSS=True if m.flag==1 else False
486 def createTexture(path):
487 image = Blender.Image.Load(path.encode(INTERNAL_ENCODING))
488 texture = Blender.Texture.New(path.encode(INTERNAL_ENCODING))
489 texture.type = Blender.Texture.Types.IMAGE
490 texture.image = image
491 return texture, image
494 def materialAddTexture(material, texture):
495 material.mode = material.mode | Blender.Material.Modes.TEXFACE
496 material.setTexture(0, texture, Blender.Texture.TexCo.UV)
499 def createMesh(scene, name):
500 mesh = Blender.Mesh.New()
501 mesh_object=scene.objects.new(mesh, name.encode(INTERNAL_ENCODING))
502 return mesh, mesh_object
505 def objectMakeParent(parent, child):
506 parent.makeParent([child])
509 def meshAddMaterial(mesh, material):
510 mesh.materials+=[material]
513 def meshAddMqoGeometry(mesh, o, materials, imageMap, scale):
515 mesh.verts.extend(Mathutils.Vector(0, 0, 0)) # dummy
516 mesh.verts.extend([(v.x, -v.z, v.y) for v in o.vertices])
521 for i in xrange(face.index_count):
522 face_indices.append(face.getIndex(i)+1)
523 mesh_faces.append(face_indices)
524 #new_faces=mesh.faces.extend([face.indices for face in o.faces],
525 new_faces=mesh.faces.extend(mesh_faces,
530 # gather used materials
535 materialMap[o.faces[i].material_index]=True
537 # blender limits 16 materials per mesh
539 for i, material_index in enumerate(materialMap.keys()):
541 print("over 16 materials!")
543 mesh.materials+=[materials[material_index]]
544 materialMap[material_index]=i
547 for i, f in enumerate(o.faces):
548 if not type(new_faces[i]) is int:
551 face=mesh.faces[new_faces[i]]
554 for i in xrange(f.index_count):
555 uv_array.append(Blender.Mathutils.Vector(
561 except Exception as msg:
563 #print face.index, uv_array
566 if f.material_index in materialMap:
567 face.mat = materialMap[f.material_index]
571 # rmeove dummy 0 vertex
574 mesh.mode |= Blender.Mesh.Modes.AUTOSMOOTH
575 mesh.maxSmoothAngle = int(o.smoothing)
583 mod=mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)
585 def getTexture(m, dirname):
589 for texture in m.getTextures():
590 if texture and texture.tex and texture.tex.getImage():
591 image=texture.tex.getImage()
594 imagePath=Blender.sys.expandpath(image.getFilename())
595 if len(dirname)>0 and imagePath.startswith(dirname):
597 imagePath=imagePath[len(dirname)+1:len(imagePath)]
599 tex=" tex(\"%s\")" % imagePath
600 elif texture.mtAlpha>0:
601 aplane=" aplane(\"%s\")" % imagePath
604 def objectDuplicate(scene, obj):
605 mesh, dumy=createMesh(scene, obj.name.decode(INTERNAL_ENCODING))
606 # not apply modifiers
607 mesh.getFromObject(obj.name, 1)
609 dumy.setMatrix(obj.matrixWorld)
612 def faceVertexCount(face):
615 def faceVertices(face):
617 return [v.index for v in reversed(face.v)]
622 def faceHasUV(mesh, i, face):
623 return len(face.uv)>0
625 def faceGetUV(mesh, i, face, count):
627 return reversed(face.uv)
629 def materialToMqo(m):
630 return "\"%s\" shader(3) col(%f %f %f %f)" % (
631 m.name, m.rgbCol[0], m.rgbCol[1], m.rgbCol[2], m.alpha)
633 def faceMaterialIndex(face):
636 def objectGetData(o):
637 return o.getData(mesh=True)
639 def objectAddArmatureModifier(o, armature_object):
640 mod=o.modifiers.append(Blender.Modifier.Types.ARMATURE)
641 mod[Blender.Modifier.Settings.OBJECT] = armature_object
642 mod[Blender.Modifier.Settings.ENVELOPES] = False
647 def objectGetPose(o):
650 def poseBoneLimit(n, b):
653 if n.startswith("knee_"):
658 b.limitMax=[180, 0, 0]
659 elif n.startswith("ankle_"):
663 Blender.Window.EditMode(1)
666 Blender.Window.EditMode(0)
668 def objectDeselectAll():
669 for o in bpy.data.scenes.active.objects:
672 def objectActivate(scene, o):
674 scene.objects.active=o
676 def meshAddVertexGroup(meshObject, name):
677 meshObject.getData(mesh=True).addVertGroup(name)
679 def meshUseVertexUv(mesh):
682 def vertexSetNormal(mvert, normal):
683 mvert.no=Mathutils.Vector(*normal)
685 def vertexSetUv(mvert, uv):
688 def meshAssignVertexGroup(meshObject, name, index, weight):
689 meshObject.getData(mesh=True).assignVertsToGroup(name,
690 [index], weight, Blender.Mesh.AssignModes.ADD)
692 def meshCreateVerteicesAndFaces(mesh, vertices, faces):
693 mesh.verts.extend(vertices)
694 mesh.faces.extend(faces, ignoreDups=True)
697 mesh.addUVLayer('NewUV')
699 def meshVertsDelete(mesh, remove_vertices):
700 mesh.verts.delete(remove_vertices)
702 def createArmature(scene):
703 armature = Blender.Armature.New()
704 armature_object = scene.objects.new(armature)
707 armature_object.drawMode = (
708 armature_object.drawMode | Blender.Object.DrawModes.XRAY)
710 armature.drawType = Blender.Armature.OCTAHEDRON
711 armature.drawNames=True
712 armature.envelopes = False
713 armature.vertexGroups = True
714 armature.mirrorEdit = True
716 return armature, armature_object
718 def armatureMakeEditable(scene, armature_object):
720 armature_object.getData().makeEditable()
722 def createIkConstraint(armature_object, p_bone, effector_name, ik):
723 cSetting = Blender.Constraint.Settings
725 constraint = p_bone.constraints.append(Blender.Constraint.Type.IKSOLVER)
726 constraint[cSetting.CHAINLEN]=len(ik.children)
727 constraint[cSetting.TARGET]=armature_object
728 constraint[cSetting.USETIP]=False
729 constraint[cSetting.BONE]=effector_name
730 #ik_solver.influence=ik.weight
731 # not used. place folder when export.
732 constraint[cSetting.ROTWEIGHT]=ik.weight
733 constraint[cSetting.ITERATIONS]=ik.iterations * 10
736 def createArmatureBone(armature, name):
737 bone=Blender.Armature.Editbone()
739 armature.bones[name]=bone
742 def boneSetConnected(bone):
743 bone.options+=[Blender.Armature.CONNECTED]
745 def createVector(x, y, z):
746 return Mathutils.Vector(x, y, z)
748 def armatureUpdate(armature):
751 def boneLayerMask(bone, mask):
753 for i, enable in enumerate(mask):