-
-
Save torque/6453947 to your computer and use it in GitHub Desktop.
| # 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, 2), | |
| "blender": (2, 62, 0), | |
| "location": "File > Export > Adobe After Effects 6.0 Keyframe Data", | |
| "warning": "", | |
| "category": "Import-Export", | |
| } | |
| import bpy, mathutils, math, pyperclip | |
| 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 = [] | |
| clipboard = "" | |
| f.write("Adobe After Effects 6.0 Keyframe Data\r\n\r\n") | |
| clipboard += "Adobe After Effects 6.0 Keyframe Data\r\n\r\n" | |
| f.write("\tUnits Per Second\t{0:.3f}\r\n".format(fps)) | |
| clipboard += "\tUnits Per Second\t{0:.3f}\r\n".format(fps) | |
| f.write("\tSource Width\t{0}\r\n".format(clip.size[0])) | |
| clipboard += "\tSource Width\t{0}\r\n".format(clip.size[0]) | |
| f.write("\tSource Height\t{0}\r\n".format(clip.size[1])) | |
| clipboard += "\tSource Height\t{0}\r\n".format(clip.size[1]) | |
| f.write("\tSource Pixel Aspect Ratio\t1\r\n") | |
| clipboard += "\tSource Pixel Aspect Ratio\t1\r\n" | |
| f.write("\tComp Pixel Aspect Ratio\t1\r\n\r\n") | |
| clipboard += "\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") | |
| clipboard += "Anchor Point\r\n" | |
| f.write("\tFrame\tX pixels\tY pixels\tZ pixels\r\n") | |
| clipboard += "\tFrame\tX pixels\tY pixels\tZ pixels\r\n" | |
| f.write(positions) | |
| clipboard += positions | |
| f.write("Position\r\n") | |
| clipboard += "Position\r\n" | |
| f.write("\tFrame\tX pixels\tY pixels\tZ pixels\r\n") | |
| clipboard += "\tFrame\tX pixels\tY pixels\tZ pixels\r\n" | |
| f.write(positions) | |
| clipboard += positions | |
| f.write("Scale\r\n") | |
| clipboard += "Scale\r\n" | |
| f.write("\tFrame\tX percent\tY percent\tZ percent\r\n") | |
| clipboard += "\tFrame\tX percent\tY percent\tZ percent\r\n" | |
| f.write(scales) | |
| clipboard += scales | |
| f.write("Rotation\r\n") | |
| clipboard += "Rotation\r\n" | |
| f.write("\tFrame Degrees\r\n") | |
| clipboard += "\tFrame Degrees\r\n" | |
| f.write(rotations) | |
| clipboard += rotations | |
| f.write("End of Keyframe Data\r\n") | |
| clipboard += "End of Keyframe Data\r\n" | |
| trackno += 1 | |
| clipno += 1 | |
| pyperclip.copy(clipboard) | |
| 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) | |
| def menu_func(self, context): | |
| self.layout.operator(ExportAFXKey.bl_idname, text="Adobe After Effects 6.0 Keyframe Data") | |
| def register(): | |
| bpy.utils.register_class(ExportAFXKey) | |
| bpy.types.INFO_MT_file_export.append(menu_func) | |
| def unregister(): | |
| bpy.utils.unregister_class(ExportAFXKey) | |
| bpy.types.INFO_MT_file_export.remove(menu_func) | |
| if __name__ == "__main__": | |
| register() |
Hi torque,
I seem to have a problem with 2nd round of exporting motion tracking data. The first exports fine, but the second comes up with the following error:
http://i.imgur.com/59z7lt0.png
I dont know if this is an issue with pyperclip, or aae-export, but thought I would take a chance and post it here. It seems to me that pyperclip takes over the default clipboard that Windows uses, and is only available to me again when I close and exit Blender!
Im using Windows 7 Professional x64, pyperclip 1.5.6, and Blender 2.7.3
Edit:
Fixed this by removing all pyperclip related functions from the aae-export v1.2 script.
On Line 26 remove ', pyperclip' and
on line 158 remove 'pyperclip.copy(clipboard)'
Pyperclip is somewhat brittle at this point. I think it can handle most unicode, but doesn't handle non-text data (though that isn't an issue in this case). Though from the error message, it looks like it might not necessarily be something in Pyperclip.
Sorry I can't be more helpful.
I use your very nice script with Aegisub, there is only one thing I need to change:
=> positions = "\r\n".join([posline.format(d[0], d[1], (clip.size[1]-d[2])) for d in data]) + "\r\n\r\n"
(Line 100)
If someone need this for subbing with Aegisub.
(in Aegisub is the coordinate of y is reverse)
👍 I publish it on github: https://github.com/Subarashii-no-Fansub/AAE-Export
hello
I am very interested in the above script. What version does it work it? On 2.69 mac I get the following errors we I try to install activate it.
Any ideas what I am doing wrong please?
Thanks
Christopher
par57p00446:~ lowdenc$ /Applications/Blender/blender.app/Contents/MacOS/blender ; exit;
ndof: 3Dx driver not found
Read new prefs: /Users/lowdenc/Library/Application Support/Blender/2.69/config/userpref.blend
found bundled python: /Applications/Blender/blender.app/Contents/MacOS/2.69/python
reloading addon: aae-export 1392996961.0 1392997153.0 /Users/lowdenc/Library/Application Support/Blender/2.69/scripts/addons/aae-export.py
Modules Installed from '/Users/lowdenc/Desktop/aae-export.py' into '/Users/lowdenc/Library/Application Support/Blender/2.69/scripts/addons' ()
reloading addon: aae-export 1392997153.0 1392997159.0 /Users/lowdenc/Library/Application Support/Blender/2.69/scripts/addons/aae-export.py
Modules Installed from '/Users/lowdenc/Desktop/aae-export.py' into '/Users/lowdenc/Library/Application Support/Blender/2.69/scripts/addons' ()
Traceback (most recent call last):
File "/Applications/Blender/blender.app/Contents/MacOS/2.69/scripts/modules/addon_utils.py", line 298, in enable
mod = import(module_name)
File "/Users/lowdenc/Library/Application Support/Blender/2.69/scripts/addons/aae-export.py", line 29
scene = context.scene
^
IndentationError: expected an indented block