Skip to content
Snippets Groups Projects
camera_turnaround.py 11.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • # ***** 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()