123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- '''
- CSV exporter for the BCK animation type
- CSV to be used with the j3d animation editor program
- '''
- import bpy, math, re
- from mathutils import Matrix
- from .my_functions import *
-
- def write_csv_bck(context, filepath, loop_mode, export_mode):
-
-
- scene = bpy.context.scene
-
-
- loop_number = 0
-
- if (loop_mode == "OPT_A"):
- loop_number = 0
- elif (loop_mode == "OPT_B"):
- loop_number = 1
- elif (loop_mode == "OPT_C"):
- loop_number = 2
- elif (loop_mode == "OPT_D"):
- loop_number = 3
- elif (loop_mode == "OPT_E"):
- loop_number = 4
-
-
- if (scene.objects.active == None
- or
- scene.objects.active.type != 'ARMATURE'):
- error_string = "No Armature object selected. Select one and try again."
- print("\n### ERROR ###\n" + error_string + "\n### ERROR ###\n")
- show_message(error_string, "Error exporting collada file", 'ERROR')
- return {'FINISHED'}
-
-
- armature = scene.objects.active
- print()
- print("###############")
- print("Armature found: %s" % armature.name)
- print()
-
- print("Creating CSV file (for BCK)...")
-
-
- f = open(filepath, 'w', encoding='utf-8')
-
- print("Writing CSV header...")
-
-
-
-
-
- animation_length = scene.frame_end + 1
- f.write("%d,%d,%d,%s" % (loop_number, animation_length - 1, 0, ".bck"))
- f.write("\n")
-
- f.write("Bone Name,Tangent Interpolation,Component")
- for frame in range(animation_length):
- f.write(",Frame %d" % (frame))
- f.write("\n")
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- bone_kf_data = []
-
- for i in range(len(armature.animation_data.action.fcurves)):
-
-
- curve = armature.animation_data.action.fcurves[i]
-
- bone_kf_data.append([])
-
-
-
-
-
- bone_kf_data[i].append(re.search('\["(.+?)"\]', curve.data_path).group(1))
-
-
- if (curve.data_path.find("scale") + 1):
- bone_kf_data[i].append("scale")
- elif (curve.data_path.find("rotation_euler") + 1):
- bone_kf_data[i].append("rotation")
- elif (curve.data_path.find("location") + 1):
- bone_kf_data[i].append("translation")
-
- if (curve.array_index == 0):
- bone_kf_data[i].append("x")
- elif (curve.array_index == 1):
- bone_kf_data[i].append("y")
- elif (curve.array_index == 2):
- bone_kf_data[i].append("z")
-
-
- for j in range(len(curve.keyframe_points)):
- keyframe = curve.keyframe_points[j]
- bone_kf_data[i].append(int(keyframe.co[0]))
-
-
-
- print()
- for row in bone_kf_data:
- print(row)
-
-
-
-
-
-
-
-
-
-
- bone_last_kf_pos = []
- for i in range(len(bone_kf_data)):
-
- if (len(bone_last_kf_pos) != 0):
-
-
- if (bone_last_kf_pos[len(bone_last_kf_pos) - 2] == bone_kf_data[i][0]):
-
- if (bone_last_kf_pos[len(bone_last_kf_pos) - 1] < bone_kf_data[i][len(bone_kf_data[i]) - 1]):
- bone_last_kf_pos[len(bone_last_kf_pos) - 1] = bone_kf_data[i][len(bone_kf_data[i]) - 1]
- continue
-
-
-
- if (len(bone_kf_data[i]) > 4):
- bone_last_kf_pos.append(bone_kf_data[i][0])
- bone_last_kf_pos.append(bone_kf_data[i][len(bone_kf_data[i]) - 1])
-
-
-
- print()
- print(bone_last_kf_pos)
- print()
-
-
-
-
-
-
-
-
- for i in range(len(armature.pose.bones)):
-
-
- bone = armature.pose.bones[i]
-
- print("Processing animation for bone: %s" % (bone.name))
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- bone_anim_data = [[], [], [], [], [], [], [], [], []]
-
-
-
- for j in range(len(bone_anim_data)):
- for k in range(animation_length):
- bone_anim_data[j].append("")
-
-
-
-
-
- bone_has_anim = False
- anim_length_for_bone = 0 + 1
- for j in range(int(len(bone_last_kf_pos) / 2)):
-
- if (bone_last_kf_pos[2 * j] == bone.name):
- bone_has_anim = True
- anim_length_for_bone = bone_last_kf_pos[(2 * j) + 1] + 1
- break
-
-
- print("Bone has animation? ", end = "")
- print(bone_has_anim)
- print("Bone animation length: %d" % (anim_length_for_bone))
-
-
-
-
-
-
- current_bone_kf_data = []
- bone_kfs = []
- if (export_mode == "OPT_B" and bone_has_anim == True):
-
-
-
-
- current_bone_kf_data = []
- for j in range(len(bone_kf_data)):
- if (bone_kf_data[j][0] == bone.name):
- current_bone_kf_data.append(bone_kf_data[j])
-
-
-
-
- for j in range(len(current_bone_kf_data)):
-
-
-
- if (j == 0):
- for k in range(len(current_bone_kf_data[0])):
-
- if (k < 3):
- continue
- bone_kfs.append(current_bone_kf_data[j][k])
-
-
- for k in range(len(current_bone_kf_data[j])):
-
- if (k < 3):
- continue
-
-
- keyframe_exists = False
- for l in range(len(bone_kfs)):
- if (current_bone_kf_data[j][k] == bone_kfs[l]):
- keyframe_exists = True
- break
-
- if (keyframe_exists == False):
- bone_kfs.append(current_bone_kf_data[j][k])
-
-
-
- print("Bone's keyframes position:")
- print(bone_kfs)
-
-
- print()
-
-
-
-
-
-
-
-
-
- k = 0
- for j in range(anim_length_for_bone):
-
-
-
- if (export_mode == "OPT_B" and bone_has_anim == True and j != 0):
-
-
- if (k == len(bone_kfs)):
- break
-
- frame = bone_kfs[k]
- scene.frame_set(frame)
- k = k + 1
-
- else:
-
- frame = j
- scene.frame_set(frame)
-
-
-
-
- if (i == 0):
-
- rot_mat = calc_rotation_matrix(math.radians(-90), 0, 0)
-
-
- bone_rel_to_parent_mat = rot_mat * bone.matrix
- else:
- bone_rel_to_parent_mat = bone.parent.matrix.inverted() * bone.matrix
-
-
-
-
-
- bone_scale = bone_rel_to_parent_mat.to_scale()
-
- bone_rotation = bone_rel_to_parent_mat.to_euler("XYZ")
-
- bone_translation = 100 * bone_rel_to_parent_mat.to_translation()
-
-
-
-
-
- bone_anim_data[0][frame] = round(bone_scale[0], 2)
- bone_anim_data[1][frame] = round(bone_scale[1], 2)
- bone_anim_data[2][frame] = round(bone_scale[2], 2)
-
-
- bone_anim_data[3][frame] = round(math.degrees(bone_rotation[0]), 2)
- bone_anim_data[4][frame] = round(math.degrees(bone_rotation[1]), 2)
- bone_anim_data[5][frame] = round(math.degrees(bone_rotation[2]), 2)
-
-
- bone_anim_data[6][frame] = round(bone_translation[0], 2)
- bone_anim_data[7][frame] = round(bone_translation[1], 2)
- bone_anim_data[8][frame] = round(bone_translation[2], 2)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- for j in range(9):
-
-
-
-
-
-
- if (j == 0):
- f.write("%s,Linear,Scale X:" % (bone.name))
- elif(j == 1):
- f.write(",Linear,Scale Y:")
- elif(j == 2):
- f.write(",Linear,Scale Z:")
- elif(j == 3):
- f.write(",Linear,Rotation X:")
- elif(j == 4):
- f.write(",Linear,Rotation Y:")
- elif(j == 5):
- f.write(",Linear,Rotation Z:")
- elif(j == 6):
- f.write(",Linear,Translation X:")
- elif(j == 7):
- f.write(",Linear,Translation Y:")
- elif(j == 8):
- f.write(",Linear,Translation Z:")
-
-
-
-
-
- for k in range(animation_length):
-
-
- current_value = bone_anim_data[j][k]
-
-
- if (k == 0):
- f.write(",%.2f" % (current_value))
-
-
-
- elif (old_value == current_value or current_value == ""):
- f.write(",")
- else:
- f.write(",%.2f" % (current_value))
-
-
- if (k == (animation_length - 1)):
- f.write("\n")
-
-
- if (current_value != ""):
- old_value = current_value
-
-
-
-
-
- return {'FINISHED'}
- from bpy_extras.io_utils import ExportHelper
- from bpy.props import StringProperty, BoolProperty, EnumProperty
- from bpy.types import Operator
- class Export_CSV_BCK(Operator, ExportHelper):
- """Save a CSV file for BCK conversion (to use with J3D Animation Editor)"""
- bl_idname = "export_scene.csv_bck"
- bl_label = "Export CSV (for BCK)"
- filename_ext = ".csv"
- filter_glob = StringProperty(
- default="*.csv",
- options={'HIDDEN'},
- maxlen=255,
- )
- loop_mode = EnumProperty(
- name="Loop Mode",
- description="Choose the loop mode for the animation",
- items=( ('OPT_A', "Once", "Play the animation once and stop at the last frame"),
- ('OPT_B', "Once and Reset", "Play the animation once and stop at the first frame"),
- ('OPT_C', "Loop", "Loop the animation infinitely"),
- ('OPT_D', "Mirrored Once", "Play the animation forwards and then backwards once. Stops at the first frame"),
- ('OPT_E', "Mirrored Loop", "Play the animation forwards and then backwards infinitely")
- ), default='OPT_A'
- )
- export_mode = EnumProperty(
- name="Export Mode",
- description="Choose the method used to export the model animation data",
- items=( ('OPT_A', "All Frames", "Export animation values for each frame of the animation. Slow, higher CSV file size, more accurate animation"),
- ('OPT_B', "Only Keyframes", "Only export the animation keyframe values of each bone. Fast, lower CSV file size, least accurate animation"),
- ), default='OPT_A'
- )
-
- def execute(self, context):
- return write_csv_bck(context, self.filepath, self.loop_mode, self.export_mode)
- def menu_export_csv_bck(self, context):
- self.layout.operator(Export_CSV_BCK.bl_idname, text="CSV Animation Table (for BCK) (.csv)")
- bpy.utils.register_class(Export_CSV_BCK)
- bpy.types.INFO_MT_file_export.append(menu_export_csv_bck)
- bpy.ops.export_scene.csv_bck('INVOKE_DEFAULT')
|