import sys
import os
import Blender
+from Blender import Mathutils
+
# \e$B%U%!%$%k%7%9%F%`$NJ8;z%3!<%I\e(B
# \e$B2~B$HG$H$N6&MQ$N$?$a\e(B
else:
INTERNAL_ENCODING=FS_ENCODING
+
def createEmptyObject(scene, name):
empty=scene.objects.new("Empty")
empty.setName(name)
return empty
-def createMaterial(m):
+
+def createMqoMaterial(m):
material = Blender.Material.New(m.getName().encode(INTERNAL_ENCODING))
material.mode |= Blender.Material.Modes.SHADELESS
material.rgbCol = [m.color.r, m.color.g, m.color.b]
material.hard = int(255 * m.power)
return material
+
def createTexture(path):
image = Blender.Image.Load(path.encode(INTERNAL_ENCODING))
texture = Blender.Texture.New(path.encode(INTERNAL_ENCODING))
texture.image = image
return texture, image
+
def materialAddTexture(material, texture):
material.mode = material.mode | Blender.Material.Modes.TEXFACE
material.setTexture(0, texture, Blender.Texture.TexCo.UV)
+
+def createMesh(scene, name):
+ mesh = Blender.Mesh.New()
+ mesh_object=scene.objects.new(mesh, name.encode(INTERNAL_ENCODING))
+ return mesh, mesh_object
+
+
+def objectMakeParent(parent, child):
+ parent.makeParent([child])
+
+
+def meshAddMqoGeometry(mesh, o, materials, imageMap, scale):
+ # add vertices
+ mesh.verts.extend(Mathutils.Vector(0, 0, 0)) # dummy
+ mesh.verts.extend([(v.x, -v.z, v.y) for v in o.vertices])
+ # add faces
+ mesh_faces=[]
+ for face in o.faces:
+ face_indices=[]
+ for i in xrange(face.index_count):
+ face_indices.append(face.getIndex(i)+1)
+ mesh_faces.append(face_indices)
+ #new_faces=mesh.faces.extend([face.indices for face in o.faces],
+ new_faces=mesh.faces.extend(mesh_faces,
+ #ignoreDups=True,
+ indexList=True)
+ mesh.update()
+
+ # gather used materials
+ materialMap = {}
+ if new_faces:
+ for i in new_faces:
+ if type(i) is int:
+ materialMap[o.faces[i].material_index]=True
+
+ # blender limits 16 materials per mesh
+ # separate mesh ?
+ for i, material_index in enumerate(materialMap.keys()):
+ if i>=16:
+ print("over 16 materials!")
+ break
+ mesh.materials+=[materials[material_index]]
+ materialMap[material_index]=i
+
+ # set face params
+ for i, f in enumerate(o.faces):
+ if not type(new_faces[i]) is int:
+ continue
+
+ face=mesh.faces[new_faces[i]]
+
+ uv_array=[]
+ for i in xrange(f.index_count):
+ uv_array.append(Blender.Mathutils.Vector(
+ f.getUV(i).x,
+ 1.0-f.getUV(i).y)
+ )
+ try:
+ face.uv=uv_array
+ except Exception as msg:
+ #print msg
+ #print face.index, uv_array
+ pass
+
+ if f.material_index in materialMap:
+ face.mat = materialMap[f.material_index]
+
+ face.smooth = 1
+
+ # rmeove dummy 0 vertex
+ mesh.verts.delete(0)
+
+ mesh.mode |= Blender.Mesh.Modes.AUTOSMOOTH
+ mesh.maxSmoothAngle = int(o.smoothing)
+ mesh.smooth()
+ mesh.calcNormals()
+ mesh.flipNormals()
+ mesh.update()
+
+ # mirror modifier
+ if o.mirror:
+ mod=mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)
+
+###############################################################################
+# for mqo mikoto bone.
+###############################################################################
+class MikotoBone(object):
+ __slots__=[
+ 'name',
+ 'iHead', 'iTail', 'iUp',
+ 'vHead', 'vTail', 'vUp',
+ 'parent', 'isFloating',
+ 'children',
+ ]
+ def __init__(self, face=None, vertices=None, materials=None):
+ self.parent=None
+ self.isFloating=False
+ self.children=[]
+ if not face:
+ self.name='root'
+ return
+
+ self.name=materials[face.material_index].name.encode('utf-8')
+
+ i0=face.indices[0]
+ i1=face.indices[1]
+ i2=face.indices[2]
+ v0=vertices[i0]
+ v1=vertices[i1]
+ v2=vertices[i2]
+ e01=v1-v0
+ e12=v2-v1
+ e20=v0-v2
+ sqNorm0=e01.getSqNorm()
+ sqNorm1=e12.getSqNorm()
+ sqNorm2=e20.getSqNorm()
+ if sqNorm0>sqNorm1:
+ if sqNorm1>sqNorm2:
+ # e01 > e12 > e20
+ self.iHead=i2
+ self.iTail=i1
+ self.iUp=i0
+ else:
+ if sqNorm0>sqNorm2:
+ # e01 > e20 > e12
+ self.iHead=i2
+ self.iTail=i0
+ self.iUp=i1
+ else:
+ # e20 > e01 > e12
+ self.iHead=i1
+ self.iTail=i0
+ self.iUp=i2
+ else:
+ # 0 < 1
+ if sqNorm1<sqNorm2:
+ # e20 > e12 > e01
+ self.iHead=i1
+ self.iTail=i2
+ self.iUp=i0
+ else:
+ if sqNorm0<sqNorm2:
+ # e12 > e20 > e01
+ self.iHead=i0
+ self.iTail=i2
+ self.iUp=i1
+ else:
+ # e12 > e01 > e20
+ self.iHead=i0
+ self.iTail=i1
+ self.iUp=i2
+ self.vHead=vertices[self.iHead]
+ self.vTail=vertices[self.iTail]
+ self.vUp=vertices[self.iUp]
+
+ if self.name.endswith('[]'):
+ basename=self.name[0:-2]
+ # expand LR name
+ if self.vTail.x>0:
+ self.name="%s_L" % basename
+ else:
+ self.name="%s_R" % basename
+
+
+ def setParent(self, parent, floating=False):
+ if floating:
+ self.isFloating=True
+ self.parent=parent
+ parent.children.append(self)
+
+ def printTree(self, indent=''):
+ print("%s%s" % (indent, self.name))
+ for child in self.children:
+ child.printTree(indent+' ')
+
+
+def build_armature(armature, mikotoBone, parent=None):
+ """
+ create a armature bone.
+ """
+ bone = Armature.Editbone()
+ bone.name = mikotoBone.name.encode('utf-8')
+ armature.bones[bone.name] = bone
+
+ bone.head = Mathutils.Vector(*mikotoBone.vHead.to_a())
+ bone.tail = Mathutils.Vector(*mikotoBone.vTail.to_a())
+ if parent:
+ bone.parent=parent
+ if mikotoBone.isFloating:
+ pass
+ else:
+ bone.options=[Armature.CONNECTED]
+
+ for child in mikotoBone.children:
+ build_armature(armature, child, bone)
+
+
+def create_armature(scene, mqo):
+ """
+ create armature
+ """
+ boneObject=None
+ for o in mqo.objects:
+ if o.name.startswith('bone'):
+ boneObject=o
+ break
+ if not boneObject:
+ return
+
+ tailMap={}
+ for f in boneObject.faces:
+ if f.index_count!=3:
+ print("invalid index_count: %d" % f.index_count)
+ continue
+ b=MikotoBone(f, boneObject.vertices, mqo.materials)
+ tailMap[b.iTail]=b
+
+ ####################
+ # build mikoto bone tree
+ ####################
+ mikotoRoot=MikotoBone()
+
+ for b in tailMap.values():
+ # each bone has unique parent or is root bone.
+ if b.iHead in tailMap:
+ b.setParent(tailMap[b.iHead])
+ else:
+ isFloating=False
+ for e in boneObject.edges:
+ if b.iHead==e.indices[0]:
+ # floating bone
+ if e.indices[1] in tailMap:
+ b.setParent(tailMap[e.indices[1]], True)
+ isFloating=True
+ break
+ elif b.iHead==e.indices[1]:
+ # floating bone
+ if e.indices[0] in tailMap:
+ b.setParent(tailMap[e.indices[0]], True)
+ isFloating=True
+ break
+ if isFloating:
+ continue
+
+ # no parent bone
+ b.setParent(mikotoRoot, True)
+
+ if len(mikotoRoot.children)==0:
+ print("no root bone")
+ return
+
+ if len(mikotoRoot.children)==1:
+ # single root
+ mikotoRoot=mikotoRoot.children[0]
+ mikotoRoot.parent=None
+ else:
+ mikotoRoot.vHead=Vector3(0, 10, 0)
+ mikotoRoot.vTail=Vector3(0, 0, 0)
+
+ ####################
+ # create armature
+ ####################
+ armature = Armature.New()
+ # link to object
+ armature_object = scene.objects.new(armature)
+ # create action
+ act = Armature.NLA.NewAction()
+ act.setActive(armature_object)
+ # set XRAY
+ armature_object.drawMode |= Object.DrawModes.XRAY
+ # armature settings
+ armature.drawType = Armature.OCTAHEDRON
+ armature.envelopes = False
+ armature.vertexGroups = True
+ armature.mirrorEdit = True
+ armature.drawNames=True
+
+ # edit bones
+ armature.makeEditable()
+ build_armature(armature, mikotoRoot)
+ armature.update()
+
+ return armature_object
+
+
+class TrianglePlane(object):
+ """
+ mikoto\e$BJ}<0%\!<%s$N%"%s%+!<%&%'%$%H7W;;MQ!#\e(B
+ (\e$BIT40A4\e(B)
+ """
+ __slots__=['normal',
+ 'v0', 'v1', 'v2',
+ ]
+ def __init__(self, v0, v1, v2):
+ self.v0=v0
+ self.v1=v1
+ self.v2=v2
+
+ def isInsideXY(self, p):
+ v0=Vector2(self.v0.x, self.v0.y)
+ v1=Vector2(self.v1.x, self.v1.y)
+ v2=Vector2(self.v2.x, self.v2.y)
+ e01=v1-v0
+ e12=v2-v1
+ e20=v0-v2
+ c0=Vector2.cross(e01, p-v0)
+ c1=Vector2.cross(e12, p-v1)
+ c2=Vector2.cross(e20, p-v2)
+ if c0>=0 and c1>=0 and c2>=0:
+ return True
+ if c0<=0 and c1<=0 and c2<=0:
+ return True
+
+ def isInsideYZ(self, p):
+ v0=Vector2(self.v0.y, self.v0.z)
+ v1=Vector2(self.v1.y, self.v1.z)
+ v2=Vector2(self.v2.y, self.v2.z)
+ e01=v1-v0
+ e12=v2-v1
+ e20=v0-v2
+ c0=Vector2.cross(e01, p-v0)
+ c1=Vector2.cross(e12, p-v1)
+ c2=Vector2.cross(e20, p-v2)
+ if c0>=0 and c1>=0 and c2>=0:
+ return True
+ if c0<=0 and c1<=0 and c2<=0:
+ return True
+
+ def isInsideZX(self, p):
+ v0=Vector2(self.v0.z, self.v0.x)
+ v1=Vector2(self.v1.z, self.v1.x)
+ v2=Vector2(self.v2.z, self.v2.x)
+ e01=v1-v0
+ e12=v2-v1
+ e20=v0-v2
+ c0=Vector2.cross(e01, p-v0)
+ c1=Vector2.cross(e12, p-v1)
+ c2=Vector2.cross(e20, p-v2)
+ if c0>=0 and c1>=0 and c2>=0:
+ return True
+ if c0<=0 and c1<=0 and c2<=0:
+ return True
+
+
+class MikotoAnchor(object):
+ """
+ mikoto\e$BJ}<0%9%1%k%H%s$N%"%s%+!<!#\e(B
+ """
+ __slots__=[
+ "triangles", "bbox",
+ ]
+ def __init__(self):
+ self.triangles=[]
+ self.bbox=None
+
+ def push(self, face, vertices):
+ if face.index_count==3:
+ self.triangles.append(TrianglePlane(
+ vertices[face.indices[0]],
+ vertices[face.indices[1]],
+ vertices[face.indices[2]]
+ ))
+ elif face.index_count==4:
+ self.triangles.append(TrianglePlane(
+ vertices[face.indices[0]],
+ vertices[face.indices[1]],
+ vertices[face.indices[2]]
+ ))
+ self.triangles.append(TrianglePlane(
+ vertices[face.indices[2]],
+ vertices[face.indices[3]],
+ vertices[face.indices[0]]
+ ))
+ # bounding box
+ if not self.bbox:
+ self.bbox=BoundingBox(vertices[face.indices[0]])
+ for i in face.indices:
+ self.bbox.expand(vertices[i])
+
+
+ def calcWeight(self, v):
+ if not self.bbox.isInside(v):
+ return 0
+
+ if self.anyXY(v.x, v.y) and self.anyYZ(v.y, v.z) and self.anyZX(v.z, v.x):
+ return 1.0
+ else:
+ return 0
+
+ def anyXY(self, x, y):
+ for t in self.triangles:
+ if t.isInsideXY(Vector2(x, y)):
+ return True
+ return False
+
+ def anyYZ(self, y, z):
+ for t in self.triangles:
+ if t.isInsideYZ(Vector2(y, z)):
+ return True
+ return False
+
+ def anyZX(self, z, x):
+ for t in self.triangles:
+ if t.isInsideZX(Vector2(z, x)):
+ return True
+ return False
+
+
+def create_bone_weight(scene, mqo, armature_object, objects):
+ """
+ create mikoto bone weight.
+ """
+ anchorMap={}
+ # setup mikoto anchors
+ for o in mqo.objects:
+ if o.name.startswith("anchor"):
+ for f in o.faces:
+ name=mqo.materials[f.material_index].name
+ if name.endswith('[]'):
+ basename=name[0:-2]
+ v=o.vertices[f.indices[0]]
+ if(v.x>0):
+ # L
+ name_L=basename+'_L'
+ if not name_L in anchorMap:
+ anchorMap[name_L]=MikotoAnchor()
+ anchorMap[name_L].push(f, o.vertices)
+ elif(v.x<0):
+ # R
+ name_R=basename+'_R'
+ if not name_R in anchorMap:
+ anchorMap[name_R]=MikotoAnchor()
+ anchorMap[name_R].push(f, o.vertices)
+ else:
+ print("no side", v)
+ else:
+ if not name in anchorMap:
+ anchorMap[name]=MikotoAnchor()
+ anchorMap[name].push(f, o.vertices)
+
+ for o in objects:
+ # add armature modifier
+ mod=o.modifiers.append(Modifier.Types.ARMATURE)
+ mod[Modifier.Settings.OBJECT] = armature_object
+ mod[Modifier.Settings.ENVELOPES] = False
+ o.makeDisplayList()
+ # create vertex group
+ mesh=o.getData(mesh=True)
+ for name in anchorMap.keys():
+ mesh.addVertGroup(name)
+ mesh.update()
+
+ # assing vertices to vertex group
+ for o in objects:
+ mesh=o.getData(mesh=True)
+ for i, mvert in enumerate(mesh.verts):
+ hasWeight=False
+ for name, anchor in anchorMap.items():
+ weight=anchor.calcWeight(mvert.co)
+ if weight>0:
+ mesh.assignVertsToGroup(
+ name, [i], weight, Mesh.AssignModes.ADD)
+ hasWeight=True
+ if not hasWeight:
+ # debug orphan vertex
+ print('orphan', mvert)
+ mesh.update()
+
import bl25 as bl\r
\r
\r
-###############################################################################\r
-# implement\r
-###############################################################################\r
def has_mikoto(mqo):\r
return False\r
\r
-if isBlender24():\r
- def create_objects(scene, mqo, root, materials, imageMap=None, scale=None):\r
- """\r
- create blender mesh objects.\r
- """\r
- # store hierarchy\r
- stack=[root] \r
-\r
- objects=[]\r
- for o in mqo.objects:\r
- #print "%s:v(%d),f(%d)" % (o.name, len(o.vertices), len(o.faces))\r
- # create mesh\r
- mesh = Blender.Mesh.New()\r
- mesh_object=scene.objects.new(mesh, o.name.encode('utf-8'))\r
-\r
- # add hierarchy\r
- stack_depth=len(stack)-1\r
- print(o.depth, stack_depth)\r
- if o.depth<stack_depth:\r
- for i in range(stack_depth-o.depth):\r
- stack.pop()\r
- stack[-1].makeParent([mesh_object])\r
- stack.append(mesh_object)\r
-\r
- if o.name.startswith('sdef'):\r
- # add sdef object\r
- objects.append(mesh_object)\r
- elif o.name.startswith('anchor'):\r
- #print("hide %s" % o.name)\r
- #mesh_object.restrictDisplay=False\r
- mesh_object.layers=[2]\r
- elif o.name.startswith('bone'):\r
- mesh_object.layers=[2]\r
-\r
- # add vertices\r
- mesh.verts.extend(Mathutils.Vector(0, 0, 0)) # dummy\r
- mesh.verts.extend([(v.x, -v.z, v.y) for v in o.vertices])\r
- # add faces\r
- mesh_faces=[]\r
- for face in o.faces:\r
- face_indices=[]\r
- for i in xrange(face.index_count):\r
- face_indices.append(face.getIndex(i)+1)\r
- mesh_faces.append(face_indices)\r
- #new_faces=mesh.faces.extend([face.indices for face in o.faces], \r
- new_faces=mesh.faces.extend(mesh_faces,\r
- #ignoreDups=True, \r
- indexList=True)\r
- mesh.update()\r
- \r
- # gather used materials\r
- usedMaterials = {}\r
- if new_faces:\r
- for i in new_faces:\r
- if type(i) is int:\r
- usedMaterials[o.faces[i].material_index]=True\r
-\r
- # blender limits 16 materials per mesh\r
- # separate mesh ?\r
- for i, material_index in enumerate(usedMaterials.keys()):\r
- if i>=16:\r
- print("over 16 materials!")\r
- break\r
- mesh.materials+=[materials[material_index]]\r
- usedMaterials[material_index]=i\r
- \r
- # set face params\r
- for i, f in enumerate(o.faces): \r
- if not type(new_faces[i]) is int:\r
- continue\r
-\r
- face=mesh.faces[new_faces[i]]\r
-\r
- uv_array=[]\r
- for i in xrange(f.index_count):\r
- uv_array.append(Blender.Mathutils.Vector(\r
- f.getUV(i).x, \r
- 1.0-f.getUV(i).y)\r
- )\r
- try:\r
- face.uv=uv_array\r
- except Exception as msg:\r
- #print msg\r
- #print face.index, uv_array\r
- pass\r
- \r
- if f.material_index in usedMaterials:\r
- face.mat = usedMaterials[f.material_index]\r
-\r
- face.smooth = 1\r
-\r
- # rmeove dummy 0 vertex\r
- mesh.verts.delete(0)\r
- \r
- mesh.mode |= Blender.Mesh.Modes.AUTOSMOOTH\r
- mesh.maxSmoothAngle = int(o.smoothing)\r
- mesh.smooth()\r
- mesh.calcNormals()\r
- mesh.flipNormals()\r
- mesh.update()\r
-\r
- # mirror modifier\r
- if o.mirror:\r
- mod=mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)\r
-\r
- return objects\r
-\r
-\r
- class MikotoBone(object):\r
- __slots__=[\r
- 'name',\r
- 'iHead', 'iTail', 'iUp',\r
- 'vHead', 'vTail', 'vUp',\r
- 'parent', 'isFloating',\r
- 'children',\r
- ]\r
- def __init__(self, face=None, vertices=None, materials=None):\r
- self.parent=None\r
- self.isFloating=False\r
- self.children=[]\r
- if not face:\r
- self.name='root'\r
- return\r
-\r
- self.name=materials[face.material_index].name.encode('utf-8')\r
-\r
- i0=face.indices[0]\r
- i1=face.indices[1]\r
- i2=face.indices[2]\r
- v0=vertices[i0]\r
- v1=vertices[i1]\r
- v2=vertices[i2]\r
- e01=v1-v0\r
- e12=v2-v1\r
- e20=v0-v2\r
- sqNorm0=e01.getSqNorm()\r
- sqNorm1=e12.getSqNorm()\r
- sqNorm2=e20.getSqNorm()\r
- if sqNorm0>sqNorm1:\r
- if sqNorm1>sqNorm2:\r
- # e01 > e12 > e20\r
- self.iHead=i2\r
- self.iTail=i1\r
- self.iUp=i0\r
- else:\r
- if sqNorm0>sqNorm2:\r
- # e01 > e20 > e12\r
- self.iHead=i2\r
- self.iTail=i0\r
- self.iUp=i1\r
- else:\r
- # e20 > e01 > e12\r
- self.iHead=i1\r
- self.iTail=i0\r
- self.iUp=i2\r
- else:\r
- # 0 < 1\r
- if sqNorm1<sqNorm2:\r
- # e20 > e12 > e01\r
- self.iHead=i1\r
- self.iTail=i2\r
- self.iUp=i0\r
- else:\r
- if sqNorm0<sqNorm2:\r
- # e12 > e20 > e01\r
- self.iHead=i0\r
- self.iTail=i2\r
- self.iUp=i1\r
- else:\r
- # e12 > e01 > e20\r
- self.iHead=i0\r
- self.iTail=i1\r
- self.iUp=i2\r
- self.vHead=vertices[self.iHead]\r
- self.vTail=vertices[self.iTail]\r
- self.vUp=vertices[self.iUp]\r
-\r
- if self.name.endswith('[]'):\r
- basename=self.name[0:-2]\r
- # expand LR name\r
- if self.vTail.x>0:\r
- self.name="%s_L" % basename\r
- else:\r
- self.name="%s_R" % basename\r
-\r
-\r
- def setParent(self, parent, floating=False):\r
- if floating:\r
- self.isFloating=True\r
- self.parent=parent\r
- parent.children.append(self)\r
-\r
- def printTree(self, indent=''):\r
- print("%s%s" % (indent, self.name))\r
- for child in self.children:\r
- child.printTree(indent+' ')\r
-\r
-\r
- def build_armature(armature, mikotoBone, parent=None):\r
- """\r
- create a armature bone.\r
- """\r
- bone = Armature.Editbone()\r
- bone.name = mikotoBone.name.encode('utf-8')\r
- armature.bones[bone.name] = bone\r
-\r
- bone.head = Mathutils.Vector(*mikotoBone.vHead.to_a())\r
- bone.tail = Mathutils.Vector(*mikotoBone.vTail.to_a())\r
- if parent:\r
- bone.parent=parent\r
- if mikotoBone.isFloating:\r
- pass\r
- else:\r
- bone.options=[Armature.CONNECTED]\r
-\r
- for child in mikotoBone.children:\r
- build_armature(armature, child, bone)\r
-\r
-\r
- def create_armature(scene, mqo):\r
- """\r
- create armature\r
- """\r
- boneObject=None\r
- for o in mqo.objects:\r
- if o.name.startswith('bone'):\r
- boneObject=o\r
- break\r
- if not boneObject:\r
- return\r
-\r
- tailMap={}\r
- for f in boneObject.faces:\r
- if f.index_count!=3:\r
- print("invalid index_count: %d" % f.index_count)\r
- continue\r
- b=MikotoBone(f, boneObject.vertices, mqo.materials)\r
- tailMap[b.iTail]=b\r
-\r
- #################### \r
- # build mikoto bone tree\r
- #################### \r
- mikotoRoot=MikotoBone()\r
-\r
- for b in tailMap.values():\r
- # each bone has unique parent or is root bone.\r
- if b.iHead in tailMap:\r
- b.setParent(tailMap[b.iHead])\r
- else: \r
- isFloating=False\r
- for e in boneObject.edges:\r
- if b.iHead==e.indices[0]:\r
- # floating bone\r
- if e.indices[1] in tailMap:\r
- b.setParent(tailMap[e.indices[1]], True)\r
- isFloating=True\r
- break\r
- elif b.iHead==e.indices[1]:\r
- # floating bone\r
- if e.indices[0] in tailMap:\r
- b.setParent(tailMap[e.indices[0]], True)\r
- isFloating=True\r
- break\r
- if isFloating:\r
- continue\r
-\r
- # no parent bone\r
- b.setParent(mikotoRoot, True)\r
-\r
- if len(mikotoRoot.children)==0:\r
- print("no root bone")\r
- return\r
-\r
- if len(mikotoRoot.children)==1:\r
- # single root\r
- mikotoRoot=mikotoRoot.children[0]\r
- mikotoRoot.parent=None\r
- else:\r
- mikotoRoot.vHead=Vector3(0, 10, 0)\r
- mikotoRoot.vTail=Vector3(0, 0, 0)\r
-\r
- #################### \r
- # create armature\r
- #################### \r
- armature = Armature.New()\r
- # link to object\r
- armature_object = scene.objects.new(armature)\r
- # create action\r
- act = Armature.NLA.NewAction()\r
- act.setActive(armature_object)\r
- # set XRAY\r
- armature_object.drawMode |= Object.DrawModes.XRAY\r
- # armature settings\r
- armature.drawType = Armature.OCTAHEDRON\r
- armature.envelopes = False\r
- armature.vertexGroups = True\r
- armature.mirrorEdit = True\r
- armature.drawNames=True\r
-\r
- # edit bones\r
- armature.makeEditable()\r
- build_armature(armature, mikotoRoot)\r
- armature.update()\r
-\r
- return armature_object\r
- \r
-\r
- class TrianglePlane(object):\r
- """\r
- mikoto方式ボーンのアンカーウェイト計算用。\r
- (不完全)\r
- """\r
- __slots__=['normal', \r
- 'v0', 'v1', 'v2',\r
- ]\r
- def __init__(self, v0, v1, v2):\r
- self.v0=v0\r
- self.v1=v1\r
- self.v2=v2\r
-\r
- def isInsideXY(self, p):\r
- v0=Vector2(self.v0.x, self.v0.y)\r
- v1=Vector2(self.v1.x, self.v1.y)\r
- v2=Vector2(self.v2.x, self.v2.y)\r
- e01=v1-v0\r
- e12=v2-v1\r
- e20=v0-v2\r
- c0=Vector2.cross(e01, p-v0)\r
- c1=Vector2.cross(e12, p-v1)\r
- c2=Vector2.cross(e20, p-v2)\r
- if c0>=0 and c1>=0 and c2>=0:\r
- return True\r
- if c0<=0 and c1<=0 and c2<=0:\r
- return True\r
-\r
- def isInsideYZ(self, p):\r
- v0=Vector2(self.v0.y, self.v0.z)\r
- v1=Vector2(self.v1.y, self.v1.z)\r
- v2=Vector2(self.v2.y, self.v2.z)\r
- e01=v1-v0\r
- e12=v2-v1\r
- e20=v0-v2\r
- c0=Vector2.cross(e01, p-v0)\r
- c1=Vector2.cross(e12, p-v1)\r
- c2=Vector2.cross(e20, p-v2)\r
- if c0>=0 and c1>=0 and c2>=0:\r
- return True\r
- if c0<=0 and c1<=0 and c2<=0:\r
- return True\r
-\r
- def isInsideZX(self, p):\r
- v0=Vector2(self.v0.z, self.v0.x)\r
- v1=Vector2(self.v1.z, self.v1.x)\r
- v2=Vector2(self.v2.z, self.v2.x)\r
- e01=v1-v0\r
- e12=v2-v1\r
- e20=v0-v2\r
- c0=Vector2.cross(e01, p-v0)\r
- c1=Vector2.cross(e12, p-v1)\r
- c2=Vector2.cross(e20, p-v2)\r
- if c0>=0 and c1>=0 and c2>=0:\r
- return True\r
- if c0<=0 and c1<=0 and c2<=0:\r
- return True\r
-\r
-\r
- class MikotoAnchor(object):\r
- """\r
- mikoto方式スケルトンのアンカー。\r
- """\r
- __slots__=[\r
- "triangles", "bbox",\r
- ]\r
- def __init__(self):\r
- self.triangles=[]\r
- self.bbox=None\r
-\r
- def push(self, face, vertices):\r
- if face.index_count==3:\r
- self.triangles.append(TrianglePlane(\r
- vertices[face.indices[0]],\r
- vertices[face.indices[1]],\r
- vertices[face.indices[2]]\r
- ))\r
- elif face.index_count==4:\r
- self.triangles.append(TrianglePlane(\r
- vertices[face.indices[0]],\r
- vertices[face.indices[1]],\r
- vertices[face.indices[2]]\r
- ))\r
- self.triangles.append(TrianglePlane(\r
- vertices[face.indices[2]],\r
- vertices[face.indices[3]],\r
- vertices[face.indices[0]]\r
- ))\r
- # bounding box\r
- if not self.bbox:\r
- self.bbox=BoundingBox(vertices[face.indices[0]])\r
- for i in face.indices:\r
- self.bbox.expand(vertices[i])\r
-\r
-\r
- def calcWeight(self, v):\r
- if not self.bbox.isInside(v):\r
- return 0\r
-\r
- if self.anyXY(v.x, v.y) and self.anyYZ(v.y, v.z) and self.anyZX(v.z, v.x):\r
- return 1.0\r
- else:\r
- return 0\r
- \r
- def anyXY(self, x, y):\r
- for t in self.triangles:\r
- if t.isInsideXY(Vector2(x, y)):\r
- return True\r
- return False\r
-\r
- def anyYZ(self, y, z):\r
- for t in self.triangles:\r
- if t.isInsideYZ(Vector2(y, z)):\r
- return True\r
- return False\r
-\r
- def anyZX(self, z, x):\r
- for t in self.triangles:\r
- if t.isInsideZX(Vector2(z, x)):\r
- return True\r
- return False\r
-\r
-\r
- def create_bone_weight(scene, mqo, armature_object, objects):\r
- """\r
- create mikoto bone weight.\r
- """\r
- anchorMap={}\r
- # setup mikoto anchors\r
- for o in mqo.objects:\r
- if o.name.startswith("anchor"):\r
- for f in o.faces:\r
- name=mqo.materials[f.material_index].name\r
- if name.endswith('[]'):\r
- basename=name[0:-2]\r
- v=o.vertices[f.indices[0]]\r
- if(v.x>0):\r
- # L\r
- name_L=basename+'_L'\r
- if not name_L in anchorMap:\r
- anchorMap[name_L]=MikotoAnchor()\r
- anchorMap[name_L].push(f, o.vertices)\r
- elif(v.x<0):\r
- # R\r
- name_R=basename+'_R'\r
- if not name_R in anchorMap:\r
- anchorMap[name_R]=MikotoAnchor()\r
- anchorMap[name_R].push(f, o.vertices)\r
- else:\r
- print("no side", v)\r
- else:\r
- if not name in anchorMap:\r
- anchorMap[name]=MikotoAnchor()\r
- anchorMap[name].push(f, o.vertices)\r
-\r
- for o in objects:\r
- # add armature modifier\r
- mod=o.modifiers.append(Modifier.Types.ARMATURE)\r
- mod[Modifier.Settings.OBJECT] = armature_object\r
- mod[Modifier.Settings.ENVELOPES] = False\r
- o.makeDisplayList()\r
- # create vertex group\r
- mesh=o.getData(mesh=True)\r
- for name in anchorMap.keys():\r
- mesh.addVertGroup(name)\r
- mesh.update()\r
- \r
- # assing vertices to vertex group\r
- for o in objects:\r
- mesh=o.getData(mesh=True)\r
- for i, mvert in enumerate(mesh.verts):\r
- hasWeight=False\r
- for name, anchor in anchorMap.items():\r
- weight=anchor.calcWeight(mvert.co)\r
- if weight>0:\r
- mesh.assignVertsToGroup(\r
- name, [i], weight, Mesh.AssignModes.ADD)\r
- hasWeight=True\r
- if not hasWeight:\r
- # debug orphan vertex\r
- print('orphan', mvert)\r
- mesh.update()\r
- \r
-\r
-\r
-else:\r
- def create_objects(scene, mqo, parent, materials, imageMap, scale):\r
- for o in mqo.objects:\r
-\r
- # create mesh\r
- mesh=bpy.data.meshes.new("Mesh")\r
- meshObject= bpy.data.objects.new(o.getName(), mesh)\r
- scene.objects.link(meshObject)\r
- meshObject.parent=parent\r
-\r
- # count triangle and quadrangle\r
- faceCount=0\r
- for f in o.faces:\r
- if f.index_count==3 or f.index_count==4:\r
- faceCount+=1\r
- mesh.add_geometry(len(o.vertices), 0, faceCount)\r
-\r
- # add vertex\r
- unpackedVertices=[]\r
- for v in o.vertices:\r
- # convert right-handed y-up to right-handed z-up\r
- unpackedVertices.extend(\r
- (scale*v.x, scale*-v.z, scale*v.y))\r
- mesh.verts.foreach_set("co", unpackedVertices)\r
-\r
- # add face\r
- unpackedFaces = []\r
- usedMaterial=set()\r
-\r
- def getFace(f):\r
- face = []\r
- for i in range(f.index_count):\r
- face.append(f.getIndex(i))\r
- return face\r
-\r
- for f in o.faces:\r
- face=getFace(f)\r
- if len(face) != 3 and len(face) != 4:\r
- print("{0} vertices in face.".format(len(face)))\r
- continue\r
-\r
- if len(face) == 4:\r
- if face[3] == 0:\r
- # rotate indices if the 4th is 0\r
- face = [face[3], face[0], face[1], face[2]]\r
- elif len(face) == 3:\r
- if face[2] == 0:\r
- # rotate indices if the 3rd is 0\r
- face = [face[2], face[0], face[1], 0]\r
- else:\r
- face.append(0)\r
-\r
- unpackedFaces.extend(face)\r
- usedMaterial.add(f.material_index)\r
- try:\r
- mesh.faces.foreach_set("verts_raw", unpackedFaces)\r
- except:\r
- #print([getFace(f) for f in o.faces])\r
- print("fail to mesh.faces.foreach_set")\r
- return\r
-\r
- # add material\r
- meshMaterialMap={}\r
- materialIndex=0\r
- for i in usedMaterial:\r
- mesh.add_material(materials[i])\r
- meshMaterialMap[i]=materialIndex\r
- materialIndex+=1\r
-\r
- # each face\r
- mesh.add_uv_texture()\r
- for mqo_face, blender_face, uv_face in zip(\r
- o.faces, mesh.faces, mesh.uv_textures[0].data):\r
- if mqo_face.index_count<3:\r
- continue\r
- blender_face.material_index=meshMaterialMap[mqo_face.material_index]\r
- if mqo_face.index_count>=3:\r
- uv_face.uv1=[mqo_face.getUV(0).x, 1.0-mqo_face.getUV(0).y]\r
- uv_face.uv2=[mqo_face.getUV(1).x, 1.0-mqo_face.getUV(1).y]\r
- uv_face.uv3=[mqo_face.getUV(2).x, 1.0-mqo_face.getUV(2).y]\r
- if mqo_face.index_count==4:\r
- uv_face.uv4=[\r
- mqo_face.getUV(3).x, 1.0-mqo_face.getUV(3).y]\r
- if materials[mqo_face.material_index] in imageMap:\r
- uv_face.image=imageMap[mqo_face.material_index]\r
- uv_face.tex=True\r
-\r
- mesh.update()\r
-\r
\r
def __createMaterials(scene, mqo, directory):\r
"""\r
if len(mqo.materials)>0:\r
for material_index, m in enumerate(mqo.materials):\r
# material\r
- material=bl.createMaterial(m)\r
+ material=bl.createMqoMaterial(m)\r
materials.append(material)\r
# texture\r
texture_name=m.getTexture()\r
return materials, imageMap\r
\r
\r
+def __createObjects(scene, mqo, root, materials, imageMap, scale=1.0):\r
+ """\r
+ create blender mesh objects.\r
+ """\r
+ # store hierarchy\r
+ stack=[root] \r
+ objects=[]\r
+ for o in mqo.objects:\r
+ mesh, mesh_object=bl.createMesh(scene, o.getName())\r
+\r
+ # add hierarchy\r
+ stack_depth=len(stack)-1\r
+ print(o.depth, stack_depth)\r
+ if o.depth<stack_depth:\r
+ for i in range(stack_depth-o.depth):\r
+ stack.pop()\r
+ bl.objectMakeParent(stack[-1], mesh_object)\r
+ stack.append(mesh_object)\r
+\r
+ if o.name.startswith('sdef'):\r
+ # add sdef object\r
+ objects.append(mesh_object)\r
+ elif o.name.startswith('anchor'):\r
+ #print("hide %s" % o.name)\r
+ #mesh_object.restrictDisplay=False\r
+ mesh_object.layers=[2]\r
+ elif o.name.startswith('bone'):\r
+ mesh_object.layers=[2]\r
+\r
+ bl.meshAddMqoGeometry(mesh, o, materials, imageMap, scale)\r
+\r
+ return objects\r
+\r
+\r
def __execute(filename, scene, scale=1.0):\r
# parse file\r
io=mqo.IO()\r
\r
# create objects\r
root=bl.createEmptyObject(scene, os.path.basename(filename))\r
- objects=create_objects(scene, io, root, materials, imageMap, scale)\r
+ objects=__createObjects(scene, io, root, materials, imageMap, scale)\r
\r
if has_mikoto(io):\r
# create mikoto bone\r