# ##### 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 LICENSE BLOCK ##### bl_info = { "name": "Export Fusion Composition", "author": "Michael Vorberg, Christian Brinkmann", "version": (0, 6, 0), "blender": (2, 80, 0), "location": "File > Export > Fusion Comp (.comp)", "description": "Export Cameras and PointClouds of motion tracking into a Fusion Composition(.comp)", "warning": "", "category": "Import-Export", } import bpy from bpy_extras.io_utils import ExportHelper, axis_conversion import math import mathutils import os def write_cameras(context, filepath, frame_start, frame_end, only_selected=False): data_attrs = ( 'lens', 'shift_x', 'shift_y', 'dof_distance', 'clip_start', 'clip_end', 'draw_size', ) scene = context.scene bl_display_colorspace = scene.display_settings.display_device #print (bl_display_colorspace) fu_display_colorspace = "" try: if bl_display_colorspace == "sRGB": fu_display_colorspace = "sRGB" elif bl_display_colorspace == "Rec709": fu_display_colorspace = "Rec709Display" elif bl_display_colorspace == "XYZ": fu_display_colorspace = "DCI" elif bl_display_colorspace == "None": fu_display_colorspace = "No Change" elif bl_display_colorspace == "Filmic": fu_display_colorspace = "" elif bl_display_colorspace == "sRGB / BT.709": fu_display_colorspace = "sRGB" except: fu_display_colorspace = "" rot_x_neg90 = mathutils.Matrix.Rotation(-math.pi/2.0, 4, 'X') obj_attrs = ( 'hide_render', ) with open(filepath, "w") as fw: cameras = [] for obj in scene.objects: if only_selected and not obj.select_get(): continue if obj.type != 'CAMERA': continue cameras.append((obj, obj.data)) if len(cameras) == 0: raise RuntimeError("no camera selected but \"only selected\" activated") # write some settings for the composition frame_range = range(frame_start, frame_end + 1) fw.write("Composition {\n" " CurrentTime = 0,\n") fw.write(" RenderRange = { %d, %d, },\n"%(frame_start, frame_end)) fw.write(" GlobalRange = { %d, %d, },\n"%(frame_start, frame_end)) fw.write("""Prefs = { Comp = { Views = { Right = { Viewer = { EnableLUTs = true, LUTPlugin = "GamutViewLUT", LUTSelected = "Gamut View LUT", }, ViewLUT = { { Tools = ordered() { GamutViewLUT1 = ViewOperator { CtrlWZoom = false, NameSet = true, Inputs = {""") fw.write(" OutputSpace = Input { Value = FuID { \"%s\", }, },"%fu_display_colorspace) fw.write(""" }, }, }, ID = "GamutViewLUT", }, SelectedPlugin = "GamutViewLUT", SelectedName = "Gamut View LUT", }, }, Left = { Viewer = { EnableLUTs = true, LUTPlugin = "GamutViewLUT", LUTSelected = "Gamut View LUT", }, ViewLUT = { { Tools = ordered() { GamutViewLUT = ViewOperator { CtrlWZoom = false, NameSet = true, Inputs = {""") fw.write(" OutputSpace = Input { Value = FuID { \"%s\", }, },"%fu_display_colorspace) fw.write(""" }, }, }, ID = "GamutViewLUT", }, SelectedPlugin = "GamutViewLUT", SelectedName = "Gamut View LUT", }, }, View1 = { }, }, FrameFormat = { Name = "Multimedia", """) fw.write("Width = %d,\n"%(scene.render.resolution_x)) fw.write("Height = %d,\n"%(scene.render.resolution_y)) fw.write("Rate = %d,\n"%(scene.render.fps)) fw.write("""PerFeet = 1, GuideRatio = 1.77777777777778, }, }, Views = { Right = { SideB = { PrevCtrlInactiveColor = 65280, PickW = 1, PickH = 1, PrevCtrlActiveColor = 255, Viewer = { EnableLUTs = false, LUTPlugin = "FusionViewLUT", FitMarginY = 0, FitMarginX = 0, FitMarginType = 0, FarZ = -1000, NearZ = 0, }, }, Viewer = { EnableLUTs = true, LUTPlugin = "GamutViewLUT", LUTSelected = "Gamut View LUT", }, ViewLUT = { { Tools = ordered() { GamutViewLUT1 = ViewOperator { NameSet = true, Inputs = {""") fw.write(" OutputSpace = Input { Value = FuID { \"%s\", }, },"%fu_display_colorspace) fw.write(""" }, CtrlWZoom = false, }, }, ID = "GamutViewLUT", }, Recent = { SelectedPlugin = "GamutViewLUT", FusionViewLUT = { Tools = ordered() { FusionViewLUT = ViewLUTOp { NameSet = true, Inputs = { }, }, }, }, SelectedName = "Gamut View LUT", }, SelectedName = "Gamut View LUT", SelectedPlugin = "GamutViewLUT", }, }, Left = { SideB = { PrevCtrlInactiveColor = 65280, PickW = 1, PickH = 1, PrevCtrlActiveColor = 255, Viewer = { EnableLUTs = false, LUTPlugin = "FusionViewLUT", FitMarginY = 0, FitMarginX = 0, FitMarginType = 0, FarZ = -1000, NearZ = 0, }, }, Viewer = { EnableLUTs = true, LUTPlugin = "GamutViewLUT", LUTSelected = "Gamut View LUT", }, ViewLUT = { { Tools = ordered() { GamutViewLUT = ViewOperator { NameSet = true, Inputs = {""") fw.write(" OutputSpace = Input { Value = FuID { \"%s\", }, },"%fu_display_colorspace) fw.write(""" }, CtrlWZoom = false, }, }, ID = "GamutViewLUT", }, SelectedPlugin = "GamutViewLUT", SelectedName = "Gamut View LUT", }, }, View1 = { PrevCtrlInactiveColor = 0, PickW = 1, PickH = 1, PrevCtrlActiveColor = 0, SideB = { PrevCtrlInactiveColor = 65280, PickW = 1, PickH = 1, PrevCtrlActiveColor = 255, Viewer = { EnableLUTs = false, LUTPlugin = "FusionViewLUT", FitMarginY = 0, FitMarginX = 0, FitMarginType = 0, FarZ = -1000, NearZ = 0, }, }, }, }, }, """) # starting with the actual nodes fw.write("Tools = {\n") # look if we have a clip in the scene and create a loader node for it try: if bpy.data.movieclips[0]: fw.write("""Loader1 = Loader { Clips = { Clip { ID = "Clip1",\n""") clip_filepath = os.path.normpath(bpy.data.movieclips[0].filepath) clip_filepath_four_slashes = clip_filepath.replace("\\", "\\\\") fw.write("Filename = \" %s \",\n"%(clip_filepath_four_slashes)) fw.write("StartFrame = %d,\n"%(frame_start)) fw.write("Length = %d,\n"%(frame_end)) fw.write("LengthSetManually = true,\n") fw.write("TrimIn = %d,\n"%(frame_start-1)) fw.write("TrimOut = %d,\n"%(frame_end-1)) fw.write("""ExtendFirst = 0, ExtendLast = 0, Loop = 1, AspectMode = 0, Depth = 0, TimeCode = 0,""") fw.write("GlobalStart = %d,\n"%(frame_start)) fw.write("GlobalEnd = %d,\n"%(frame_end)) fw.write("""}, }, ViewInfo = OperatorInfo { Pos = { 300, 0, }, }, CtrlWZoom = false, }, Gamut1 = GamutConvert { Inputs = { SourceSpace = Input { Value = FuID { "sRGB", }, }, Input = Input { SourceOp = "Loader1", Source = "Output", }, }, ViewInfo = OperatorInfo { Pos = { 300, 100, }, }, },""") except: print("No clip found for Loader") # create Camera3D nodes try: for obj, obj_data in cameras: fw.write(" Camera3D_%s = Camera3D {\n" %obj_data.name.replace(".", "_").replace(".", "_")) fw.write(" CtrlWZoom = false,\n" " Inputs = {\n" " [\"PerspNearClip\"] = Input {\n" " SourceOp = \"Camera3D_%s_PerspNearClip\",\n" %obj_data.name.replace(".", "_")) fw.write(" Source = \"Value\",\n" " },\n" " [\"PerspFarClip\"] = Input {\n" " SourceOp = \"Camera3D_%s_PerspFarClip\",\n" %obj_data.name.replace(".", "_")) fw.write(" Source = \"Value\",\n" " },\n" " [\"FLength\"] = Input {\n" " SourceOp = \"Camera3D_%s_LensFlength\",\n" %obj_data.name.replace(".", "_")) fw.write(" Source = \"Value\",\n" " },\n" " [\"PlaneOfFocus\"] = Input {\n" " SourceOp = \"Camera3D_%s_PlaneOfFocus\",\n" %obj_data.name.replace(".", "_")) fw.write(" Source = \"Value\",\n" " },\n" " [\"Transform3DOp.Translate.X\"] = Input {\n" " SourceOp = \"Camera3D_%s_XOffset\",\n" %obj_data.name.replace(".", "_")) fw.write(" Source = \"Value\",\n" " },\n" " [\"Transform3DOp.Translate.Y\"] = Input {\n" " SourceOp = \"Camera3D_%s_YOffset\",\n" %obj_data.name.replace(".", "_")) fw.write(" Source = \"Value\",\n" " },\n" " [\"Transform3DOp.Translate.Z\"] = Input {\n" " SourceOp = \"Camera3D_%s_ZOffset\",\n" %obj_data.name.replace(".", "_")) fw.write(" Source = \"Value\",\n") fw.write(" },\n" " [\"Transform3DOp.Rotate.X\"] = Input {\n" " SourceOp = \"Camera3D_%s_XRotation\",\n"%obj_data.name.replace(".", "_")) fw.write(" Source = \"Value\",\n") fw.write(" },\n" " [\"Transform3DOp.Rotate.Y\"] = Input {\n" " SourceOp = \"Camera3D_%s_YRotation\",\n" %obj_data.name.replace(".", "_")) fw.write(" Source = \"Value\",\n") fw.write(" },\n" " [\"Transform3DOp.Rotate.Z\"] = Input {\n" " SourceOp = \"Camera3D_%s_ZRotation\",\n" %obj_data.name.replace(".", "_")) fw.write(" Source = \"Value\",\n") fw.write(" },\n") fw.write(" [\"Stereo.Mode\"] = Input { Value = FuID { \"Mono\", }, },\n" " FilmBack = Input { Value = 1, },\n" " FilmGate = Input { Value = FuID { \"User\", }, },\n") fw.write(" LensShiftX = Input { Value = %r, },\n" %(-obj_data.shift_x)) fw.write(" LensShiftY = Input { Value = %r, },\n" %(-obj_data.shift_y*(scene.render.resolution_x/scene.render.resolution_y))) ap_w = float(obj_data.sensor_width) / 25.4 fw.write(" ApertureW = Input { Value = %s, },\n" %str(ap_w)) ap_h = ap_w/(scene.render.resolution_x/scene.render.resolution_y) fw.write(" ApertureH = Input { Value = %s, },\n" %str(ap_h)) if obj_data.sensor_fit == "HORIZONTAL": fw.write(" AovType = Input { Value = 1, },\n") if obj_data.sensor_fit == "VERTICAL": fw.write(" AovType = Input { Value = 0, },\n") fw.write(''' [\"SurfacePlaneInputs.ObjectID.ObjectID\"] = Input { Value = 1, },\n [\"MtlStdInputs.MaterialID\"] = Input { Value = 1, },\n },\n ViewInfo = OperatorInfo { Pos = { 0, 100, }, }, },\n''' ) fw.write(" Camera3D_%s_XOffset = BezierSpline {\n" %obj_data.name.replace(".", "_")) fw.write(''' NameSet = true,\n KeyFrames = {\n''') # X Translation for f in frame_range: scene.frame_set(f) matrix = obj.matrix_world.copy() fw.write(" [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, matrix.to_translation()[0])) fw.write(" },\n" "},\n") # Y Translation (Fusion Y) fw.write(" Camera3D_%s_YOffset = BezierSpline {\n" %obj_data.name.replace(".", "_")) fw.write(" NameSet = true,\n" " KeyFrames = {\n") for f in frame_range: scene.frame_set(f) matrix = obj.matrix_world.copy() fw.write(" [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, matrix.to_translation()[2])) fw.write(" },\n" "},\n") # Z Translation (Fusion Z) fw.write(" Camera3D_%s_ZOffset = BezierSpline {\n" %obj_data.name.replace(".", "_")) fw.write(" NameSet = true,\n" " KeyFrames = {\n") for f in frame_range: scene.frame_set(f) matrix = obj.matrix_world.copy() fw.write(" [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, -matrix.to_translation()[1])) fw.write(" },\n" "},\n") # X Rotation (Fusion X) fw.write(" Camera3D_%s_XRotation = BezierSpline {\n" %obj_data.name.replace(".", "_")) fw.write(" NameSet = true,\n" " KeyFrames = {\n") for f in frame_range: scene.frame_set(f) matrix_org = obj.matrix_world.copy() matrix = rot_x_neg90 * matrix_org fw.write(" [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, (math.degrees(matrix.to_euler()[0])))) fw.write(" },\n" "},\n") # Y Rotation (Fusion Y) fw.write(" Camera3D_%s_YRotation = BezierSpline {\n" %obj_data.name.replace(".", "_")) fw.write(" NameSet = true,\n" " KeyFrames = {\n") for f in frame_range: scene.frame_set(f) matrix_org = obj.matrix_world.copy() matrix = rot_x_neg90 * matrix_org fw.write(" [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, math.degrees(matrix.to_euler()[1]))) fw.write(" },\n" "},\n") # Z Rotation (Fusion Z) fw.write(" Camera3D_%s_ZRotation = BezierSpline {\n" %obj_data.name.replace(".", "_")) fw.write(" NameSet = true,\n" " KeyFrames = {\n") for f in frame_range: scene.frame_set(f) matrix_org = obj.matrix_world.copy() matrix = rot_x_neg90 * matrix_org fw.write(" [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, math.degrees(matrix.to_euler()[2]))) fw.write(" },\n" "},\n") fw.write(" Camera3D_%s_LensFlength = BezierSpline {\n" %obj_data.name.replace(".", "_")) fw.write(" NameSet = true,\n" " KeyFrames = {\n") for f in frame_range: scene.frame_set(f) fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, obj_data.lens)) fw.write(" },\n" "},\n") fw.write(" Camera3D_%s_PlaneOfFocus = BezierSpline {\n" %obj_data.name.replace(".", "_")) fw.write(" NameSet = true,\n" " KeyFrames = {\n") for f in frame_range: scene.frame_set(f) fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, obj_data.dof_distance)) fw.write(" },\n" "},\n") fw.write(" Camera3D_%s_PerspNearClip = BezierSpline {\n" %obj_data.name.replace(".", "_")) fw.write(" NameSet = true,\n" " KeyFrames = {\n") for f in frame_range: scene.frame_set(f) fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, obj_data.clip_start)) fw.write(" },\n" "},\n") fw.write(" Camera3D_%s_PerspFarClip = BezierSpline {\n" %obj_data.name.replace(".", "_")) fw.write(''' NameSet = true,\n KeyFrames = {\n''') for f in frame_range: scene.frame_set(f) fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, obj_data.clip_end)) fw.write(''' },\n },\n''') obj.select_set(False) except: print("No camera found/selected") # write pointcloud3D node # look if we have a clip in the scene try: if bpy.data.movieclips[0]: fw.write(''' PointCloud3D1 = PointCloud3D {\n CtrlWZoom = false,\n ViewInfo = OperatorInfo { Pos = { 150, 0, }, },\n Positions = {\n Version = 0,\n ''') curr_clip = bpy.data.movieclips[0] zeroPosition = [0, 0, 0] sceneCamera = bpy.data.objects['Camera'] track_list = [] for track in curr_clip.tracking.tracks: if track.has_bundle is False: continue track_list.append(track) for track in track_list: track_name = track.name bpy.ops.object.add(type='EMPTY',location = [0, 0, 0]) current_obj = context.active_object bpy.ops.object.constraint_add(type="FOLLOW_TRACK") context.object.constraints["Follow Track"].use_3d_position = True context.object.constraints["Follow Track"].object = "Camera" context.object.constraints["Follow Track"].track = track_name context.object.constraints["Follow Track"].camera = sceneCamera current_obj_data = bpy.data.objects[current_obj.name] current_obj_data.name = track_name print ("created object: ", current_obj_data.name) i = 0 for track in track_list: track_name = track.name current_obj = context.active_object current_obj_data = bpy.data.objects[track_name] obj_name_matrix = current_obj_data.matrix_world.copy() fw.write( "[%d] = { %r, %r, %r, \"%s\", \"\", },\n" % ( i, obj_name_matrix.to_translation()[0], obj_name_matrix.to_translation()[2], -obj_name_matrix.to_translation()[1], track_name ) ) i += 1 current_obj_data.select_set(True) # delete all helper tracks bpy.ops.object.delete(use_global=False) # close pointcloud3D and create Merge3D fw.write(''' },\n },\n Merge3D1 = Merge3D { Inputs = { SceneInput1 = Input {''') try: if not obj_data.name: fw.write("SourceOp = \"Camera3D_%s\",\n" % obj_data.name.replace(".", "_").replace(".", "_")) else: fw.write("SourceOp = \"\",\n") except: raise RuntimeError("no camera selected") fw.write('''Source = \"Output\", }, SceneInput2 = Input { SourceOp = \"PointCloud3D1\", Source = \"Output\", }, }, ViewInfo = OperatorInfo { Pos = { 151, 100, }, }, },''') except: print("No clip found") try: if bpy.data.movieclips[0]: #create2d trackers print ("trying 2d tracks") curr_clip = bpy.data.movieclips[0] track_list = [] for track in curr_clip.tracking.tracks: if track.has_bundle is False: continue track_list.append(track) fw.write(""" Tracker1 = Tracker { Trackers = { """) for track in track_list: track_name = track.name.replace(".", "_") track_name_orig = track.name fw.write("""{ PatternTime = 1, PatternX = 0.392840626111704, PatternY = 0.699857685009488, },""") fw.write("""}, CtrlWZoom = false, Inputs = {TrackerList = Input { Value = 1, },""") i = 0 for track in track_list: track_name = track.name.replace(".", "_") track_name_orig = track.name i += 1 fw.write("Name%d = Input { Value = \"%s\", }," %(i, track_name)) fw.write("PatternCenter%d = Input { Value = { %r, %r, }, },"% ( i, bpy.data.movieclips[0].tracking.tracks[track_name_orig].markers[0].co.x, bpy.data.movieclips[0].tracking.tracks[track_name_orig].markers[0].co.y) ) fw.write("PatternWidth%d = Input { Value = 0.0154571326929918, },"%i) fw.write("PatternHeight%d = Input { Value = 0.020841239721695, },"%i) fw.write("SearchWidth%d = Input { Value = 0.0574350764852365, },"%i) fw.write("SearchHeight%d = Input { Value = 0.0714421252371915, }," %i) fw.write("TrackedCenter%d = Input {" %i) fw.write("SourceOp = \"Tracker1%sXYPath\"," %track_name) fw.write("""Source = "Value", }, """) fw.write("""},\n ViewInfo = OperatorInfo { Pos = { 500, 0, }, }, },""") for track in track_list: track_name = track.name.replace(".", "_") track_name_orig = track.name print ("creating animation for 2d tracker: ", track_name) fw.write("Tracker1%sXYPath = XYPath {" %track_name) fw.write("""ShowKeyPoints = false, DrawMode = "ModifyOnly", CtrlWZoom = false, NameSet = true, Inputs = { X = Input {""") fw.write("SourceOp = \"XYPath_%sX\"," %track_name) fw.write("""Source = "Value", }, Y = Input {""") fw.write("SourceOp = \"XYPath_%sY\"," %track_name) fw.write("""Source = "Value", }, }, }, """) fw.write("XYPath_%sX = BezierSpline {" %track_name) fw.write("""SplineColor = { Red = 255, Green = 0, Blue = 0, }, NameSet = true, KeyFrames = { """) for f in frame_range: marker_at_frame = bpy.data.movieclips[0].tracking.tracks[track_name_orig].markers.find_frame(f) if not marker_at_frame: continue fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, marker_at_frame.co.x)) fw.write(""" },\n },\n""") fw.write("XYPath_%sY = BezierSpline {" %track_name) fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, }, NameSet = true, KeyFrames = { """) for f in frame_range: marker_at_frame = bpy.data.movieclips[0].tracking.tracks[track_name_orig].markers.find_frame(f) if not marker_at_frame: continue fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, marker_at_frame.co.y)) fw.write(""" },\n },\n""") #create lens distortion node fw.write("""LensDistort1 = LensDistort { CtrlWZoom = false, Inputs = { LensDistortionModel = Input { Value = 1, }, Model = Input { Value = FuID { "PFTrack", }, },\n""") fw.write("[\"PFTrack.LowOrderDistortion\"] = Input { Value = %r, },\n" %-bpy.data.movieclips[0].tracking.camera.k1) fw.write("[\"PFTrack.HighOrderDistortion\"] = Input { Value = %r, },\n" %-bpy.data.movieclips[0].tracking.camera.k2) fw.write("[\"PFTrack.LensCenterX\"] = Input { Value = %r, },\n" % (bpy.data.movieclips[0].tracking.camera.principal[0]/bpy.data.movieclips[0].size[0])) fw.write("[\"PFTrack.LensCenterY\"] = Input { Value = %r, },\n" %(bpy.data.movieclips[0].tracking.camera.principal[1]/bpy.data.movieclips[0].size[1])) fw.write("""}, ViewInfo = OperatorInfo { Pos = { 700, 0, }, }, }, """) except: print("No clip found") try: if bpy.data.movieclips[0]: curr_clip = bpy.data.movieclips[0] plane_track_list = [] for plane_track in curr_clip.tracking.plane_tracks: plane_track_list.append(plane_track) if len(plane_track_list)>0: for i,track in enumerate(plane_track_list): track_name = track.name.replace(".", "_") track_name_orig = track.name fw.write("CornerPositioner%d = CornerPositioner {" %i) fw.write('''Inputs = { TopLeft = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack1XYPath\"," %i) fw.write('''Source = "Value", }, TopRight = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack2XYPath\"," %i) fw.write('''Source = "Value", }, BottomLeft = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack3XYPath\"," %i) fw.write('''Source = "Value", }, BottomRight = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack4XYPath\"," %i) fw.write('''Source = "Value", }, },''') toolPos = 900+i*100 fw.write("ViewInfo = OperatorInfo { Pos = { %d, 0, }, }," %toolPos) fw.write('''},''') fw.write("PlaneTrack%dTrack1XYPath = XYPath {" %i) fw.write('''ShowKeyPoints = false, DrawMode = "InsertAndModify", NameSet = true, Inputs = { X = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack1XYPath%dX\"," %(i,i)) fw.write('''Source = "Value", }, Y = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack1XYPath%dY\"," %(i,i)) fw.write('''Source = "Value", }, }, },''') fw.write("PlaneTrack%dTrack2XYPath = XYPath {" %i) fw.write('''ShowKeyPoints = false, DrawMode = "InsertAndModify", NameSet = true, Inputs = { X = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack2XYPath%dX\"," %(i,i)) fw.write('''Source = "Value", }, Y = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack2XYPath%dY\"," %(i,i)) fw.write('''Source = "Value", }, }, },''') fw.write("PlaneTrack%dTrack3XYPath = XYPath {" %i) fw.write('''ShowKeyPoints = false, DrawMode = "InsertAndModify", NameSet = true, Inputs = { X = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack3XYPath%dX\"," %(i,i)) fw.write('''Source = "Value", }, Y = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack3XYPath%dY\"," %(i,i)) fw.write('''Source = "Value", }, }, },''') fw.write("PlaneTrack%dTrack4XYPath = XYPath {" %i) fw.write('''ShowKeyPoints = false, DrawMode = "InsertAndModify", NameSet = true, Inputs = { X = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack4XYPath%dX\"," %(i,i)) fw.write('''Source = "Value", }, Y = Input {''') fw.write("SourceOp = \"PlaneTrack%dTrack4XYPath%dY\"," %(i,i)) fw.write('''Source = "Value", }, }, },''') fw.write("PlaneTrack%dTrack1XYPath%dX = BezierSpline {" %(i,i)) fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, }, NameSet = true, KeyFrames = { """) for j, marker in enumerate(track.markers): fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[3][0])) fw.write(""" },\n },\n""") fw.write("PlaneTrack%dTrack1XYPath%dY = BezierSpline {" %(i,i)) fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, }, NameSet = true, KeyFrames = { """) for j, marker in enumerate(track.markers): fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[3][1])) fw.write(""" },\n },\n""") fw.write("PlaneTrack%dTrack2XYPath%dX = BezierSpline {" %(i,i)) fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, }, NameSet = true, KeyFrames = { """) for j, marker in enumerate(track.markers): fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[2][0])) fw.write(""" },\n },\n""") fw.write("PlaneTrack%dTrack2XYPath%dY = BezierSpline {" %(i,i)) fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, }, NameSet = true, KeyFrames = { """) for j, marker in enumerate(track.markers): fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[2][1])) fw.write(""" },\n },\n""") fw.write("PlaneTrack%dTrack3XYPath%dX = BezierSpline {" %(i,i)) fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, }, NameSet = true, KeyFrames = { """) for j, marker in enumerate(track.markers): fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[0][0])) fw.write(""" },\n },\n""") fw.write("PlaneTrack%dTrack3XYPath%dY = BezierSpline {" %(i,i)) fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, }, NameSet = true, KeyFrames = { """) for j, marker in enumerate(track.markers): fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[0][1])) fw.write(""" },\n },\n""") fw.write("PlaneTrack%dTrack4XYPath%dX = BezierSpline {" %(i,i)) fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, }, NameSet = true, KeyFrames = { """) for j, marker in enumerate(track.markers): fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[1][0])) fw.write(""" },\n },\n""") fw.write("PlaneTrack%dTrack4XYPath%dY = BezierSpline {" %(i,i)) fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, }, NameSet = true, KeyFrames = { """) for j, marker in enumerate(track.markers): fw.write(" [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[1][1])) fw.write(""" },\n },\n""") fw.write(""" Tracker2 = Tracker { Trackers = { """) fw.write("""{ PatternTime = 1, PatternX = 0.392840626111704, PatternY = 0.699857685009488, },\n { PatternTime = 1, PatternX = 0.392840626111704, PatternY = 0.699857685009488, },\n { PatternTime = 1, PatternX = 0.392840626111704, PatternY = 0.699857685009488, },\n { PatternTime = 1, PatternX = 0.392840626111704, PatternY = 0.699857685009488, },\n """) fw.write("""}, CtrlWZoom = false, Inputs = {TrackerList = Input { Value = 2, },""") fw.write("Name1 = Input { Value = \"PlaneTrack1\", }," ) fw.write("PatternCenter1 = Input { Value = { %r, %r, }, },"%( marker.corners[0][0],marker.corners[0][1])) fw.write("PatternWidth1 = Input { Value = 0.0154571326929918, },") fw.write("PatternHeight1 = Input { Value = 0.020841239721695, },") fw.write("SearchWidth1 = Input { Value = 0.0574350764852365, },") fw.write("SearchHeight1 = Input { Value = 0.0714421252371915, },") fw.write("TrackedCenter1 = Input {" ) fw.write("SourceOp = \"PlaneTrack%dTrack1XYPath\"," %i) fw.write("""Source = "Value", }, """) fw.write("Name2 = Input { Value = \"PlaneTrack2\", }," ) fw.write("PatternCenter2 = Input { Value = { %r, %r, }, },"%( marker.corners[1][0],marker.corners[1][1])) fw.write("PatternWidth2 = Input { Value = 0.0154571326929918, },") fw.write("PatternHeight2 = Input { Value = 0.020841239721695, },") fw.write("SearchWidth2 = Input { Value = 0.0574350764852365, },") fw.write("SearchHeight2 = Input { Value = 0.0714421252371915, },") fw.write("TrackedCenter2 = Input {" ) fw.write("SourceOp = \"PlaneTrack%dTrack2XYPath\"," %i) fw.write("""Source = "Value", }, """) fw.write("Name3 = Input { Value = \"PlaneTrack3\", }," ) fw.write("PatternCenter3 = Input { Value = { %r, %r, }, },"%( marker.corners[2][0],marker.corners[2][1])) fw.write("PatternWidth3 = Input { Value = 0.0154571326929918, },") fw.write("PatternHeight3 = Input { Value = 0.020841239721695, },") fw.write("SearchWidth3 = Input { Value = 0.0574350764852365, },") fw.write("SearchHeight3 = Input { Value = 0.0714421252371915, },") fw.write("TrackedCenter3 = Input {" ) fw.write("SourceOp = \"PlaneTrack%dTrack3XYPath\"," %i) fw.write("""Source = "Value", }, """) fw.write("Name4 = Input { Value = \"PlaneTrack4\", }," ) fw.write("PatternCenter4 = Input { Value = { %r, %r, }, },"%( marker.corners[3][0],marker.corners[3][1])) fw.write("PatternWidth4 = Input { Value = 0.0154571326929918, },") fw.write("PatternHeight4 = Input { Value = 0.020841239721695, },") fw.write("SearchWidth4 = Input { Value = 0.0574350764852365, },") fw.write("SearchHeight4 = Input { Value = 0.0714421252371915, },") fw.write("TrackedCenter4 = Input {" ) fw.write("SourceOp = \"PlaneTrack%dTrack4XYPath\"," %i) fw.write("""Source = "Value", }, """) ##toolPosTracker = 1200+i*100 fw.write("ViewInfo = OperatorInfo { Pos = { %d, 100 } }," %toolPos) fw.write(""" },},""") i += 1 except: print("No clip found plane_track") # close composition fw.write(" },\n}\n") fw.close() print("finished export to fusion comp") # ------------------------------------------------------------------------ # Export Operator # ------------------------------------------------------------------------ class EXPORT_OT_fusionComp(bpy.types.Operator, ExportHelper): """Save a python script which re-creates cameras and markers elsewhere""" bl_idname = "export_scene.fusion_comp" bl_label = "Export Fusion Composition" filename_ext = ".comp" filter_glob: bpy.props.StringProperty( default="*.comp", options={'HIDDEN'} ) frame_start: bpy.props.IntProperty( name="Start Frame", description="Start frame for export", default=1, min=0, max=300000 ) frame_end: bpy.props.IntProperty( name="End Frame", description="End frame for export", default=250, min=1, max=300000 ) only_selected: bpy.props.BoolProperty( name="Only Selected", default=False ) def execute(self, context): write_cameras(context, self.filepath, self.frame_start, self.frame_end, self.only_selected) return {'FINISHED'} def invoke(self, context, event): self.frame_start = context.scene.frame_start self.frame_end = context.scene.frame_end wm = context.window_manager wm.fileselect_add(self) return {'RUNNING_MODAL'} def draw_fusion_export_menu(self, context): default_path = os.path.splitext(bpy.data.filepath)[0] + ".comp" self.layout.operator( EXPORT_OT_fusionComp.bl_idname, text="Fusion Composition (.comp)" ).filepath = default_path # ------------------------------------------------------------------------ # Registration # ------------------------------------------------------------------------ def register(): bpy.utils.register_class(EXPORT_OT_fusionComp) bpy.types.TOPBAR_MT_file_export.append(draw_fusion_export_menu) def unregister(): bpy.types.TOPBAR_MT_file_export.remove(draw_fusion_export_menu) bpy.utils.unregister_class(EXPORT_OT_fusionComp) if __name__ == "__main__": register()