class Bone(object):
- __slots__=['index', 'name', 'pos', 'parent_index', 'tail_index', 'type']
- def __init__(self, name, pos):
+ __slots__=['index', 'name',
+ 'pos', 'tail', 'parent_index', 'tail_index', 'type', 'isConnect']
+ def __init__(self, name, pos, tail):
self.index=-1
self.name=name
- self.pos=[pos.x, pos.y, pos.z]
+ self.pos=pos
+ self.tail=tail
self.parent_index=None
self.tail_index=None
self.type=0
+ self.isConnect=False
+
+ def __eq__(self, rhs):
+ return self.index==rhs.index
def __str__(self):
return "<Bone %s %d>" % (self.name, self.type)
self.ik_list=[]
def build(self, armatureObj):
- if armatureObj:
- armature=armatureObj.getData()
- for b in armature.bones.values():
- if b.name=='center':
- # root bone
- bone=Bone(b.name, b.head['ARMATURESPACE'])
- self.__addBone(bone)
- self.__getBone(bone, b)
-
- for b in armature.bones.values():
- if not b.parent and b.name!='center':
- # root bone
- bone=Bone(b.name, b.head['ARMATURESPACE'])
- self.__addBone(bone)
- self.__getBone(bone, b)
+ if not armatureObj:
+ return
+ print("gather bones")
+ armature=armatureObj.getData()
+ for b in armature.bones.values():
+ if b.name=='center':
+ # root bone
+ bone=Bone(b.name,
+ b.head['ARMATURESPACE'][0:3],
+ b.tail['ARMATURESPACE'][0:3])
+ self.__addBone(bone)
+ self.__getBone(bone, b)
+
+ for b in armature.bones.values():
+ if not b.parent and b.name!='center':
+ # root bone
+ bone=Bone(b.name,
+ b.head['ARMATURESPACE'][0:3],
+ b.tail['ARMATURESPACE'][0:3])
+ self.__addBone(bone)
+ self.__getBone(bone, b)
+
+ print("check connection")
+ for b in armature.bones.values():
+ if not b.parent:
+ self.__checkConnection(b, None)
+
+ print("create tail")
+ before=self.bones[:]
+ for b in before:
+ if not b.isConnect:
+ # 末端の非表示ボーン
+ if not b.tail:
+ print(b.name)
+ assert(False)
+ bone=Bone(b.name+'_t', b.tail, None)
+ bone.type=7
+ self.__addBone(bone)
+ bone.parent_index=b.index
+ b.tail_index=bone.index
+
+ print("gather ik")
pose = armatureObj.getPose()
cSetting=Blender.Constraint.Settings
for b in pose.bones.values():
if target_tail.type!=7:
target_bone=armature.bones[target.name]
bone=Bone(target.name+'_t',
- target_bone.tail['ARMATURESPACE'])
+ target_bone.tail['ARMATURESPACE'][0:3],
+ None)
bone.type=7
self.__addBone(bone)
bone.parent_index=target.index
target.tail_index=bone.index
+ def __checkConnection(self, b, p):
+ if Blender.Armature.CONNECTED in b.options:
+ parent=self.__boneByName(p.name)
+ parent.isConnect=True
+
+ for c in b.children:
+ self.__checkConnection(c, b)
+
+ def sortBy(self, boneMap):
+ """
+ boneMap順に並べ替える
+ """
+ original=self.bones[:]
+ def getIndex(bone):
+ for i, k_v in enumerate(boneMap):
+ if k_v[0]==bone.name:
+ return i
+ print(bone)
+
+ self.bones.sort(lambda l, r: getIndex(l)-getIndex(r))
+ sortMap={}
+ for i, b in enumerate(self.bones):
+ src=original.index(b)
+ sortMap[src]=i
+ for b in self.bones:
+ b.index=sortMap[b.index]
+ if b.parent_index:
+ b.parent_index=sortMap[b.parent_index]
+ if b.tail_index:
+ b.tail_index=sortMap[b.tail_index]
+
def getIndex(self, bone):
for i, b in enumerate(self.bones):
if b==bone:
return self.bones[self.boneMap[name]]
def __getBone(self, parent, b):
- if not Blender.Armature.CONNECTED in b.options:
- #print b, b.options
- pass
-
- if len(b.children)==0:
- # 末端の非表示ボーン
- bone=Bone(b.name+'_t', b.tail['ARMATURESPACE'])
- bone.type=7
- self.__addBone(bone)
- assert(parent)
- bone.parent_index=parent.index
- parent.tail_index=bone.index
- return
-
for i, c in enumerate(b.children):
- bone=Bone(c.name, c.head['ARMATURESPACE'])
+ bone=Bone(c.name,
+ c.head['ARMATURESPACE'][0:3],
+ c.tail['ARMATURESPACE'][0:3])
self.__addBone(bone)
if parent:
bone.parent_index=parent.index
print(self.oneSkinMesh)
self.name=root.o.name
+ # skeleton
+ self.builder=BoneBuilder()
+ self.builder.build(self.armatureObj)
+ self.builder.sortBy(englishmap.boneMap)
+
def __createOneSkinMesh(self, node):
############################################################
# search armature modifier
io.comment="blender export"
io.version=1.0
- # skeleton
- builder=BoneBuilder()
- builder.build(self.armatureObj)
-
# 頂点
for pos, normal, uv, b0, b1, weight in self.oneSkinMesh.vertexArray.zip():
# convert right-handed z-up to left-handed y-up
v.normal.z=normal[1]
v.uv.x=uv[0]
v.uv.y=uv[1]
- v.bone0=builder.boneMap[b0] if b0 in builder.boneMap else 0
- v.bone1=builder.boneMap[b1] if b1 in builder.boneMap else 0
+ v.bone0=self.builder.boneMap[b0] if b0 in self.builder.boneMap else 0
+ v.bone1=self.builder.boneMap[b1] if b1 in self.builder.boneMap else 0
v.weight0=int(100*weight)
v.edge_flag=0 # edge flag, 0: enable edge, 1: not edge
#io.indices.append(indices[i+2])
# bones
- for b in builder.bones:
+ for b in self.builder.bones:
+ if b.name.endswith("_t"):
+ if b.name.startswith("arm twist1_") or b.name.startswith("arm twist2_"):
+ # skip
+ print "skip %s" % b.name
+ continue
+
bone=io.addBone()
- unicode=englishmap.getUnicodeBoneName(b.name)
- if unicode:
- cp932=unicode.encode('cp932')
- else:
- cp932=b.name
+ v=englishmap.getUnicodeBoneName(b.name)
+ assert(v)
+ cp932=v[1].encode('cp932')
bone_name="%s\n" % cp932
assert(len(bone_name)<20)
bone.name=bone_name
assert(len(bone_english_name)<20)
bone.english_name=bone_english_name
- bone.type=b.type
+ if len(v)>=3:
+ bone.type=v[2]
+ else:
+ bone.type=b.type
bone.parent_index=b.parent_index if b.parent_index!=None else 0xFFFF
- bone.tail_index=b.tail_index if b.tail_index!=None else 0
+
+ if b.tail_index!=None:
+ if bone.type==9:
+ bone.tail_index=0
+ else:
+ bone.tail_index=b.tail_index
+ else:
+ bone.tail_index=0
# ToDo
bone.ik_index=0xFFFF
# convert right-handed z-up to left-handed y-up
bone.pos.z=b.pos[1]
# IK
- for ik in builder.ik_list:
+ for ik in self.builder.ik_list:
solver=io.addIK()
- solver.index=builder.getIndex(ik.target)
- solver.target=builder.getIndex(ik.effector)
+ solver.index=self.builder.getIndex(ik.target)
+ solver.target=self.builder.getIndex(ik.effector)
solver.length=ik.length
- b=builder.bones[ik.effector.parent_index]
+ b=self.builder.bones[ik.effector.parent_index]
for i in xrange(solver.length):
- solver.children.append(builder.getIndex(b))
- b=builder.bones[b.parent_index]
+ solver.children.append(self.builder.getIndex(b))
+ b=self.builder.bones[b.parent_index]
solver.iterations=ik.iterations
solver.weight=ik.weight
boneDisplayName.name="bones\n"
boneDisplayName.english_name="bones\n"
displayIndex=1
- for i, b in enumerate(builder.bones):
+ for i, b in enumerate(self.builder.bones):
if b.type in [6, 7]:
io.addBoneDisplay(i, displayIndex)
return vertex_map
-def build_bone(armature, b, parent=None):
- if b.tail_index==0:
- return
+def validParent(parent):
+ if parent==None:
+ return False
+ if parent.name.startswith("arm twist"):
+ return False
+ if parent.name.startswith("wrist twist"):
+ return False
+ return True
+
+
+class Builder(object):
+ def __init__(self):
+ self.boneMap={}
+
+ def build(self, armature, bones):
+ for b in bones:
+ if not b.parent:
+ self.__build(armature, b, None, None)
+
+ def __build(self, armature, b, p, parent):
+ name=englishmap.getEnglishBoneName(b.getName())
+ if not name:
+ name=b.getName().encode(INTERNAL_ENCODING)
+ self.boneMap[name]=b
+
+ if b.tail_index==0:
+ return
+
+ bone=Blender.Armature.Editbone()
+ bone.name=name
+ armature.bones[name] = bone
+
+ if bone.name=='center':
+ # center
+ pos=Mathutils.Vector(*convert_coord(b.pos))
+ bone.tail = pos
+ bone.head = pos-Mathutils.Vector(0, 0.01, 0)
+ else:
+ bone.head = Mathutils.Vector(*convert_coord(b.pos))
+ bone.tail = Mathutils.Vector(*convert_coord(b.tail))
+
+ if validParent(parent):
+ bone.parent=parent
+ if parent.tail==bone.head:
+ bone.parent=parent
+ bone.options=[Blender.Armature.CONNECTED]
- bone = Blender.Armature.Editbone()
- name=englishmap.getEnglishBoneName(b.getName())
- bone.name = name if name else b.getName().encode(
- INTERNAL_ENCODING)
- armature.bones[bone.name] = bone
- if parent:
- bone.head = Mathutils.Vector(*convert_coord(b.pos))
- bone.parent=parent
- options=[]
- if parent.tail==bone.head:
- options.append(Blender.Armature.CONNECTED)
- bone.options=options
- bone.tail = Mathutils.Vector(*convert_coord(b.tail))
- if bone.head==bone.tail:
- bone.tail=bone.head-Mathutils.Vector(0, 1, 0)
- elif b.type==pmd.BONE_IK:
- bone.head = Mathutils.Vector(*convert_coord(b.pos))
- bone.tail = Mathutils.Vector(*convert_coord(b.tail))
- else:
- # center
- print(bone.name)
- pos=Mathutils.Vector(*convert_coord(b.pos))
- bone.tail = pos
- bone.head = pos-Mathutils.Vector(0, 0.01, 0)
-
- for child in b.children:
- build_bone(armature, child, bone)
+ if bone.head==bone.tail:
+ bone.tail=bone.head-Mathutils.Vector(0, 1, 0)
+ for c in b.children:
+ self.__build(armature, c, b, bone)
+
+ def connect(self, armature):
+ def getKey(index):
+ for key, value in self.boneMap.items():
+ if index==value.index:
+ return key
+
+ for k, b in self.boneMap.items():
+ if b.tail_index==0:
+ continue
+ bone=armature.bones[k]
+ key=getKey(b.tail_index)
+ if not key:
+ return
+ try:
+ tail=armature.bones[key]
+ # connect
+ tail.parent=bone
+ tail.options=[Blender.Armature.CONNECTED]
+ except:
+ pass
def importArmature(scene, l):
# create armature
# create armature
armature.makeEditable()
- for b in l.bones:
- if not b.parent:
- build_bone(armature, b)
+
+ builder=Builder()
+ builder.build(armature, l.bones)
+ builder.connect(armature)
+
armature.update()
############################################################
###############################################################################
# 日本語名との変換マップ
###############################################################################
-boneMap={
-"center":"センター",
-"upper body":"上半身",
-"neck":"首",
-"head":"頭",
-"eye_L":"左目",
-"eye_R":"右目",
-"necktie1":"ネクタイ1",
-"necktie2":"ネクタイ2",
-"necktie3":"ネクタイ3",
-"lower body":"下半身",
-"waist accessory":"腰飾り",
-"hair1_L":"左髪1",
-"hair2_L":"左髪2",
-"hair3_L":"左髪3",
-"hair4_L":"左髪4",
-"hair5_L":"左髪5",
-"hair6_L":"左髪6",
-"shoulder_L":"左肩",
-"arm_L":"左腕",
-"arm twist_L":"左腕捩",
-"elbow_L":"左ひじ",
-"wrist twist_L":"左手捩",
-"wrist_L":"左手首",
-"sleeve_L":"左袖",
-"thumb1_L":"左親指1",
-"thumb2_L":"左親指2",
-"fore1_L":"左人指1",
-"fore2_L":"左人指2",
-"fore3_L":"左人指3",
-"middle1_L":"左中指1",
-"middle2_L":"左中指2",
-"middle3_L":"左中指3",
-"third1_L":"左薬指1",
-"third2_L":"左薬指2",
-"third3_L":"左薬指3",
-"little1_L":"左小指1",
-"little2_L":"左小指2",
-"little3_L":"左小指3",
-"front skirt_L":"左スカート前",
-"back skirt_L":"左スカート後",
-"leg_L":"左足",
-"knee_L":"左ひざ",
-"ankle_L":"左足首",
-"hair1_R":"右髪1",
-"hair2_R":"右髪2",
-"hair3_R":"右髪3",
-"hair4_R":"右髪4",
-"hair5_R":"右髪5",
-"hair6_R":"右髪6",
-"shoulder_R":"右肩",
-"arm_R":"右腕",
-"arm twist_R":"右腕捩",
-"elbow_R":"右ひじ",
-"wrist twist_R":"右手捩",
-"wrist_R":"右手首",
-"sleeve_R":"右袖",
-"thumb1_R":"右親指1",
-"thumb2_R":"右親指2",
-"fore1_R":"右人指1",
-"fore2_R":"右人指2",
-"fore3_R":"右人指3",
-"middle1_R":"右中指1",
-"middle2_R":"右中指2",
-"middle3_R":"右中指3",
-"third1_R":"右薬指1",
-"third2_R":"右薬指2",
-"third3_R":"右薬指3",
-"little1_R":"右小指1",
-"little2_R":"右小指2",
-"little3_R":"右小指3",
-"front skirt_R":"右スカート前",
-"back skirt_R":"右スカート後",
-"leg_R":"右足",
-"knee_R":"右ひざ",
-"ankle_R":"右足首",
-"eyes":"両目",
-"front hair1":"前髪1",
-"front hair2":"前髪2",
-"front hair3":"前髪3",
-"eyelight_L":"左目光",
-"eyelight_R":"右目光",
-"necktie4":"ネクタイ4",
-"hair7_L":"左髪7",
-"hair7_R":"右髪7",
-"toe_L":"左つま先",
-"toe_R":"右つま先",
-"necktie IK":"ネクタイIK",
-"hair IK_L":"左髪IK",
-"hair IK_R":"右髪IK",
-"leg IK_L":"左足IK",
-"leg IK_R":"右足IK",
-"toe IK_L":"左つま先IK",
-"toe IK_R":"右つま先IK",
-"bone093":"下半身先",
-"bone094":"頭先",
-"bone095":"左目先",
-"bone096":"右目先",
-"bone097":"腰飾り先",
-"bone098":"左袖先",
-"bone099":"左手先",
-"bone100":"左親指先",
-"bone101":"左人差指先",
-"bone102":"左中指先",
-"bone103":"左薬指先",
-"bone104":"左小指先",
-"bone105":"左スカート前先",
-"bone106":"左スカート後先",
-"bone107":"右袖先",
-"bone108":"右手先",
-"bone109":"右親指先",
-"bone110":"右人差指先",
-"bone111":"右中指先",
-"bone112":"右薬指先",
-"bone113":"右小指先",
-"bone114":"右スカート前先",
-"bone115":"右スカート後先",
-"bone116":"センター先",
-"bone117":"両目先",
-"bone118":"ネクタイIK先",
-"bone119":"左髪IK先",
-"bone120":"右髪IK先",
-"bone121":"左足IK先",
-"bone122":"右足IK先",
-"bone123":"左つま先IK先",
-"bone124":"右つま先IK先",
-"bone125":"前髪1先",
-"bone126":"前髪2先",
-"bone127":"前髪3先",
-"bone128":"左目光先",
-"bone129":"右目光先",
-"bone130":"左腕捩先",
-"bone131":"左手捩先",
-"bone132":"右腕捩先",
-"bone133":"右手捩先",
-"ude hineri1_L":"左腕捩1",
-"ude hineri2_L":"左腕捩2",
-"ude hineri3_L":"左腕捩3",
-"ude hineri1_R":"右腕捩1",
-"ude hineri2_R":"右腕捩2",
-"ude hineri3_R":"右腕捩3",
-}
+boneMap=[
+("center", "センター", 1),
+("upper body", "上半身"),
+("neck", "首"),
+("head", "頭"),
+("eye_L", "左目", 5),
+("eye_R", "右目", 5),
+("necktie1", "ネクタイ1"),
+("necktie2", "ネクタイ2"),
+("necktie3", "ネクタイ3"),
+("lower body", "下半身"),
+("waist accessory", "腰飾り"),
+("hair1_L", "左髪1"),
+("hair2_L", "左髪2"),
+("hair3_L", "左髪3"),
+("hair4_L", "左髪4"),
+("hair5_L", "左髪5"),
+("hair6_L", "左髪6"),
+("shoulder_L", "左肩"),
+("arm_L", "左腕"),
+("arm twist_L", "左腕捩", 8),
+("elbow_L", "左ひじ"),
+("wrist twist_L", "左手捩", 8),
+("wrist_L", "左手首"),
+("sleeve_L", "左袖", 1),
+("thumb1_L", "左親指1"),
+("thumb2_L", "左親指2"),
+("fore1_L", "左人指1"),
+("fore2_L", "左人指2"),
+("fore3_L", "左人指3"),
+("middle1_L", "左中指1"),
+("middle2_L", "左中指2"),
+("middle3_L", "左中指3"),
+("third1_L", "左薬指1"),
+("third2_L", "左薬指2"),
+("third3_L", "左薬指3"),
+("little1_L", "左小指1"),
+("little2_L", "左小指2"),
+("little3_L", "左小指3"),
+("front skirt_L", "左スカート前"),
+("back skirt_L", "左スカート後"),
+("leg_L", "左足"),
+("knee_L", "左ひざ"),
+("ankle_L", "左足首"),
+("hair1_R", "右髪1"),
+("hair2_R", "右髪2"),
+("hair3_R", "右髪3"),
+("hair4_R", "右髪4"),
+("hair5_R", "右髪5"),
+("hair6_R", "右髪6"),
+("shoulder_R", "右肩"),
+("arm_R", "右腕"),
+("arm twist_R", "右腕捩", 8),
+("elbow_R", "右ひじ"),
+("wrist twist_R", "右手捩", 8),
+("wrist_R", "右手首"),
+("sleeve_R", "右袖", 1),
+("thumb1_R", "右親指1"),
+("thumb2_R", "右親指2"),
+("fore1_R", "右人指1"),
+("fore2_R", "右人指2"),
+("fore3_R", "右人指3"),
+("middle1_R", "右中指1"),
+("middle2_R", "右中指2"),
+("middle3_R", "右中指3"),
+("third1_R", "右薬指1"),
+("third2_R", "右薬指2"),
+("third3_R", "右薬指3"),
+("little1_R", "右小指1"),
+("little2_R", "右小指2"),
+("little3_R", "右小指3"),
+("front skirt_R", "右スカート前"),
+("back skirt_R", "右スカート後"),
+("leg_R", "右足"),
+("knee_R", "右ひざ"),
+("ankle_R", "右足首"),
+("eyes", "両目"),
+("front hair1", "前髪1"),
+("front hair2", "前髪2"),
+("front hair3", "前髪3"),
+("eyelight_L", "左目光"),
+("eyelight_R", "右目光"),
+("necktie3_t", "ネクタイ4"),
+("hair6_L_t", "左髪7"),
+("hair6_R_t", "右髪7"),
+("ankle_L_t", "左つま先"),
+("ankle_R_t", "右つま先"),
+("necktie IK", "ネクタイIK"),
+("hair IK_L", "左髪IK"),
+("hair IK_R", "右髪IK"),
+("leg IK_L", "左足IK"),
+("leg IK_R", "右足IK"),
+("toe IK_L", "左つま先IK"),
+("toe IK_R", "右つま先IK"),
+
+("lower body_t", "下半身先"),
+("head_t", "頭先"),
+("eye_L_t", "左目先"),
+("eye_R_t", "右目先"),
+("waist accessory_t", "腰飾り先"),
+
+("sleeve_L_t", "左袖先"),
+("wrist_L_t", "左手先"),
+("thumb2_L_t", "左親指先"),
+("fore3_L_t", "左人差指先"),
+("middle3_L_t", "左中指先"),
+("third3_L_t", "左薬指先"),
+("little3_L_t", "左小指先"),
+("front skirt_L_t", "左スカート前先"),
+("back skirt_L_t", "左スカート後先"),
+
+("sleeve_R_t", "右袖先"),
+("wrist_R_t", "右手先"),
+("thumb2_R_t", "右親指先"),
+("fore3_R_t", "右人差指先"),
+("middle3_R_t", "右中指先"),
+("third3_R_t", "右薬指先"),
+("little3_R_t", "右小指先"),
+("front skirt_R_t", "右スカート前先"),
+("back skirt_R_t", "右スカート後先"),
+
+("center_t", "センター先"),
+("eyes_t", "両目先"),
+("necktie IK_t", "ネクタイIK先"),
+("hair IK_L_t", "左髪IK先"),
+("hair IK_R_t", "右髪IK先"),
+("leg IK_L_t", "左足IK先"),
+("leg IK_R_t", "右足IK先"),
+("toe IK_L_t", "左つま先IK先"),
+("toe IK_R_t", "右つま先IK先"),
+("front hair1_t", "前髪1先"),
+("front hair2_t", "前髪2先"),
+("front hair3_t", "前髪3先"),
+("eyelight_L_t", "左目光先"),
+("eyelight_R_t", "右目光先"),
+("arm twist_L_t", "左腕捩先"),
+("wrist twist_L_t", "左手捩先"),
+("arm twist_R_t", "右腕捩先"),
+("wrist twist_R_t", "右手捩先"),
+("arm twist1_L", "左腕捩1", 9),
+("arm twist2_L", "左腕捩2", 9),
+("arm twist3_L", "左腕捩3", 9),
+("arm twist1_R", "右腕捩1", 9),
+("arm twist2_R", "右腕捩2", 9),
+("arm twist3_R", "右腕捩3", 9),
+#
+("arm twist1_L_t", "左腕捩1先"),
+("arm twist2_L_t", "左腕捩2先"),
+("arm twist3_L_t", "左腕捩3先"),
+("arm twist1_R_t", "右腕捩1先"),
+("arm twist2_R_t", "右腕捩2先"),
+("arm twist3_R_t", "右腕捩3先"),
+]
def getEnglishBoneName(name):
- for k, v in boneMap.items():
- if v==name:
- return k
+ for v in boneMap:
+ if v[1]==name:
+ return v[0]
def getUnicodeBoneName(name):
- if name.endswith('_t'):
- name=name[:-2]
- if name in boneMap:
- return boneMap[name]+(u'先' if sys.version_info[0]<3 else '先')
- else:
- if name in boneMap:
- return boneMap[name]
+ for v in boneMap:
+ if v[0]==name:
+ return v
skinMap={
"skin000":"base",
print 'convert boneMap and skinMap to unicode...',
# python2.x
# unicodeに変換
- for k in boneMap.keys():
- boneMap[k]=boneMap[k].decode('utf-8')
+ for i, l in enumerate(boneMap):
+ replace=[]
+ for j, m in enumerate(l):
+ if j==1:
+ replace.append(m.decode('utf-8'))
+ else:
+ replace.append(m)
+ boneMap[i]=replace
+
for k in skinMap.keys():
skinMap[k]=skinMap[k].decode('utf-8')
print('done')