[Bf-extensions-cvs] [6f6c3374] master: io_export_after_effects: moved to contrib: T63750
meta-androcto
noreply at git.blender.org
Fri May 24 03:35:37 CEST 2019
Commit: 6f6c33743030d62c1d6ce81c0c0bbb19775e2847
Author: meta-androcto
Date: Fri May 24 11:35:08 2019 +1000
Branches: master
https://developer.blender.org/rBAC6f6c33743030d62c1d6ce81c0c0bbb19775e2847
io_export_after_effects: moved to contrib: T63750
===================================================================
A io_export_after_effects.py
===================================================================
diff --git a/io_export_after_effects.py b/io_export_after_effects.py
new file mode 100644
index 00000000..c0afe51f
--- /dev/null
+++ b/io_export_after_effects.py
@@ -0,0 +1,779 @@
+# ##### 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 2
+# 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, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+bl_info = {
+ "name": "Export: Adobe After Effects (.jsx)",
+ "description": "Export cameras, selected objects & camera solution "
+ "3D Markers to Adobe After Effects CS3 and above",
+ "author": "Bartek Skorupa",
+ "version": (0, 65),
+ "blender": (2, 79, 0),
+ "location": "File > Export > Adobe After Effects (.jsx)",
+ "warning": "",
+ "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
+ "Scripts/Import-Export/Adobe_After_Effects",
+ "category": "Import-Export",
+}
+
+
+import bpy
+import datetime
+from math import degrees, floor
+from mathutils import Matrix
+
+
+# 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
+ start = scene.frame_start
+ end = scene.frame_end
+ active_cam_frames = get_active_cam_for_each_frame(scene, start, end)
+ fps = floor(scene.render.fps / (scene.render.fps_base) * 1000.0) / 1000.0
+
+ return {
+ 'scn': scene,
+ 'width': scene.render.resolution_x,
+ 'height': scene.render.resolution_y,
+ 'aspect': aspect,
+ 'fps': fps,
+ 'start': start,
+ 'end': end,
+ 'duration': (end - start + 1.0) / fps,
+ 'active_cam_frames': active_cam_frames,
+ 'curframe': scene.frame_current,
+ }
+
+
+# create list of active camera for each frame in case active camera is set by markers
+def get_active_cam_for_each_frame(scene, start, end):
+ active_cam_frames = []
+ sorted_markers = []
+ markers = scene.timeline_markers
+ if markers:
+ for marker in markers:
+ if marker.camera:
+ sorted_markers.append([marker.frame, marker])
+ sorted_markers = sorted(sorted_markers)
+
+ if sorted_markers:
+ for frame in range(start, end + 1):
+ for m, marker in enumerate(sorted_markers):
+ if marker[0] > frame:
+ if m != 0:
+ active_cam_frames.append(sorted_markers[m - 1][1].camera)
+ else:
+ active_cam_frames.append(marker[1].camera)
+ break
+ elif m == len(sorted_markers) - 1:
+ active_cam_frames.append(marker[1].camera)
+ if not active_cam_frames:
+ if scene.camera:
+ # in this case active_cam_frames array will have legth of 1. This will indicate that there is only one active cam in all frames
+ active_cam_frames.append(scene.camera)
+
+ return(active_cam_frames)
+
+
+# create manageable list of selected objects
+def get_selected(context):
+ cameras = [] # list of selected cameras
+ solids = [] # list of all selected meshes that can be exported as AE's solids
+ lights = [] # list of all selected lamps that can be exported as AE's lights
+ nulls = [] # list of all selected objects except cameras (will be used to create nulls in AE)
+ obs = context.selected_objects
+
+ for ob in obs:
+ if ob.type == 'CAMERA':
+ cameras.append([ob, convert_name(ob.name)])
+
+ elif is_plane(ob):
+ # not ready yet. is_plane(object) returns False in all cases. This is temporary
+ solids.append([ob, convert_name(ob.name)])
+
+ elif ob.type == 'LIGHT':
+ lights.append([ob, ob.data.type + convert_name(ob.name)]) # Type of lamp added to name
+
+ else:
+ nulls.append([ob, convert_name(ob.name)])
+
+ selection = {
+ 'cameras': cameras,
+ 'solids': solids,
+ 'lights': lights,
+ 'nulls': nulls,
+ }
+
+ return selection
+
+
+# check if object is plane and can be exported as AE's solid
+def is_plane(object):
+ # work in progress. Not ready yet
+ return False
+
+
+# convert names of objects to avoid errors in AE.
+def convert_name(name):
+ name = "_" + name
+ '''
+ # Digits are not allowed at beginning of AE vars names.
+ # This section is commented, as "_" is added at beginning of names anyway.
+ # Placeholder for this name modification is left so that it's not ignored if needed
+ if name[0].isdigit():
+ name = "_" + name
+ '''
+ name = bpy.path.clean_name(name)
+ name = name.replace("-", "_")
+
+ return name
+
+
+# get object's blender's location rotation and scale and return AE's Position, Rotation/Orientation and scale
+# this function will be called for every object for every frame
+def convert_transform_matrix(matrix, width, height, aspect, x_rot_correction=False, ae_size=100.0):
+
+ # get blender transform data for ob
+ b_loc = matrix.to_translation()
+ b_rot = matrix.to_euler('ZYX') # ZYX euler matches AE's orientation and allows to use x_rot_correction
+ b_scale = matrix.to_scale()
+
+ # convert to AE Position Rotation and Scale
+ # 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 * ae_size) / aspect + width / 2.0 # calculate AE's X position
+ y = (-b_loc.z * ae_size) + (height / 2.0) # calculate AE's Y position
+ z = b_loc.y * ae_size # calculate AE's Z position
+ # Convert rotations to match AE's orientation.
+ rx = degrees(b_rot.x) # if not x_rot_correction - AE's X orientation = blender's X rotation if 'ZYX' euler.
+ ry = -degrees(b_rot.y) # AE's Y orientation is negative blender's Y rotation if 'ZYX' euler
+ rz = -degrees(b_rot.z) # AE's Z orientation is negative blender's Z rotation if 'ZYX' euler
+ if x_rot_correction:
+ rx -= 90.0 # In blender - ob of zero rotation lay on floor. In AE layer of zero orientation "stands"
+ # Convert scale to AE scale
+ sx = b_scale.x * 100.0 # scale of 1.0 is 100% in AE
+ sy = b_scale.z * 100.0 # scale of 1.0 is 100% in AE
+ sz = b_scale.y * 100.0 # scale of 1.0 is 100% in AE
+
+ return x, y, z, rx, ry, rz, sx, sy, sz
+
+# 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.
+#
+# ZOOM VALUE CALCULATIONS:
+#
+# Given values:
+# - sensor width (camera.data.sensor_width)
+# - sensor height (camera.data.sensor_height)
+# - sensor fit (camera.data.sensor_fit)
+# - lens (blender's lens in mm)
+# - width (width of the composition/scene in pixels)
+# - height (height of the composition/scene in pixels)
+# - PAR (pixel aspect ratio)
+#
+# Calculations are made using sensor's size and scene/comp dimension (width or height).
+# If camera.sensor_fit is set to 'AUTO' or 'HORIZONTAL' - sensor = camera.data.sensor_width, dimension = width.
+# If camera.sensor_fit is set to 'VERTICAL' - sensor = camera.data.sensor_height, dimension = height
+#
+# zoom can be calculated using simple proportions.
+#
+# |
+# / |
+# / |
+# / | d
+# s |\ / | i
+# e | \ / | m
+# n | \ / | e
+# s | / \ | n
+# o | / \ | s
+# r |/ \ | i
+# \ | o
+# | | \ | n
+# | | \ |
+# | | |
+# lens | zoom
+#
+# zoom / dimension = lens / sensor =>
+# zoom = lens * dimension / sensor
+#
+# above is true if square pixels are used. If not - aspect compensation is needed, so final formula is:
+# zoom = lens * dimension / sensor * aspect
+
+
+def convert_lens(camera, width, height, aspect):
+ if camera.data.sensor_fit == 'VERTICAL':
+ sensor = camera.data.sensor_height
+ dimension = height
+ else:
+ sensor = camera.data.sensor_width
+ dimension = width
+
+ zoom = camera.data.lens * dimension / sensor * aspect
+
+ return zoom
+
+# convert object bundle's matrix. Not ready yet. Temporarily not active
+#def get_ob_bundle_matrix_world(cam_matrix_world, bundle_matrix):
+# matrix = cam_matrix_basis
+# return matrix
+
+
+# jsx script for AE creation
+def write_jsx_file(file, data, selection, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles, ae_size):
+
+ print("\n---------------------------\n- Export to After Effects -\n---------------------------")
+ # store the current frame to restore it at the end of export
+ curframe = data['curframe']
+ # create array which will contain all keyframes values
+ js_data = {
+ 'times': '',
+ 'cameras': {},
+ 'solids': {}, # not ready yet
+ 'lights': {},
+ 'nulls': {},
+ 'bundles_cam': {},
+ 'bundles_ob': {}, # not ready yet
+ }
+
+ # create structure for active camera/cameras
+ active_cam_name = ''
+ if include_active_cam and data['active_cam_frames'] != []:
+ # check if more that one active cam exist (true
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list