Jump to: Board index » General » Fusion

Nuke Keyframes to Fusion Script Not Working

Learn about 3D compositing, animation, broadcast design and VFX workflows.
  • Author
  • Message
Offline
User avatar

Eugene Afanasiev

  • Posts: 600
  • Joined: Sun Aug 30, 2015 2:57 pm
  • Location: Russia

Nuke Keyframes to Fusion Script Not Working

PostMon Apr 25, 2016 4:41 pm

I've found this script, but can not get it to work, any help?..

Code: Select all
------------------------------------------------------------------------------
-- Import Animation from Text File:
-- A powerful script to import keyframes from files where there is one line of data
-- for each frame (space or comma-separated). Can be used to animate 2D point controls
-- or single value sliders. The script tries to be smart by suggesting to animate a tool's
-- Center or Angle property by default, depending on the file's data. Regular
-- paths as well as XY-Paths are supported.
-- You can choose which column of data is used to animate a control, and the frame
-- number where the new keyframes will be pasted to.
-- The file's values can be Fusion's normalized coordinates or they can denote
-- pixels with the origin being at the bottom, top or center. You can also choose
-- to skip a certain number of lines before the first line of data is read.
--
-- This is a tool script!
-- written by Stefan Ihringer, stefan@bildfehler.de
-- based on "Import Boujou Track" by Isaac Guenard
--
-- Version 1.0 - 2010-1101:
-- Ideas: Detect 3D coordinates and import three values automatically
--        Ask to replace existing animation instead of merging keyframes
------------------------------------------------------------------------------


-----------------------------------------------------
-- trim(strTrim)
--
-- returns strTrim with leading and trailing spaces
-- removed.
-----------------------------------------------------
function trim(strTrim)
   strTrim = string.gsub(strTrim, "^(%s+)", "") -- remove leading spaces
   strTrim = string.gsub(strTrim, "$(%s+)", "") -- remove trailing spaces
   return strTrim
end



------------------------------------------------------------------------------
-- SETUP ---------------------------------------------------------------------
------------------------------------------------------------------------------
INFOTXT = "This script will load keyframes from a text file. It can handle files where there is one line for each frame with values separated by spaces or commas."
PIXELOPTIONS = {"Pixels (zero is bottom/left)", "Pixels (zero is top/left)", "Pixels (zero is image center)", "Fusion (0.5 is image center)"}
PATHOPTIONS = {"XY Path", "PolyLine Path"}

if not tool then
   tool = composition:GetAttrs().COMPH_ActiveTool
   if not tool then
      print("This is a tool script, you must select a tool in the flow to run this script")
      composition:GetFrameList()[1]:SwitchMainView('ConsoleView')
      exit()
   end
end



------------------------------------------------------------------------------
-- MAIN ----------------------------------------------------------------------
------------------------------------------------------------------------------

fileName = nil
-- build a table of controls that can be animated (Points or Numbers)
controls = {}
controlNames = {}
-- don't show inputs with these IDs in the dialog
filterInputs = {Quality = true, ShutterAngle = true, CenterBias = true, SampleSpread = true,}

inps = tool:GetInputList()
for i, inp in inps do
   local attrs = inp:GetAttrs()
   -- allow all point inputs but filter numbers to some pre-defined well-known inputs.
   if attrs.INP_External ~= false then
      if attrs.INPS_DataType == "Point" then
         -- todo: mark inputs that are already animated with an asterisk
         table.insert(controlNames, attrs.INPS_Name .. " (2D Point)")
         table.insert(controls, inp)
      elseif attrs.INPID_InputControl == "SliderControl" or attrs.INPID_InputControl == "ScrewControl" then
         if filterInputs[attrs.INPS_ID] ~= true then
            table.insert(controlNames, attrs.INPS_Name)
            table.insert(controls, inp)
         end
      end
   end
end

-- complain if none of the controls have this datatype
if table.getn(controls) == 0 then
   print("Can't find a number or point control that could be animated.")
   composition:GetFrameList()[1]:SwitchMainView('ConsoleView')
   exit()
end


while fileHandle == nil do
   -- ask the user what text file to process
   dialog = {{"infotxt", Name = "", "Text", Default = INFOTXT, Wrap = true, Lines = 3, ReadOnly = true}}
   if ret == nil then
      table.insert(dialog, {"filename", "FileBrowse", Default = ""})
   else
      table.insert(dialog, {"filename", "FileBrowse", Default = ret.filename})
   end
   
   if err then
      table.insert(dialog, {"warning", Name = "Warning", "Text", Default = err, Wrap = true, Lines = 4, ReadOnly = true})
   end
   
   ret = composition:AskUser("Select a text file containing the animation", dialog)
   if ret == nil then return end
   
   -- can we open the file?
   fileName = MapPath(ret.filename)
   fileHandle, err = io.open(fileName, "r")
end


-- read the first few lines so we can display a preview in the next dialog.
firstDataLine = nil
i = 0
preview = ""
line = fileHandle:read("*l")
while line and (i < 50) do
   -- look for first line that starts with a number (in case we have to skip some initial lines)
   -- and try to detect the number of columns per line
   if firstDataLine == nil and string.find(line, "^%s*-?%d+") then
      firstDataLine = i
      detectColumns = 0
      string.gsub(trim(line), "([^%s,;]+)", function(v) detectColumns = detectColumns + 1 end)
      --print("detected columns in 1st line:", detectColumns)
   end
   preview = preview .. line .. "\n"
   line = fileHandle:read("*l")
   i = i + 1
end
fileHandle:close()
if i == 50 and line ~= nil then
   preview = preview .. "(...)\n"
end
if firstDataLine == nil then
   print("This file doesn't seem to have any data that can be imported.")
   composition:GetFrameList()[1]:SwitchMainView('ConsoleView')
   exit()
end
-- get filename for text label
string.gsub(fileName, "^.+[/\\](.-)$", function(s) fileNameLabel = s end)


-- set up defaults
ret = {}
ret.skip = firstDataLine
ret.control = 1
if detectColumns == 1 then
   -- If only one column has been detected, default input should be "angle" (if available).
   ret.control = eyeon.get_table_index(controlNames, "Angle") or 1
else
   -- If two or more columns have been detected, default input should be "center" (if available).
   ret.control = eyeon.get_table_index(controlNames, "Center (2D Point)") or 1
end

-- detect image width, either from tool itself or from comp preferences
compAttrs = comp:GetAttrs()
attrs = tool:GetAttrs()
if attrs.TOOLI_ImageWidth == nil then
   local prefs = composition:GetPrefs()
   ret.width = prefs.Comp.FrameFormat.Width
   ret.height = prefs.Comp.FrameFormat.Height
else
   ret.width = attrs.TOOLI_ImageWidth
   ret.height = attrs.TOOLI_ImageHeight
end

-- show preview dialog. remember: dropdown indices are zero based while LUA tables start with an index of 1.
ret = composition:AskUser("Import Animation", {
   {"preview", Name = "Preview of "..fileNameLabel, "Text", Default = preview, Wrap = true, Lines = 6, ReadOnly = true},
   {"skip", Name = "Lines to skip", "Slider", Integer = true, Default = ret.skip, Min = 0, Max = 50},
   {"column1", Name = "Column of 1st value", "Slider", Integer = true, Default = 1, Min = 1, Max = 10},
   {"column2", Name = "Column of 2nd value (2D points only)", "Slider", Integer = true, Default = 2, Min = 1, Max = 10},
   {"startframe", Name = "Start frame of imported animation", "Slider", Integer = true, Default = compAttrs.COMPN_CurrentTime, Min = compAttrs.COMPN_GlobalStart, Max = compAttrs.COMPN_GlobalEnd},
   {"control", Name = "Apply to:", "Dropdown", Options = controlNames, Default = ret.control - 1},
   {"type", Name = "If 2D, type is:", "Dropdown", Options = PIXELOPTIONS},
   {"path", Name = "If 2D, animate as:", "Dropdown", Options = PATHOPTIONS},
   {"text", Name = "", "Text", Default = "If the text file contains pixel values, you have to specify the image width and height as well, so the values can be converted correctly.", Wrap=true, Lines=3, ReadOnly = true},
   {"width", "Slider", Name="Image Width", Integer=true, Default=ret.width, Min=2, Max=10000},
   {"height", "Slider", Name="Image Height", Integer=true, Default=ret.height , Min=2, Max=10000}
   })

if ret == nil then return end
theControl = controls[ret.control + 1]
is2DPoint = theControl:GetAttrs()["INPS_DataType"] == "Point" or false

-- start reading file for real
fileHandle, err = io.open(fileName, "r")
if fileHandle == nil then
   print(err)
   composition:GetFrameList()[1]:SwitchMainView('ConsoleView')
   exit()
end

-- skip a number of lines
i = ret.skip
line = fileHandle:read("*l")
while i > 0 do
   line = fileHandle:read("*l")
   i = i - 1
end

-- collect values in this array
values = {}
i = 0
while line do
   line = trim(line)
   if string.sub(line, 1, 1) ~= "#" then
      values[i] = {}
      string.gsub(line, "([^%s,;]+)", function(v) table.insert(values[i], tonumber(v)) end)
      if #values[i] > 0 then
         i = i + 1
      end
   end
   line = fileHandle:read("*l")
end
fileHandle:close()
fileHandle = nil


composition:StartUndo("Import Animation on "..attrs.TOOLS_Name..":"..controlNames[ret.control + 1])

-- is the control animated?
deleteKeyAt = nil
-- todo: ask to replace values
if theControl:GetAttrs().INPB_Connected == true then
   local ret = composition:AskUser(theControl:GetAttrs().INPS_Name .. " is animated!", {
      {"warning", Name = "warning", "Text", Default="The selected control is already animated or connected to another control."..
      "\n\nSelect OK to continue anyway, or CANCEL to abort. If you select OK the keys in the track file will be merged with existing keys.", Wrap=true, Lines=8}
      })
   if ret == nil then
      composition:EndUndo(false)
      exit()
   end
else
   if is2DPoint then
      if ret.path == 0 then
         theControl:ConnectTo(XYPath({}))
      else
         theControl:ConnectTo(Path({}))
      end
   else
      theControl:ConnectTo(BezierSpline({}))
   end
   -- a keyframe is created at the current time. It needs to be deleted
   -- if it isn't overwritten by imported data
   deleteKeyAt = comp:GetAttrs().COMPN_CurrentTime
end


--finally do the keyframes
if composition.UpdateMode then
   if composition.UpdateMode == "None" or composition.UpdateMode == "Some" then
      hold = composition.UpdateMode
      composition.UpdateMode = "All"
   end
end

-- set up default coordinate if user requested a column that doesn't exist or
-- some values could not be converted to a number
defaultCoordinate = ret.type == 3 and 0.5 or 0
for f, coord in pairs(values) do
   local frame = tonumber(f) + ret.startframe
   if is2DPoint == true then
      local x = tonumber(coord[ret.column1] or defaultCoordinate)
      local y = tonumber(coord[ret.column2] or x)
      -- convert pixel values if data isn't already Fusion's normalized coordinates
      if ret.type == 0 then
         -- pixels bottom/left
         x = x / ret.width
         y = y / ret.height
      elseif ret.type == 1 then
         -- pixels top/left
         x = x / ret.width
         y = 1 - y / ret.height
      elseif ret.type == 2 then
         -- pixels centered
         x = x / ret.width + 0.5
         y = y / ret.width + 0.5
      end
      theControl[frame] = {x, y}
   else
      local x = tonumber(coord[ret.column1] or 0)
      theControl[frame] = x
   end
   -- delete frame that might have been created automatically when the control was animated
   if deleteKeyAt ~= nil then
      if deleteKeyAt ~= frame then
         theControl[deleteKeyAt] = nil
      end
      deleteKeyAt = nil
   end
end

print("Imported "..#values.." keys to "..tool:GetAttrs().TOOLS_Name..":"..theControl:GetAttrs().INPS_Name)
composition:EndUndo(true)
if hold then composition.UpdateMode = hold end


__
--[[BMD's cameras and Resolve all-post workflow evangelist
My old stuff: http://www.youtube.com/rebelorelse
Debug: Asus ROG Duo GX550 i9 10980 48Gb RAM RTX2080MaxQ DaVinci Resolve Studio / Fusion Studio Latest Version]]--
Offline
User avatar

Chad Capeland

  • Posts: 3025
  • Joined: Mon Nov 10, 2014 9:40 pm

Re: Nuke Keyframes to Fusion Script Not Working

PostMon Apr 25, 2016 10:07 pm

There's no eyeon stdlib anymore, I think it's bmd now?
Chad Capeland
Indicated, LLC
www.floweffects.com
Offline
User avatar

Eugene Afanasiev

  • Posts: 600
  • Joined: Sun Aug 30, 2015 2:57 pm
  • Location: Russia

Re: Nuke Keyframes to Fusion Script Not Working

PostTue Apr 26, 2016 3:20 pm

renamed to bmd all eyeon in the script. but still not working.

console says:
...gic Design/Fusion/Scripts/Comp/Keyframes Data Import.lua:70: attempt to call a table value
__
--[[BMD's cameras and Resolve all-post workflow evangelist
My old stuff: http://www.youtube.com/rebelorelse
Debug: Asus ROG Duo GX550 i9 10980 48Gb RAM RTX2080MaxQ DaVinci Resolve Studio / Fusion Studio Latest Version]]--
Offline
User avatar

Eric Westphal

  • Posts: 214
  • Joined: Thu Nov 20, 2014 1:59 pm

Re: Nuke Keyframes to Fusion Script Not Working

PostWed Apr 27, 2016 5:34 pm

Without testing I would assume that the script wasn't updated to the latest changes in FuScript.

The
Code: Select all
for i, inp in inps do

in line 68 was a "hack", not according to the lua specs.
It should actually read
Code: Select all
for i, inp in pairs (inps) do


IIRC....
my hovercraft is full of eels.

Return to Fusion

Who is online

Users browsing this forum: Aymeric_Pihery and 59 guests