diff --git a/io_export_after_effects.py b/io_export_after_effects.py index 871e098176dbc10fa6b577dd0703db1153a9002e..1c4942ad8e8f78e48fc556ea3aeea12fe3414155 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):