[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [2529] trunk/py/scripts/addons/ io_export_after_effects.py: adding After Effects Exporter to trunk
Bartek Skorupa
bartekskorupa at bartekskorupa.com
Wed Oct 26 11:40:10 CEST 2011
Revision: 2529
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=2529
Author: bartekskorupa
Date: 2011-10-26 09:40:10 +0000 (Wed, 26 Oct 2011)
Log Message:
-----------
adding After Effects Exporter to trunk
Added Paths:
-----------
trunk/py/scripts/addons/io_export_after_effects.py
Copied: trunk/py/scripts/addons/io_export_after_effects.py (from rev 2528, contrib/py/scripts/addons/io_export_after_effects.py)
===================================================================
--- trunk/py/scripts/addons/io_export_after_effects.py (rev 0)
+++ trunk/py/scripts/addons/io_export_after_effects.py 2011-10-26 09:40:10 UTC (rev 2529)
@@ -0,0 +1,403 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# The Original Code is: all of this file.
+#
+# ***** END GPL LICENSE BLOCK *****
+#
+bl_info = {
+ 'name': 'Export: Adobe After Effects (.jsx)',
+ 'description': 'Export selected cameras, objects & bundles to Adobe After Effects CS3 and above',
+ 'author': 'Bartek Skorupa',
+ 'version': (0, 55),
+ 'blender': (2, 6, 0),
+ 'api': 41098,
+ 'location': 'File > Export > Adobe After Effects (.jsx)',
+ 'category': 'Import-Export',
+ "warning": "",
+ "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/Scripts/Import-Export/Adobe_After_Effects"
+ }
+
+
+from math import pi
+import bpy
+import datetime
+
+
+# create list of static blender's data
+def get_comp_data(context):
+ scene = context.scene
+ aspect_x = scene.render.pixel_aspect_x
+ aspect_y = scene.render.pixel_aspect_y
+ aspect = aspect_x / aspect_y
+ fps = scene.render.fps
+
+ return {
+ 'scn': scene,
+ 'width': scene.render.resolution_x,
+ 'height': scene.render.resolution_y,
+ 'aspect': aspect,
+ 'fps': fps,
+ 'start': scene.frame_start,
+ 'end': scene.frame_end,
+ 'duration': (scene.frame_end - scene.frame_start + 1.0) / fps,
+ 'curframe': scene.frame_current,
+ }
+
+
+# create managable list of selected objects
+# (only selected objects will be analyzed and exported)
+def get_selected(context, prefix):
+ cameras = [] # list of selected cameras
+ cams_names = [] # list of selected cameras' names (prevent from calling "ConvertName(ob)" function too many times)
+ nulls = [] # list of all selected objects exept cameras (will be used to create nulls in AE)
+ nulls_names = [] # list of above objects names (prevent from calling "ConvertName(ob)" function too many times)
+ obs = context.selected_objects
+
+ for ob in obs:
+ if ob.type == 'CAMERA':
+ cameras.append(ob)
+ cams_names.append(convert_name(ob, prefix))
+ else:
+ nulls.append(ob)
+ nulls_names.append(convert_name(ob, prefix))
+
+ selection = {
+ 'cameras': cameras,
+ 'cams_names': cams_names,
+ 'nulls': nulls,
+ 'nulls_names': nulls_names,
+ }
+
+ return selection
+
+
+# convert names of objects to avoid errors in AE. Add user specified prefix
+def convert_name(ob, prefix):
+ ob_name = ob.name
+ for c in (" ", ".", ",", "-", "=", "+", "*"):
+ ob_name = ob_name.replace(c, "_")
+
+ return prefix + ob_name
+
+
+# get object's blender's location and rotation and return AE's Position and Rotation/Orientation
+# this function will be called for every object for every frame
+def convert_pos_rot_matrix(matrix, width, height, aspect, x_rot_correction=False):
+
+ # get blender location for ob
+ b_loc_x, b_loc_y, b_loc_z = matrix.to_translation()
+ b_rot_x, b_rot_y, b_rot_z = matrix.to_euler()
+
+ # get blender rotation for ob
+ if x_rot_correction:
+ b_rot_x = b_rot_x / pi * 180.0 - 90.0
+ else:
+ b_rot_x = b_rot_x / pi * 180.0
+ b_rot_y = b_rot_y / pi * 180.0
+ b_rot_z = b_rot_z / pi * 180.0
+
+ # convert to AE Position and Rotation
+ # Axes in AE are different. AE's X is blender's X, AE's Y is negative Blender's Z, AE's Z is Blender's Y
+ x = (b_loc_x * 100.0) / aspect + width / 2.0 # calculate AE's X position
+ y = (-b_loc_z * 100.0) + (height / 2.0) # calculate AE's Y position
+ z = b_loc_y * 100.0 # calculate AE's Z position
+ rx = b_rot_x # calculate AE's X rotation. Will become AE's RotationX property
+ ry = -b_rot_z # calculate AE's Y rotation. Will become AE's OrientationY property
+ rz = b_rot_y # calculate AE's Z rotation. Will become AE's OrentationZ property
+ # Using AE's rotation combined with AE's orientation allows to compensate for different euler rotation order.
+
+ return x, y, z, rx, ry, rz
+
+
+def convert_pos_rot(obj, width, height, aspect, x_rot_correction=False):
+ matrix = obj.matrix_world.copy()
+ return convert_pos_rot_matrix(matrix, width, height, aspect, x_rot_correction)
+
+
+# get camera's lens and convert to AE's "zoom" value in pixels
+# this function will be called for every camera for every frame
+#
+#
+# AE's lens is defined by "zoom" in pixels. Zoom determines focal angle or focal length.
+# AE's camera's focal length is calculated basing on zoom value.
+#
+# Known values:
+# - sensor (blender's sensor is 32mm)
+# - lens (blender's lens in mm)
+# - width (witdh of the composition/scene in pixels)
+#
+# zoom can be calculated from simple proportions.
+#
+# |
+# / |
+# / |
+# / | w
+# s |\ / | i
+# e | \ / | d
+# n | \ / | t
+# s | / \ | h
+# o | / \ |
+# r |/ \ |
+# \ |
+# | | \ |
+# | | \ |
+# | | |
+# lens | zoom
+#
+# zoom/width = lens/sensor =>
+# zoom = lens/sensor*width = lens*width * (1/sensor)
+# sensor - sensor_width will be taken into account if version of blender supports it. If not - standard blender's 32mm will be caclulated.
+#
+#
+# above is true if square pixels are used. If not - aspect compensation is needed, so final formula is:
+# zoom = lens * width * (1/sensor) * aspect
+#
+def convert_lens(camera, width, aspect):
+ # wrap camera.data.sensor_width in 'try' to maintain compatibility with blender version not supporting camera.data.sensor_width
+ try:
+ sensor = camera.data.sensor_width # if camera.data.sensor_width is supported - it will be taken into account
+ except:
+ sensor = 32 # if version of blender doesn't yet support sensor_width - default blender's 32mm will be taken.
+ zoom = camera.data.lens * width * (1.0 / sensor) * aspect
+
+ return zoom
+
+
+# jsx script for AE creation
+def write_jsx_file(file, data, selection, export_bundles, comp_name, prefix):
+ from mathutils import Matrix
+
+ print("\n---------------------------\n- Export to After Effects -\n---------------------------")
+ #store the current frame to restore it at the enf of export
+ curframe = data['curframe']
+ #create array which will contain all keyframes values
+ js_data = {
+ 'times': '',
+ 'cameras': {},
+ 'objects': {},
+ }
+
+ # create camera structure
+ for i, cam in enumerate(selection['cameras']): # more than one camera can be selected
+ name_ae = selection['cams_names'][i]
+ js_data['cameras'][name_ae] = {
+ 'position': '',
+ 'pointOfInterest': '',
+ 'orientation': '',
+ 'rotationX': '',
+ 'zoom': '',
+ }
+
+ # create object structure
+ for i, obj in enumerate(selection['nulls']): # nulls representing blender's obs except cameras
+ name_ae = selection['nulls_names'][i]
+ js_data['objects'][name_ae] = {
+ 'position': '',
+ 'orientation': '',
+ 'rotationX': '',
+ }
+
+ # get all keyframes for each objects and store into dico
+ for frame in range(data['start'], data['end'] + 1):
+ print("working on frame: " + str(frame))
+ data['scn'].frame_set(frame)
+
+ #get time for this loop
+ js_data['times'] += '%f ,' % ((frame - data['start']) / data['fps'])
+
+ # keyframes for all cameras
+ for i, cam in enumerate(selection['cameras']):
+ #get cam name
+ name_ae = selection['cams_names'][i]
+ #convert cam position to AE space
+ ae_pos_rot = convert_pos_rot(cam, data['width'], data['height'], data['aspect'], x_rot_correction=True)
+ #convert Blender's cam zoom to AE's
+ zoom = convert_lens(cam, data['width'], data['aspect'])
+ #store all the value into dico
+ js_data['cameras'][name_ae]['position'] += '[%f,%f,%f],' % (ae_pos_rot[0], ae_pos_rot[1], ae_pos_rot[2])
+ js_data['cameras'][name_ae]['pointOfInterest'] += '[%f,%f,%f],' % (ae_pos_rot[0], ae_pos_rot[1], ae_pos_rot[2])
+ js_data['cameras'][name_ae]['orientation'] += '[%f,%f,%f],' % (0, ae_pos_rot[4], ae_pos_rot[5])
+ js_data['cameras'][name_ae]['rotationX'] += '%f ,' % (ae_pos_rot[3])
+ js_data['cameras'][name_ae]['zoom'] += '[%f],' % (zoom)
+
+ #keyframes for all nulls
+ for i, ob in enumerate(selection['nulls']):
+ #get object name
+ name_ae = selection['nulls_names'][i]
+ #convert ob position to AE space
+ ae_pos_rot = convert_pos_rot(ob, data['width'], data['height'], data['aspect'], x_rot_correction=False)
+ #store all datas into dico
+ js_data['objects'][name_ae]['position'] += '[%f,%f,%f],' % (ae_pos_rot[0], ae_pos_rot[1], ae_pos_rot[2])
+ js_data['objects'][name_ae]['orientation'] += '[%f,%f,%f],' % (0, ae_pos_rot[4], ae_pos_rot[5])
+ js_data['objects'][name_ae]['rotationX'] += '%f ,' % (ae_pos_rot[3])
+
+ # ---- write JSX file
+ jsx_file = open(file, 'w')
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list