As I continue to use Nuke in ways in which it was never intended to be used (read: motion graphics), I keep finding small bits of friction that I just can't help but remove with app customizations.
My latest annoyance stems from an animated project that involved more traditional motion-graphics-style animation than the typical interface design and animation I usually create. I built all the graphic assets I would need for the video ahead of time, then assembled and animated them into a sequence, entirely in Nuke.
Again and again, I would merge a new graphic asset onto my shot, and I would have to do some math to figure out how to transform it into the center of the frame. Since the origin (0,0) of a Nuke frame is the bottom left corner, by default, images show up in the lower left of the frame rather than the center. Which is not what I want.
So, I'd add a Transform to the asset and move it to the center of the 1920 x 1080 frame. Since I care about precision, I didn't just eyeball the transform. I want it to be exact.
As long as I add a Transform to a graphic element with the upstream node selected, the Transform will detect the width and height of the asset and place the transform jack in the center of the object. As a Nuke user, you already knew that.
Then, I place my cursor in the x translate
parameter box and type 1920/2 -
whatever value was in the x center
position, as determined by the upstream node. I repeat this process for the y translate
parameter, using 1080/2
to match the frame's height.
And lo, we have discovered another simple, math-based operation, prone to human error, ripe for automation. The formula is simple:
- The
x translate
parameter should be defined as half theframe width
minus half theasset width
. - The
y translate
parameter should be defined as half theframe height
minus half theasset height
. - If we have added the Translate node directly to the asset — which is to say we have not added it to our script unconnected — the
x center
andy center
parameters will be automatically filled with the half-width and half-height values of our asset.
In Nuke Python, this formula would be expressed as:
n = nuke.thisNode()
# Get the x and y values of the Transform's center point
xVal = n['center'].value(0)
yVal = n['center'].value(1)
# Get the width and height of the frame format
rVal = nuke.Root()
xfVal = rVal.width()
yfVal = rVal.height()
# Define the variables to set the translate values
txVal = n['translate'].value(0)
tyVal = n['translate'].value(1)
# Find difference between center of frame and center of transform
cxVal = xfVal/2-xVal
cyVal = yfVal/2-yVal
# Translate to center of frame format
n['translate'].setValue(cxVal, 0)
n['translate'].setValue(cyVal, 1)
Next, we take that nicely formatted Python script and shove it into an addOnUserCreate
function within our Menu.py file thusly:
def OnTransformCreate():
nTR = nuke.thisNode()
if nTR != None:
script="n = nuke.thisNode(); xVal = n['center'].value(0); yVal = n['center'].value(1); rVal = nuke.Root(); xfVal = rVal.width(); yfVal = rVal.height(); txVal = n['translate'].value(0); tyVal = n['translate'].value(1); cxVal = xfVal/2-xVal; cyVal = yfVal/2-yVal; n['translate'].setValue(cxVal, 0); n['translate'].setValue(cyVal, 1);"
k = nuke.PyScript_Knob('center_trans', 'Center Transform')
k.setCommand(script)
nTR.addKnob(k)
nuke.addOnUserCreate(OnTransformCreate, nodeClass="Transform")
Now, every Transform node created will have a nice big "Center Transform" button added to it automatically.
So, when I bring in a 584 x 1024 graphic asset like, say, this:
And I merge it over a 1920 x 1080 background...
...add a Transform node — which will find the center point to be (292,512)
All I have to do to center my graphic asset is click this button...
...and boom. Automated.
