5 from Blender import Mathutils
8 #
\e$B%U%!%$%k%7%9%F%`$NJ8;z%3!<%I
\e(B
9 #
\e$B2~B$HG$H$N6&MQ$N$?$a
\e(B
10 FS_ENCODING=sys.getfilesystemencoding()
11 if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):
12 INTERNAL_ENCODING='utf-8'
14 INTERNAL_ENCODING=FS_ENCODING
18 def __init__(self, path, encoding):
19 self.io=open(path, "wb")
20 self.encoding=encoding
32 def createEmptyObject(scene, name):
33 empty=scene.objects.new("Empty")
38 def createMqoMaterial(m):
39 material = Blender.Material.New(m.getName().encode(INTERNAL_ENCODING))
40 material.mode |= Blender.Material.Modes.SHADELESS
41 material.rgbCol = [m.color.r, m.color.g, m.color.b]
42 material.alpha = m.color.a
43 material.amb = m.ambient
44 material.spec = m.specular
45 material.hard = int(255 * m.power)
49 def createTexture(path):
50 image = Blender.Image.Load(path.encode(INTERNAL_ENCODING))
51 texture = Blender.Texture.New(path.encode(INTERNAL_ENCODING))
52 texture.type = Blender.Texture.Types.IMAGE
57 def materialAddTexture(material, texture):
58 material.mode = material.mode | Blender.Material.Modes.TEXFACE
59 material.setTexture(0, texture, Blender.Texture.TexCo.UV)
62 def createMesh(scene, name):
63 mesh = Blender.Mesh.New()
64 mesh_object=scene.objects.new(mesh, name.encode(INTERNAL_ENCODING))
65 return mesh, mesh_object
68 def objectMakeParent(parent, child):
69 parent.makeParent([child])
72 def meshAddMqoGeometry(mesh, o, materials, imageMap, scale):
74 mesh.verts.extend(Mathutils.Vector(0, 0, 0)) # dummy
75 mesh.verts.extend([(v.x, -v.z, v.y) for v in o.vertices])
80 for i in xrange(face.index_count):
81 face_indices.append(face.getIndex(i)+1)
82 mesh_faces.append(face_indices)
83 #new_faces=mesh.faces.extend([face.indices for face in o.faces],
84 new_faces=mesh.faces.extend(mesh_faces,
89 # gather used materials
94 materialMap[o.faces[i].material_index]=True
96 # blender limits 16 materials per mesh
98 for i, material_index in enumerate(materialMap.keys()):
100 print("over 16 materials!")
102 mesh.materials+=[materials[material_index]]
103 materialMap[material_index]=i
106 for i, f in enumerate(o.faces):
107 if not type(new_faces[i]) is int:
110 face=mesh.faces[new_faces[i]]
113 for i in xrange(f.index_count):
114 uv_array.append(Blender.Mathutils.Vector(
120 except Exception as msg:
122 #print face.index, uv_array
125 if f.material_index in materialMap:
126 face.mat = materialMap[f.material_index]
130 # rmeove dummy 0 vertex
133 mesh.mode |= Blender.Mesh.Modes.AUTOSMOOTH
134 mesh.maxSmoothAngle = int(o.smoothing)
142 mod=mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)
144 ###############################################################################
145 # for mqo mikoto bone.
146 ###############################################################################
147 class MikotoBone(object):
150 'iHead', 'iTail', 'iUp',
151 'vHead', 'vTail', 'vUp',
152 'parent', 'isFloating',
155 def __init__(self, face=None, vertices=None, materials=None):
157 self.isFloating=False
163 self.name=materials[face.material_index].name.encode('utf-8')
174 sqNorm0=e01.getSqNorm()
175 sqNorm1=e12.getSqNorm()
176 sqNorm2=e20.getSqNorm()
212 self.vHead=vertices[self.iHead]
213 self.vTail=vertices[self.iTail]
214 self.vUp=vertices[self.iUp]
216 if self.name.endswith('[]'):
217 basename=self.name[0:-2]
220 self.name="%s_L" % basename
222 self.name="%s_R" % basename
225 def setParent(self, parent, floating=False):
229 parent.children.append(self)
231 def printTree(self, indent=''):
232 print("%s%s" % (indent, self.name))
233 for child in self.children:
234 child.printTree(indent+' ')
237 def build_armature(armature, mikotoBone, parent=None):
239 create a armature bone.
241 bone = Armature.Editbone()
242 bone.name = mikotoBone.name.encode('utf-8')
243 armature.bones[bone.name] = bone
245 bone.head = Mathutils.Vector(*mikotoBone.vHead.to_a())
246 bone.tail = Mathutils.Vector(*mikotoBone.vTail.to_a())
249 if mikotoBone.isFloating:
252 bone.options=[Armature.CONNECTED]
254 for child in mikotoBone.children:
255 build_armature(armature, child, bone)
258 def create_armature(scene, mqo):
263 for o in mqo.objects:
264 if o.name.startswith('bone'):
271 for f in boneObject.faces:
273 print("invalid index_count: %d" % f.index_count)
275 b=MikotoBone(f, boneObject.vertices, mqo.materials)
279 # build mikoto bone tree
281 mikotoRoot=MikotoBone()
283 for b in tailMap.values():
284 # each bone has unique parent or is root bone.
285 if b.iHead in tailMap:
286 b.setParent(tailMap[b.iHead])
289 for e in boneObject.edges:
290 if b.iHead==e.indices[0]:
292 if e.indices[1] in tailMap:
293 b.setParent(tailMap[e.indices[1]], True)
296 elif b.iHead==e.indices[1]:
298 if e.indices[0] in tailMap:
299 b.setParent(tailMap[e.indices[0]], True)
306 b.setParent(mikotoRoot, True)
308 if len(mikotoRoot.children)==0:
309 print("no root bone")
312 if len(mikotoRoot.children)==1:
314 mikotoRoot=mikotoRoot.children[0]
315 mikotoRoot.parent=None
317 mikotoRoot.vHead=Vector3(0, 10, 0)
318 mikotoRoot.vTail=Vector3(0, 0, 0)
323 armature = Armature.New()
325 armature_object = scene.objects.new(armature)
327 act = Armature.NLA.NewAction()
328 act.setActive(armature_object)
330 armature_object.drawMode |= Object.DrawModes.XRAY
332 armature.drawType = Armature.OCTAHEDRON
333 armature.envelopes = False
334 armature.vertexGroups = True
335 armature.mirrorEdit = True
336 armature.drawNames=True
339 armature.makeEditable()
340 build_armature(armature, mikotoRoot)
343 return armature_object
346 class TrianglePlane(object):
348 mikoto
\e$BJ}<0%\!<%s$N%"%s%+!<%&%'%$%H7W;;MQ!#
\e(B
354 def __init__(self, v0, v1, v2):
359 def isInsideXY(self, p):
360 v0=Vector2(self.v0.x, self.v0.y)
361 v1=Vector2(self.v1.x, self.v1.y)
362 v2=Vector2(self.v2.x, self.v2.y)
366 c0=Vector2.cross(e01, p-v0)
367 c1=Vector2.cross(e12, p-v1)
368 c2=Vector2.cross(e20, p-v2)
369 if c0>=0 and c1>=0 and c2>=0:
371 if c0<=0 and c1<=0 and c2<=0:
374 def isInsideYZ(self, p):
375 v0=Vector2(self.v0.y, self.v0.z)
376 v1=Vector2(self.v1.y, self.v1.z)
377 v2=Vector2(self.v2.y, self.v2.z)
381 c0=Vector2.cross(e01, p-v0)
382 c1=Vector2.cross(e12, p-v1)
383 c2=Vector2.cross(e20, p-v2)
384 if c0>=0 and c1>=0 and c2>=0:
386 if c0<=0 and c1<=0 and c2<=0:
389 def isInsideZX(self, p):
390 v0=Vector2(self.v0.z, self.v0.x)
391 v1=Vector2(self.v1.z, self.v1.x)
392 v2=Vector2(self.v2.z, self.v2.x)
396 c0=Vector2.cross(e01, p-v0)
397 c1=Vector2.cross(e12, p-v1)
398 c2=Vector2.cross(e20, p-v2)
399 if c0>=0 and c1>=0 and c2>=0:
401 if c0<=0 and c1<=0 and c2<=0:
405 class MikotoAnchor(object):
407 mikoto
\e$BJ}<0%9%1%k%H%s$N%"%s%+!<!#
\e(B
416 def push(self, face, vertices):
417 if face.index_count==3:
418 self.triangles.append(TrianglePlane(
419 vertices[face.indices[0]],
420 vertices[face.indices[1]],
421 vertices[face.indices[2]]
423 elif face.index_count==4:
424 self.triangles.append(TrianglePlane(
425 vertices[face.indices[0]],
426 vertices[face.indices[1]],
427 vertices[face.indices[2]]
429 self.triangles.append(TrianglePlane(
430 vertices[face.indices[2]],
431 vertices[face.indices[3]],
432 vertices[face.indices[0]]
436 self.bbox=BoundingBox(vertices[face.indices[0]])
437 for i in face.indices:
438 self.bbox.expand(vertices[i])
441 def calcWeight(self, v):
442 if not self.bbox.isInside(v):
445 if self.anyXY(v.x, v.y) and self.anyYZ(v.y, v.z) and self.anyZX(v.z, v.x):
450 def anyXY(self, x, y):
451 for t in self.triangles:
452 if t.isInsideXY(Vector2(x, y)):
456 def anyYZ(self, y, z):
457 for t in self.triangles:
458 if t.isInsideYZ(Vector2(y, z)):
462 def anyZX(self, z, x):
463 for t in self.triangles:
464 if t.isInsideZX(Vector2(z, x)):
469 def create_bone_weight(scene, mqo, armature_object, objects):
471 create mikoto bone weight.
474 # setup mikoto anchors
475 for o in mqo.objects:
476 if o.name.startswith("anchor"):
478 name=mqo.materials[f.material_index].name
479 if name.endswith('[]'):
481 v=o.vertices[f.indices[0]]
485 if not name_L in anchorMap:
486 anchorMap[name_L]=MikotoAnchor()
487 anchorMap[name_L].push(f, o.vertices)
491 if not name_R in anchorMap:
492 anchorMap[name_R]=MikotoAnchor()
493 anchorMap[name_R].push(f, o.vertices)
497 if not name in anchorMap:
498 anchorMap[name]=MikotoAnchor()
499 anchorMap[name].push(f, o.vertices)
502 # add armature modifier
503 mod=o.modifiers.append(Modifier.Types.ARMATURE)
504 mod[Modifier.Settings.OBJECT] = armature_object
505 mod[Modifier.Settings.ENVELOPES] = False
507 # create vertex group
508 mesh=o.getData(mesh=True)
509 for name in anchorMap.keys():
510 mesh.addVertGroup(name)
513 # assing vertices to vertex group
515 mesh=o.getData(mesh=True)
516 for i, mvert in enumerate(mesh.verts):
518 for name, anchor in anchorMap.items():
519 weight=anchor.calcWeight(mvert.co)
521 mesh.assignVertsToGroup(
522 name, [i], weight, Mesh.AssignModes.ADD)
525 # debug orphan vertex
526 print('orphan', mvert)
529 ###############################################################################
530 def getTexture(m, dirname):
534 for texture in m.getTextures():
535 if texture and texture.tex and texture.tex.getImage():
536 image=texture.tex.getImage()
539 imagePath=Blender.sys.expandpath(image.getFilename())
540 if len(dirname)>0 and imagePath.startswith(dirname):
541 #
\e$BAjBP%Q%9$KJQ49$9$k
\e(B
542 imagePath=imagePath[len(dirname)+1:len(imagePath)]
544 tex=" tex(\"%s\")" % imagePath
545 elif texture.mtAlpha>0:
546 aplane=" aplane(\"%s\")" % imagePath
549 def objectDuplicate(scene, obj):
550 mesh, dumy=createMesh(scene, obj.name.decode(INTERNAL_ENCODING))
551 # not apply modifiers
552 mesh.getFromObject(obj.name, 1)
554 dumy.setMatrix(obj.matrixWorld)
557 def faceVertexCount(face):
560 def faceVertices(face):
562 return [v.index for v in reversed(face.v)]
567 def faceHasUV(mesh, i, face):
568 return len(face.uv)>0
570 def faceGetUV(mesh, i, face, count):
572 return reversed(face.uv)
574 def materialToMqo(m):
575 return "\"%s\" shader(3) col(%f %f %f %f)" % (
576 m.name, m.rgbCol[0], m.rgbCol[1], m.rgbCol[2], m.alpha)
578 def faceMaterialIndex(face):