From c0e51313be9ef559fc695db53b3de5240698aa51 Mon Sep 17 00:00:00 2001 From: Bartek Skorupa <bartekskorupa@bartekskorupa.com> Date: Sat, 10 Mar 2012 09:11:43 +0000 Subject: [PATCH] 1. Added export of Blender's lamps as After Effects lights. Type of Blender's lamp is added to name of After Effects light 2. Added option to export static scene. In this case not necessary to go through each frame and refresh context 3. Added several conditions to prevent from adding unnecessary keyframes in After Effects. Values of properties that don't changed are set once and no keyframes are added --- io_export_after_effects.py | 380 ++++++++++++++++++++++++++++--------- 1 file changed, 292 insertions(+), 88 deletions(-) diff --git a/io_export_after_effects.py b/io_export_after_effects.py index 871e09817..1c4942ad8 100644 --- a/io_export_after_effects.py +++ b/io_export_after_effects.py @@ -22,7 +22,7 @@ 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, 6, 1), + 'version': (0, 6, 2), 'blender': (2, 6, 2), 'location': 'File > Export > Adobe After Effects (.jsx)', "warning": "", @@ -112,8 +112,7 @@ def get_selected(context): solids.append([ob, convert_name(ob.name)]) elif ob.type == 'LAMP': - # not ready yet. Lamps will be exported as nulls. This is temporary - nulls.append([ob, convert_name(ob.name)]) + lights.append([ob, ob.data.type + convert_name(ob.name)]) # Type of lamp added to name else: nulls.append([ob, convert_name(ob.name)]) @@ -137,10 +136,13 @@ def is_plane(object): # 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("-", "_") @@ -151,18 +153,17 @@ def convert_name(name): # this function will be called for every object for every frame def convert_transform_matrix(matrix, width, height, aspect, x_rot_correction=False): - # get blender location for ob + # get blender transform data 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() b_scale_x, b_scale_y, b_scale_z = matrix.to_scale() - # 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 + # convert radians to degrees + 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 + if x_rot_correction: + b_rot_x -= 90.0 # 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 @@ -244,16 +245,16 @@ def convert_lens(camera, width, height, aspect): # jsx script for AE creation -def write_jsx_file(file, data, selection, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles, include_rotation, include_scale): +def write_jsx_file(file, data, selection, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles): print("\n---------------------------\n- Export to After Effects -\n---------------------------") - #store the current frame to restore it at the enf of export + # store the current frame to restore it at the end of export curframe = data['curframe'] - #create array which will contain all keyframes values + # create array which will contain all keyframes values js_data = { 'times': '', 'cameras': {}, - 'solids': {}, + 'solids': {}, # not ready yet 'lights': {}, 'nulls': {}, 'bundles_cam': {}, @@ -271,10 +272,17 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c active_cam_name = name_ae # store name to be used when creating keyframes for active cam. js_data['cameras'][name_ae] = { 'position': '', - 'pointOfInterest': '', + 'position_static': '', + 'position_anim': False, 'orientation': '', + 'orientation_static': '', + 'orientation_anim': False, 'rotationX': '', + 'rotationX_static': '', + 'rotationX_anim': False, 'zoom': '', + 'zoom_static': '', + 'zoom_anim': False, } # create camera structure for selected cameras @@ -284,10 +292,17 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c name_ae = selection['cameras'][i][1] js_data['cameras'][name_ae] = { 'position': '', - 'pointOfInterest': '', + 'position_static': '', + 'position_anim': False, 'orientation': '', + 'orientation_static': '', + 'orientation_anim': False, 'rotationX': '', + 'rotationX_static': '', + 'rotationX_anim': False, 'zoom': '', + 'zoom_static': '', + 'zoom_anim': False, } ''' # create structure for solids. Not ready yet. Temporarily not active @@ -299,17 +314,36 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c 'rotationX': '', 'scale': '', } - - # create structure for lights. Not ready yet. Temporarily not active - for i, obj in enumerate(selection['lights']): - name_ae = selection['lights'][i][1] - js_data['nulls'][name_ae] = { - 'position': '', - 'orientation': '', - 'rotationX': '', - 'scale': '', - } ''' + # create structure for lights + for i, obj in enumerate(selection['lights']): + if include_selected_objects: + name_ae = selection['lights'][i][1] + js_data['lights'][name_ae] = { + 'type': selection['lights'][i][0].data.type, + 'energy': '', + 'energy_static': '', + 'energy_anim': False, + 'cone_angle': '', + 'cone_angle_static': '', + 'cone_angle_anim': False, + 'cone_feather': '', + 'cone_feather_static': '', + 'cone_feather_anim': False, + 'color': '', + 'color_static': '', + 'color_anim': False, + 'position': '', + 'position_static': '', + 'position_anim': False, + 'orientation': '', + 'orientation_static': '', + 'orientation_anim': False, + 'rotationX': '', + 'rotationX_static': '', + 'rotationX_anim': False, + } + # create structure for nulls for i, obj in enumerate(selection['nulls']): # nulls representing blender's obs except cameras, lamps and solids @@ -317,14 +351,22 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c name_ae = selection['nulls'][i][1] js_data['nulls'][name_ae] = { 'position': '', + 'position_static': '', + 'position_anim': False, 'orientation': '', + 'orientation_static': '', + 'orientation_anim': False, 'rotationX': '', + 'rotationX_static': '', + 'rotationX_anim': False, 'scale': '', + 'scale_static': '', + 'scale_anim': False, } # create structure for cam bundles including positions (cam bundles don't move) if include_cam_bundles: - # go through each selected Camera and active cameras + # go through each selected camera and active cameras selected_cams = [] active_cams = [] if include_active_cam: @@ -340,7 +382,7 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c for constraint in cam.constraints: # does the camera have a Camera Solver constraint if constraint.type == 'CAMERA_SOLVER': - # Which movie clip does it use ? + # Which movie clip does it use if constraint.use_active_clip: clip = data['scn'].active_clip else: @@ -362,7 +404,11 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c js_data['bundles_cam'][name_ae]['position'] += '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2]) # get all keyframes for each object and store in dico - for frame in range(data['start'], data['end'] + 1): + if include_animation: + end = data['end'] + 1 + else: + end = data['start'] + 1 + for frame in range(data['start'], end): print("working on frame: " + str(frame)) data['scn'].frame_set(frame) @@ -383,11 +429,29 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c # convert Blender's lens to AE's zoom in pixels zoom = convert_lens(active_cam, data['width'], data['height'], data['aspect']) # store all values in dico - js_data['cameras'][name_ae]['position'] += '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2]) - js_data['cameras'][name_ae]['pointOfInterest'] += '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2]) - js_data['cameras'][name_ae]['orientation'] += '[%f,%f,%f],' % (0, ae_transform[4], ae_transform[5]) - js_data['cameras'][name_ae]['rotationX'] += '%f ,' % (ae_transform[3]) - js_data['cameras'][name_ae]['zoom'] += '[%f],' % (zoom) + position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2]) + orientation = '[%f,%f,%f],' % (0, ae_transform[4], ae_transform[5]) + rotationX = '%f ,' % (ae_transform[3]) + zoom = '%f,' % (zoom) + js_data['cameras'][name_ae]['position'] += position + js_data['cameras'][name_ae]['orientation'] += orientation + js_data['cameras'][name_ae]['rotationX'] += rotationX + js_data['cameras'][name_ae]['zoom'] += zoom + # Check if properties change values compared to previous frame + # If property don't change through out the whole animation - keyframes won't be added + if frame != data['start']: + if position != js_data['cameras'][name_ae]['position_static']: + js_data['cameras'][name_ae]['position_anim'] = True + if orientation != js_data['cameras'][name_ae]['orientation_static']: + js_data['cameras'][name_ae]['orientation_anim'] = True + if rotationX != js_data['cameras'][name_ae]['rotationX_static']: + js_data['cameras'][name_ae]['rotationX_anim'] = True + if zoom != js_data['cameras'][name_ae]['zoom_static']: + js_data['cameras'][name_ae]['zoom_anim'] = True + js_data['cameras'][name_ae]['position_static'] = position + js_data['cameras'][name_ae]['orientation_static'] = orientation + js_data['cameras'][name_ae]['rotationX_static'] = rotationX + js_data['cameras'][name_ae]['zoom_static'] = zoom # keyframes for selected cameras if include_selected_cams: @@ -400,26 +464,90 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c # convert Blender's lens to AE's zoom in pixels zoom = convert_lens(cam[0], data['width'], data['height'], data['aspect']) # store all values in dico - js_data['cameras'][name_ae]['position'] += '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2]) - js_data['cameras'][name_ae]['pointOfInterest'] += '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2]) - js_data['cameras'][name_ae]['orientation'] += '[%f,%f,%f],' % (0, ae_transform[4], ae_transform[5]) - js_data['cameras'][name_ae]['rotationX'] += '%f ,' % (ae_transform[3]) - js_data['cameras'][name_ae]['zoom'] += '[%f],' % (zoom) - + position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2]) + orientation = '[%f,%f,%f],' % (0, ae_transform[4], ae_transform[5]) + rotationX = '%f ,' % (ae_transform[3]) + zoom = '%f,' % (zoom) + js_data['cameras'][name_ae]['position'] += position + js_data['cameras'][name_ae]['orientation'] += orientation + js_data['cameras'][name_ae]['rotationX'] += rotationX + js_data['cameras'][name_ae]['zoom'] += zoom + # Check if properties change values compared to previous frame + # If property don't change through out the whole animation - keyframes won't be added + if frame != data['start']: + if position != js_data['cameras'][name_ae]['position_static']: + js_data['cameras'][name_ae]['position_anim'] = True + if orientation != js_data['cameras'][name_ae]['orientation_static']: + js_data['cameras'][name_ae]['orientation_anim'] = True + if rotationX != js_data['cameras'][name_ae]['rotationX_static']: + js_data['cameras'][name_ae]['rotationX_anim'] = True + if zoom != js_data['cameras'][name_ae]['zoom_static']: + js_data['cameras'][name_ae]['zoom_anim'] = True + js_data['cameras'][name_ae]['position_static'] = position + js_data['cameras'][name_ae]['orientation_static'] = orientation + js_data['cameras'][name_ae]['rotationX_static'] = rotationX + js_data['cameras'][name_ae]['zoom_static'] = zoom + ''' # keyframes for all solids. Not ready yet. Temporarily not active for i, ob in enumerate(selection['solids']): #get object name name_ae = selection['solids'][i][1] #convert ob position to AE space - - - # keyframes for all lights. Not ready yet. Temporarily not active - for i, ob in enumerate(selection['lights']): - #get object name - name_ae = selection['lights'][i][1] - #convert ob position to AE space ''' + + # keyframes for all lights. + if include_selected_objects: + for i, ob in enumerate(selection['lights']): + #get object name + name_ae = selection['lights'][i][1] + type = selection['lights'][i][0].data.type + # convert ob transform properties to AE space + ae_transform = convert_transform_matrix(ob[0].matrix_world.copy(), data['width'], data['height'], data['aspect'], x_rot_correction=True) + color = ob[0].data.color + # store all values in dico + position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2]) + orientation = '[%f,%f,%f],' % (0, ae_transform[4], ae_transform[5]) + rotationX = '%f ,' % (ae_transform[3]) + energy = '[%f],' % (ob[0].data.energy * 100.0) + color = '[%f,%f,%f],' % (color[0], color[1], color[2]) + js_data['lights'][name_ae]['position'] += position + js_data['lights'][name_ae]['orientation'] += orientation + js_data['lights'][name_ae]['rotationX'] += rotationX + js_data['lights'][name_ae]['energy'] += energy + js_data['lights'][name_ae]['color'] += color + # Check if properties change values compared to previous frame + # If property don't change through out the whole animation - keyframes won't be added + if frame != data['start']: + if position != js_data['lights'][name_ae]['position_static']: + js_data['lights'][name_ae]['position_anim'] = True + if orientation != js_data['lights'][name_ae]['orientation_static']: + js_data['lights'][name_ae]['orientation_anim'] = True + if rotationX != js_data['lights'][name_ae]['rotationX_static']: + js_data['lights'][name_ae]['rotationX_anim'] = True + if energy != js_data['lights'][name_ae]['energy_static']: + js_data['lights'][name_ae]['energy_anim'] = True + if color != js_data['lights'][name_ae]['color_static']: + js_data['lights'][name_ae]['color_anim'] = True + js_data['lights'][name_ae]['position_static'] = position + js_data['lights'][name_ae]['orientation_static'] = orientation + js_data['lights'][name_ae]['rotationX_static'] = rotationX + js_data['lights'][name_ae]['energy_static'] = energy + js_data['lights'][name_ae]['color_static'] = color + if type == 'SPOT': + cone_angle = '[%f],' % (ob[0].data.spot_size / pi * 180.0) + cone_feather = '[%f],' % (ob[0].data.spot_blend * 100.0) + js_data['lights'][name_ae]['cone_angle'] += cone_angle + js_data['lights'][name_ae]['cone_feather'] += cone_feather + # Check if properties change values compared to previous frame + # If property don't change through out the whole animation - keyframes won't be added + if frame != data['start']: + if cone_angle != js_data['lights'][name_ae]['cone_angle_static']: + js_data['lights'][name_ae]['cone_angle_anim'] = True + if orientation != js_data['lights'][name_ae]['cone_feather_static']: + js_data['lights'][name_ae]['cone_feather_anim'] = True + js_data['lights'][name_ae]['cone_angle_static'] = cone_angle + js_data['lights'][name_ae]['cone_feather_static'] = cone_feather # keyframes for all nulls if include_selected_objects: @@ -429,23 +557,42 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c # convert ob transform properties to AE space ae_transform = convert_transform_matrix(ob[0].matrix_world.copy(), data['width'], data['height'], data['aspect'], x_rot_correction=True) # store all values in dico - js_data['nulls'][name_ae]['position'] += '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2]) - if include_rotation: - js_data['nulls'][name_ae]['orientation'] += '[%f,%f,%f],' % (0, ae_transform[4], ae_transform[5]) - js_data['nulls'][name_ae]['rotationX'] += '%f ,' % (ae_transform[3]) - if include_scale: - js_data['nulls'][name_ae]['scale'] += '[%f,%f,%f],' % (ae_transform[6], ae_transform[7], ae_transform[8]) + position = '[%f,%f,%f],' % (ae_transform[0], ae_transform[1], ae_transform[2]) + orientation = '[%f,%f,%f],' % (0, ae_transform[4], ae_transform[5]) + rotationX = '%f ,' % (ae_transform[3]) + scale = '[%f,%f,%f],' % (ae_transform[6], ae_transform[7], ae_transform[8]) + js_data['nulls'][name_ae]['position'] += position + js_data['nulls'][name_ae]['orientation'] += orientation + js_data['nulls'][name_ae]['rotationX'] += rotationX + js_data['nulls'][name_ae]['scale'] += scale + # Check if properties change values compared to previous frame + # If property don't change through out the whole animation - keyframes won't be added + if frame != data['start']: + if position != js_data['nulls'][name_ae]['position_static']: + js_data['nulls'][name_ae]['position_anim'] = True + if orientation != js_data['nulls'][name_ae]['orientation_static']: + js_data['nulls'][name_ae]['orientation_anim'] = True + if rotationX != js_data['nulls'][name_ae]['rotationX_static']: + js_data['nulls'][name_ae]['rotationX_anim'] = True + if scale != js_data['nulls'][name_ae]['scale_static']: + js_data['nulls'][name_ae]['scale_anim'] = True + js_data['nulls'][name_ae]['position_static'] = position + js_data['nulls'][name_ae]['orientation_static'] = orientation + js_data['nulls'][name_ae]['rotationX_static'] = rotationX + js_data['nulls'][name_ae]['scale_static'] = scale # keyframes for all object bundles. Not ready yet. # # # + # ---- write JSX file jsx_file = open(file, 'w') # make the jsx executable in After Effects (enable double click on jsx) jsx_file.write('#target AfterEffects\n\n') + # Script's header jsx_file.write('/**************************************\n') jsx_file.write('Scene : %s\n' % data['scn'].name) jsx_file.write('Resolution : %i x %i\n' % (data['width'], data['height'])) @@ -459,7 +606,7 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c jsx_file.write("function compFromBlender(){\n") # create new comp jsx_file.write('\nvar compName = prompt("Blender Comp\'s Name \\nEnter Name of newly created Composition","BlendComp","Composition\'s Name");\n') - jsx_file.write('if (compName){') + jsx_file.write('if (compName){') # Continue only if comp name is given. If not - terminate jsx_file.write('\nvar newComp = app.project.items.addComp(compName, %i, %i, %f, %f, %i);' % (data['width'], data['height'], data['aspect'], data['duration'], data['fps'])) jsx_file.write('\nnewComp.displayStartTime = %f;\n\n\n' % ((data['start'] + 1.0) / data['fps'])) @@ -482,36 +629,100 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c jsx_file.write('var %s = newComp.layers.addNull();\n' % (name_ae)) jsx_file.write('%s.threeDLayer = true;\n' % name_ae) jsx_file.write('%s.source.name = "%s";\n' % (name_ae, name_ae)) - jsx_file.write('%s.property("position").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['nulls'][obj]['position'])) - if include_rotation: + # Set values of properties, add kyeframes only where needed + jsx_file.write('%s.property("rotationY").setValue(0);\n' % name_ae) + jsx_file.write('%s.property("rotationZ").setValue(0);\n' % name_ae) + if include_animation and js_data['nulls'][name_ae]['position_anim']: + jsx_file.write('%s.property("position").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['nulls'][obj]['position'])) + else: + jsx_file.write('%s.property("position").setValue(%s);\n' % (name_ae, js_data['nulls'][obj]['position_static'])) + if include_animation and js_data['nulls'][name_ae]['orientation_anim']: jsx_file.write('%s.property("orientation").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['nulls'][obj]['orientation'])) + else: + jsx_file.write('%s.property("orientation").setValue(%s);\n' % (name_ae, js_data['nulls'][obj]['orientation_static'])) + if include_animation and js_data['nulls'][name_ae]['rotationX_anim']: jsx_file.write('%s.property("rotationX").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['nulls'][obj]['rotationX'])) - jsx_file.write('%s.property("rotationY").setValue(0);\n' % name_ae) - jsx_file.write('%s.property("rotationZ").setValue(0);\n\n\n' % name_ae) - if include_scale: + else: + jsx_file.write('%s.property("rotationX").setValue(%s);\n' % (name_ae, js_data['nulls'][obj]['rotationX_static'])) + if include_animation and js_data['nulls'][name_ae]['scale_anim']: jsx_file.write('%s.property("scale").setValuesAtTimes([%s],[%s]);\n\n\n' % (name_ae, js_data['times'], js_data['nulls'][obj]['scale'])) - + else: + jsx_file.write('%s.property("scale").setValue(%s);\n\n\n' % (name_ae, js_data['nulls'][obj]['scale_static'])) # create solids (not ready yet) - # create lights (not ready yet) + # create lights + jsx_file.write('// ************** LIGHTS **************\n\n\n') + for i, obj in enumerate(js_data['lights']): + name_ae = obj + jsx_file.write('var %s = newComp.layers.addLight("%s", [0.0, 0.0]);\n' % (name_ae, name_ae)) + jsx_file.write('%s.autoOrient = AutoOrientType.NO_AUTO_ORIENT;\n' % name_ae) + # Set values of properties, add kyeframes only where needed + jsx_file.write('%s.property("rotationY").setValue(0);\n' % name_ae) + jsx_file.write('%s.property("rotationZ").setValue(0);\n' % name_ae) + if include_animation and js_data['lights'][name_ae]['position_anim']: + jsx_file.write('%s.property("position").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['position'])) + else: + jsx_file.write('%s.property("position").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['position_static'])) + if include_animation and js_data['lights'][name_ae]['orientation_anim']: + jsx_file.write('%s.property("orientation").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['orientation'])) + else: + jsx_file.write('%s.property("orientation").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['orientation_static'])) + if include_animation and js_data['lights'][name_ae]['rotationX_anim']: + jsx_file.write('%s.property("rotationX").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['rotationX'])) + else: + jsx_file.write('%s.property("rotationX").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['rotationX_static'])) + if include_animation and js_data['lights'][name_ae]['energy_anim']: + jsx_file.write('%s.property("intensity").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['energy'])) + else: + jsx_file.write('%s.property("intensity").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['energy_static'])) + if include_animation and js_data['lights'][name_ae]['color_anim']: + jsx_file.write('%s.property("Color").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['color'])) + else: + jsx_file.write('%s.property("Color").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['color_static'])) + if js_data['lights'][obj]['type'] == 'SPOT': + if include_animation and js_data['lights'][name_ae]['cone_angle_anim']: + jsx_file.write('%s.property("Cone Angle").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['cone_angle'])) + else: + jsx_file.write('%s.property("Cone Angle").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['cone_angle_static'])) + if include_animation and js_data['lights'][name_ae]['cone_feather_anim']: + jsx_file.write('%s.property("Cone Feather").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['lights'][obj]['cone_feather'])) + else: + jsx_file.write('%s.property("Cone Feather").setValue(%s);\n' % (name_ae, js_data['lights'][obj]['cone_feather_static'])) + jsx_file.write('\n\n') # create cameras jsx_file.write('// ************** CAMERAS **************\n\n\n') for i, cam in enumerate(js_data['cameras']): # more than one camera can be selected name_ae = cam jsx_file.write('var %s = newComp.layers.addCamera("%s",[0,0]);\n' % (name_ae, name_ae)) - jsx_file.write('%s.property("position").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['position'])) - jsx_file.write('%s.property("pointOfInterest").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['pointOfInterest'])) - jsx_file.write('%s.property("orientation").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['orientation'])) - jsx_file.write('%s.property("rotationX").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['rotationX'])) + jsx_file.write('%s.autoOrient = AutoOrientType.NO_AUTO_ORIENT;\n' % name_ae) + # Set values of properties, add kyeframes only where needed jsx_file.write('%s.property("rotationY").setValue(0);\n' % name_ae) jsx_file.write('%s.property("rotationZ").setValue(0);\n' % name_ae) - jsx_file.write('%s.property("zoom").setValuesAtTimes([%s],[%s]);\n\n\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['zoom'])) + if include_animation and js_data['cameras'][name_ae]['position_anim']: + jsx_file.write('%s.property("position").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['position'])) + else: + jsx_file.write('%s.property("position").setValue(%s);\n' % (name_ae, js_data['cameras'][cam]['position_static'])) + if include_animation and js_data['cameras'][name_ae]['orientation_anim']: + jsx_file.write('%s.property("orientation").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['orientation'])) + else: + jsx_file.write('%s.property("orientation").setValue(%s);\n' % (name_ae, js_data['cameras'][cam]['orientation_static'])) + if include_animation and js_data['cameras'][name_ae]['rotationX_anim']: + jsx_file.write('%s.property("rotationX").setValuesAtTimes([%s],[%s]);\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['rotationX'])) + else: + jsx_file.write('%s.property("rotationX").setValue(%s);\n' % (name_ae, js_data['cameras'][cam]['rotationX_static'])) + if include_animation and js_data['cameras'][name_ae]['zoom_anim']: + jsx_file.write('%s.property("zoom").setValuesAtTimes([%s],[%s]);\n\n\n' % (name_ae, js_data['times'], js_data['cameras'][cam]['zoom'])) + else: + jsx_file.write('%s.property("zoom").setValue(%s);\n\n\n' % (name_ae, js_data['cameras'][cam]['zoom_static'])) + # Exit import if no comp name given jsx_file.write('\n}else{alert ("Exit Import Blender animation data \\nNo Comp\'s name has been chosen","EXIT")};') + # Close function jsx_file.write("}\n\n\n") + # Execute function. Wrap in "undo group" for easy undoing import process jsx_file.write('app.beginUndoGroup("Import Blender animation data");\n') - jsx_file.write('compFromBlender();\n') + jsx_file.write('compFromBlender();\n') # execute function jsx_file.write('app.endUndoGroup();\n\n\n') jsx_file.close() @@ -521,11 +732,10 @@ def write_jsx_file(file, data, selection, include_active_cam, include_selected_c # DO IT ########################################## - -def main(file, context, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles, include_rotation, include_scale): +def main(file, context, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles): data = get_comp_data(context) selection = get_selected(context) - write_jsx_file(file, data, selection, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles, include_rotation, include_scale) + write_jsx_file(file, data, selection, include_animation, include_active_cam, include_selected_cams, include_selected_objects, include_cam_bundles) print ("\nExport to After Effects Completed") return {'FINISHED'} @@ -544,29 +754,24 @@ class ExportJsx(bpy.types.Operator, ExportHelper): filename_ext = ".jsx" filter_glob = StringProperty(default="*.jsx", options={'HIDDEN'}) + include_animation = BoolProperty( + name="Animation", + description="Animate Exported Cameras and Objects", + default=True, + ) include_active_cam = BoolProperty( name="Active Camera", - description="Include Active Camera Data", + description="Include Active Camera", default=True, ) include_selected_cams = BoolProperty( name="Selected Cameras", - description="Add Selected Cameras Data", + description="Add Selected Cameras", default=True, ) include_selected_objects = BoolProperty( name="Selected Objects", - description="Add Selected Objects Data", - default=True, - ) - include_rotation = BoolProperty( - name="Rotation", - description="Include rotation of selected objects", - default=True, - ) - include_scale = BoolProperty( - name="Scale", - description="Include scale of selected object", + description="Export Selected Objects", default=True, ) include_cam_bundles = BoolProperty( @@ -584,13 +789,12 @@ class ExportJsx(bpy.types.Operator, ExportHelper): layout = self.layout box = layout.box() + box.label('Animation:') + box.prop(self, 'include_animation') box.label('Include Cameras and Objects:') box.prop(self, 'include_active_cam') box.prop(self, 'include_selected_cams') box.prop(self, 'include_selected_objects') - box.label("Include Objects' Properties:") - box.prop(self, 'include_rotation') - box.prop(self, 'include_scale') box.label("Include Tracking Data:") box.prop(self, 'include_cam_bundles') # box.prop(self, 'include_ob_bundles') @@ -604,7 +808,7 @@ class ExportJsx(bpy.types.Operator, ExportHelper): return ok def execute(self, context): - return main(self.filepath, context, self.include_active_cam, self.include_selected_cams, self.include_selected_objects, self.include_cam_bundles, self.include_rotation, self.include_scale) + return main(self.filepath, context, self.include_animation, self.include_active_cam, self.include_selected_cams, self.include_selected_objects, self.include_cam_bundles) def menu_func(self, context): -- GitLab