# ***** 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 LICENCE BLOCK ***** bl_info = { "name": "Turnaround Camera", "author": "Antonio Vazquez (antonioya)", "version": (0, 2, 4), "blender": (2, 68, 0), "location": "View3D > Toolshelf > Animation > Turnaround camera", "description": "Add a camera rotation around selected object.", "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Animation/TurnaroundCamera", "category": "Camera"} import bpy import math # ------------------------------------------------------ # Action class # ------------------------------------------------------ class RunAction(bpy.types.Operator): bl_idname = "object.rotate_around" bl_label = "Turnaround" bl_description = "Create camera rotation around selected object" # ------------------------------ # Execute # ------------------------------ def execute(self, context): # ---------------------- # Save old data # ---------------------- scene = context.scene selectobject = context.active_object camera = bpy.data.objects[bpy.context.scene.camera.name] savedcursor = bpy.context.scene.cursor_location.copy() # cursor position savedframe = scene.frame_current if scene.use_cursor is False: bpy.ops.view3d.snap_cursor_to_selected() # ------------------------- # Create empty and parent # ------------------------- bpy.ops.object.empty_add(type='PLAIN_AXES') myempty = bpy.data.objects[bpy.context.active_object.name] myempty.location = selectobject.location savedstate = myempty.matrix_world myempty.parent = selectobject myempty.name = 'MCH_Rotation_target' myempty.matrix_world = savedstate # ------------------------- # Parent camera to empty # ------------------------- savedstate = camera.matrix_world camera.parent = myempty camera.matrix_world = savedstate # ------------------------- # Now add revolutions # (make empty active object) # ------------------------- bpy.ops.object.select_all(False) myempty.select = True bpy.context.scene.objects.active = myempty # save current configuration savedinterpolation = context.user_preferences.edit.keyframe_new_interpolation_type # change interpolation mode context.user_preferences.edit.keyframe_new_interpolation_type = 'LINEAR' # create first frame myempty.rotation_euler = (0, 0, 0) myempty.empty_draw_size = 0.1 bpy.context.scene.frame_set(scene.frame_start) myempty.keyframe_insert(data_path='rotation_euler', frame=scene.frame_start) # Dolly zoom if scene.dolly_zoom != "0": bpy.data.cameras[camera.name].lens = scene.camera_from_lens bpy.data.cameras[camera.name].keyframe_insert('lens', frame=scene.frame_start) # Calculate rotation XYZ if scene.inverse_x: ix = -1 else: ix = 1 if scene.inverse_y: iy = -1 else: iy = 1 if scene.inverse_z: iz = -1 else: iz = 1 xrot = (math.pi * 2) * scene.camera_revol_x * ix yrot = (math.pi * 2) * scene.camera_revol_y * iy zrot = (math.pi * 2) * scene.camera_revol_z * iz # create middle frame if scene.back_forw is True: myempty.rotation_euler = (xrot, yrot, zrot) myempty.keyframe_insert(data_path='rotation_euler', frame=((scene.frame_end - scene.frame_start) / 2)) # reverse xrot *= -1 yrot *= -1 zrot = 0 # Dolly zoom if scene.dolly_zoom == "2": bpy.data.cameras[camera.name].lens = scene.camera_to_lens bpy.data.cameras[camera.name].keyframe_insert('lens', frame=((scene.frame_end - scene.frame_start) / 2)) # create last frame myempty.rotation_euler = (xrot, yrot, zrot) myempty.keyframe_insert(data_path='rotation_euler', frame=scene.frame_end) # Dolly zoom if scene.dolly_zoom != "0": if scene.dolly_zoom == "1": bpy.data.cameras[camera.name].lens = scene.camera_to_lens # final else: bpy.data.cameras[camera.name].lens = scene.camera_from_lens # back to init bpy.data.cameras[camera.name].keyframe_insert('lens', frame=scene.frame_end) # Track constraint if scene.track is True: bpy.context.scene.objects.active = camera bpy.ops.object.constraint_add(type='TRACK_TO') bpy.context.object.constraints[-1].track_axis = 'TRACK_NEGATIVE_Z' bpy.context.object.constraints[-1].up_axis = 'UP_Y' bpy.context.object.constraints[-1].target = bpy.data.objects[myempty.name] # back previous configuration context.user_preferences.edit.keyframe_new_interpolation_type = savedinterpolation bpy.context.scene.cursor_location = savedcursor # ------------------------- # Back to old selection # ------------------------- bpy.ops.object.select_all(False) selectobject.select = True bpy.context.scene.objects.active = selectobject bpy.context.scene.frame_set(savedframe) return {'FINISHED'} # ------------------------------------------------------ # UI Class # ------------------------------------------------------ class PanelUI(bpy.types.Panel): bl_label = "Turnaround Camera" bl_space_type = "VIEW_3D" bl_region_type = "TOOLS" bl_category = "Animation" # ------------------------------ # Draw UI # ------------------------------ def draw(self, context): layout = self.layout scene = context.scene try: bpy.context.scene.camera.name except AttributeError: row = layout.row(align=False) row.label("No defined camera for scene", icon="ERROR") return if context.active_object is not None: if context.active_object.type != 'CAMERA': buf = context.active_object.name row = layout.row(align=False) row.operator("object.rotate_around", icon='OUTLINER_DATA_CAMERA') row.label(buf, icon='MESH_DATA') row = layout.row() row.prop(scene, "use_cursor") row = layout.row(align=False) row.prop(scene, "camera") row = layout.row() row.prop(scene, "frame_start") row.prop(scene, "frame_end") row = layout.row() row.prop(scene, "camera_revol_x") row.prop(scene, "camera_revol_y") row.prop(scene, "camera_revol_z") row = layout.row() row.prop(scene, "inverse_x") row.prop(scene, "inverse_y") row.prop(scene, "inverse_z") row = layout.row() row.prop(scene, "back_forw") row = layout.row() row.prop(scene, "dolly_zoom") if scene.dolly_zoom != "0": row = layout.row() row.prop(scene, "camera_from_lens") row.prop(scene, "camera_to_lens") row = layout.row() row.prop(scene, "track") else: buf = "No valid object selected" layout.label(buf, icon='MESH_DATA') # ------------------------------------------------------ # Registration # ------------------------------------------------------ def register(): bpy.utils.register_class(RunAction) bpy.utils.register_class(PanelUI) # Define properties bpy.types.Scene.camera_revol_x = bpy.props.FloatProperty(name='X', min=0, max=25, default=0, precision=2, description='Number total of revolutions in X axis') bpy.types.Scene.camera_revol_y = bpy.props.FloatProperty(name='Y', min=0, max=25, default=0, precision=2, description='Number total of revolutions in Y axis') bpy.types.Scene.camera_revol_z = bpy.props.FloatProperty(name='Z', min=0, max=25, default=1, precision=2, description='Number total of revolutions in Z axis') bpy.types.Scene.inverse_x = bpy.props.BoolProperty(name="-X", description="Inverse rotation", default=False) bpy.types.Scene.inverse_y = bpy.props.BoolProperty(name="-Y", description="Inverse rotation", default=False) bpy.types.Scene.inverse_z = bpy.props.BoolProperty(name="-Z", description="Inverse rotation", default=False) bpy.types.Scene.use_cursor = bpy.props.BoolProperty(name="Use cursor position", description="Use cursor position instead of object origin", default=False) bpy.types.Scene.back_forw = bpy.props.BoolProperty(name="Back and forward", description="Create back and forward animation", default=False) bpy.types.Scene.dolly_zoom = bpy.props.EnumProperty(items=(('0', "None", ""), ('1', "Dolly zoom", ""), ('2', "Dolly zoom B/F", "")), name="Lens Effects", description="Create a camera lens movement") bpy.types.Scene.camera_from_lens = bpy.props.FloatProperty(name='From', min=1, max=500, default=35, precision=3, description='Start lens value') bpy.types.Scene.camera_to_lens = bpy.props.FloatProperty(name='To', min=1, max=500, default=35, precision=3, description='End lens value') bpy.types.Scene.track = bpy.props.BoolProperty(name="Create track constraint", description="Add a track constraint to the camera", default=False) def unregister(): bpy.utils.unregister_class(RunAction) bpy.utils.unregister_class(PanelUI) del bpy.types.Scene.camera_revol_x del bpy.types.Scene.camera_revol_y del bpy.types.Scene.camera_revol_z del bpy.types.Scene.inverse_x del bpy.types.Scene.inverse_y del bpy.types.Scene.inverse_z del bpy.types.Scene.use_cursor del bpy.types.Scene.back_forw del bpy.types.Scene.dolly_zoom del bpy.types.Scene.camera_from_lens del bpy.types.Scene.camera_to_lens del bpy.types.Scene.track if __name__ == "__main__": register()