Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

테드옹의 VFX

Python in Nuke 본문

Nuke

Python in Nuke

Tedd_Kim 2025. 1. 19. 15:35

파이프라인 TD가 되기 위한 베이비스텝 시작..!

https://learn.foundry.com/nuke/developers/140/pythonreference/

 

Welcome to NUKE Python Developer’s Guide — Nuke Python API Reference

© Copyright 2024, The Foundry. Python API Reference for Nuke 14.0v7. Last updated on Feb 09, 2024.

learn.foundry.com

https://learn.foundry.com/nuke/developers/70/pythonreference/

 

Nuke Python API

 

learn.foundry.com

 

[ Must-Know ]

- 특정 클래스의 레퍼런스를 가지고 Tab키를 누르면 사용 가능한 함수들이 나온다

- 혹은 help()함수를 이용할 수도 있다

- 최상위 루트는 nuke.root()로 가져올 수 있다

- Shift + S -> Preference

- Shift + Tab -> 인덴트 삭제

- Ctrl + / -> 코멘트 주석

 

[예시 코드 01 - 노드 순회하기]

for node in nuke.selectedNodes():
    node.knob('postage_stamp').setValue(False)
    node.knob('disable').setValue(True)

 

선택한 노드의 리스트를 가져오는 함수는 Houdini API와 굉장히 비슷하다 ex. hou.selectedNodes()

하지만 밑에서부터는 조금 다른데

 

- node.knob() = node.parm()

- knob.setValue() = parm.set()

 

후기니에서 parm클래스는 누크에서 knob이고 set()함수는 setValue()이다

 

[예시 코드 02 - 노드 만들기]

x = nuke.createNode('BackdropNode', inpanel=False)
x.getNodes() // 백드롭 안에 있는 노드들을 리턴

 

마찬가지로 hou.node('/obj').createNode() 와 비슷한 구조이다

 

 

[예시 코드 03 - 그룹 노드 안쪽을 순회하는 방법]

with nuke.toNode('Group1'):
    nuke.toNode('Transform1')['disable'].setValue(True)
    nuke.toNode('Blur1')['disable'].setValue(True)
    
nuke.toNode('Grad1')['disable'].setValue(True)

nuke.toNode('Group1.Grade1').fullName() // .를 통해 Group안에 있는 Grade1 노드를 가져올 수 있음

 

 

[예시 코드 04 - 노드를 순회할 때 사용할 여러가지 방법]

all_nodes = nuke.allNodes() # hou.allNodes()와 같음

# LBYL : Look Before You Leap
for node in all_nodes:
    if node.knob('which'):
    	node.knob('which').setValue(0)
    else:
    	pass
        
# EAFP : Easier to Ask Forgiveness that Permission
# aka : duck typing
for node in all_nodes:
    try:
    	node.knob('which').set(0)
    except AttributeError:
    	pass

 

파이썬 개발자들은 EAFP방식을 더 선호한다고 한다. (퍼포먼스가 LBYL보다 좋다고 함)

 

 

[예시 코드 05 - 함수 만들기]

def set_tile_color(node, r=1, g=0, b=1):
    """Set the tile_color knob of the node the rgh provided.

    r,g,b values must be between 0 and 1.
    values outside this range will be cliped to 0 and 1.
    """

    r = min(r, 1)
    r = max(r, 0)
    r = int(r * 255)

    g = 1 if g > 1 else g
    g = 0 if g < 0 else g
    g = int(g * 255)

    b = max(min(b, 1), 0)
    b = int(b * 255)

    a = 1 # Alpha
    a = int(a * 255)

    new_color = (r << 24) + (g << 16) + (a << 0) # voodoo magic
    node['tile_color'].setValue(new_color)

n = nuke.toNode('Blur1')

set_tile_color(n, 1,1,1)

 

max(min(value, 1,) 0) 은 자주 쓸 수도 있으니 알아두고

함수를 만들 때는 항상 맨 위에 주석을 다는 습관을 들이자

 

 

[예시 코드 06 - 관련 노드 순회하기]

"""누크는 만약 merge노드에 B, A1, mask, A2, A3 이렇게 연결되어있으면
B, A, mask는 무조건 순서대로 0, 1, 2인덱스 고정이다
그렇기 때문에 merge에 B, A1, A2가 꼽혀있다고 해도 input(2)를 써봤자 A2노드를 얻을 수 없다 (mask 고정이라)
이러한 특성 때문에 dependencies()라는 함수를 쓰는 것도 하나의 방법이다
dependencies()함수의 장점은 꼽혀있는 인풋을 알려줄 뿐만 아니라 Expression링크가 걸린 노드도 알려준다
"""

for input_number in range(0, node.inputs()):
    if node.input(input_number):
    	print(node.input(input_number).name())
        
all_nodes = nuke.allNodes()
all_nodes_i_care_about = [ node for node in all_nodes if node.name() == nuke.selectedNode().name() ]

dependencies = []
for clone in all_nodes_i_care_about:
	if clone.dependencies(nuke.EXPRESSIONS):
        	dependencies = clone.dependencies(nuke.EXPRESSIONS)
            
dependencies.extend(nuke.selectedNode().dependencies())

 

 

[예시 코드 07 - RegEx]

#RegEx 

""" positional anchor
    ^ 			start of text
    $ 			end of text

    wildcard
    . 			literally whatever

    how many? (aka. quantifiers)
    + 			1 or more
    * 			0 or more
    ? 			0 or 1

    groups
    (aaa|bbb|ccc) 			aaa OR bbb OR ccc

    classes
    [abc] 			anything in the class 'abc' (so basically, a or b or c) 
    [^abc] 			anything OTHER than class 'abc' (so basically, a or b or c)

    shortcuts
    [a-z] 			all lowercase
    [A-Z] 			all uppercase
    [0-9] 			all numbers

    example
    ^n : words that start with an n
    d$ : words that end with a d
    ^n....d$ : words that start with an n (4 letters inbetween)
    ^n.+d$ : start with an n and search whatever words inbeween and end with a d

    clour?r : color or colour
    ^light_[0-9]? : light_00, light_022, light_, light_로 시작하고 숫자가 숫자가 뒤에 오거나 없거나

"""

 

이건 진짜 지금까지 본 RegEx 중 최고의 설명이었다

 

 

[ 예시 코드 09 - TopNode 찾기]

후디니의 Hscript처럼 누크도 자체 익스프레션을 가지고 있는데 그것을 TCL이라 칭하는 것 같다.

TCL함수로 [ topnode ]를 입력하면 무슨 요상한 메모리 주소같은 것을 리턴한다.

그것을 [ value [topnode].name ] 으로 바꾸면 해당 노드의 name을 리턴해준다.

 

B파이프의 최상위 노드만을 리턴하며 A파이프나 mask파이프는 계산하지 않는다.

 

* 설치폴더의 plugins 폴더에 들어가면 여러가지의 .tcl 파일이 있고 파일을 열어보면 소스코드를 볼 수 있다

 

nuke.tcl('value [topnode Merge1].name') # tcl함수를 파이썬에서 실행, Merge1의 탑노드 이름을 알려줌


def topNode(node, max_depth=None):
    """Return the top most node on the B-stream (input 0)
       Go at MOST max_depth (if none, go forever)
       return that node that you find
    """
    
    current_node = node
    depth = 0
    
    while True:
    	if current_node.input(0) is None:
        	return current_node
        elif max_depth and depth > max_depth:
        	return current_node
        else:
        	depth += 1
        	current_node = current_node.input(0)
            
node = nuke.selectedNode()            
print(topnode(node, 4).name())


def topNode_r(node):
    
    current_node = node
    
    if current_node.input(0) is None:
    	return current_node
        
    return topNode_r(current_node.input(0))
    
node = nuke.selectedNode()            
print(topnode_r(node).name())

 

While반복문과 재귀함수를 활용한 TopNode 찾는 방법

 

 

[ 예시 코드 10 - 메뉴탭]

the_menu = nuke.menu('Nodes')
the_menu.items()
the_menu.name()

for menu in the_menu.items():
    print(menu.name())
    
the_itme = the_menu.addCommand('HI', 'nuke.message("Hello World")') # 두번째 인자는 스크립트로 생각
the_real_menu = the_menu.findItem('Color/Math') # 서치 기능이 있음

 

setScript()

removeItem()

 

[ 예시 코드 11 - AOV 셔플 만들기 ]

def create_shuffle_nodes():
    # 현재 선택된 노드 가져오기
    selected_node = nuke.selectedNode()
    
    if not selected_node or selected_node.Class() != "Read":
        nuke.message("Please, Selcet Read Node.")
        return
    
    # 모든 채널 가져오기
    channels = selected_node.channels()
    
    # 채널에서 AOV 리스트 추출
    aov_list = sorted(list(set([channel.split('.')[0] for channel in channels])))
    
    # Shuffle2 노드 생성 (오른쪽으로 정렬)
    x_offset = 150  # 노드 간 간격 설정
    y_offset = 0  # 세로 간격 제거
    y_position = selected_node.ypos() + 200  # Read 노드 아래 배치
    x_position = selected_node.xpos()
    
    for i, aov in enumerate(aov_list):
        shuffle_node = nuke.createNode("Shuffle2", inpanel=False) # 리뉴얼된 Shuffle노드 생성
        shuffle_node.setInput(0, selected_node)
        shuffle_node["in1"].setValue(aov) # aov 연결
        shuffle_node["label"].setValue("[value in1]") 
        
        # 위치 조정 (오른쪽으로 정렬)
        shuffle_node.setXpos(x_position + i * x_offset)
        shuffle_node.setYpos(y_position)

create_shuffle_nodes()

 

channels()

ypos()

xpos()

Class()

'Nuke' 카테고리의 다른 글

누크 강의 정리  (1) 2024.09.01
Lens FX  (0) 2024.09.01
Cryptomatte 추출하기  (0) 2024.04.04
디지털 색상에 관하여  (0) 2024.03.17