AWS Thinkbox Discussion Forums

TVPaint Being More Customisable?

I’d been looking at automated TVPaint rendering previously, so I was interested to see the way 7.2 integrates TVPaint.
I hadn’t spotted the way to minimise the program, it’s handy! All my automatic renders had been happening in the foreground. And having Deadline write a George script is a great way to customise it.

One thing I found is that there’s a way to send George commands into TVP directly, without having to write an actual script. You can pass “cmd=tv_quit” to quit TVPaint for instance. But the other advantage to this is that you can stack several commands as well as scripts. For example:

tvpaint.exe "cmd=tv_loadProject filename.tvpp" "cmd=tv_savemode PNG" "script=render.grg"

(I don’t think that’s accurate syntax, as it was weeks ago when I was experimenting with this, but you get the idea)
The advantage to something like this is that you could theoretically have a saved George script that you use and then just use the cmd format for things that vary, like background setting and file format.

Depending on how deep in you want to go, I did also find ways to write scripts to export all the layers individually as sets of images, set TVPaint to only export a new image when there’s a new drawing and to only export frames that are marked certain colours. These scripts are useful for our purposes, so I can explain if anyone else is interested.

But more importantly, I think it would be a good idea to have an option for users to write their own George script and use that to render instead. Using a pre-written script does provide problems with how it interacts with Deadline since that’s how Deadline specifies a frame range, export path and file format. But perhaps there’s a way that you could create a template script that Deadline can read, and rewrite key parts to match the job’s settings.

I think it would definitely be a good feature if there’s a good way to make it work. So I’d like to hear what everyone else thinks.

Hey Gary,

Sorry for the slow reply on this. If you have any extra info on ways to render within George that would be a great help (we have minimal TVPaint experience so any outside expertise is appreciated). For doing it all as individual cmd scripts that could work we will need to do some testing to make sure it will cover what we need but that would allow for extra commands to be added easier. For using a template script, what we could easily do is add a “script job” mode to the plugin that will pass in a script. For rewriting scripts, we can probably copy them then rewrite those we will need to see how we want to do it. I need to check to see if we can pass in variables into scripts, if so that will work.

Grant

Hi Grant!

I’ll explain some of the stuff I figured out. George is a bit of a funny language, and since you didn’t work with the more complicated stuff I’ll explain it. Sorry if I’m retreading known ground for you. Also, as far as I could find there was no way to pass parameters into a script called from the commandline. That was one of the reasons that I found using the individual argument syntax helpful, since I could pass parameters to those.

Sorry this is such a long post, but feel free to take your time reading through and following. Also ask for more detail if I’ve made parts too confusing.

Some notes about these solutions. George has a funny way of returning values from functions. When you call a function, it will then return a value to the keyword ‘result’ on the next line after the function call. You don’t seem to be able to set the value on the same line as the return statement.
Also the way to check equivalence is to wrap two parameters in a CMP() function (which I assume is short for Compare) and seeing if it returns as True or False.
String concatenation is tricky to follow too, because George will attach variables and quoted literals together. And to attach two variables together, you need to put an empty string between them. It’s probably easiest to show by examples:

[code]name = “George”
num = “001”
filetype = “.grg”

//With these you can make
name’.png’ >> “George.png”
name’‘num >> “George_001”
name’
‘num’'filetype >> “George_001.png”[/code]
Lastly, when you want to get a set of different values from a result, you use the keyword PARSE and then a set of variable names to save the different values into.
Hopefully those explanations make sense, I’m not very clear on how these work myself but I can try explain more if you need me to.

The first thing I was looking into was being able to export layers as separate images. The main problem I found with doing this was how to tell what layers existed in the document. I never found out a way to read that effectively for the script, however I did discover that their unique IDs are pretty simple (starting at 1 and incrementing) and that TVPaint doesn’t throw an error for trying to select an invalid ID. So I actually set up a script that would loop through every possible ID number from 1 to 10000, checking if they corresponding to an actual layer. It works quite well, and there’s no lag at all, it passes by the invalid IDs incredibly quickly.

Anyway, here’s the script:

[code]//All the preparation code for setting background mode and filetype goes above here

//This changes a setting so that only the currently selected layer will display/render
tv_Display “current”
//It returns the previous display mode as a result, which can be saved and restored after the script is done.
display = result

FOR id = 1 to 10000
//Using the id, attempt to select a layer.
tv_LayerSet id

//Check if we successfully selected a layer
IF (CMP(result,'') == 1)
    //Now get the information for the currently selected layer, just so we have the layerName
    tv_LayerInfo
    PARSE result layerDisplay layerPosition layerOpacity layerName layerType layerStart layerEnd layerPrelighttable layerPostlighttable
    
    //Render frames now, since this is a real layer
    tv_savesequence filename'_'layerName''filetype frameIn frameOut "Camera"
END

END

tv_Display result
[/code]

So this loops over all possible layers (up to 10000, but that number could be increased if it ever seemed to be necessary) and then just exports the frame range of it. The filename is generated from the layer’s name. You could also separate them into different folders just by adding a slash and folder name, as long as you run the folder creation before the George script.

I also found some ways to test frames and layers. TVPaint frames have an attribute called ‘exposureinfo’ that tells you if there’s actually a new drawing on that layer. Often there are holds on individual layers, where the same image is sustained over a period of time. Using this, I was able to prevent every single frame from every single layer exporting, I was able to only export the necessary frames.

This is how it works: (this goes in the if block that tests if a layer ID is real)

NOTE: This solution makes use of a function that someone on the TVPaint forums wrote. It’s helpful for padding a frame number out to have the right number of digits. To include a function, just add it at the end of the script, after all the main code.

[code]FOR i = frameIn TO frameOut
//Use i to check exposure info on the current frame
tv_exposureinfo i
IF (CMP(result,“Head”) == 1)
//Head means that there’s a new key, so this frame should be exported
// Make a filename for this frame
name = string_addZeros(’_’,i,5)
filename = ‘"‘projname’‘layerName’‘name’.png"’
tv_savesequence filename i i “Camera”
END
END

//Here’s the addZeros function.
FUNCTION string_addZeros(prefix,digit,length)
LOCAL cur i
length=length1
digit=digit
1
cur = LEN(digit)
length=length-1
FOR i=cur TO length
prefix=prefix"0"
END
prefix =prefix""digit
result = prefix
RETURN result
END[/code]

I think I’ll stop there for now, I have a bit more. Like how to test if a layer or frame are marked with a certain colour and render on that basis. But this is lots to read already, so I’ll post about that another time.

Hope this helps and is clear!
Gary

I was also testing the TVPaint rendering properly today and I have some thoughts about it.

First of all, it seems like TVPaint jobs don’t have the output directory and filename in their job files, even though the plugin file has a full output path (I noticed because when I tried to right click and go to open output the option wasn’t there).
Also this might just be not done yet, but TVPaint jobs don’t have the TVP icon next to them, even though the icon does show up in the list of Submission scripts.

I came across a bug when I had filepaths with spaces in them, it turns out that to make that work you actually need to wrap the sceneFile and outputPath in an extra pair of quotes, this is what I edited it to:

writer.WriteLine( "tv_LoadProject '\""+sceneFile+"\"'" ) ... writer.WriteLine( "tv_SaveSequence '\""+outputPath+"\"' "+startFrame+" "+endFrame )

Though I rewrote it to try be less confusing:

writer.WriteLine( "tv_SaveSequence '\"{}\"' {} {}".format(outputPath, startFrame, endFrame) )

The other thing that I noticed when testing this is that the command renders the whole canvas, not just what’s within the bounds of TVPaint’s camera. There is a parameter you can use to have TVPaint only render what’s in the camera’s frame, but it’s called with a different function, ‘tv_ProjectSaveSequence’.

There are a couple of differences. One has a “Camera” parameter you can use and tv_SaveSequence has an optional interlacing parameter. Also it seems like tv_ProjectSaveSequence can’t save frames that are outside the project’s framerange, it will just prematurely quit the script instead. Unfortunately, since TVPaint doesn’t seem to send out any information that Deadline could parse, there’s no way to catch that this has happened apart from having a script run that checks if all the expected image files exported.
I’ve asked about what the other differences between them on the forums might be. The devs often respond there, so they’ll likely respond and let me know if there’s something else I haven’t caught.

So this is the command that renders the camera view:

writer.WriteLine( "tv_ProjectSaveSequence '\"{}\"' {} {} \"camera\"".format(outputPath, startFrame, endFrame) )

Note that camera has to be wrapped in quotation marks.

Having a tickbox option for whether or not to render the camera in the submission script would be a must for us. Most of the production based renders wouldn’t need it, but it’d be vital for dailies.

Hi Gary,
thanks for your note, they have been really helpful.

I was looking at the bug that occurs when there is a space in the file path, your solution works just fine in a script but when passing it as a command from a terminal:

 "cmd =tv_SaveSequence '"C:\Users\Admin\Documents\Autodesk Application Manager\out_0003"' 3 7"

TVPaint interprets the command as a file path and i get a “can’t open file” error

however, this works (but only in a case where there is no space in the filepath):

 "cmd =tv_SaveSequence C:\Users\Admin\Documents\Autodesk\out_0003 3 7"

Notice that there are no quotes surrounding the filepath, this is because with quotes the command doesn’t work and TVPaint doesn’t throw any error.
I was hoping you would be able to shed some light on this. Thanks.

Oh, that is odd behaviour. I hadn’t seen it before actually, and I tried a few different arrangements but none of them really worked. I’m not sure if there’s a syntax I’m missing or this is an oversight, I’ll try get in contact about it. I have a work around solution that I was going to tell you about anyway, since it’s quite a useful feature for your purposes.

There is an indirect way to pass information to TVPaint. There are two commands called tv_WriteUserString and tv_ReadUserString. They basically allow you to store information into a retained config file that persists from TVPaint session to TVPaint session. You can use the cmd to write information with this or write this information from within TVPaint. You can then read the information with a George script. However, since using the ‘result’ keyword doesn’t work on the command line I haven’t been able to use that to get information outside TVPaint.

Here’s a quick demonstration of how this can work in a George script:

[code]tv_WriteUserString ‘Section’ ‘Line’ ‘I am saved text’
tv_ReadUserString ‘Section’ Line’ ‘default’
tv_warn result

Returns ‘I am saved text’[/code]

Section and line are just parameters that you can arbitrarily decide on. ‘Line’ is essentially just a variable name, and ‘Section’ basically a namespace. It’s best to decide on a section/s to always use like Deadline or DeadlineConfig so that you don’t clash with a user’s variable names. The third parameter sets what string will be stored in the file, and this will be retained even after quitting TVP.
(Also note that the third parameter for ReadUserString is a default value, for if it doesn’t get a result for the section and line parameters supplied)

The reason this is useful here, is that you can use tv_WriteUserString as a cmd and if you don’t wrap the parameters in quotation marks you can still include spaces without errors. So here’s an example of how you might do it:

[code][Export.grg Script]
tv_ReadUserString “Deadline” “ExportPath” “C:/Deadline7/TVPaintCache”
tv_SaveSequence result frameIn frameOut
tv_Quit

[Command for commandline]
“TVPaint Animation 11 Pro (64bits).exe” “cmd=tv_WriteUserString Deadline ExportPath Z:/Export Folder/Scene102” “script=Export.grg”
[/code]

This could potentially allow scripts themselves to be more fixed if you were to instead pass parameters in this way for the changing elements and have the contents of the script relatively unchanged.

Hey there! I went through some of the testing on the updated version of this and it’s working great. I like the dropdown selector for choosing what George procedure to run, it definitely works really well.

To give some feedback, I did forget to tell you about something. Adding the line

tv_AlphaSaveMode "NoPreMultiply"

will enable transparency in an image. There’s a few options that tv_AlphaSaveMode can take, you can see them here. We’ll only need “NoPreMultiply” but I figured I’d link that in case you wanted it, since there is a mode for just exporting an alpha channel with no RGB. In particular this is helpful for using in exportLayers, otherwise individual layers will be exported with a white background.

Also I personally found it was more helpful to copy a lot of the functions from your scripts. I ended up ripping out most of initialisation and then just adding my code at the end for our custom script job. This did also mean I had to change the submission script so it would attach frame information etc. to the job. You may have intentionally tried to block that off to avoid confusing users about why frames wont apply to their custom scripts, but we’ll probably just edit the submission script to keep all that stuff if the final release has it sectioned off.

On that note, is there a planned date for 7.2’s release? We’re wondering if it’ll be ready in time for our production.

Thanks all!

Thanks for the comment Gary, it’s been really helpful. We will make the changes to the TVPaint plugin accordingly. And for the release date for 7.2, we’re hoping sometime in September.

Cheers.

That’s great, should give us enough time to implement it. Glad I could be of help!

Privacy | Site terms | Cookie preferences