1# ##### BEGIN GPL LICENSE BLOCK ##### 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU General Public License 5# as published by the Free Software Foundation; either version 2 6# of the License, or (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software Foundation, 15# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16# 17# ##### END GPL LICENSE BLOCK ##### 18 19# <pep8 compliant> 20 21bl_info = { 22 "name": "Export Camera Animation", 23 "author": "Campbell Barton", 24 "version": (0, 1), 25 "blender": (2, 80, 0), 26 "location": "File > Export > Cameras & Markers (.py)", 27 "description": "Export Cameras & Markers (.py)", 28 "warning": "", 29 "doc_url": "{BLENDER_MANUAL_URL}/addons/import_export/anim_camera.html", 30 "support": 'OFFICIAL', 31 "category": "Import-Export", 32} 33 34 35import bpy 36 37 38def write_cameras(context, filepath, frame_start, frame_end, only_selected=False): 39 40 data_attrs = ( 41 'lens', 42 'shift_x', 43 'shift_y', 44 'dof_distance', 45 'clip_start', 46 'clip_end', 47 'display_size', 48 ) 49 50 obj_attrs = ( 51 'hide_render', 52 ) 53 54 fw = open(filepath, 'w').write 55 56 scene = bpy.context.scene 57 58 cameras = [] 59 60 for obj in scene.objects: 61 if only_selected and not obj.select_get(): 62 continue 63 if obj.type != 'CAMERA': 64 continue 65 66 cameras.append((obj, obj.data)) 67 68 frame_range = range(frame_start, frame_end + 1) 69 70 fw("import bpy\n" 71 "cameras = {}\n" 72 "scene = bpy.context.scene\n" 73 "frame = scene.frame_current - 1\n" 74 "\n") 75 76 for obj, obj_data in cameras: 77 fw("data = bpy.data.cameras.new(%r)\n" % obj.name) 78 for attr in data_attrs: 79 fw("data.%s = %s\n" % (attr, repr(getattr(obj_data, attr)))) 80 81 fw("obj = bpy.data.objects.new(%r, data)\n" % obj.name) 82 83 for attr in obj_attrs: 84 fw("obj.%s = %s\n" % (attr, repr(getattr(obj, attr)))) 85 86 fw("bpy.context.collection.objects.link(obj)\n") 87 fw("cameras[%r] = obj\n" % obj.name) 88 fw("\n") 89 90 for f in frame_range: 91 scene.frame_set(f) 92 fw("# new frame\n") 93 fw("scene.frame_set(%d + frame)\n" % f) 94 95 for obj, obj_data in cameras: 96 fw("obj = cameras['%s']\n" % obj.name) 97 98 matrix = obj.matrix_world.copy() 99 fw("obj.location = %r, %r, %r\n" % matrix.to_translation()[:]) 100 fw("obj.scale = %r, %r, %r\n" % matrix.to_scale()[:]) 101 fw("obj.rotation_euler = %r, %r, %r\n" % matrix.to_euler()[:]) 102 103 fw("obj.keyframe_insert('location')\n") 104 fw("obj.keyframe_insert('scale')\n") 105 fw("obj.keyframe_insert('rotation_euler')\n") 106 107 # only key the angle 108 fw("data = obj.data\n") 109 fw("data.lens = %s\n" % obj_data.lens) 110 fw("data.keyframe_insert('lens')\n") 111 112 fw("\n") 113 114 # now markers 115 fw("# markers\n") 116 for marker in scene.timeline_markers: 117 fw("marker = scene.timeline_markers.new(%r)\n" % marker.name) 118 fw("marker.frame = %d + frame\n" % marker.frame) 119 120 # will fail if the cameras not selected 121 if marker.camera: 122 fw("marker.camera = cameras.get(%r)\n" % marker.camera.name) 123 fw("\n") 124 125 126from bpy.props import StringProperty, IntProperty, BoolProperty 127from bpy_extras.io_utils import ExportHelper 128 129 130class CameraExporter(bpy.types.Operator, ExportHelper): 131 """Save a python script which re-creates cameras and markers elsewhere""" 132 bl_idname = "export_animation.cameras" 133 bl_label = "Export Camera & Markers" 134 135 filename_ext = ".py" 136 filter_glob: StringProperty(default="*.py", options={'HIDDEN'}) 137 138 frame_start: IntProperty(name="Start Frame", 139 description="Start frame for export", 140 default=1, min=1, max=300000) 141 frame_end: IntProperty(name="End Frame", 142 description="End frame for export", 143 default=250, min=1, max=300000) 144 only_selected: BoolProperty(name="Only Selected", 145 default=True) 146 147 def execute(self, context): 148 write_cameras(context, self.filepath, self.frame_start, self.frame_end, self.only_selected) 149 return {'FINISHED'} 150 151 def invoke(self, context, event): 152 self.frame_start = context.scene.frame_start 153 self.frame_end = context.scene.frame_end 154 155 wm = context.window_manager 156 wm.fileselect_add(self) 157 return {'RUNNING_MODAL'} 158 159 160def menu_export(self, context): 161 import os 162 default_path = os.path.splitext(bpy.data.filepath)[0] + ".py" 163 self.layout.operator(CameraExporter.bl_idname, text="Cameras & Markers (.py)").filepath = default_path 164 165 166def register(): 167 bpy.utils.register_class(CameraExporter) 168 bpy.types.TOPBAR_MT_file_export.append(menu_export) 169 170 171def unregister(): 172 bpy.utils.unregister_class(CameraExporter) 173 bpy.types.TOPBAR_MT_file_export.remove(menu_export) 174 175 176if __name__ == "__main__": 177 register() 178