Thanks Erwan! Good advice, as-per-usual.
Forum Posts
Yeah, it's still annoying though because you have to iterate over all the knobs, and if any user knobs are found, you have to recreate them somehow.
The
The
nuke.createNode("Read", source.writeKnobs(nuke.WRITE_USER_KNOB_DEFS | nuke.WRITE_NON_DEFAULT_ONLY | nuke.TO_SCRIPT), inpanel=False)
method handles all that for you.So, I'm still randomly plagued by Nuke's annoying "ValueError: A PythonObject is not attached to a node" error, but in this case, I'm not able to stifle it with a try/except VaueError.
This time, I'm creating a temporary node and deleting it shorlty thereafter, but I get an error when it's a Read node (exr) because of nuke's built in readviewscheck callback.
Simple repro:
How can I suppress the error?! (Happens in Nuke 11.1v3 as well.)
This time, I'm creating a temporary node and deleting it shorlty thereafter, but I get an error when it's a Read node (exr) because of nuke's built in readviewscheck callback.
Simple repro:
# First, load some footage with a Read node named "Read1"
source = nuke.toNode("Read1")
# Now, let's duplicate it
new_read = nuke.createNode("Read", source.writeKnobs(nuke.WRITE_USER_KNOB_DEFS | nuke.WRITE_NON_DEFAULT_ONLY | nuke.TO_SCRIPT), inpanel=False)
# Do stuff
print new_read.name(), new_read['file'].value()
# Now just delete the node
nuke.delete(new_read)
# Result: Traceback (most recent call last):
File "/mnt/tools/binlinux/apps/D2Software/Nuke10.0v6/plugins/nukescripts/readviewscheck.py", line 98, in <lambda>
QTimer.singleShot(0, lambda: checkReadNodeViews(read))
File "/mnt/tools/binlinux/apps/D2Software/Nuke10.0v6/plugins/nukescripts/readviewscheck.py", line 68, in checkReadNodeViews
views = getViews(read)
File "/mnt/tools/binlinux/apps/D2Software/Nuke10.0v6/plugins/nukescripts/readviewscheck.py", line 36, in getViews
if read['disable'].value():
ValueError: A PythonObject is not attached to a node
How can I suppress the error?! (Happens in Nuke 11.1v3 as well.)
you may want to try 11.1v3 or the latest 11 beta.
Otherwise, you should report the error to support:
https://support.foundry.com/hc/en-us/requests/new?ticket_form_id=91115]
Otherwise, you should report the error to support:
https://support.foundry.com/hc/en-us/requests/new?ticket_form_id=91115]
I ran into this problem and even though this thread is old, since there aren't any solutions posed, I thought I would add mine for the next person looking for this answer.
Also, since the name column only returns "0.0", that is included to.
Also, since the name column only returns "0.0", that is included to.
# Select track node first
tracker = nuke.selectedNode()
tracks = tracker['tracks'].toScript().split('\n {')[1:]
track_count = len(tracks)
for idx in range(track_count):
track_name = tracks[idx].split('"')[1]
print track_name
Oh, so close :)
I tried the resize method yesterday, but on an array knob, and ran into the error described here https://community.foundry.com/discuss/topic/129852/nuke-python-panel-array-knob-cannot-resize-nuke-10-0, so I gave up. I guess the range knob is the way to go.
I tried the resize method yesterday, but on an array knob, and ran into the error described here https://community.foundry.com/discuss/topic/129852/nuke-python-panel-array-knob-cannot-resize-nuke-10-0, so I gave up. I guess the range knob is the way to go.
:(
I was still hoping for the 4 values where A<B<C<D with the visual feedback like the keyer, only better ;)
It's probably not possible right now, but was hoping there was some qt magic to resize the Keyer_Knob.
I was still hoping for the 4 values where A<B<C<D with the visual feedback like the keyer, only better ;)
It's probably not possible right now, but was hoping there was some qt magic to resize the Keyer_Knob.
Why is the keyer's range control widget so huge? Whenever I add it to a custom gizmo's control panel, it hogs up a lot of the property bin's real estate. Is there any way to shrink it down or build a custom one with PySide QT?
The example here would do if there was a widget similar to range that could set the A B C D trapezoid values on the keyer.
http://tylerart.com/sketchbook/22/12/2015/pyside-widgets-inside-a-nuke-gizmo
The example here would do if there was a widget similar to range that could set the A B C D trapezoid values on the keyer.
http://tylerart.com/sketchbook/22/12/2015/pyside-widgets-inside-a-nuke-gizmo
I'm learning to use the blink script node, and was wondering if there's a way print intermediate variable values or get other debugging feedback?
I've been looking into logging nuke's errors to a file, but so far am unsuccessful.
I've tried a method based on:
http://kwblog.two3dmonkeys.com/?p=193
which basically reuses the built in functions nuke.stderr_redirector(out) and nuke.output_redirector(out), but I get an error when I launch nuke
ERROR:root:Traceback (most recent call last):
Child returned 1
I've also tried simply overriding sys.stdout and sys.stderr to point to a file as explained in one of these answers:
https://stackoverflow.com/questions/4675728/redirect-stdout-to-a-file-in-python
No error is thrown this time, but nothing is written to the file that gets created either.
Has anyone gotten this to work? Anyone know why the Foundry doesn't provide a mechanism for this natively? Seems like a developer friendly tool like Nuke should have this out of the box, ideally driven by an environment variable.
I've tried a method based on:
http://kwblog.two3dmonkeys.com/?p=193
which basically reuses the built in functions nuke.stderr_redirector(out) and nuke.output_redirector(out), but I get an error when I launch nuke
ERROR:root:Traceback (most recent call last):
Child returned 1
I've also tried simply overriding sys.stdout and sys.stderr to point to a file as explained in one of these answers:
https://stackoverflow.com/questions/4675728/redirect-stdout-to-a-file-in-python
No error is thrown this time, but nothing is written to the file that gets created either.
Has anyone gotten this to work? Anyone know why the Foundry doesn't provide a mechanism for this natively? Seems like a developer friendly tool like Nuke should have this out of the box, ideally driven by an environment variable.
I have a timeline that I would like to export showing each clip's shot name and frame # using the burnin gizmo.
In version 9 I was able to use an expression to pull the shot name from a tag and the frame # from the metadata, but this is not working in NukeStudio 10.0v4.
When I view the metadata, the shot_name tag/key (>) is under some nested folders (+):
The expected syntax for getting the shot_name value isn't working in the burnin gizmo or softeffect:
/User/Tags/clip\\ naming/shot_name/shot_name
Furthermore, we would like our lower right corner to show the frames number with "x" prefix ("x ####"). using "input/frame" gets the correct value, but I can't add the "x" in front of it.
In version 9 I was able to use an expression to pull the shot name from a tag and the frame # from the metadata, but this is not working in NukeStudio 10.0v4.
When I view the metadata, the shot_name tag/key (>) is under some nested folders (+):
+ User
+ Tags
+ clip naming
+ shot_name
> shot_name
The expected syntax for getting the shot_name value isn't working in the burnin gizmo or softeffect:
/User/Tags/clip\\ naming/shot_name/shot_name
Furthermore, we would like our lower right corner to show the frames number with "x" prefix ("x ####"). using "input/frame" gets the correct value, but I can't add the "x" in front of it.
Since there's no response here, I've logged a bug with Foundry Support (#27174)
I'm trying to add a menu at the top of the Nodes toolbar, but no matter what I do, the icon always gets added to the bottom.
Consider this code:
It should add the Blur icon on a menu at the top of the toolbar, but it doesn't.
Consider this code:
menubar = nuke.menu('Nodes')
m = menubar.addMenu("NewMenu_0", icon='Blur.png', index=0)
It should add the Blur icon on a menu at the top of the toolbar, but it doesn't.
you pretty much have it. just use "self." instead of "newpanel."
Ok, so since the goal of having the node selection was to relatively lock the position of the input0 to the node I went with this which does the trick.
Then I thought, well, what about relatively locking the position of any node? I should be able to do something like this:
Notice, the only difference here is that I'm getting the name of input0 specifically and returning the node with nuke.toNode(). This could be a function that returns any node though so we could link adjacent nodes that aren't connected for example.
The weird thing is, now there's an expression link that shouldn't be there. We would rather not have this expression link show up because it's distracting and falsely leads the artist to believe there's an expression when there isn't.
Any ideas why this might be happening? Any ways around it?
c="""
k = nuke.thisKnob()
if k.name() in ['xpos', 'ypos']:
n = nuke.thisNode()
d = n.input(0)
d.setSelected(True)
"""
s = nuke.createNode('Dot')
m = nuke.createNode('NoOp')
m.setInput(0, s)
m['knobChanged'].setValue(c)
Then I thought, well, what about relatively locking the position of any node? I should be able to do something like this:
c="""
k = nuke.thisKnob()
if k.name() in ['xpos', 'ypos']:
n = nuke.thisNode()
d_name = n.input(0).name()
d = nuke.toNode(d_name)
d.setSelected(True)
"""
s = nuke.createNode('Dot')
m = nuke.createNode('NoOp')
m.setInput(0, s)
m['knobChanged'].setValue(c)
Notice, the only difference here is that I'm getting the name of input0 specifically and returning the node with nuke.toNode(). This could be a function that returns any node though so we could link adjacent nodes that aren't connected for example.
The weird thing is, now there's an expression link that shouldn't be there. We would rather not have this expression link show up because it's distracting and falsely leads the artist to believe there's an expression when there isn't.
Any ideas why this might be happening? Any ways around it?
Unfortunately, Michael's solution has similar quirkiness. Selecting the first time seems to work, but reclicking the node deselects the input.
from PySide import QtCore
def setSelected(n, k):
n.input(0)['selected'].setValue(k.value())
c="""
k = nuke.thisKnob()
if k.name() == 'selected':
n = nuke.thisNode()
print n.name(), n.input(0).name(), k.value()
QtCore.QTimer.singleShot(0, lambda :setSelected(n,k))
"""
s = nuke.createNode('Dot')
m = nuke.createNode('NoOp')
m.setInput(0, s)
m['knobChanged'].setValue(c)
So, let's say we want to select a slave node whenever a master node is selected. For simplicity we will make the slave the input(0) of the master node. The following knobChange callback on the "selected" knob should work:
Of course it's not as simple as that, so let's try with a redundant thread calling back into the main thread
Closer, but it only really registers when the mouse click is down or if the node's position is changed.
I've also tried an UpdateUI callback, but get the same result.
What's going on here? Why won't the slaved node keep it's select value?
c="""
k = nuke.thisKnob()
if k.name() == 'selected':
n = nuke.thisNode()
print n.name(), n.input(0).name(), k.value()
n.input(0)['selected'].setValue(k.value())
"""
s = nuke.createNode('Dot')
m = nuke.createNode('NoOp')
m.setInput(0, s)
m['knobChanged'].setValue(c)
Of course it's not as simple as that, so let's try with a redundant thread calling back into the main thread
import thread
c="""
k = nuke.thisKnob()
if k.name() == 'selected':
n = nuke.thisNode()
print n.name(), n.input(0).name(), k.value()
thread.start_new_thread(nuke.executeInMainThread, (n.input(0)['selected'].setValue, (k.value())))
"""
s = nuke.createNode('Dot')
m = nuke.createNode('NoOp')
m.setInput(0, s)
m['knobChanged'].setValue(c)
Closer, but it only really registers when the mouse click is down or if the node's position is changed.
I've also tried an UpdateUI callback, but get the same result.
What's going on here? Why won't the slaved node keep it's select value?
For other people's benefit, I'm commenting on this old thread to confirm Wouter is right to avoid the external pyseq module.
I had been using pyseq to check for missing frames but it's pretty slow, taking about 1.5 seconds to check a single sequence. This adds up quick if you're checking several sequences as I was.
Also, I wanted to allow my function to be usable outside nuke, so I'm using a similar "glob" method as mentioned by Dimitri rather than the "evaluate(frame)" method Wouter mentioned. Now it takes less than .3 seconds to check the same sequence.
I had been using pyseq to check for missing frames but it's pretty slow, taking about 1.5 seconds to check a single sequence. This adds up quick if you're checking several sequences as I was.
Also, I wanted to allow my function to be usable outside nuke, so I'm using a similar "glob" method as mentioned by Dimitri rather than the "evaluate(frame)" method Wouter mentioned. Now it takes less than .3 seconds to check the same sequence.
Hello!
Simple task: We want to distinguish PostageStamps from Reads by building them with an input Dot automatically. I wrote a custom build_postage_stamp function to do this, but have a problem centering the incoming dot above the PostageStamp? The code I have will not get the proper values for the node screenWidth().
Other posts mention calling the xpos() function on the nodes to gets it closer, but the dot's screenWidth still seems to not update.
Sorry for the large amount of code for such a simple task, but I've made reusable functions for common tasks and want my repro to be accurate to my case.
Simple task: We want to distinguish PostageStamps from Reads by building them with an input Dot automatically. I wrote a custom build_postage_stamp function to do this, but have a problem centering the incoming dot above the PostageStamp? The code I have will not get the proper values for the node screenWidth().
Other posts mention calling the xpos() function on the nodes to gets it closer, but the dot's screenWidth still seems to not update.
Sorry for the large amount of code for such a simple task, but I've made reusable functions for common tasks and want my repro to be accurate to my case.
def last_clicked_position():
"""
returns the x and y coordinates of the last position clicked by the user
"""
selection = nuke.selectedNodes()
[n.setSelected(False) for n in selection]
temp = nuke.createNode("Dot")
xy = [0, 0]
try:
xy = [temp.xpos(), temp.ypos()]
except:
pass
finally:
nuke.delete(temp)
[n.setSelected(True) for n in selection]
return xy
def place_in_y(node, reference_node, spacing=150, centered=True):
"""
Move node's position to be next to reference_node vertically, offset by the spacing amount
"""
# Refresh dag properties
node.xpos()
reference_node.xpos()
spacing = int(spacing)
if centered:
node.setXpos(int((reference_node.xpos() + (reference_node.screenWidth() / 2)) - (node.screenWidth() / 2)))
if spacing == 0:
node.setYpos(reference_node.ypos())
else:
node.setYpos(int(reference_node.ypos() + ((reference_node.screenHeight() + spacing) if spacing > 0 else spacing)))
def build_dot(name="", label="", xy_pos=None, input_node=None):
dot_node = nuke.nodes.Dot()
if name:
dot_node.setName(name)
if label:
dot_node['label'].setValue(label)
if input_node:
dot_node.setInput(0, input_node)
if not xy_pos:
xy_pos = last_clicked_position()
dot_node.setXYpos(xy_pos[0], xy_pos[1])
return dot_node
def build_postage_stamp(input_node=None, hide_input=False, lock_input=False):
"""
This builds a postage stamp with an incoming dot to help distinguish it from a standard Read node.
"""
if not input_node:
input_node = nuke.selectedNode() if nuke.selectedNodes() else None
nukescripts.clear_selection_recursive()
ps = nuke.nodes.PostageStamp()
ps['postage_stamp'].setValue(True)
dot_label = ''
xy_pos = last_clicked_position()
if input_node:
input_name = input_node.name()
dot_label = input_name
dy = xy_pos[1]-input_node.ypos()
if (abs(dy)+17) < 20:
dy = -50 if dy < 0 else 50
xy_pos[1] += dy
ps.setXYpos(*xy_pos)
dot_name = 'Dot_{}'.format(ps.name())
dot = build_dot(dot_name, dot_label, input_node=input_node)
dot.setSelected(False)
ps.setInput(0, dot)
dot['hide_input'].setValue(hide_input)
ps.xpos()
dot.xpos()
place_in_y(dot, ps, -25, True)
lock_input_relative_position(ps)
if lock_input:
lock_inputs(dot)
return dot, ps
# This is not working?
build_postage_stamp()
# Then why does this work?
ps = nuke.nodes.PostageStamp()
dot = nuke.nodes.Dot()
ps.setInput(0, dot)
place_in_y(dot, ps, -25, True)
Thanks Wouter!
It was finding the derivative that I was missing. I reduced the expression on the rotation knob to this:
(translate.x.derivative>=0 )?(translate.x.derivative==0 && translate.y.derivative==0)?rotate(t-1):degrees(atan(translate.y.derivative/translate.x.derivative)):180 + degrees(atan(translate.y.derivative/translate.x.derivative))
This orients the rotation based on the nodes translation. Spot on.
It was finding the derivative that I was missing. I reduced the expression on the rotation knob to this:
(translate.x.derivative>=0 )?(translate.x.derivative==0 && translate.y.derivative==0)?rotate(t-1):degrees(atan(translate.y.derivative/translate.x.derivative)):180 + degrees(atan(translate.y.derivative/translate.x.derivative))
This orients the rotation based on the nodes translation. Spot on.
How do I align an object along the curve generated by it's position?
say I have an arrow moving along a random path, how do i make the arrow always point forward in it's direction?
say I have an arrow moving along a random path, how do i make the arrow always point forward in it's direction?
Hey Dimitre, that is pretty good and definitely fast, but since it depends on the play-head's frame, it's unreliable. What if the rendered frame is 1001, but the play-head is on 1100?
I found the pyseq module calls pretty quick and easy to use, so here's what I ended up coming up with:
I found the pyseq module calls pretty quick and easy to use, so here's what I ended up coming up with:
import pyseq
import os.path
def get_rendered_frames(write):
# Return the list of file rendered image paths of the given write node
filepath = write['file'].toScript()
filename = os.path.basename(filepath)
render_dir = os.path.dirname(filepath) + os.sep
seqs = pyseq.get_sequences(render_dir)
for seq in seqs:
head, padding, tail = seq.head(), seq.format("%p"), seq.tail()
if not (filename.startswith(head) and filename.endswith(tail)):
# This is not the sequence you're looking for
continue
return ["{folder}{head}{frame}{tail}".format(folder=render_dir, head=head, frame=padding%f, tail=tail) for f in seq.frames()]
return []
def get_missing_frames(write, start=None, end=None):
# Return the list of file rendered image paths of the given write node
filepath = write['file'].toScript()
filename = os.path.basename(filepath)
render_dir = os.path.dirname(filepath) + os.sep
seqs = pyseq.get_sequences(render_dir)
for seq in seqs:
head, padding, tail = seq.head(), seq.format("%p"), seq.tail()
if not (filename.startswith(head) and filename.endswith(tail)):
# This is not the sequence you're looking for
continue
if start and end:
missing = []
for f in range(start, end+1):
framepath = "{folder}{head}{frame}{tail}".format(folder=render_dir, head=head, frame=padding%f, tail=tail)
if not os.path.exists(framepath):
missing.append(framepath)
else:
missing = seq.missing()
if missing:
return missing
return []
Hey Nuke Gurus... (Nukurus?) riddle me this (what should be simple) question:
Write nodes understand frame padding, but AFAIK there's no built in way to check if a write node has been rendered and has files existing.
Some os.path.exists equivalent for nuke would be lovely like:
nuke.path.exists(write_node)
So, there are a bunch of ways I could approach this, but I'm curious how others have done it and what's most efficient?
pyseq?
os.listdir?
glob?
iterate over frame range?
I don't even really care if all the files are present as there may be cases when a still frame is rendered from a write node set to render a frame range, but I would want to know that that frame exists.
What's your favorite way to verify a render?
Write nodes understand frame padding, but AFAIK there's no built in way to check if a write node has been rendered and has files existing.
Some os.path.exists equivalent for nuke would be lovely like:
nuke.path.exists(write_node)
So, there are a bunch of ways I could approach this, but I'm curious how others have done it and what's most efficient?
pyseq?
os.listdir?
glob?
iterate over frame range?
I don't even really care if all the files are present as there may be cases when a still frame is rendered from a write node set to render a frame range, but I would want to know that that frame exists.
What's your favorite way to verify a render?
try using a new thread to reach back in to the main thread
example:
import thread
thread.start_new_thread(nuke.executeInMainThread, (panel.show, ()))
example:
import thread
thread.start_new_thread(nuke.executeInMainThread, (panel.show, ()))
Hmm, I guess this isn't set automatically. I found it buried in our callbacks, so I've just added a version check to make sure the correct knob (colorManagement in nuke 10) is being set.