I’m in the process of trying to learn Python, so I can do things faster in Nuke.  It’s tough.  I have no experience with computer programming at all, and it’s not really coming naturally to me.  I do have some resources to learn from though.  I thought the best way would be to just dive in and start trying things.  Something that I do all the time is make a projection camera from a tracked camera.  There are similar scripts on Nukepedia, but I thought I’d take a crack at it myself.

The first thing I did was make a list of what I would need my script to do.  So, assuming that I had selected a tracked 3D camera in Nuke, I would want my script to do the following:

-First thing, check and make sure it’s a Camera node.  If it’s not a Camera node, then put up a message saying “This isn’t a Camera’.

-Copy and Paste the Camera, so that the original camera doesn’t get messed up.

-Add in a control panel that allows me to select the frame I want the projection camera set to.  Ideally, this would be in the frame range of my project.  Even better would be a button to allow me to select the current frame.

-Connect the animation to the control panel, so that the control panel actually does something.

-Change the color of the pasted Camera node in the DAG.  I always change my projection cameras to a bright purple color.

-Change the name of the pasted Camera to ‘Projection Camera’, and give it an autolabel so that whatever frame I select, it’ll show up in the DAG.

I was actually able to make this, but I needed a lot of help.  I went to Nukepedia and downloaded a similar Python script.  On Nukepedia there’s a script called copyCamForProj (v3.1) (http://www.nukepedia.com/python-scripts/3d/copycamforproj/) by Marco Leone.  This is a great script, and by downloading it and checking it out, I learned a lot about python scripting.  Basically, I would try to build the tool on my own.  When I would run into problems, I’d refer to Marco’s script to try to help me through it.  If you compare the two scripts, you can see I needed a lot of help, and I’d say that most of this is Marco’s work.  But by the end I had learnt a lot about Python, so it was fairly successful.

So, the first thing is to copy and paste the Camera node.  Nuke does have a python command that allows us to copy a node to the operating system’s clipboard, then paste it back into the DAG.

nuke.nodeCopy('%clipboard%')

nuke.nodePaste('%clipboard%')

We want to change it’s name to Projection Camera, so there’s a command for that:

nuke.selectedNode().setName(‘Projection Camera’)

We’re going to be using the command ‘nuke.selectedNode()’ pretty often.  The good thing is that when you copy and paste a node in Nuke, then the pasted node automatically is selected.  We’ll be making a variable for that expression and put it at the top of the script editor:

n = nuke.selected Node()

Then we’re going to change the set name command to accommodate the expression.

So,

nuke.selectedNode().setName(‘Projection Camera’) becomes:

n.setName(‘Projection Camera’)

Our program now looks like:

#Assign variable to the selected node

n = nuke.selectedNode()

#Copy and Paste the Camera

nuke.nodeCopy('%clipboard%')

nuke.nodePaste('%clipboard%')

#Give it the name 'Projection Camera'

n.setName('Projection Camera')

The next thing to do is to change the node’s colors in the DAG and the Open GL view.

#Change it’s color

n[‘tile_color’].setValue(4278255615)

n['gl_color'].setValue(4278255615)

The color value there is a pretty crazy number, but that’s a hexadecimal number for the RGB values.  If you want to add your own color, the easy way to find the hexadecimal value is to color a node, then run this command in the script editor:

nuke.selectedNode()['tile_color'].value()

It will print out a number that you’ll be able to use in your script.

Once we have that, we want to add the control panel to have our slider on.

n.addKnob(nuke.WH_Knob('projFrame', 'Projection Frame’))

This is a long command, which can be confusing to read.  We’re going to break it up into two lines, one line assigning it to a variable called ‘control’.

#Assign a variable to the new projection frame control 

control=nuke.WH_Knob('projFrame', 'Projection Frame')

#Add the knob for the projection frame control

n.addKnob(control)

Then we want to link the new control panel to the translate, rotate and focal length sliders

#Add in the Projection Frame control to the expressions

n.knob('translate').setExpression("curve(projFrame)")

n.knob('rotate').setExpression("curve(projFrame)")

n.knob('focal').setExpression("curve(projFrame)")

Our tool now works, but it just barely.  We need to add a few things.  The main thing is that we need to make sure that this only works on Camera nodes.  We can do this by adding in a ‘if’ statement.  We can say that if the selected node is a Camera node, then run the commands.  If it’s not, then put up a message to the user.  We can do this by typing:

#Check to make sure that a Camera Node is selected

if (n.Class() == 'Camera2') or (n.Class() == 'Camera'):

  #Copy and Paste the Camera

        nuke.nodeCopy('%clipboard%')

        nuke.nodePaste('%clipboard%')

        #Give it the name 'Projection Camera'

        n.setName('Projection Camera')

        #Change it's color

        n['tile_color'].setValue(4278255615)

        n['gl_color'].setValue(4278255615)

        #Assign a variable to the new projection frame control 

        control=nuke.WH_Knob('projFrame', 'Projection Frame')

        #Add the knob for the projection frame control

        n.addKnob(control)

        #Add in the Projection Frame control to the expressions

        n.knob('translate').setExpression("curve(projFrame)")

        n.knob('rotate').setExpression("curve(projFrame)")

        n.knob('focal').setExpression("curve(projFrame)")

    else:

        nuke.message("This is not a camera node")

Now we can add in a few things that will make it a bit more convenient.  We’re going to get the values of the first frame and last frame of our comp and put those in a list.  We can do that by typing:

    #Assign variable to the shot's first and last frame

    Min_Max = []

    #Get the first and last frame numbers, append these values to the variable

    Min_Max.append(nuke.Root()['first_frame'].value())

    Min_Max.append(nuke.Root()['last_frame'].value())

    print Min_Max

Then in the body of the script, we add in a command to get those values:

#Set the first and last name of the control panel

control.setRange(Min_Max[0], Min_Max[1])

#Assign the first frame of the shot

n['projFrame'].setValue(Min_Max[0])

Then we’re going to add a button on our control panel that will set the value of our Projection Frame slider to the current frame:

#Make the 'Set Current Frame Button

n.addKnob(nuke.PyScript_Knob('curFrameBut', 'Set To Current Frame', 'nuke.thisNode()["projFrame"].setValue(nuke.frame())'))

Last thing is adding in a command to put down a command to write the frame number we’re using in the Camera node:

n['label'].setValue('Frame:[value projFrame]')

So our script will now look like this:

    #Assign variable to the selected node

    n = nuke.selectedNode()

    #Assign variable to the shot's first and last frame

    Min_Max = []

    #Get the first and last frame numbers, append these values to the variable

    Min_Max.append(nuke.Root()['first_frame'].value())

    Min_Max.append(nuke.Root()['last_frame'].value())

    print Min_Max

    #Check to make sure that a Camera Node is selected

    if (n.Class() == 'Camera2') or (n.Class() == 'Camera'):

        #Copy and Paste the Camera

        nuke.nodeCopy('%clipboard%')

        nuke.nodePaste('%clipboard%')

        #Give it the name 'Projection Camera'

        n.setName('Projection Camera')

        #Change it's color

        n['tile_color'].setValue(4278255615)

        n['gl_color'].setValue(4278255615)

        n['label'].setValue('Frame:[value projFrame]')

        #Assign a variable to the new projection frame control 

        control=nuke.WH_Knob('projFrame', 'Projection Frame')

        #Add the knob for the projection frame control

        n.addKnob(control)

        #Set the first and last name of the control panel

        control.setRange(Min_Max[0], Min_Max[1])

        #Assign the first frame of the shot

        n['projFrame'].setValue(Min_Max[0])

        #Make the 'Set Current Frame Button

        n.addKnob(nuke.PyScript_Knob('curFrameBut', 'Set To Current Frame', 'nuke.thisNode()["projFrame"].setValue(nuke.frame())'))

        #Add in the Projection Frame control to the expressions

        n.knob('translate').setExpression("curve(projFrame)")

        n.knob('rotate').setExpression("curve(projFrame)")

        n.knob('focal').setExpression("curve(projFrame)")

    else:

        nuke.message("This is not a camera node")

The last thing is to save this script out as a Python file.  In order for Nuke to import this command for it to use, we need to add in two lines at the top:

import nuke

def makeProjectionCam():

Now we want to add this so that every time Nuke runs, we can use this script.  So we need to add the following to our menu.py file:

import makeProjectionCam

nuke.toolbar('Nodes').addMenu('Downloaded Gizmos’).addCommand('3D/Projection Camera', 'makeProjectionCam.makeProjectionCam()', 'shift+V')

This will create a new menu item in Nuke that’s linked to the Python script.

Hopefully you found this helpful.  If you have any tips on making it better, please leave a comment, I need all the help I can get.

Below is a video, showing the tool in action: