Skip to content

Instantly share code, notes, and snippets.

@tin2tin
Last active June 12, 2019 16:38
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tin2tin/4c4d3179cd0b48f85dc81216b18c4e20 to your computer and use it in GitHub Desktop.
Save tin2tin/4c4d3179cd0b48f85dc81216b18c4e20 to your computer and use it in GitHub Desktop.
Sequencer Preview in 3D Viewport sets up the Video Editor to control the camera selection in the 3D View on frame updates. Which makes it possible to edit the clip timings on the same screen and at the same time as editing cameras and everything else in the 3D Viewport.
# Sequencer Preview in 3D Viewport
#
# Version: 0.1
# About:
# Sequencer Preview in 3D Viewport sets up the Video Editor to
# control the camera selection in the 3D View on frame updates.
# Which makes it possible to edit the clip timings on the same
# screen and at the same time as editing cameras and everything
# else in the 3D Viewport.
# Run the script:
# 1. Run the script in the text-editor.
# 2. Find the functions in the bottom of the right-hand-side
# properties menu of the 3D View.
# Functions:
# "Add 3D Camera to Sequencer" will add a scene strip
# in the Sequencer with the current camera starting from the
# current frame.
# "Link Sequencer to 3D Viewport" will switch cameras in the 3D
# View acording to the timings of the scene strips in the sequencer.
# NB.:
# - Jitter in the Sequencer playback means hit "Refresh Sequencer" button.
# - Only scene strips are supported for showing in 3D Viewport in the sequencer.
# - And only cameras from the current scene can be shown in 3d View.
# (This is a limitation of Blender. There is only one scene pr.
# Screen)
bl_info = {
"name": "Sequencer Preview in 3D Viewport",
"author": "Tintwotin",
"version": (0, 2),
"blender": (2, 80, 0),
"location": "Sequencer Sidebar - Misc Tab",
"description": "Preview Sequencer Scene Strip edits in the 3D Viewport",
"warning": "",
"wiki_url": "https://github.com/tin2tin/PrevizCameraTools/",
"category": "Sequencer"}
import bpy
import mathutils
from mathutils import Matrix
from bpy.utils import register_class, unregister_class
from bpy.props import BoolProperty, EnumProperty
from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
from operator import attrgetter
#Set 3D View to Global. Cameras can't be switched in local.
# Def currently not working
def set3dViewGlobal():
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
space = area.spaces[0]
if space.local_view: #check if using local view
for region in area.regions:
if region.type == 'WINDOW':
override = {'area': area, 'region': region} #override context
bpy.ops.view3d.localview(override) #switch to global view
# ------------------------------------------------------------------------
# Swich 3D Viewport-Cameras from Sequencer
# ------------------------------------------------------------------------
oldStrip = ""
def SwichCameraAtFrameChange(*pArgs):
global oldStrip
scn = bpy.context.scene
seq = scn.sequence_editor.sequences
seq=sorted(seq, key=attrgetter('channel', 'frame_final_start'))
cf = scn.frame_current
for i in seq:
try:
if i.type == "SCENE" and i.name!=oldStrip:
if (i.frame_final_start <= cf
and i.frame_final_end > cf
and i.scene.name==bpy.context.scene.name #Only if current scene in scene-strip
and not i.mute):
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
bpy.context.scene.camera = bpy.data.objects[i.scene_camera.name] # Select camera as view
area.spaces.active.region_3d.view_perspective = 'CAMERA' # Use camera view
oldStrip = i.name
break
except AttributeError:
pass
# ------------------------------------------------------------------------
# Un/link 3D Cameras from/to Sequencer at frame change
# ------------------------------------------------------------------------
def attachAsHandler():
bpy.app.handlers.frame_change_pre.append(SwichCameraAtFrameChange)
def detachAsHandler():
bpy.app.handlers.frame_change_pre.clear()
# ------------------------------------------------------------------------
# Make 3D Preview Panel
# ------------------------------------------------------------------------
class PropertyGroup(bpy.types.PropertyGroup):
LinkSeqTo3DView: bpy.props.BoolProperty(
name = ' Link Sequencer to 3D View',
description = 'Sequencer swiches cameras in 3D Viewport')
class THREEDPREVIEW_PT_MakerPanel(bpy.types.Panel) :
"""Creates a Panel in the Object properties window"""
bl_label = "Preview in 3D Viewport"
bl_space_type = "SEQUENCE_EDITOR"
bl_region_type = "UI"
def draw_header(self, context):
layout = self.layout
layout.label(text="", icon="VIEW3D")
def draw(self, context) :
layout = self.layout
TheCol = layout.column(align = (False))
scene = context.scene
view = context.space_data
manager = context.scene.asset_manager
wm = context.window_manager
manager = context.scene.asset_manager
TheCol.prop(manager, "LinkSeqTo3DView", text="Link Sequencer to 3D Viewport", toggle=True, icon="LINKED")
TheCol.operator("view3d.add_scene_strip", text = "Add Camera to Sequencer", icon="CAMERA_DATA")
TheCol.separator()
TheCol.operator("sequencer.convert_cameras", text = "Convert Camera Markes to Strips", icon="MARKER")
# check if bool property is enabled
if (context.scene.asset_manager.LinkSeqTo3DView == True):
SwichCameraAtFrameChange()
attachAsHandler()
else:
detachAsHandler()
# ------------------------------------------------------------------------
# Add Camera as Scene Strip in Sequencer
# ------------------------------------------------------------------------
class THREEDPREVIEW_PT_AddSceneStrip(bpy.types.Operator) :
"""Adds current camera scene strip with to Sequencer"""
bl_idname = "view3d.add_scene_strip"
bl_label = "Camera"
bl_options = {'REGISTER',"UNDO"}
def invoke(self, context, event) :
if not bpy.context.scene.sequence_editor:
bpy.context.scene.sequence_editor_create()
scn = bpy.context.scene
seq = scn.sequence_editor
cf = scn.frame_current
addSceneIn = cf
addSceneOut = scn.frame_end
addSceneChannel = 2
addSceneTlStart = cf
newScene=seq.sequences.new_scene('Scene', bpy.context.scene, addSceneChannel, addSceneTlStart)
seq.sequences_all[newScene.name].scene_camera = bpy.data.objects[bpy.context.scene.camera.name]
seq.sequences_all[newScene.name].animation_offset_start = addSceneIn
seq.sequences_all[newScene.name].frame_final_end = addSceneOut
seq.sequences_all[newScene.name].frame_start = cf
return {"FINISHED"}
# ------------------------------------------------------------------------
# Add Camera Markers as Scene Strips in Sequencer
# ------------------------------------------------------------------------
class SEQUENCE_PT_convert_cameras(bpy.types.Operator):
"""Converts 'Bind Camera To Markers' to Scene Strips"""
bl_label = "Camera Markers"
bl_idname = "sequencer.convert_cameras"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene=bpy.context.scene
if not bpy.context.scene.sequence_editor: #create sequence, if missing
bpy.context.scene.sequence_editor_create()
marker_camera=[]
marker_frame=[]
marker_name=[]
cam_marker=[]
cnt=0
mi=bpy.context.scene.timeline_markers.items()
for marker in scene.timeline_markers: #find the cameras and their frame
if marker.camera:
cam_marker.insert(cnt,[marker.frame, marker.camera.name])#mi[cnt][0]])
cnt+=1
if len(cam_marker)==0: # cancel if no cameras
return {'CANCELLED'}
cam_marker=sorted(cam_marker,key=lambda mark: mark[0]) # Sort the markers after frame nr.
#add cameras to sequencer
cnt=0 # counter
for i in cam_marker:
cf = cam_marker[cnt][0]
addSceneIn = cf
if cnt<len(cam_marker)-1: # find out frame
addSceneOut = cam_marker[cnt+1][0]
else:
addSceneOut = addSceneIn +151 #last clip extented 30 fps*5 frames + an ekstra frame for the hack.
bpy.context.scene.frame_end=addSceneIn +150 # extent preview area or add scene strip may fail
addSceneChannel = 1 # attempt to add in this channel - if full, strips will be moved upwards
addSceneTlStart = cf
# Hack: adding a scene strip will make a hard cut one frame before preview area end.
bpy.context.scene.frame_end=bpy.context.scene.frame_end+1
# add scene strip in current scene at in and out frame numbers
newScene=bpy.context.scene.sequence_editor.sequences.new_scene(cam_marker[cnt][1], bpy.context.scene, addSceneChannel, addSceneTlStart)
newScene.scene_camera = bpy.data.objects[cam_marker[cnt][1]]
newScene=bpy.context.scene.sequence_editor.sequences_all[newScene.name]
newScene.animation_offset_start = addSceneIn
newScene.frame_final_end = addSceneOut
newScene.frame_start = cf
cnt+=1
# Hack: remove the extra frame again of the preview area.
bpy.context.scene.frame_end=bpy.context.scene.frame_end-1
return {'FINISHED'}
def menu_append(self, context):
self.layout.operator(THREEDPREVIEW_PT_AddSceneStrip.bl_idname)
classes = (
THREEDPREVIEW_PT_AddSceneStrip,
THREEDPREVIEW_PT_MakerPanel,
PropertyGroup,
SEQUENCE_PT_convert_cameras,
)
register, unregister = bpy.utils.register_classes_factory(classes)
def register():
for i in classes:
register_class(i)
bpy.types.Scene.asset_manager = bpy.props.PointerProperty(type=PropertyGroup)
bpy.types.SEQUENCER_MT_add.append(menu_append)
def unregister():
for i in classes:
unregister_class(i)
#del bpy.types.Scene.LinkSeqTo3DView error
bpy.types.SEQUENCER_MT_add.remove(menu_append)
if __name__ == "__main__" :
register()
#unregister()
@AndreaMonzini
Copy link

AndreaMonzini commented May 25, 2019

Hello!
With Blender 2.80.72. and a simple Cube scene the FPS are ~ 3-4 in EEVEE ( GNU/Linux, AMD® Ryzen 1700 @ 3.7 and RX 580 ).
Blender crashed when i tried to render in EEVEE.
I see just a typo for "Camera Markes" instead of "Camera Markers" in the last button GUI.
Is it like your "Previz Camera Tools" but for the 2.80?
Thank you.

@Draise14
Copy link

Love this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment