In the olden days, producers knew what visual effects were. Now they’ve gotten into this methodology where they’ll hire a middleman – a visual effects supervisor, and this person works for the producing studio.
They’re middle managers. And when you go into a review with one of them, there’s this weird sort of competition that happens.

It’s a game called ‘Find What’s Wrong With This Shot’. And there’s always going to be something wrong, because everything’s subjective. And you can micromanage it down to a pixel, and that happens all the time. We’re doing it digitally, so there’s no pressure to save on film costs or whatever, so it’s not unusual to go through 500 revisions of the same shot, moving pixels around and scrutinizing this or that.

That’s not how you manage artists. You encourage artists, and then you’ll get – you know – art.

If your idea of managing artists is just pointing out what’s wrong and making them fix it over and over again, you end up with artists who just stand around asking “OK lady, where do you want this sofa? You want it over there? No? Fine. You want it over there? I don’t give a fuck. I’ll put it wherever you want it.” It’s creative mismanagement, it’s part of the whole corporate modality. The fish stinks from the head on down. Back on Star Wars, Robocop, we never thought about what was wrong with a shot.

We just thought about how to make it better.

Phil Tippett

Saver Path Expression

Moderator: Tilt

joergmark
Posts: 3
Joined: Sat Jan 03, 2015 1:59 am

Saver Path Expression

Post #1 by joergmark » Fri Apr 24, 2015 5:19 am

Hi, I would like to create a functionality in Fusion that allows to set up a global path in a project which generates via an expression the filenames for many savers in the project.

e.g.

global path: V:/Project/

saver 1: V:/Project/cam_01/view_01_####.jpeg
saver 2: V:/Project/cam_02/view_02_####.jpeg

until now i could not figure out how to build something like this – does the file dialogue support expressions??

jörg-mark

Tags:

pingking
Fusionista
Posts: 395
Joined: Thu Aug 14, 2014 8:10 am
Been thanked: 7 times

Re: Saver Path Expression

Post #2 by pingking » Fri Apr 24, 2015 5:42 am

you cant use expression in the filenames, but you maybe you could use path maps

you can create in the preferences a new path map "global_path" set it to "v:\project" and use in the file name "global_path:\cam02\view_02_#####.jpg"

joergmark
Posts: 3
Joined: Sat Jan 03, 2015 1:59 am

Re: Saver Path Expression

Post #3 by joergmark » Fri Apr 24, 2015 10:18 am

my idea was to have e.g. a "master" saver node from wich i get the path and derive the numbering (01,02 etc.) from other nodes...

i#m doing conversion from stereo to multi view formats and so it is always the same naming schema, but different project paths

User avatar
Tilt
Site Admin
Posts: 336
Joined: Sat Aug 02, 2014 3:10 am
Location: Munich, Germany
Contact:

Re: Saver Path Expression

Post #4 by Tilt » Fri Apr 24, 2015 11:04 am

saver expressions have often been requested... maybe we'll get them one day.

Path maps are cool (and I'm currently using nested path maps to make comps work across 2 workstations where one has the footage stored locally and the other one accesses it through a network share) but they are no replacement for actual expressions.

You could write a script that you run before you render. It could create the file names for the savers based on anything you can think of: the name of a node, the contents of a node's comment field... and so on. You'd have to run this script every time before you start rendering.

skittixch
Posts: 6
Joined: Mon Sep 28, 2015 2:33 pm

Re: Saver Path Expression

Post #5 by skittixch » Fri Jan 06, 2017 2:37 pm

Tilt wrote:You could write a script that you run before you render. It could create the file names for the savers based on anything you can think of: the name of a node, the contents of a node's comment field... and so on. You'd have to run this script every time before you start rendering.


Sorry to bring up a dead thread, but I'm curious if you or anyone else could elaborate on this? I'd love to write a script to pull from a particular loader, and replace _part of_ all the clip names of all the savers in the comp

For example, if I make 3 savers, and their clipnames are "comp:/OVERWITEME_x", "comp:/OVERWITEME_y", and "comp:/OVERWITEME_z" respectively, how can I write a script that will overwrite the "OVERWRITEME" part of each saver with the filename of the file in my one and only loader in my comp?

Hope that makes sense, thanks in advance!

Midgardsormr
Fusioneer
Posts: 52
Joined: Wed Nov 26, 2014 8:04 pm
Location: Los Angeles, CA, USA
Been thanked: 1 time
Contact:

Re: Saver Path Expression

Post #6 by Midgardsormr » Fri Jan 06, 2017 2:57 pm

I don't have time to actually answer, but here's a script we use to create savers for our 2d plate preparation process. You may be able to learn some things for it. It's fairly well-documented, but there may be some things in there that I changed in a hurry without commenting. There's some stuff for detecting and replacing strings at around line 105. Setting the filename in a Saver is at line 397.


Code: Select all

-- Muse VFX Create Layout Savers script by Bryan Ray <bray@musevfx.com>
-- version 0.6, 11/3/2016
--
-- Intended to be run on a The Grid-generated Layout template, the script prompts the user for which processes
-- (denoise, undistort, etc) are being run, then creates Savers pointed to the correct elements folders.
-- This script is designed specifically for the pipeline in use at MuseVFX and will not operate outside
-- of that environment without changes.

-- changelog, v0.6:
--    Now gets the output path by parsing the Composition's path rather than the plate's, reducing errors due to plates being
--    off-pipeline and removing the need to make exceptions for projects that do not conform to the Season/Episode/Shot structure.
--    The drive letter is no longer hard-coded.

-- changelog, v0.5:
--    Added routine for handling optional proxy EXR output and an exception for PAF project structure.

-- changelog, v0.4:
--    Moved error messages into pop-ups. Still needs some fine-tuning related to window size and removing the "cancel" button.
--    Removed test for Undistort or Stabilize for making Modified Resolution saver. So if you're just down-sampling a plate,
--      the script will no longer refuse to make your saver.
--    Added an error pop-up if no Savers were requested.

-- changelog, v0.3:
--     Added a stabilize mode.

-- changelog, v0.2:
--    Added a routine to extract the element name from the comp name and use it to populate the Element Name
--      field in the user dialog. Also gets the version number properly.
--    The script will make the -original saver by default now but will not make a modified resolution EXR unless asked to.
--    Added checkboxes to enable the artist to turn off specific savers if they are not required.
--    Added a test for existing savers from previous runs of the script and prompts the user to delete them, only make new savers, or
--      create duplicate savers (not recommended).
--    If the Element Name is blank, remove the leading dash from the description.
--    Better logic for creation of the pathmod. It now detects the retime flag.

if composition == nil then
   oops = composition:AskUser("This is a composition script. It should be run from within Fusion.", {})
   exit()
end

if nullexr then
else
   oops = composition:AskUser("This comp does not conform to the Layout template. Aborting.", {})
   exit()
end

c = composition

if LDR then
else
   oops = composition:AskUser("No Loader called LDR found.", {})
   exit()
end

attrs = LDR:GetAttrs()
if attrs["TOOLS_RegID"] == "Loader" then
else
   oops = composition:AskUser("LDR is not a Loader or does not exist.", {})
   exit()
end

composition.CurrentFrame:ViewOn(nullexr, 2) -- put the null in the viewer in order to initialize its resolution attributes
composition.CurrentFrame:ViewOn(nulljpg, 2)
composition.CurrentFrame:ViewOn(nullprox, 2)
composition.CurrentFrame:ViewOn(LDR, 2)

-- get the comp's filename
fusion = Fusion()
comp=fusion:GetCurrentComp()

compName=string.gsub(comp:GetAttrs().COMPS_Name, "%.comp", "")

if compName == false then
   print("Warning, either this comp has not been saved, or the extension is missing from the file name.")
   print("The following clip name will be used:")
   compName=comp:GetAttrs().COMPS_Name.."."
   print(compName)
   print("\n")
end

-- Parse the filename, detecting characters between "layout-" and "_", and putting those characters in Element Name

_, i = string.find(compName, "layout") -- finds the end index of "layout"

if i then -- test for correct comp name.
else
   oops = composition.AskUser("Comp Type is not Layout. Aborting script.", {})
   exit()
end

hyphencheck = string.sub(compName, i+1, i+1)

if hyphencheck == "-" then -- if the hyphen is found next, make the elname
   j, k = string.find(compName, "_", i+1) -- finds the index of the underscore
   elname = string.sub(compName, i+2, j-1) -- this gets the element name.
else
   elname = "" -- if the hyphen is not found, the element name is empty
   j = i+1
end

-- Extract the version number, which should be right after that "_"
version = string.sub(compName, j+1, j+3)

fp = eyeon.parseFilename(comp:GetAttrs().COMPS_FileName) -- get the compositions's path information
-- fp.FullPath = string.gsub(fp.FullPath, "\\Frames", "", 1) -- Strips out "Frames" folder if found. No longer needed.

-- i, j = string.find(fp.FullPath, "\\v%d%d") -- get the plate's version number (deprecated)
-- version = string.sub(fp.FullPath, i+1, j) --

pathtable = eyeon.split(fp.FullPath, "\\") -- creates a table containing each folder in the Loader's path

-- Replace the 2d folder with elements, remove the last two entries in the table, and append Plates and version number to form
-- the base output path

pathtable[3] = "elements"

j = 0
print("Listing folders:\n")
for i, folder in pairs(pathtable) do
   print(i .. ": " .. folder)
   j= j+1             -- j now holds the index of the last item in the table, which should be the filename.
end
 
shot = pathtable[j-2]
 
outputpath = ""

for i=1,j-2 do
   outputpath=outputpath .. pathtable[i] .. "\\"
end
 
-- the below routine is deprecated due to better handling of the path
-- show = pathtable[2] -- The second entry in the table should always be the Show name

-- NCIS has a unique structure because we don't have a season folder. All episodics should have a season folder below show name
-- followed by episode name then shot name. Features should have a "feature" folder below show name, then sequence name and shot name.
-- EMB was ingested prior to implementing strict pipeline procedures.
-- if show == "NCIS" then
--   episode = pathtable[3]
--   shot = pathtable[4]
--elseif show == "EMB" then
--   oops = composition.AskUser("EMB is off pipeline. Set your savers manually.", {})
--   exit()
--elseif show == "PAF" then
--   episode = pathtable[3]
--   shot = pathtable[4]
--else
--   episode = pathtable[3] .. "\\" .. pathtable[4]
--   shot = pathtable[5]
--end

-- Pop up a dialog asking the user to indicate the name of the plate and which operations are being performed.
-- Add checkboxes for the different kinds of savers.

exrprox = 0 -- initialize variable

-- test for presence of nullproxexr node. If found, use alternate dialog.
if nullproxexr then
exrprox = 1
end

if (exrprox == 1) then
   dialog = composition:AskUser("Layout Script", {
                        {"Element Name", "Text", Lines = 1, Default = elname},
                        {"Undistort", "Checkbox", Default = 0},
                        {"Stabilize", "Checkbox", Default = 0},
                        {"Denoise", "Checkbox", Default = 1},
                        {"Retime", "Checkbox", Default = 0},
                        {"Create these savers:"},
                        {"Original Resolution EXR", "Checkbox", Default = 1},
                        {"Modified Resolution EXR", "Checkbox", Default = 0},
                        {"Proxy EXR", "Checkbox", Default = 0},
                        {"Full Size Jpeg", "Checkbox", Default = 1},
                        {"0.5 Proxy Jpeg", "Checkbox", Default = 1},
                        })
else
   dialog = composition:AskUser("Layout Script", {
                        {"Element Name", "Text", Lines = 1, Default = elname},
                        {"Undistort", "Checkbox", Default = 0},
                        {"Stabilize", "Checkbox", Default = 0},
                        {"Denoise", "Checkbox", Default = 1},
                        {"Retime", "Checkbox", Default = 0},
                        {"Create these savers:"},
                        {"Original Resolution EXR", "Checkbox", Default = 1},
                        {"Modified Resolution EXR", "Checkbox", Default = 0},
                        {"Full Size Jpeg", "Checkbox", Default = 1},
                        {"0.5 Proxy Jpeg", "Checkbox", Default = 1},
                        })
end
                        
pathmod = ""
description = ""
elempath = ""

if (dialog["Original Resolution EXR"] == 0 and dialog["Modified Resolution EXR"] == 0 and dialog["Full Size Jpeg"] == 0 and dialog["0.5 Proxy Jpeg"] == 0) then
   oops = composition:AskUser("No Savers selected. Aborting Script.", {})
   exit()
end
   
if dialog then
   if dialog["Element Name"] == "" then
   else
   description = dialog["Element Name"] .. "-"
   elempath = dialog["Element Name"] .. "_" -- Adds the underscore for the path.
   dialog["Element Name"] = description -- Adds the hyphen into the name in the table.
   end
   if dialog["Denoise"] == 1 then
      description = description .. "denoise"
      pathmod = ".denoise"
      origpathmod = ".denoise"
   end
   if dialog["Retime"] == 1 then
      if dialog["Denoise"] == 1 then  -- Detect presence of previous description mods and add hyphen to account for it.
         description = description .. "-"
      end
      description = description .. "retime"
      pathmod = ".retime"
   end
   if dialog["Undistort"] == 1 then
      origpathmod = pathmod -- creates a pathmod fork for the original resolution
      origdescr = description -- creates a description fork for the original res files
      if dialog["Denoise"] == 1 or dialog["Retime"] == 1 then
         description = description .. "-"
      end
      description = description .. "undist"
      pathmod = ".undist"
   else
      origpathmod = pathmod
      origdescr = description
   end -- If undistort box is not checked, the main linear saver will no longer get a -original tag.
   if dialog["Stabilize"] == 1 then
      if dialog["Undistort"] == 1 then
         origdescr = origdescr .. "-"
      else
         origpathmod = pathmod -- creates a pathmod fork for the original resolution
         origdescr = description -- creates a description fork for the original res files
      end
      if dialog["Denoise"] == 1 or dialog["Retime"] ==1 or dialog["Undistort"] == 1 then
         description = description .. "-"
      end
      description = description .. "stab"
      pathmod = ".stab"
   end
else -- If user hits "Cancel"
   error("Script cancelled by user.")
end

-- Test for existing savers and prompt for instructions.
saverfound = 0
exrfound = 0
jpgfound = 0
proxfound = 0
origfound = 0
exrproxfound = 0

mysavers = composition:GetToolList(false, "Saver") -- puts all savers into a table

if table.getn(mysavers) > 0 then
   for i, tool in pairs(mysavers) do
      name = tool:GetAttrs().TOOLS_Name
      if name == "exrsaver" then
         saverfound = 1
         exrfound = 1
      elseif name == "jpgsaver" then
         saverfound = 1
         jpgfound = 1
      elseif name == "proxsaver" then
         saverfound = 1
         proxfound = 1
      elseif name == "origsaver" then
         saverfound = 1
         origfound = 1
      elseif name == "proxexr" then
         saverfound = 1
         exrproxfound = 1
      end
   end
end

-- initialize some variables.
overwrite = 0
make = 0
delete = 0

-- check existence of savers vs options in dialog
if dialog["Original Resolution EXR"] == 1 and origfound == 1 then
   overwrite = 1
end
if dialog["Modified Resolution EXR"] == 1 and exrfound == 1 then
   overwrite = 1
end
if dialog["Full Size Jpeg"] == 1 and jpgfound == 1 then
   overwrite = 1
end
if dialog["0.5 Proxy Jpeg"] == 1 and proxfound == 1 then
   overwrite = 1
end
if dialog["Proxy EXR"] == 1 and exrproxfound == 1 then
   overwrite = 1
end

if overwrite == 1 then -- Determine overwrite behavior
   options = {"Replace Existing Savers", "Skip Existing Savers", "Create Duplicate Savers (not recommended)"}
   savtreatment = composition:AskUser("Existing Savers Found.",
                              {{"Action", "Dropdown", Options = options}
                              })
   if savtreatment then
      if savtreatment["Action"] == 0 then
         delete = 1
         make = 1
      elseif savtreatment["Action"] == 2 then
         delete = 0
         make = 1
      else
         delete = 0
         make = 0
      end
   else
      print("User cancelled procedure. Skipping existing Savers.")
      delete = 0
      make = 0
   end
end
c:StartUndo("MakeSavers Script")
-- Delete existing savers

if (dialog["Original Resolution EXR"] * origfound * delete) > 0 then
   c.origsaver:Delete()
end

if (dialog["Modified Resolution EXR"] * exrfound * delete) > 0 then
   c.exrsaver:Delete()
end

if (dialog["Full Size Jpeg"] * jpgfound * delete) > 0 then
   c.jpgsaver:Delete()
end

if (dialog["0.5 Proxy Jpeg"] * proxfound * delete) > 0 then
   c.proxsaver:Delete()
end

if exrprox == 1 then
   if (dialog["Proxy EXR"] * exrproxfound * delete) > 0 then
      c.proxexrsaver:Delete()
   end
end

-- Get resolution for each saver

composition.CurrentFrame:ViewOn(nullexr, 2) -- put the null in the viewer in order to initialize its resolution attributes
exrattrs = nullexr:GetAttrs() -- put the attributes in a table
exrwidth = exrattrs["TOOLI_ImageWidth"] -- query the table for the image dimensions
exrheight = exrattrs["TOOLI_ImageHeight"]

composition.CurrentFrame:ViewOn(nulljpg, 2)
jpgattrs = nulljpg:GetAttrs()
jpgwidth = jpgattrs["TOOLI_ImageWidth"]
jpgheight = jpgattrs["TOOLI_ImageHeight"]

composition.CurrentFrame:ViewOn(nullprox, 2)
proxattrs = nullprox:GetAttrs()
proxwidth = proxattrs["TOOLI_ImageWidth"]
proxheight = proxattrs["TOOLI_ImageHeight"]

composition.CurrentFrame:ViewOn(LDR, 2)
origattrs = LDR:GetAttrs()
origwidth = origattrs["TOOLIT_Clip_Width"][1]
origheight = origattrs["TOOLIT_Clip_Height"][1]

if exrprox == 1 then
   composition.CurrentFrame:ViewOn(nullproxexr, 2)
   proxexrattrs = nullproxexr:GetAttrs()
   proxexrwidth = proxexrattrs["TOOLI_ImageWidth"]
   proxexrheight = proxexrattrs["TOOLI_ImageHeight"]
end

-- create saver paths for exr, jpg and proxy jpg. Also original resolution denoised.

exrpath = outputpath .. "plates\\" .. elempath  .. version .. "\\" .. exrwidth .. "x" .. exrheight .. pathmod .. ".exr\\" .. shot .. "_" .. description .. "_" .. version .. ".1234.exr"
jpgpath = outputpath .. "plates\\" .. elempath  .. version .. "\\" .. jpgwidth .. "x" .. jpgheight .. pathmod .. ".jpg\\" .. shot .. "_" .. description .. "_" .. version .. ".1234.jpg"
proxpath = outputpath .. "plates\\" .. elempath .. version .. "\\" .. proxwidth .. "x" .. proxheight .. pathmod .. ".jpg\\" .. shot .. "_" .. description .. "_" .. version .. ".1234.jpg"
origpath = outputpath .. "plates\\" .. elempath .. version .. "\\" .. origwidth .. "x" .. origheight .. origpathmod .. ".exr\\" .. shot .. "_" .. origdescr .. "-original" .. "_" .. version .. ".1234.exr"

if exrprox == 1 then
   proxexrpath = outputpath .. "plates\\" .. elempath .. version .. "\\" .. proxexrwidth .. "x" .. proxexrheight .. pathmod .. ".exr\\" .. shot .. "_" .. description .. "_" .. version .. ".1234.exr"
end

-- create the requested savers

comp:Lock()

if exrprox == 1 then
   if (dialog["Proxy EXR"] * ((1-exrproxfound)+make)) > 0 then
      x,y = c.CurrentFrame.FlowView:GetPos(nullproxexr)
      proxexrsv = comp:AddTool("Saver", x+2, y+1)
      proxexrsv.Clip = proxexrpath
      proxexrsv.OpenEXRFormat.Depth = 1
      proxexrsv.CreateDir = 1
      proxexrsv.Input = nullproxexr.Output
      proxexrsv:SetAttrs({TOOLS_Name = "proxexrsaver"})
   end
end

if (dialog["Modified Resolution EXR"] * ((1-exrfound)+make)) > 0 then
   x,y = c.CurrentFrame.FlowView:GetPos(nullexr) -- gets location of nullexr node
   exrsv = comp:AddTool("Saver", x+2, y+1) -- creates Saver to the right of the null
   exrsv.Clip = exrpath -- places the constructed path in the Clip field. This automatically sets the file type to OpenEXR.
   exrsv.OpenEXRFormat.Depth = 1 -- sets the bit depth to float16. This saves space and bandwidth on the network. User can manually
                        -- change it to float 32 if needed.
   exrsv.CreateDir = 1 -- Enables the Saver to create the path.
   exrsv.Input = nullexr.Output
   exrsv:SetAttrs({TOOLS_Name = "exrsaver"}) -- Sets the name of the saver.
end
--
if (dialog["Full Size Jpeg"] * ((1-jpgfound)+make)) > 0 then
   x,y = c.CurrentFrame.FlowView:GetPos(nulljpg)
   jpgsv = comp:AddTool("Saver", x+2, y+1)
   jpgsv.Clip = jpgpath
   jpgsv.CreateDir = 1
   jpgsv.Input = nulljpg.Output
   jpgsv:SetAttrs({TOOLS_Name = "jpgsaver"})
end

--
if (dialog["0.5 Proxy Jpeg"] * ((1-proxfound)+make)) > 0 then
   x,y = c.CurrentFrame.FlowView:GetPos(nullprox)
   proxsv = comp:AddTool("Saver", x+2, y+1)
   proxsv.Clip = proxpath
   proxsv.CreateDir = 1
   proxsv.Input = nullprox.Output
   proxsv:SetAttrs({TOOLS_Name = "proxsaver"})
end

-- no longer optional. Create the original resolution desnoised plate if an undistort has been made.

--
if (dialog["Original Resolution EXR"] * ((1-origfound)+make)) > 0 then
   x,y = c.CurrentFrame.FlowView:GetPos(nullorig)
   origsv = comp:AddTool("Saver", x+2, y+1)
   origsv.Clip = origpath
   origsv.CreateDir = 1
   origsv.OpenEXRFormat.Depth = 1
   origsv.Input = nullorig.Output
   origsv:SetAttrs({TOOLS_Name = "origsaver"})
end

comp:Unlock()

c:EndUndo(True)


User avatar
ISOTRON
Fusioneer
Posts: 105
Joined: Mon Aug 04, 2014 10:54 am
Location: Germany, Munich
Contact:

Re: Saver Path Expression

Post #7 by ISOTRON » Mon Jan 09, 2017 2:31 am

u cant expect a out of the box script, because your own needs, but let say it easy, you need to split the Saver Path (.split("_")[number]), in your part, like: comp:changemenot_changeme.extension. Change "changeme" and put it togehter again.

maybe a PythonScript will help you, here i use the Compname to set the saver path with our needs (compname+artist+version+addon.ext)

Code: Select all

import re
tool = comp.ActiveTool

fullnamecomp = comp.GetAttrs()['COMPS_FileName']
rendername = re.sub("Comps","RENDER",fullnamecomp)
rendername = re.sub("COMPS","RENDER",rendername)
rendernameext = re.sub(".comp","_.dpx",rendername)

artist = rendernameext.split("_")[-2]

artistt = "_" + artist
filename = re.sub(artistt,"",rendernameext)

file = filename.split("\\") [-1]

filedir = re.sub("_" + file.split("_")[-1] ,"",file)
version = filedir.split("_")[-1]
fileshort = re.sub("_"+version,"",filedir)
rendernameextfile = rendernameext.split("\\")[-1]   
directory = re.sub(rendernameextfile,"",rendernameext) + fileshort + "\\" + version + "\\"
extension = file.split("_")[-1]

filename4render = directory + re.sub(version,"",filedir) + version + "_" + artist + "_" + extension

skittixch
Posts: 6
Joined: Mon Sep 28, 2015 2:33 pm

Re: Saver Path Expression

Post #8 by skittixch » Mon Jan 09, 2017 8:38 am

Thanks to both of you! Lots of info to pour through, but this really helps. I appreciate it!

Who is online

Users browsing this forum: No registered users and 1 guest