# Copyright (c) 2013, Martin Herkt # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. bl_info = { "name": "Export: Adobe After Effects 6.0 Keyframe Data", "description": "Export motion tracking markers to Adobe After Effects 6.0 compatible files", "author": "Martin Herkt", "version": (0, 1, 4), "blender": (2, 80, 0), "location": "File > Export > Adobe After Effects 6.0 Keyframe Data", "warning": "", "category": "Import-Export", } import bpy, mathutils, math def write_files(prefix, context): scene = context.scene fps = scene.render.fps / scene.render.fps_base clipno = 0 for clip in bpy.data.movieclips: trackno = 0 for track in clip.tracking.tracks: with open("{0}_c{1:02d}_t{2:02d}.txt".format(prefix, clipno, trackno), "w") as f: frameno = clip.frame_start startarea = None startwidth = None startheight = None startrot = None data = [] f.write("Adobe After Effects 6.0 Keyframe Data\r\n\r\n") f.write("\tUnits Per Second\t{0:.3f}\r\n".format(fps)) f.write("\tSource Width\t{0}\r\n".format(clip.size[0])) f.write("\tSource Height\t{0}\r\n".format(clip.size[1])) f.write("\tSource Pixel Aspect Ratio\t1\r\n") f.write("\tComp Pixel Aspect Ratio\t1\r\n\r\n") while frameno <= clip.frame_duration: marker = track.markers.find_frame(frameno) frameno += 1 if not marker or marker.mute: continue coords = marker.co corners = marker.pattern_corners area = 0 width = math.sqrt((corners[1][0] - corners[0][0]) * (corners[1][0] - corners[0][0]) + (corners[1][1] - corners[0][1]) * (corners[1][1] - corners[0][1])) height = math.sqrt((corners[3][0] - corners[0][0]) * (corners[3][0] - corners[0][0]) + (corners[3][1] - corners[0][1]) * (corners[3][1] - corners[0][1])) for i in range(1,3): x1 = corners[i][0] - corners[0][0] y1 = corners[i][1] - corners[0][1] x2 = corners[i+1][0] - corners[0][0] y2 = corners[i+1][1] - corners[0][1] area += x1 * y2 - x2 * y1 area = abs(area / 2) if startarea == None: startarea = area if startwidth == None: startwidth = width if startheight == None: startheight = height zoom = math.sqrt(area / startarea) * 100 xscale = width / startwidth * 100 yscale = height / startheight * 100 p1 = mathutils.Vector(corners[0]) p2 = mathutils.Vector(corners[1]) mid = (p1 + p2) / 2 diff = mid - mathutils.Vector((0,0)) rotation = math.atan2(diff[0], diff[1]) * 180 / math.pi if startrot == None: startrot = rotation rotation = 0 else: rotation -= startrot - 360 x = coords[0] * clip.size[0] y = (1 - coords[1]) * clip.size[1] data.append([marker.frame, x, y, xscale, yscale, rotation]) posline = "\t{0}\t{1:.3f}\t{2:.3f}\t0" scaleline = "\t{0}\t{1:.3f}\t{2:.3f}\t100" rotline = "\t{0}\t{1:.3f}" positions = "\r\n".join([posline.format(d[0], d[1], d[2]) for d in data]) + "\r\n\r\n" scales = "\r\n".join([scaleline.format(d[0], d[3], d[4]) for d in data]) + "\r\n\r\n" rotations = "\r\n".join([rotline.format(d[0], d[5]) for d in data]) + "\r\n\r\n" f.write("Anchor Point\r\n") f.write("\tFrame\tX pixels\tY pixels\tZ pixels\r\n") f.write(positions) f.write("Position\r\n") f.write("\tFrame\tX pixels\tY pixels\tZ pixels\r\n") f.write(positions) f.write("Scale\r\n") f.write("\tFrame\tX percent\tY percent\tZ percent\r\n") f.write(scales) f.write("Rotation\r\n") f.write("\tFrame Degrees\r\n") f.write(rotations) f.write("End of Keyframe Data\r\n") trackno += 1 clipno += 1 return {'FINISHED'} from bpy_extras.io_utils import ExportHelper from bpy.props import StringProperty class ExportAFXKey(bpy.types.Operator, ExportHelper): """Export motion tracking markers to Adobe After Effects 6.0 compatible files""" bl_idname = "export.afxkey" bl_label = "Export to Adobe After Effects 6.0 Keyframe Data" filename_ext = "" filter_glob = StringProperty(default="*", options={'HIDDEN'}) def execute(self, context): return write_files(self.filepath, context) classes = ( ExportAFXKey, ) def menu_func_export(self, context): self.layout.operator(ExportAFXKey.bl_idname, text="Adobe After Effects 6.0 Keyframe Data") def register(): from bpy.utils import register_class for cls in classes: register_class(cls) bpy.types.TOPBAR_MT_file_export.append(menu_func_export) def unregister(): from bpy.utils import unregister_class for cls in reversed(classes): unregister_class(cls) bpy.types.TOPBAR_MT_file_export.remove(menu_func_export) if __name__ == "__main__": register()