skeleton.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import sys
  2. import os
  3. from struct import pack
  4. from copy import deepcopy
  5. from Blender import Mathutils
  6. from Blender.Mathutils import *
  7. import Blender
  8. #=======================================================================================================================
  9. # multMatrix =
  10. #=======================================================================================================================
  11. def multMatrix(m, b):
  12. c = Matrix()
  13. c[0][0] = m[0][0]*b[0][0] + m[0][1]*b[1][0] + m[0][2]*b[2][0] + m[0][3]*b[3][0]
  14. c[0][1] = m[0][0]*b[0][1] + m[0][1]*b[1][1] + m[0][2]*b[2][1] + m[0][3]*b[3][1]
  15. c[0][2] = m[0][0]*b[0][2] + m[0][1]*b[1][2] + m[0][2]*b[2][2] + m[0][3]*b[3][2]
  16. c[0][3] = m[0][0]*b[0][3] + m[0][1]*b[1][3] + m[0][2]*b[2][3] + m[0][3]*b[3][3]
  17. c[1][0] = m[1][0]*b[0][0] + m[1][1]*b[1][0] + m[1][2]*b[2][0] + m[1][3]*b[3][0]
  18. c[1][1] = m[1][0]*b[0][1] + m[1][1]*b[1][1] + m[1][2]*b[2][1] + m[1][3]*b[3][1]
  19. c[1][2] = m[1][0]*b[0][2] + m[1][1]*b[1][2] + m[1][2]*b[2][2] + m[1][3]*b[3][2]
  20. c[1][3] = m[1][0]*b[0][3] + m[1][1]*b[1][3] + m[1][2]*b[2][3] + m[1][3]*b[3][3]
  21. c[2][0] = m[2][0]*b[0][0] + m[2][1]*b[1][0] + m[2][2]*b[2][0] + m[2][3]*b[3][0]
  22. c[2][1] = m[2][0]*b[0][1] + m[2][1]*b[1][1] + m[2][2]*b[2][1] + m[2][3]*b[3][1]
  23. c[2][2] = m[2][0]*b[0][2] + m[2][1]*b[1][2] + m[2][2]*b[2][2] + m[2][3]*b[3][2]
  24. c[2][3] = m[2][0]*b[0][3] + m[2][1]*b[1][3] + m[2][2]*b[2][3] + m[2][3]*b[3][3]
  25. c[3][0] = m[3][0]*b[0][0] + m[3][1]*b[1][0] + m[3][2]*b[2][0] + m[3][3]*b[3][0]
  26. c[3][1] = m[3][0]*b[0][1] + m[3][1]*b[1][1] + m[3][2]*b[2][1] + m[3][3]*b[3][1]
  27. c[3][2] = m[3][0]*b[0][2] + m[3][1]*b[1][2] + m[3][2]*b[2][2] + m[3][3]*b[3][2]
  28. c[3][3] = m[3][0]*b[0][3] + m[3][1]*b[1][3] + m[3][2]*b[2][3] + m[3][3]*b[3][3]
  29. return c
  30. #=======================================================================================================================
  31. # rotMat =
  32. #=======================================================================================================================
  33. rotMat = Matrix()
  34. rotMat[0][0] = 1.0
  35. rotMat[0][1] = 0.0
  36. rotMat[0][2] = 0.0
  37. rotMat[0][3] = 0.0
  38. rotMat[1][0] = 0.0
  39. rotMat[1][1] = 0.0
  40. rotMat[1][2] = 1.0
  41. rotMat[1][3] = 0.0
  42. rotMat[2][0] = 0.0
  43. rotMat[2][1] = -1.0
  44. rotMat[2][2] = 0.0
  45. rotMat[2][3] = 0.0
  46. rotMat[3][0] = 0.0
  47. rotMat[3][1] = 0.0
  48. rotMat[3][2] = 0.0
  49. rotMat[3][3] = 1.0
  50. rotMat.transpose()
  51. #=======================================================================================================================
  52. # Initializer =
  53. #=======================================================================================================================
  54. class Initializer:
  55. def __init__(self):
  56. self.blSkeleton = None # Blender Armature
  57. self.saveDir = "" # the name of the saved file
  58. self.flipYZ = 0 #convert from bl to right handed coord system
  59. #======================================================================================================================
  60. # getBlSkeletonFromBlObj =
  61. #=======================================================================================================================
  62. def getBlSkeletonFromBlObj(obj):
  63. # check if obj is correct class
  64. if(obj.__class__.__name__ != "Blender Object"):
  65. raise RuntimeError("The given func param is not a \"Blender Object\" class but a \"" + obj.__class__.__name__ + "\"")
  66. # check modifiers
  67. if len(obj.modifiers) < 1:
  68. raise RuntimeError("Obj \"" + obj.getName() + "\" doesnt have modifiers so no armature found")
  69. # search for modifier of skeleton type
  70. for mod in obj.modifiers:
  71. if mod.type == Blender.Modifier.Types.ARMATURE:
  72. aobj = mod[Blender.Modifier.Settings.OBJECT]
  73. skeleton = Blender.Object.Get(aobj.name).getData(0, 1) # set skeleton
  74. return skeleton
  75. raise RuntimeError("Obj \"" + obj.getName() + "\" has no modifier of type armature")
  76. #=======================================================================================================================
  77. # getAnkiSkeletonScript =
  78. #=======================================================================================================================
  79. def getAnkiSkeletonScript(skeleton, flipYZ):
  80. """ftxt = "" # file text
  81. # write the file
  82. boneNames = skeleton.bones.keys()
  83. boneNames.sort() # the bones are written in alpabetical order
  84. ftxt += str(len(boneNames)) + "\n"
  85. for boneName in boneNames:
  86. bone = skeleton.bones[boneName]
  87. # name
  88. ftxt += "\"" + bone.name + "\"\n"
  89. # head
  90. co = bone.head["ARMATURESPACE"]
  91. if flipYZ:
  92. ftxt += str(co.x) + " " + str(co.z) + " " + str(-co.y) + "\n"
  93. else:
  94. ftxt += str(co.x) + " " + str(co.y) + " " + str(co.z) + "\n"
  95. # tail
  96. co = bone.tail["ARMATURESPACE"]
  97. if flipYZ:
  98. ftxt += str(co.x) + " " + str(co.z) + " " + str(-co.y) + "\n"
  99. else:
  100. ftxt += str(co.x) + " " + str(co.y) + " " + str(co.z) + "\n"
  101. # matrix
  102. m4 = bone.matrix["ARMATURESPACE"].copy()
  103. if flipYZ:
  104. m4 = multMatrix(m4, rotMat)
  105. for i_ in range(0, 4):
  106. for j_ in range(0, 4):
  107. ftxt += str(m4[j_][i_]) + " "
  108. ftxt += "\n"
  109. # write the parent
  110. if not bone.parent:
  111. ftxt += "NULL\n"
  112. else:
  113. ftxt += str(boneNames.index(bone.parent.name)) + "\n"
  114. # write the childs
  115. ftxt += str(len(bone.children)) + "\n"
  116. for child in bone.children:
  117. ftxt += str(boneNames.index(child.name)) + " "
  118. ftxt += "\n"
  119. return ftxt"""
  120. buff = pack("8s", "ANKISKEL")
  121. boneNames = skeleton.bones.keys()
  122. boneNames.sort() # the bones are written in alpabetical order
  123. buff += pack("I", len(boneNames))
  124. for boneName in boneNames:
  125. bone = skeleton.bones[boneName]
  126. # name
  127. str_ = bone.name
  128. buff += pack("I" + str(len(str_)) + "s", len(str_), str_)
  129. # head
  130. co = bone.head["ARMATURESPACE"]
  131. if flipYZ:
  132. buff += pack("fff", co.x, co.z, -co.y)
  133. else:
  134. buff += pack("fff", co.x, co.y, co.z)
  135. # tail
  136. co = bone.tail["ARMATURESPACE"]
  137. if flipYZ:
  138. buff += pack("fff", co.x, co.z, -co.y)
  139. else:
  140. buff += pack("fff", co.x, co.y, co.z)
  141. # matrix
  142. m4 = bone.matrix["ARMATURESPACE"].copy()
  143. if flipYZ:
  144. m4 = multMatrix(m4, rotMat)
  145. for i_ in range(0, 4):
  146. for j_ in range(0, 4):
  147. buff += pack("f", m4[j_][i_])
  148. # write the parent
  149. if not bone.parent:
  150. buff += pack("I", 0xFFFFFFFF)
  151. else:
  152. buff += pack("I", boneNames.index(bone.parent.name))
  153. # write the childs
  154. buff += pack("I", len(bone.children))
  155. for child in bone.children:
  156. buff += pack("I", boneNames.index(child.name))
  157. # end!
  158. return buff
  159. #=======================================================================================================================
  160. # export =
  161. #=======================================================================================================================
  162. def export(skeletonInit):
  163. skeleton = skeletonInit.skeleton
  164. #check if mesh is the correct class
  165. if(skeleton.__class__.__name__ != "Armature"):
  166. raise RuntimeError("The given func param is not a \"Armature\" class but a \"" + skeleton.__class__.__name__ + "\"")
  167. print("Trying to export skeleton \"" + skeleton.name + "\"")
  168. filename = skeletonInit.saveDir + skeleton.name + ".skel"
  169. file = open(filename, "wb")
  170. file.write(getAnkiSkeletonScript(skeleton, skeletonInit.flipYZ))
  171. print("Skeleton exported!! \"" + filename + "\"")