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 def progress_start(base):
69 progressBar=ProgressBar(base)
71 def progress_finish():
75 def progress_print(message, progress=0.05):
77 progressBar.advance(message, progress)
79 def progress_set(message, progress):
81 progressBar.set(message, progress)
84 ###############################################################################
85 # for mqo mikoto bone.
86 ###############################################################################
87 class MikotoBone(object):
90 'iHead', 'iTail', 'iUp',
91 'vHead', 'vTail', 'vUp',
92 'parent', 'isFloating',
95 def __init__(self, face=None, vertices=None, materials=None):
103 self.name=materials[face.material_index].name.encode('utf-8')
114 sqNorm0=e01.getSqNorm()
115 sqNorm1=e12.getSqNorm()
116 sqNorm2=e20.getSqNorm()
152 self.vHead=vertices[self.iHead]
153 self.vTail=vertices[self.iTail]
154 self.vUp=vertices[self.iUp]
156 if self.name.endswith('[]'):
157 basename=self.name[0:-2]
160 self.name="%s_L" % basename
162 self.name="%s_R" % basename
165 def setParent(self, parent, floating=False):
169 parent.children.append(self)
171 def printTree(self, indent=''):
172 print("%s%s" % (indent, self.name))
173 for child in self.children:
174 child.printTree(indent+' ')
177 def build_armature(armature, mikotoBone, parent=None):
179 create a armature bone.
181 bone = Armature.Editbone()
182 bone.name = mikotoBone.name.encode('utf-8')
183 armature.bones[bone.name] = bone
185 bone.head = Mathutils.Vector(*mikotoBone.vHead.to_a())
186 bone.tail = Mathutils.Vector(*mikotoBone.vTail.to_a())
189 if mikotoBone.isFloating:
192 bone.options=[Armature.CONNECTED]
194 for child in mikotoBone.children:
195 build_armature(armature, child, bone)
198 def create_armature(scene, mqo):
203 for o in mqo.objects:
204 if o.name.startswith('bone'):
211 for f in boneObject.faces:
213 print("invalid index_count: %d" % f.index_count)
215 b=MikotoBone(f, boneObject.vertices, mqo.materials)
219 # build mikoto bone tree
221 mikotoRoot=MikotoBone()
223 for b in tailMap.values():
224 # each bone has unique parent or is root bone.
225 if b.iHead in tailMap:
226 b.setParent(tailMap[b.iHead])
229 for e in boneObject.edges:
230 if b.iHead==e.indices[0]:
232 if e.indices[1] in tailMap:
233 b.setParent(tailMap[e.indices[1]], True)
236 elif b.iHead==e.indices[1]:
238 if e.indices[0] in tailMap:
239 b.setParent(tailMap[e.indices[0]], True)
246 b.setParent(mikotoRoot, True)
248 if len(mikotoRoot.children)==0:
249 print("no root bone")
252 if len(mikotoRoot.children)==1:
254 mikotoRoot=mikotoRoot.children[0]
255 mikotoRoot.parent=None
257 mikotoRoot.vHead=Vector3(0, 10, 0)
258 mikotoRoot.vTail=Vector3(0, 0, 0)
263 armature = Armature.New()
265 armature_object = scene.objects.new(armature)
267 act = Armature.NLA.NewAction()
268 act.setActive(armature_object)
270 armature_object.drawMode |= Object.DrawModes.XRAY
272 armature.drawType = Armature.OCTAHEDRON
273 armature.envelopes = False
274 armature.vertexGroups = True
275 armature.mirrorEdit = True
276 armature.drawNames=True
279 armature.makeEditable()
280 build_armature(armature, mikotoRoot)
283 return armature_object
286 class TrianglePlane(object):
288 mikoto方式ボーンのアンカーウェイト計算用。
294 def __init__(self, v0, v1, v2):
299 def isInsideXY(self, p):
300 v0=Vector2(self.v0.x, self.v0.y)
301 v1=Vector2(self.v1.x, self.v1.y)
302 v2=Vector2(self.v2.x, self.v2.y)
306 c0=Vector2.cross(e01, p-v0)
307 c1=Vector2.cross(e12, p-v1)
308 c2=Vector2.cross(e20, p-v2)
309 if c0>=0 and c1>=0 and c2>=0:
311 if c0<=0 and c1<=0 and c2<=0:
314 def isInsideYZ(self, p):
315 v0=Vector2(self.v0.y, self.v0.z)
316 v1=Vector2(self.v1.y, self.v1.z)
317 v2=Vector2(self.v2.y, self.v2.z)
321 c0=Vector2.cross(e01, p-v0)
322 c1=Vector2.cross(e12, p-v1)
323 c2=Vector2.cross(e20, p-v2)
324 if c0>=0 and c1>=0 and c2>=0:
326 if c0<=0 and c1<=0 and c2<=0:
329 def isInsideZX(self, p):
330 v0=Vector2(self.v0.z, self.v0.x)
331 v1=Vector2(self.v1.z, self.v1.x)
332 v2=Vector2(self.v2.z, self.v2.x)
336 c0=Vector2.cross(e01, p-v0)
337 c1=Vector2.cross(e12, p-v1)
338 c2=Vector2.cross(e20, p-v2)
339 if c0>=0 and c1>=0 and c2>=0:
341 if c0<=0 and c1<=0 and c2<=0:
345 class MikotoAnchor(object):
356 def push(self, face, vertices):
357 if face.index_count==3:
358 self.triangles.append(TrianglePlane(
359 vertices[face.indices[0]],
360 vertices[face.indices[1]],
361 vertices[face.indices[2]]
363 elif face.index_count==4:
364 self.triangles.append(TrianglePlane(
365 vertices[face.indices[0]],
366 vertices[face.indices[1]],
367 vertices[face.indices[2]]
369 self.triangles.append(TrianglePlane(
370 vertices[face.indices[2]],
371 vertices[face.indices[3]],
372 vertices[face.indices[0]]
376 self.bbox=BoundingBox(vertices[face.indices[0]])
377 for i in face.indices:
378 self.bbox.expand(vertices[i])
381 def calcWeight(self, v):
382 if not self.bbox.isInside(v):
385 if self.anyXY(v.x, v.y) and self.anyYZ(v.y, v.z) and self.anyZX(v.z, v.x):
390 def anyXY(self, x, y):
391 for t in self.triangles:
392 if t.isInsideXY(Vector2(x, y)):
396 def anyYZ(self, y, z):
397 for t in self.triangles:
398 if t.isInsideYZ(Vector2(y, z)):
402 def anyZX(self, z, x):
403 for t in self.triangles:
404 if t.isInsideZX(Vector2(z, x)):
409 def create_bone_weight(scene, mqo, armature_object, objects):
411 create mikoto bone weight.
414 # setup mikoto anchors
415 for o in mqo.objects:
416 if o.name.startswith("anchor"):
418 name=mqo.materials[f.material_index].name
419 if name.endswith('[]'):
421 v=o.vertices[f.indices[0]]
425 if not name_L in anchorMap:
426 anchorMap[name_L]=MikotoAnchor()
427 anchorMap[name_L].push(f, o.vertices)
431 if not name_R in anchorMap:
432 anchorMap[name_R]=MikotoAnchor()
433 anchorMap[name_R].push(f, o.vertices)
437 if not name in anchorMap:
438 anchorMap[name]=MikotoAnchor()
439 anchorMap[name].push(f, o.vertices)
442 # add armature modifier
443 mod=o.modifiers.append(Modifier.Types.ARMATURE)
444 mod[Modifier.Settings.OBJECT] = armature_object
445 mod[Modifier.Settings.ENVELOPES] = False
447 # create vertex group
448 mesh=o.getData(mesh=True)
449 for name in anchorMap.keys():
450 mesh.addVertGroup(name)
453 # assing vertices to vertex group
455 mesh=o.getData(mesh=True)
456 for i, mvert in enumerate(mesh.verts):
458 for name, anchor in anchorMap.items():
459 weight=anchor.calcWeight(mvert.co)
461 mesh.assignVertsToGroup(
462 name, [i], weight, Mesh.AssignModes.ADD)
465 # debug orphan vertex
466 print('orphan', mvert)
469 ###############################################################################
470 def createEmptyObject(scene, name):
471 empty=scene.objects.new("Empty")
475 def createMaterial(name):
476 material = Blender.Material.New(name)
479 def createMqoMaterial(m):
480 material = Blender.Material.New(m.getName().encode(INTERNAL_ENCODING))
481 material.mode |= Blender.Material.Modes.SHADELESS
482 material.rgbCol = [m.color.r, m.color.g, m.color.b]
483 material.alpha = m.color.a
484 material.amb = m.ambient
485 material.spec = m.specular
486 material.hard = int(255 * m.power)
489 def createPmdMaterial(m):
490 material=Blender.Material.New()
491 material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
493 material.diffuseSize = 3.14/2
494 material.setDiffuseSmooth(0)
495 material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
496 material.setSpecSize(0)
498 material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
499 material.setAlpha(m.diffuse.a)
500 material.setSpec(m.shinness*0.1)
501 material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
502 material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
503 material.enableSSS=True if m.flag==1 else False
506 def createTexture(path):
507 image = Blender.Image.Load(path.encode(INTERNAL_ENCODING))
508 texture = Blender.Texture.New(path.encode(INTERNAL_ENCODING))
509 texture.type = Blender.Texture.Types.IMAGE
510 texture.image = image
511 return texture, image
513 def materialAddTexture(material, texture):
514 material.mode = material.mode | Blender.Material.Modes.TEXFACE
515 material.setTexture(0, texture, Blender.Texture.TexCo.UV)
518 def createMesh(scene, name):
519 mesh = Blender.Mesh.New()
520 mesh_object=scene.objects.new(mesh, name.encode(INTERNAL_ENCODING))
521 return mesh, mesh_object
524 def objectMakeParent(parent, child):
525 parent.makeParent([child])
528 def meshAddMaterial(mesh, material):
529 mesh.materials+=[material]
532 def meshAddMqoGeometry(mesh, o, materials, imageMap, scale):
534 mesh.verts.extend(Mathutils.Vector(0, 0, 0)) # dummy
535 mesh.verts.extend([(v.x, -v.z, v.y) for v in o.vertices])
540 for i in xrange(face.index_count):
541 face_indices.append(face.getIndex(i)+1)
542 mesh_faces.append(face_indices)
543 #new_faces=mesh.faces.extend([face.indices for face in o.faces],
544 new_faces=mesh.faces.extend(mesh_faces,
549 # gather used materials
554 materialMap[o.faces[i].material_index]=True
556 # blender limits 16 materials per mesh
558 for i, material_index in enumerate(materialMap.keys()):
560 print("over 16 materials!")
562 mesh.materials+=[materials[material_index]]
563 materialMap[material_index]=i
566 for i, f in enumerate(o.faces):
567 if not type(new_faces[i]) is int:
570 face=mesh.faces[new_faces[i]]
573 for i in xrange(f.index_count):
574 uv_array.append(Blender.Mathutils.Vector(
580 except Exception as msg:
582 #print face.index, uv_array
585 if f.material_index in materialMap:
586 face.mat = materialMap[f.material_index]
590 # rmeove dummy 0 vertex
593 mesh.mode |= Blender.Mesh.Modes.AUTOSMOOTH
594 mesh.maxSmoothAngle = int(o.smoothing)
602 mod=mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)
604 def getTexture(m, dirname):
608 for texture in m.getTextures():
609 if texture and texture.tex and texture.tex.getImage():
610 image=texture.tex.getImage()
613 imagePath=Blender.sys.expandpath(image.getFilename())
614 if len(dirname)>0 and imagePath.startswith(dirname):
616 imagePath=imagePath[len(dirname)+1:len(imagePath)]
618 tex=" tex(\"%s\")" % imagePath
619 elif texture.mtAlpha>0:
620 aplane=" aplane(\"%s\")" % imagePath
623 def objectDuplicate(scene, obj):
624 mesh, dumy=createMesh(scene, obj.name.decode(INTERNAL_ENCODING))
625 # not apply modifiers
626 mesh.getFromObject(obj.name, 1)
628 dumy.setMatrix(obj.matrixWorld)
631 def objectDelete(scene, obj):
632 scene.objects.unlink(obj)
634 def faceVertexCount(face):
637 def faceVertices(face):
639 return [v.index for v in reversed(face.v)]
644 def faceHasUV(mesh, i, face):
645 return len(face.uv)>0
647 def faceGetUV(mesh, i, face, count):
649 return reversed(face.uv)
651 def materialToMqo(m):
652 return "\"%s\" shader(3) col(%f %f %f %f)" % (
653 m.name, m.rgbCol[0], m.rgbCol[1], m.rgbCol[2], m.alpha)
655 def faceMaterialIndex(face):
658 def objectGetData(o):
659 return o.getData(mesh=True)
661 def objectAddArmatureModifier(o, armature_object):
662 mod=o.modifiers.append(Blender.Modifier.Types.ARMATURE)
663 mod[Blender.Modifier.Settings.OBJECT] = armature_object
664 mod[Blender.Modifier.Settings.ENVELOPES] = False
669 def objectGetPose(o):
672 def poseBoneLimit(n, b):
675 if n.startswith("knee_"):
680 b.limitMax=[180, 0, 0]
681 elif n.startswith("ankle_"):
685 Blender.Window.EditMode(1)
688 Blender.Window.EditMode(0)
690 def objectDeselectAll():
691 for o in bpy.data.scenes.active.objects:
694 def objectActivate(scene, o):
696 scene.objects.active=o
698 def objectGetActive(scene):
699 return scene.objects.active
701 def meshAddVertexGroup(meshObject, name):
702 meshObject.getData(mesh=True).addVertGroup(name)
704 def meshUseVertexUv(mesh):
707 def vertexSetNormal(mvert, normal):
708 mvert.no=Mathutils.Vector(*normal)
710 def vertexSetUv(mvert, uv):
713 def meshAssignVertexGroup(meshObject, name, index, weight):
714 meshObject.getData(mesh=True).assignVertsToGroup(name,
715 [index], weight, Blender.Mesh.AssignModes.ADD)
717 def meshCreateVerteicesAndFaces(mesh, vertices, faces):
718 mesh.verts.extend(vertices)
719 mesh.faces.extend(faces, ignoreDups=True)
722 mesh.addUVLayer('NewUV')
724 def meshVertsDelete(mesh, remove_vertices):
725 mesh.verts.delete(remove_vertices)
727 def createArmature(scene):
728 armature = Blender.Armature.New()
729 armature_object = scene.objects.new(armature)
732 armature_object.drawMode = (
733 armature_object.drawMode | Blender.Object.DrawModes.XRAY)
735 armature.drawType = Blender.Armature.OCTAHEDRON
736 armature.drawNames=True
737 armature.envelopes = False
738 armature.vertexGroups = True
739 armature.mirrorEdit = True
741 return armature, armature_object
743 def armatureMakeEditable(scene, armature_object):
745 armature_object.getData().makeEditable()
747 def createIkConstraint(armature_object, p_bone, effector_name, ik):
748 cSetting = Blender.Constraint.Settings
750 constraint = p_bone.constraints.append(Blender.Constraint.Type.IKSOLVER)
751 constraint[cSetting.CHAINLEN]=len(ik.children)
752 constraint[cSetting.TARGET]=armature_object
753 constraint[cSetting.USETIP]=False
754 constraint[cSetting.BONE]=effector_name
755 # not used. place folder when export.
756 constraint[cSetting.ROTWEIGHT]=ik.weight
757 constraint[cSetting.ITERATIONS]=ik.iterations * 10
760 def createArmatureBone(armature, name):
761 bone=Blender.Armature.Editbone()
762 bone.name=name.encode(INTERNAL_ENCODING)
763 armature.bones[name]=bone
766 def boneSetConnected(bone):
767 bone.options+=[Blender.Armature.CONNECTED]
769 def createVector(x, y, z):
770 return Mathutils.Vector(x, y, z)
772 def armatureUpdate(armature):
775 def boneLayerMask(bone, layers):
777 for i, enable in enumerate(layers):
782 def objectPinShape(o):
785 def objectAddShapeKey(o, name):
786 mesh=o.getData(mesh=True)
788 block=mesh.key.blocks[-1]
789 block.name=name.encode(INTERNAL_ENCODING)
792 def objectActivateShapeKey(o, index):
795 def shapeKeyAssign(shapeKey, index, pos):
796 shapeKey.data[index]=pos
798 def objectIsVisible(obj):
799 return obj.restrictDisplay
801 def meshVertexGroupNames(meshObject):
802 return meshObject.getData(mesh=True).getVertGroupNames()
804 def faceNormal(face):
807 def meshFaceUv(mesh, i, face):
810 def armatureModifierGetObject(m):
811 return m[Blender.Modifier.Settings.OBJECT]
813 def objectHasShapeKey(o):
814 return o.getData(mesh=True).key
816 def objectShapeKeys(o):
817 return o.getData(mesh=True).key.blocks
819 def meshVertexGroup(meshObject, name):
821 for index in meshObject.getData(mesh=True).getVertsFromGroup(name):
822 indices.append(index)
825 def materialGet(scene, material_name):
826 return Blender.Material.Get(material_name)
828 def modifierIsArmature(m):
829 return m.name=="Armature"
831 def boneHeadLocal(b):
832 return b.head['ARMATURESPACE'][0:3]
834 def boneTailLocal(b):
835 return b.tail['ARMATURESPACE'][0:3]
837 def boneIsConnected(b):
838 return Blender.Armature.CONNECTED in b.options
840 def constraintIsIKSolver(c):
841 return c.type==Blender.Constraint.Type.IKSOLVER
844 return c[Blender.Constraint.Settings.CHAINLEN]
847 return c[Blender.Constraint.Settings.BONE]
850 return c[Blender.Constraint.Settings.ITERATIONS]
852 def ikRotationWeight(c):
853 return c[Blender.Constraint.Settings.ROTWEIGHT]
855 def shapeKeyGet(b, index):