From 789323137195d6ad45b8878fbc59ef9d7f9b780c Mon Sep 17 00:00:00 2001 From: Jorge Vasquez Date: Mon, 31 Mar 2014 13:32:19 -0700 Subject: [PATCH] added the first partially working code --- ADDON_AFX_2d_Track_Exporter.py | 257 +++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 ADDON_AFX_2d_Track_Exporter.py diff --git a/ADDON_AFX_2d_Track_Exporter.py b/ADDON_AFX_2d_Track_Exporter.py new file mode 100644 index 0000000..2a611a9 --- /dev/null +++ b/ADDON_AFX_2d_Track_Exporter.py @@ -0,0 +1,257 @@ +bl_info = { + "name": "After Effects Track Exporter", + "author": "Jorge Vasquez", + "version": (1, 0), + "blender": (2, 65, 0), + "location": "Clip Editor > Tools", + "description": "Export track, and plane track information to Adobe After Effects", + "warning": "", + "wiki_url": "", + "category": "Tracking"} + +import bpy + +class AFX_Track_Exporter: + strings = { + "main" : "Adobe After Effects 6.0 Keyframe Data", + "units" : "Units Per Second", + "width" : "Source Width", + "height" : "Source Height", + "source_aspect" : "Source Pixel Aspect Ratio", + "comp_aspect" : "Comp Pixel Aspect Ratio", + "position" : "Position", + "position_units" : "Frame\tX pixels\tY pixels\tZ pixels", + "rotation" : "Rotation", + "rotation_units" : "Frame\tDegrees", + "scale" : "Scale", + "scale_units" : "Frame\tX percent\tY percent\tZ percent", + "end" : "End of Keyframe Data", + "corner_pin" : "Effects\tCorner Pin #1", + "corner_pin_units" : "Frame\tX pixels\tY pixels", + "corner_names" : ["Lower Left","Lower Right","Upper Right","Upper Left"], + "header_types" : ["main","pos","rot","sca","c_pin","p_pin","end"] + } + + def getFilePath(self): + file_path = bpy.data.filepath + file_name = bpy.path.basename(file_path) + name_start = file_path.find(file_name) + path = file_path[0:name_start] + return path + +AFXtx = AFX_Track_Exporter() + + +def write_afx_keyframe_header(file, type_index): + + t = AFXtx.strings["header_types"][type_index] + clip = bpy.context.space_data.clip + scene = bpy.context.scene + fps = scene.render.fps + source_aspect = clip.display_aspect[0]/clip.display_aspect[1] + comp_aspect = scene.render.pixel_aspect_x/scene.render.pixel_aspect_y + + if t == "main": + header = AFXtx.strings["main"]+"\n\n\t"+AFXtx.strings["units"]+"\t"+str(fps)+"\n" + header = header + "\t"+AFXtx.strings["width"]+"\t"+str(clip.size[0])+"\n" + header = header + "\t"+AFXtx.strings["height"]+"\t"+str(clip.size[1])+"\n" + header = header + "\t"+AFXtx.strings["source_aspect"]+"\t"+str(source_aspect)+"\n" + header = header + "\t"+AFXtx.strings["comp_aspect"]+"\t"+str(comp_aspect)+"\n\n" + elif t == "pos": + header = AFXtx.strings["position"]+"\n\t"+AFXtx.strings["position_units"]+"\n" + elif t == "rot": + header = AFXtx.strings["rotation"]+"\n\t"+AFXtx.strings["rotation_units"]+"\n" + elif t == "sca": + header = AFXtx.strings["scale"]+"\n\t"+AFXtx.strings["scale_units"]+"\n" + elif t == "end": + header = "\n"+AFXtx.strings["end"] + + file.write(header) + +def write_afx_cp_keyframe_header(file, type_index, corner): + + t = AFXtx.strings["header_types"][type_index] + if t == "c_pin": + header = AFXtx.strings["corner_pin"]+"\t"+corner+"\n\t"+AFXtx.strings["corner_pin_units"]+"\n" + + file.write(header) + +def calc_pos_from_corners(corners): + sumX = 0.0 + sumY = 0.0 + for i in range(4): + sumX += corners[i][0] + sumY += corners[i][1] + x = sumX/4 + y = 1-(sumY/4) ## Y down + return [x,y] + +def write_afx_pos_keyframe_header(file): + pass + +def writeRawMarkers(file): + for frame in plane_track.markers: + print(dir(frame)) + for current_corner in range(4): ## the corners are stored ina float4 0 = Lower Left, 1 = Lower Right, 2 = Upper Right, 3 = Upper Left) + for current_component in range(2): ## the location of the corner are stored in a float2 x,y + + current_point = frame.corners[current_corner][current_component] + + file.write(" ") + file.write("\n") + file.close() + +def write_pos_data(file): + for marker in range(len(plane_track.markers)): + n_format = "{0:.3f}" + size = clip.size + frame = plane_track.markers[marker].frame + pos = calc_pos_from_corners(plane_track.markers[marker].corners) + x = str(n_format.format(pos[0]*clip.size[0])) + y = str(n_format.format(pos[1]*clip.size[1])) + z = "0" + line = "\t"+str(frame)+"\t"+x+"\t"+y+"\t"+"0"+"\n" + file.write(line) + file.write("\n") + +def write_cp_data(file, plane_track): + clip = bpy.context.space_data.clip + n_format = "{0:.3f}" + for corner in range(4): + + write_afx_cp_keyframe_header(file,4,AFXtx.strings["corner_names"][corner]) + + for marker in range(len(plane_track.markers)): + frame = plane_track.markers[marker].frame + x = str(n_format.format(plane_track.markers[marker].corners[corner][0]*clip.size[0])) + y = str(n_format.format((1-plane_track.markers[marker].corners[corner][1])*clip.size[1])) + line = "\t"+str(frame)+"\t"+x+"\t"+y+"\n" + file.write(line) + file.write("\n") + +def write_pos_from_single_track(file,track): + for marker in range(len(track.markers)): + n_format = "{0:.3f}" + clip = bpy.context.space_data.clip + size = clip.size + frame = track.markers[marker].frame + pos = track.markers[marker].co + x = str(n_format.format(pos[0]*clip.size[0])) + y = str(n_format.format((1-pos[1])*clip.size[1])) + z = "0" + line = "\t"+str(frame)+"\t"+x+"\t"+y+"\t"+"0"+"\n" + file.write(line) + file.write("\n") + +def write_cp_data_from_track(file): + n_format = "{0:.3f}" + for corner in range(4): + + write_afx_cp_keyframe_header(file,4,AFXtx.strings["corner_names"][corner]) + + for marker in range(len(track.markers)): + frame = track.markers[marker].frame + x = str(n_format.format((track.markers[marker].co[0]+track.markers[marker].pattern_corners[corner][0])*clip.size[0])) + y = str(n_format.format((1-(track.markers[marker].co[1]+track.markers[marker].pattern_corners[corner][1]))*clip.size[1])) + line = "\t"+str(frame)+"\t"+x+"\t"+y+"\n" + file.write(line) + file.write("\n") + +class TrackerExportPanel(bpy.types.Panel): + """Creates a Panel in the Object properties window""" + bl_label = "AFX Plane Track Exporter" + bl_idname = "OBJECT_PT_hello" + bl_space_type = 'CLIP_EDITOR' + bl_region_type = 'TOOLS' + + def draw(self, context): + layout = self.layout + + clip = bpy.context.space_data.clip + active_track = clip.tracking.tracks.active + active_plane_track = clip.tracking.plane_tracks.active + + selected_plane_tracks = [pt for pt in clip.tracking.plane_tracks if pt.select == True] + selected_tracks = [t for t in clip.tracking.tracks if t.select == True] + + if active_track != None or (active_plane_track != None and active_plane_track.select == True) : + if active_track != None: + row = layout.row() + row.prop(active_track,"name") + row.operator("wm.export_track_pos_only") + if active_plane_track != None and active_plane_track.select == True: + row = layout.row() + row.prop(active_plane_track,"name") + row.operator("wm.export_plane_track_cp_only") + else: + layout.label(text="Select a track or a plane Track to export") + +def init_file(): + path = AFXtx.getFilePath() + file=open(path+"plane_tracks2.txt","w") + write_afx_keyframe_header(file,0) + return file + +def finalize_file(file): + write_afx_keyframe_header(file,6) + file.close() + +def export_track(context): + + clip = bpy.context.space_data.clip + active_track = clip.tracking.tracks.active + txt_data = "" + fp = init_file() + + write_afx_keyframe_header(fp,1) + write_pos_from_single_track(fp,active_track) + finalize_file(fp) + +def export_plane_track(context): + + clip = bpy.context.space_data.clip + active_plane_track = clip.tracking.plane_tracks.active + fp = init_file() + write_afx_keyframe_header(fp,1) + write_cp_data(fp,active_plane_track) + finalize_file(fp) + +class ExportTrack(bpy.types.Operator): + """Tooltip""" + bl_idname = "wm.export_track_pos_only" + bl_label = "export track" + +# @classmethod +# def poll(cls, context): +# return context.active_object is not None + + def execute(self, context): + export_track(context) + return {'FINISHED'} + +class ExportPlaneTrack(bpy.types.Operator): + """Tooltip""" + bl_idname = "wm.export_plane_track_cp_only" + bl_label = "export corner pin" + test = bpy.props.BoolProperty(name="Execute",description="If it shall actually run, for optimal performance",default=False) + +# @classmethod +# def poll(cls, context): +# return context.active_object is not None + + def execute(self, context): + export_plane_track(context) + return {'FINISHED'} + +def register(): + bpy.utils.register_class(TrackerExportPanel) + bpy.utils.register_class(ExportTrack) + bpy.utils.register_class(ExportPlaneTrack) + +def unregister(): + bpy.utils.unregister_class(TrackerExportPanel) + bpy.utils.unregister_class(ExportTrack) + bpy.utils.unregister_class(ExportPlaneTrack) + +if __name__ == "__main__": + register()