skelanim.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import sys
  2. import os
  3. from copy import deepcopy
  4. from Blender import Mathutils
  5. from Blender.Mathutils import *
  6. import Blender
  7. #=======================================================================================================================
  8. # Initializer =
  9. #=======================================================================================================================
  10. class Initializer:
  11. def __init__(self):
  12. self.obj = None
  13. self.saveDir = "" # the name of the saved file
  14. self.flipYZ = 0 # convert from bl to right handed coord system. NOT USED
  15. #=======================================================================================================================
  16. # multMatrix =
  17. #=======================================================================================================================
  18. def multMatrix(m, b):
  19. c = Matrix()
  20. 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]
  21. 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]
  22. 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]
  23. 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]
  24. 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]
  25. 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]
  26. 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]
  27. 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]
  28. 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]
  29. 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]
  30. 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]
  31. 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]
  32. 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]
  33. 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]
  34. 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]
  35. 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]
  36. return c
  37. #=======================================================================================================================
  38. # A few classes =
  39. #=======================================================================================================================
  40. class BonePose:
  41. def __init__(self):
  42. self.rotation = Quaternion(1.0, 0.0, 0.0, 0.0)
  43. self.translation = Vector(0.0, 0.0, 0.0)
  44. class BoneAnim:
  45. def __init__(self):
  46. self.keyframes = [] # before the "write to file" phase this array is ether empty
  47. # if the bone doesnt have animation or an array of poses
  48. class SkelAnim:
  49. def __init__(self):
  50. self.bones = []
  51. self.keyframes = []
  52. #=======================================================================================================================
  53. # getAnkiScript =
  54. #=======================================================================================================================
  55. def getAnkiScript(obj, flipYZ, action):
  56. skeleton = obj.getData(0, 0)
  57. # init and populate the instances
  58. skelAnim = SkelAnim()
  59. skelAnim.keyframes = action.getFrameNumbers()
  60. boneNames = deepcopy(skeleton.bones.keys())
  61. boneNames.sort()
  62. #skelAnim.bones = [BoneAnim() for anim in range(len(boneNames))]
  63. for i in range(0, len(boneNames)):
  64. skelAnim.bones.append(BoneAnim())
  65. for j in range(0, len(skelAnim.keyframes)):
  66. skelAnim.bones[i].keyframes.append(BonePose())
  67. # now populate with the correct data
  68. # for all the kframes
  69. for i in range(0, len(skelAnim.keyframes)):
  70. kframe = skelAnim.keyframes[i]
  71. Blender.Set("curframe", kframe)
  72. Blender.Redraw()
  73. pose = obj.getPose()
  74. # for all bones
  75. for j in range(0, len(boneNames)):
  76. boneName = boneNames[j]
  77. poseBone = pose.bones[boneName]
  78. bone = skeleton.bones[boneName]
  79. # rotation
  80. rot = poseBone.quat.toMatrix()
  81. rot.resize4x4()
  82. # translation
  83. tra = Matrix()
  84. tra.identity()
  85. for m in range(0, 3):
  86. tra[m][3] = poseBone.loc[m]
  87. # bone matris at armature space aka MA
  88. MA = bone.matrix["ARMATURESPACE"].copy()
  89. MAi = MA.copy()
  90. MAi.invert()
  91. # calc the m4 = MA * tra * rot * MAi
  92. rot.transpose()
  93. tra.transpose()
  94. MA.transpose()
  95. MAi.transpose()
  96. m4 = multMatrix(rot, MAi)
  97. m4 = multMatrix(tra, m4)
  98. m4 = multMatrix(MA, m4)
  99. m4.transpose()
  100. # get the final quat and loc
  101. quat = m4.rotationPart()
  102. quat = quat.toQuat()
  103. loc = m4.translationPart()
  104. quat = poseBone.quat
  105. loc = poseBone.loc
  106. for k in range(0, 4):
  107. skelAnim.bones[j].keyframes[i].rotation[k] = quat[k]
  108. for k in range(0, 3):
  109. skelAnim.bones[j].keyframes[i].translation[k] = loc[k]
  110. Blender.Set("curframe", 1)
  111. Blender.Redraw()
  112. # now do the apropriate for the bones without translation or rotation
  113. zeroVec = Vector(0.0, 0.0, 0.0)
  114. identQuat = Quaternion(1.0, 0.0, 0.0, 0.0)
  115. # for all the bones
  116. for i in range(0, len(boneNames)):
  117. noAnimNum = 0 # how many times we found that the bone has no anim
  118. bone = skelAnim.bones[i]
  119. # for all the keyframes
  120. for j in range(0, len(skelAnim.keyframes)):
  121. if bone.keyframes[j].rotation == identQuat and bone.keyframes[j].translation == zeroVec:
  122. noAnimNum = noAnimNum + 1
  123. if noAnimNum == len(skelAnim.keyframes):
  124. print("Bone \"%s\" has no animation" % boneNames[i])
  125. bone.keyframes = []
  126. # write to ftxt
  127. ftxt = ""
  128. # the keyframes
  129. ftxt += str(len(skelAnim.keyframes)) + "\n"
  130. for kf in skelAnim.keyframes:
  131. ftxt += str(kf - 1) + " "
  132. ftxt += "\n"
  133. # the bones num
  134. ftxt += str(len(boneNames)) + "\n"
  135. # for all bones
  136. for i in range(0, len(boneNames)):
  137. bone = skelAnim.bones[i]
  138. if len(bone.keyframes):
  139. ftxt += "1\n"
  140. # for all keyframes
  141. for j in range(0, len(skelAnim.keyframes)):
  142. # write rotation
  143. for k in range(0, 4):
  144. ftxt += str(bone.keyframes[j].rotation[k]) + " "
  145. ftxt += "\n"
  146. # write translation
  147. for k in range(0, 3):
  148. ftxt += str(bone.keyframes[j].translation[k]) + " "
  149. ftxt += "\n"
  150. else:
  151. ftxt += "0\n"
  152. return ftxt
  153. #=======================================================================================================================
  154. # export =
  155. #=======================================================================================================================
  156. def export(init):
  157. obj = init.obj
  158. if obj.getType() != "Armature":
  159. raise RuntimeError("Select a skeleton and not a(n) " + obj.getType())
  160. print("Trying to export skeleton animation")
  161. action = obj.getAction()
  162. if action == 0:
  163. raise RuntimeError("Empty action for obj " + obj.getName())
  164. filename = init.saveDir + action.name + "." + obj.getName() + ".anim"
  165. file = open(filename, "w")
  166. file.write(getAnkiScript(obj, init.flipYZ, action))
  167. print("Skeleton animation exported!! \"" + filename + "\"")