Dec 14, 2012

Nuke tcl tips

I have a lot of tcl expressions, and other nuke snippets written down, because always forget these. I decided to share some. In general I can say tcl in nuke is very flexible and quick for simple tasks.
For expression testing the expression I use the text node, easier than always getting into the specific knob, and click edit expression.
So first come the tcls in knob expressions, with examples:

Getting a knob's value of a specific node:
[value Read1.first]

Getting a knob's value of current node:
[value this.size]

Setting a knob's value of a specific node:
[knob Read1.first 10]

First frame of current read/write:
[value this.first_frame]

Setting a general tcl variable :
[set variablename value]
for example (tsize is the variable name):
[set tsize 15]

Using that variable later (notice the "$") for setting a knob value:
[knob this.size $tsize]

Name of the input node:
[value this.input.name]

Expressions in a group going outside (to parentgroup or root). This example gives the name of the node before the group:
[value this.parent.input.name]


String substitute and compare:

Replace string in current node file knob with regex (string "proj" to "projects" in all occurences):
[regsub -all "proj" [value [node this].file] "projects"]

String map (replace multiple stringpairs):
[string map {"aa" "xx" "bb" "yy"} "aaffffaabb" ] this returns: xxffffxxyy

Compare values:
[string equal [value Text1.message] "bla"]

Regexp matching:
[regexp -inline "_v\[0-9]{3}" [value Read2.file]]


Path manipulations:

Filepath without extension:
[file rootname [value [topnode].file]]


Filename only:
[basename [value [topnode].file ]]


Filename only without extension:
[basename[file rootname [value [topnode].file]]]


This one splits the uppermost node's (probably a readnode) filepath by slashes and then joins together until a certain point, giving a directory few levels upper than the currrent path). "File split" does the splitting, making a list of directory names, "lrange ... 0 7 "selects a range from the list, from the beginning to the 7. item, and "join ... / " joins by forward slashes (which I use always in paths):

[join [lrange [file split [value [topnode].file]] 0 7] /]


This one can be used in a writenode fileknob to quickly convert the topmost readnode's path to another format(tga). Similar to the previous, but splits path by "." (different than previous file split), and gets the range from the beginning to 2 before the end, this way cutting off the extension and the counter (framecounter must have preceeded by a "." ) :

[join [lrange [split [value [topnode].file] .] 0 end-2] .].%04d.tga
(I use similar to make the comps writenode have the output path automatically getting from path of the nukescene )

Other useful:

Get the value the channel of a node, at a specific pixelcoordinates (e.g.: 10,10):
[sample [node input] red 10 10]

Setting a variable, without returning that (useful in a textnode):
[set seq [value Read1.file]; return]


Example of "IF" in an expression:
[if {condition} {expr1} else {expr2}]
for example:
[if {[value Switch1.which]==1} {return "aaa"} {return "bbb"}]

to be continued...


Sep 6, 2012

Applauncher - setting environment for apps

Hi, sorry for not posting for a long time. But this one is really interesting! Earlier this year we had a job to recreate a character that we used in Eset commercial. It would have been an easy thing, because we had the asset, but the arnold renderer, and shaders are changed a lot since last summer. And the config wasn't backed up properly with the project. This gave the idea that we should re-think our current application-environment-management system (what an expresssion:)
Until that point, for maya we had a lot of scripts, icons, shelves on the fileserver, that accessible for every maya; and with plugins/modules on the local machine (if it would be also on fileserver, the plugins we develop can't be updated if someone is using maya loaded that plugin.) For starting maya, artists were using a custom batchfile that copies needed plugins to local, sets some environment variables, and launches. But almost everything was hard-coded to maya.env and the batchfile.
It worked to point, but wasn't effective nor elegant. So we came up with the idea of Applauncher.
Here I give a little insight about this software, maybe useful for some of you thinking about similar solution.
It is a gui for starting maya, and nuke with the proper environment. In short: in the gui the artist chooses the project (show) and the context (lighting, dynamics, animation etc.) he/she wants to work. Then applauncher copies the needed scripts, plugins, modules etc., sets the environments and launches the application.
What is needed for the given context is stored on the network in an xml file, that is easy to edit and read. It's created by sup. before the show starts, but of course can be modified later. In the xml we define what addontype (scipts, modules etc), what addon with what version is in that environment config.
So when user chose context, and clicked on launch, the needed content (plugins, scripts etc) are copied to local disk, or if that content is already there, the copy process can be skipped. After copy, depending on addontypes the proper environment variables are set.
For maya we use following addontypes: modules, scripts, shelves, icons, additional envvars. All plugins are stored in modules: that is the most flexible type of addon.
For nuke we use much more type of addons, that are differently set for the software: gizmos, scripts, plugins, icons, luts, modules, ofx, prefs etc.
Important that on the server-side the addons are versioned, but on local they are not. Always the actual version of the addon (defined in xml) is copied.
We don't make separate addon for each gizmo, or script, it would be hard to version and manage them. Rather we chose to group them along some common attribute. For example my script package for maya is 1 addon. The other developer's scripts are another addon.

Example structure in xml, for maya:

addonGroup: modules
addon:commonscriptpack
version: 1.0
addon: userscriptpack1
version: 1.1
addon: userscriptpack2
version: 1.5
addon: yeti
version: 1.0
addonGroup: shelves
addon: lighting
version: 1.3
...
Now every artist at us uses this little gui without problems. The advantages: 1. we can restore any working environment at any time 2. much faster app. loads. 3. easier distribution of tools. I even integrated it with deadline, it was a must to run renders with same environment as the artists.
I hope this writing was understandable, and useful. If needed, I can continue telling more about this, because I think it has really nice logic, and features, that now is proven to be very useful.
Further reading on this theme in these topics: 1 2 3



Jun 14, 2012

Submit nuke render job with specific views for deadline

Hi, I posted this on deadline forums, I thought it would be on a good place here too.
In this post I describe what files to edit in the deadline repository, if you want to submit not all, but specific view(s) from a multiview (stereo) nuke scene to deadline. The modification include the nuke submitter dialog, where user can check which views to render, and the nuke plugin file. Hope it helps someone. By the way it is for deadline 5.0, the exact solution for other versions may be different.


Submission/SubmitNukeToDeadline.py, gui declaration in __init__ somewhere append this:

1:   self.viewToRenderLabel = nuke.Text_Knob( "separator31", "Views to render:" )   
2:   self.addKnob( self.viewToRenderLabel)   
3:   self.views = nuke.views()   
4:   self.viewToRenderKnobs = []   
5:   for x, v in enumerate(self.views):   
6:    bknob = nuke.Boolean_Knob(('viewToRender_%d' % x), v)   
7:    bknob.setFlag(0x1000)   
8:    self.viewToRenderKnobs.append((bknob, v))   
9:    self.addKnob(bknob)   
10:   bknob.setValue(True)   


Still SubmitNukeToDeadline.py, in SubmitJob function, where writing into plugin info file, for example after: "fileHandle.write( "NukeX=%s\n" % dialog.useNukeX.value() )"


1:  viewsToRender = getSelectedViews()  
2:  viewsToRender_str = ','.join(viewsToRender)  
3:  print 'Views to render in plugin info file: %s' % viewsToRender_str  
4:  fileHandle.write( "viewsToRender=%s\n" % viewsToRender_str )  




Still SubmitNukeToDeadline.py, at the end, a new function to get list of views from submitter dialog (that the user selected) write this:

1:  def getSelectedViews():  
2:   global dialog  
3:   x = 0  
4:   viewsToRender = []  
5:   for vk in dialog.viewToRenderKnobs:  
6:    if vk[0].value():  
7:     viewsToRender.append(vk[1])     
8:   x+=1  
9:   print '\nViews to render: %s\n\n\n ' % viewsToRender  
10:  return viewsToRender  


-------
In plugins/ nuke.py file in RenderArgument function, just before return append this:


1:  viewsToRender = GetPluginInfoEntryWithDefault( "viewsToRender", "" )  
2:  if viewsToRender != '':  
3:   LogInfo( "==VIEWS==\nUsing " + viewsToRender + " view(s) for rendering\n" )  
4:   renderarguments += " -view \"" + viewsToRender + "\""   

And that's it. It's even logging the views to be rendered.
Cheers,
Gabor

May 24, 2012

Licensing

Hi,
I've been a big fan of the Foundry nuke user mailing list for years now. I strongly suggest reading that for everyone using nuke, there are interesting topics every day, the best resource to find solution to a problem.
But this is not an advertising here. A few weeks ago I read a topic in this list, where a guy, posted a pythonscript as a solution for something. This script was written by me before, even my commented lines were there. Every character is the same with a script that I posted here before. And in that mail at the mailing list there wasn't any indication that it was not written by him, but someone else. True he didn't say he wrote it, either.
I don't expect much first because these that I share here are not the best top-notch scripts/gizmos man has ever created, but I try to do my best. And I didn't put any legal notice into my scripts, until this point. But even with these things, I expected a little mentioning if someone is using my creations to help others, even if these are tiny scripts. Something like, "okay, this is from a blog" Not even have to point to this blog, but something...
Ok, no more crying :)
So from now on, I put a copyright text on the blog, at links menu. Of course nothing else will change, I will post my tools as I can.
Hope this post doesn't bothers you, I just had to do.
Cheers,
Gabor

Copyright

Copyright for all the scripts, source codes, and other kind of software extensions in this blog are under New BSD license, unless otherwise noted:


Copyright (c) 2010 till present, Gabor L. Toth (thoughtvfx.blogspot.com)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the thoughtvfx nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

May 5, 2012

10k

Okay, so we reached 10000 pageviews! (Of course not in a month or week, but all-time ) I know it's not a big thing, but for me it is. Thanks for everybody, I hope this blog could have been (and will be) useful for you! Come back more often, as I try to post even more often and on even more interesting topics. And if you find useful stuff here, and you can refer to this blog (on your own blog, anywhere), please do!

Thanks,
Gabor

May 3, 2012

Nuke multiple views in read nodes

Hi,

I had a little problem not long ago, with setting stereo sequences in readnodes. No problem when the filepaths of views differ only in the view names, like BH_010_left.%04d.dpx and BH_010_right.%04d.dpx. Then you can use "%V" as wildcard for view name. But unfortunately our 3d guys was giving me renders where the 2 view are different in version number, like BH_010_v005_layer1.beauty.%04d.exr and BH_010_v006_layer1.beauty.%04d.exr.
(We have redesigned our cg output system to handle this since then, but I share this experience anyway ) The problem is that the file knob in the readnode is capable of splitting for views (split a knob = make different values for different views in the same knob), but the automatic path manipulator tools, like version up-down script, search and replace, that are needed to change so many passes in readnodes at once, are not working with splitted filenames, only working on the view that is not splitted off. For example if you split off left, these will work only on right view.
So the workflow to handle readnodes's paths with splitted views: choose 1 view that will be split off, so you won't be able to manipulate (only one by one). Assume this is the "right" view. Put all the readnodes down, set them to desired version for "right" view. Check that you are on the "right" view (in the viewer top line). Then (while all read selected) run this script:

sn=nuke.selectedNodes('Read')
for n in sn:
n['file'].splitView()


This will split off right view in all readnodes. Now change to left view in the viewer, and then change the version (alt+shift up/down), or do search and replace, those will be effecting the left view only (the "unsplitted" view).
If you have to change both view again, (for example new versions rendered for both view) then unsplit the previously splitted view ("right" in this example), with standing on "right" view, and running this little script:

sn=nuke.selectedNodes('Read')
for n in sn:
n['file'].unsplitView()


It will make readnodes normal again, and you can start the process over again :)
Sounds complicated? It's not, just tedious. Of course I could have used separate readnodes for each view (for each pass), but hey, that would be so simple right? (And too many readnodes)

Apr 16, 2012

Deadline - nuke post job script Update

Hi,
recently I had to improve our postjobscript system: I did some code rewrite, now much more elegant. Here I post an example script, that converts the current job's output to half sized exr, and a mov.
These are the changes since the old script that is referred in my old post:
- No more batch file! Running nuke directly.
- Automatically finding the installed nuke from deadline list
- Handling multiple views (currently left-right as viewnames are hardcoded, I need to change that)
- Handling multiple job output sequences

But as usual there can be bugs, so if you find one, please report.
The process to use:
- Put the 2 scripts in a folder somewhere in the deadline repository (for example I use this: DeadlineRepository\scripts\PrePostTaskJobScripts\JobNukeConvert\)
- Edit the JobNukeConvert.py: change the path in line (65) that starts with:
arg= (" -x -F " + framesList + ... to point to the current location of the other python script
- Set the JobNukeConvert.py as a postjobscript from deadline monitor (job properties)
- That's it. It should spit out a half-res. converted exr sequence, and a mov for each job output sequence (will put beside the rendered sequence)
- Of course you need to modify the glt_deadlinepostjobscript_convert.py according to your needs (what kind of formats to convert to etc.), but if you have some knowledge of nuke-python, that can't be that hard. Or maybe I can help...

Let me know if doesn't work for some reason. Or if it does work :) You can donwnload it from here.
I hope someone finds it useful,

Gabor

Apr 8, 2012

New gizmo - PaintTrajectory

Hi,

I was watching some nice motiondesign lately (from Polynoid, great artists) and was wondering how to create nice animating thin lines in 3d space. Or at least how to draw a motionpath of something in 3d. I was experimenting with particles for a while but I found that way slow for this. But the great new python docs comes to rescue! I remembered a 2d solution for drawing a track with a paint node. And another one with projecting a 3d point to screenspace. So almost all credit goes to docs writer(s) (Frank Rueter I assume) I hacked together the 2 scripts, a bit rewrite here and there, and created a gizmo for it.
What is does:
Connect the viewing camera to cam input, and link a (animated) 3d point (that can be seen by the camera) to motionpath knob, and run. Spits out a rotopaint with the trajectory painted. In the paint node on stroke tab, set the pressure alters to size, and uncheck opacity (sorry, do it manually at this time), and you can see that the further the point from camera, the thinner the painted line. Change the brush size to make it thicker. If the bounding box clips the stroke, put a crop before the rotopaint.
Here is a picture showing what I'm talking about:



I hope someone find it useful, you can download it from here.
It's still very alpha, keep in mind.
By the way I plan to copy all my extension to nukepedia soon, just need to find some time to organize them :)

Mar 22, 2012

Data exchange between maya and nuke Part 1

I often need to get cameras, objects, or simply position information between maya and nuke. I show what I usually use for this:

- Objects: most of the time I export an obj sequence from maya with this script. Quite fast, does multiple objects, so does the job I need. I don't really like using fbx in nuke, much slower than obj sequence. But if I want motionblur, unfortunately I have to use fbx. 1 thing: from maya, I use fbx version 2009, nuke seems unable to read newer types.


- Cameras: from maya I use the pass2nuke script from 3dmation mocon package. Usually works great, there were only 1 or 2 times with complicated camera motion when didn't get exact path. (Maybe the problem was with maya camera aperture fitting, but I'm not sure.) You should turn visibility off for everything in the maya scene (to make the export fast) and call this script, and this writes out a .nk script containing the camera, and a transform node (not needed). Actually I use also this for getting simply 3d position information from maya, then I use that transform node that is in the .nk file. (I even wrote a wrapper script around this, so that it automatically bakes a multi-grouped, here-and-there transformed camera to a simple camera, and writes with proper path in our system. This is the simplest way to our artists :) )

If this pass2nuke script is not working for some reason, then I use importExportChan.mel or export to fbx.

Feb 28, 2012

Nuke quick tip: write node with disabled outside of framerange

If you have multiple write nodes in a nuke scene, and want to submit to render all at once, but running on different frame ranges(as their input's framerange), here is a simple expression to put in the write nodes disable knob:
frame < input.first_frame || frame > input.last_frame ? 1 : 0
This way the write node is disabled when current frame is not in the input framgerange. This usually happens to me when converting raw materials for different shots at once.

Feb 27, 2012

Nuke createwritedir script with multiple views

Hi, just jumped into a stereo project, and found that couple things not working properly with nuke. For example the good, ol' createwritedir script, that creates directory before rendering, doesn't handle the '%V' view tag in filenames, so I post here an updated version. This however creates directory for every view, because didn't find a way create them separately, as the script is not called in render for every view, only once.
Here is the code snippet. Sorry for misaligned lines. Anyone knows a better way for displaying code?
 def createWriteDir():  
     import nuke, os  
     import re  
     #view = nuke.thisView()  
     views = nuke.views()  
     file = nuke.filename(nuke.thisNode())  
     dir = os.path.dirname(file)  
     viewdirs = []  
     
     if re.search('%V', dir):    # replacing %V with view name  
         for v in views:  
             viewdirs.append(re.sub('%V', v, dir))  

     if len(viewdirs) == 0:  
         osdir = nuke.callbacks.filenameFilter(dir)  
         if not os.path.isdir(osdir):  
             os.makedirs (osdir)  
     else:  
         for vd in viewdirs:  
             osdir = nuke.callbacks.filenameFilter(vd)  
             if not os.path.isdir(osdir):  
                 os.makedirs (osdir)  
                 print 'Directory (with viewname) created: %s' % (osdir)  
(I edited the script, there was an unnecessary try: except part)

Feb 17, 2012

News: nuke goodie: 3d renderer- nuke connection by J3P

Whoa, second post today! :) But this one really deserves it! Looks like the guys at J3P created a nuke connection to 3d renderers, such as renderman, arnold, etc. Similar to renderman connect. Looks very promising, you can even open .ass files directly in nuke, and read it's content, and even watch the (arnold) rendering in progress, in the nuke viewer.
It's code included in the open-source cortex tools.

Demo video is here.
Feature list:
-Creates a LIVE connection to one OR MORE 3D renderer's/3D package's render stream
-This is NOT a read node loading image passes from disk, it's an open framebuffer
-Start building your comp immediately in Nuke with test render preview framebufers.
-No need to save out images from your 3D package's test render view.
-Launch preview renders from your 3D package directly into a Nuke framebuffer.
-Render exported scenes directly into Nuke framebuffers (Ribs, Arnold, etc...).
-Preview render all AOV's simultaneously and plan which passes you'll need
-Automatically detect all AOVs in scene file -- including custom AOVs
-Turn AOVs on and off *EVEN* if they aren't part of the exported scene file.
-Preview CG elements from different lighters/renderers on same network simultaneously.
-Plan your renders and comps much more efficiently.
-Let lighters know exactly which passes you need before they kick of renders.
-Harness the power of different packages without interrupting workflow.
-Allows for a package agnostic pipeline -- allows lighters to work the way they choose.
-Framebuffers automatically update as soon as a new preview render is kicked off
-Write out comp'd test framebuffers

Latest work: animation for Africa Cup

We created almost 2 minutes long, animated, realistic digital environment for the closing ceremony of the 2012 Football African Cup of Nations. It was projected (with 24 projectors) to a huge area, so the final output size was 6959x2560 pixels! The animation included more than 200 animated (wind blown) trees of specific kinds, a huge waterfall, and a growing big mountain. The work was completed less than 2 months. The animation was created so that it could be looped from a specific point to last longer than 2 minutes. Rendered with Arnold.
Sadly we had very-very little time for compositing, so there are some not so nice parts, but at least we were done in time :)

You can watch here, it starts from 9m 7s, lasts until the gorilla comes in:

Jan 1, 2012

Happy New Year!

I wish everyone a nuke-, blog-post- and vfx-rich Happy New Year!