mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merged in feature/PYPE-81-nuke-write-render-workflow (pull request #235)
Feature/PYPE-81 nuke write render workflow Approved-by: Milan Kolar <milan@orbi.tools>
This commit is contained in:
commit
b6869a9379
10 changed files with 254 additions and 121 deletions
184
pype/nuke/lib.py
184
pype/nuke/lib.py
|
|
@ -18,6 +18,7 @@ log = Logger().get_logger(__name__, "nuke")
|
|||
self = sys.modules[__name__]
|
||||
self._project = None
|
||||
|
||||
|
||||
def onScriptLoad():
|
||||
if nuke.env['LINUX']:
|
||||
nuke.tcl('load ffmpegReader')
|
||||
|
|
@ -43,7 +44,7 @@ def checkInventoryVersions():
|
|||
container = avalon.nuke.parse_container(each)
|
||||
|
||||
if container:
|
||||
node = container["_tool"]
|
||||
node = container["_node"]
|
||||
avalon_knob_data = get_avalon_knob_data(node)
|
||||
|
||||
# get representation from io
|
||||
|
|
@ -102,6 +103,9 @@ def writes_version_sync():
|
|||
|
||||
node_new_file = node_file.replace(node_version, new_version)
|
||||
each['file'].setValue(node_new_file)
|
||||
if not os.path.isdir(os.path.dirname(node_new_file)):
|
||||
log.info("path does not exist")
|
||||
os.makedirs(os.path.dirname(node_new_file), 0o766)
|
||||
except Exception as e:
|
||||
log.debug(
|
||||
"Write node: `{}` has no version in path: {}".format(each.name(), e))
|
||||
|
|
@ -172,7 +176,32 @@ def script_name():
|
|||
return nuke.root().knob('name').value()
|
||||
|
||||
|
||||
def create_write_node(name, data):
|
||||
def create_write_node(name, data, prenodes=None):
|
||||
'''Creating write node which is group node
|
||||
|
||||
Arguments:
|
||||
name (str): name of node
|
||||
data (dict): data to be imprinted
|
||||
prenodes (list, optional): list of lists, definitions for nodes
|
||||
to be created before write
|
||||
|
||||
Example:
|
||||
prenodes = [(
|
||||
"NameNode", # string
|
||||
"NodeClass", # string
|
||||
( # OrderDict: knob and values pairs
|
||||
("knobName", "knobValue"),
|
||||
("knobName", "knobValue")
|
||||
),
|
||||
( # list inputs
|
||||
"firstPrevNodeName",
|
||||
"secondPrevNodeName"
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
'''
|
||||
|
||||
nuke_dataflow_writes = get_node_dataflow_preset(**data)
|
||||
nuke_colorspace_writes = get_node_colorspace_preset(**data)
|
||||
application = lib.get_application(os.environ["AVALON_APP_NAME"])
|
||||
|
|
@ -191,16 +220,8 @@ def create_write_node(name, data):
|
|||
|
||||
# build file path to workfiles
|
||||
fpath = str(anatomy_filled["work"]["folder"]).replace("\\", "/")
|
||||
pattern = "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}"
|
||||
# Workfile paths can be configured to have host name in file path.
|
||||
# In this case we want to avoid duplicate folder names.
|
||||
if "nuke" in fpath.lower():
|
||||
pattern = pattern.replace("nuke/", "")
|
||||
|
||||
fpath = pattern.format(
|
||||
work=fpath,
|
||||
version=data["version"],
|
||||
subset=data["subset"],
|
||||
fpath = data["fpath_template"].format(
|
||||
work=fpath, version=data["version"], subset=data["subset"],
|
||||
frame=data["frame"],
|
||||
ext=data["nuke_dataflow_writes"]["file_type"]
|
||||
)
|
||||
|
|
@ -228,14 +249,89 @@ def create_write_node(name, data):
|
|||
log.debug(_data)
|
||||
|
||||
_data["frame_range"] = data.get("frame_range", None)
|
||||
log.info("__ _data3: {}".format(_data))
|
||||
instance = avalon.nuke.lib.add_write_node(
|
||||
name,
|
||||
**_data
|
||||
)
|
||||
instance = avalon.nuke.lib.imprint(instance, data["avalon"])
|
||||
add_rendering_knobs(instance)
|
||||
return instance
|
||||
|
||||
# todo: hange this to new way
|
||||
GN = nuke.createNode("Group", "name {}".format(name))
|
||||
|
||||
prev_node = None
|
||||
with GN:
|
||||
# creating pre-write nodes `prenodes`
|
||||
if prenodes:
|
||||
for name, klass, properties, set_input_to in prenodes:
|
||||
# create node
|
||||
now_node = nuke.createNode(klass, "name {}".format(name))
|
||||
|
||||
# add data to knob
|
||||
for k, v in properties:
|
||||
if k and v:
|
||||
now_node[k].serValue(str(v))
|
||||
|
||||
# connect to previous node
|
||||
if set_input_to:
|
||||
if isinstance(set_input_to, (tuple or list)):
|
||||
for i, node_name in enumerate(set_input_to):
|
||||
input_node = nuke.toNode(node_name)
|
||||
now_node.setInput(1, input_node)
|
||||
elif isinstance(set_input_to, str):
|
||||
input_node = nuke.toNode(set_input_to)
|
||||
now_node.setInput(0, input_node)
|
||||
else:
|
||||
now_node.setInput(0, prev_node)
|
||||
|
||||
# swith actual node to previous
|
||||
prev_node = now_node
|
||||
else:
|
||||
prev_node = nuke.createNode("Input", "name rgba")
|
||||
|
||||
|
||||
# creating write node
|
||||
now_node = avalon.nuke.lib.add_write_node("inside_{}".format(name),
|
||||
**_data
|
||||
)
|
||||
write_node = now_node
|
||||
# connect to previous node
|
||||
now_node.setInput(0, prev_node)
|
||||
|
||||
# swith actual node to previous
|
||||
prev_node = now_node
|
||||
|
||||
now_node = nuke.createNode("Output", "name write")
|
||||
|
||||
# connect to previous node
|
||||
now_node.setInput(0, prev_node)
|
||||
|
||||
# imprinting group node
|
||||
GN = avalon.nuke.imprint(GN, data["avalon"])
|
||||
|
||||
divider = nuke.Text_Knob('')
|
||||
GN.addKnob(divider)
|
||||
|
||||
add_rendering_knobs(GN)
|
||||
|
||||
divider = nuke.Text_Knob('')
|
||||
GN.addKnob(divider)
|
||||
|
||||
# set tile color
|
||||
tile_color = _data.get("tile_color", "0xff0000ff")
|
||||
GN["tile_color"].setValue(tile_color)
|
||||
|
||||
|
||||
# add render button
|
||||
lnk = nuke.Link_Knob("Render")
|
||||
lnk.makeLink(write_node.name(), "Render")
|
||||
lnk.setName("Render")
|
||||
GN.addKnob(lnk)
|
||||
|
||||
# linking knobs to group property panel
|
||||
linking_knobs = ["first", "last", "use_limit"]
|
||||
for k in linking_knobs:
|
||||
lnk = nuke.Link_Knob(k)
|
||||
lnk.makeLink(write_node.name(), k)
|
||||
lnk.setName(k.replace('_', ' ').capitalize())
|
||||
lnk.clearFlag(nuke.STARTLINE)
|
||||
GN.addKnob(lnk)
|
||||
|
||||
return GN
|
||||
|
||||
|
||||
def add_rendering_knobs(node):
|
||||
|
|
@ -414,8 +510,8 @@ def reset_frame_range_handles():
|
|||
|
||||
# adding handle_start/end to root avalon knob
|
||||
if not avalon.nuke.set_avalon_knob_data(root, {
|
||||
"handle_start": handle_start,
|
||||
"handle_end": handle_end
|
||||
"handle_start": int(handle_start),
|
||||
"handle_end": int(handle_end)
|
||||
}):
|
||||
log.warning("Cannot set Avalon knob to Root node!")
|
||||
|
||||
|
|
@ -436,34 +532,26 @@ def reset_resolution():
|
|||
asset = api.Session["AVALON_ASSET"]
|
||||
asset = io.find_one({"name": asset, "type": "asset"})
|
||||
|
||||
try:
|
||||
width = asset.get('data', {}).get('resolution_width', 1920)
|
||||
height = asset.get('data', {}).get('resolution_height', 1080)
|
||||
pixel_aspect = asset.get('data', {}).get('pixel_aspect', 1)
|
||||
bbox = asset.get('data', {}).get('crop', "0.0.1920.1080")
|
||||
width = asset.get('data', {}).get('resolution_width')
|
||||
height = asset.get('data', {}).get('resolution_height')
|
||||
pixel_aspect = asset.get('data', {}).get('pixel_aspect')
|
||||
|
||||
if bbox not in "0.0.1920.1080":
|
||||
try:
|
||||
x, y, r, t = bbox.split(".")
|
||||
except Exception as e:
|
||||
x = 0
|
||||
y = 0
|
||||
r = width
|
||||
t = height
|
||||
bbox = None
|
||||
log.error("{}: {} \nFormat:Crop need to be set with dots, example: "
|
||||
"0.0.1920.1080, /nSetting to default".format(__name__, e))
|
||||
else:
|
||||
bbox = None
|
||||
|
||||
except KeyError:
|
||||
log.warning(
|
||||
"No resolution information found for \"{0}\".".format(
|
||||
project["name"]
|
||||
)
|
||||
)
|
||||
log.info("pixel_aspect: {}".format(pixel_aspect))
|
||||
if any(not x for x in [width, height, pixel_aspect]):
|
||||
log.error("Missing set shot attributes in DB. \nContact your supervisor!. \n\nWidth: `{0}` \nHeight: `{1}` \nPixel Asspect: `{2}`".format(
|
||||
width, height, pixel_aspect))
|
||||
return
|
||||
|
||||
bbox = asset.get('data', {}).get('crop')
|
||||
|
||||
if bbox:
|
||||
try:
|
||||
x, y, r, t = bbox.split(".")
|
||||
except Exception as e:
|
||||
bbox = None
|
||||
log.error("{}: {} \nFormat:Crop need to be set with dots, example: "
|
||||
"0.0.1920.1080, /nSetting to default".format(__name__, e))
|
||||
|
||||
used_formats = list()
|
||||
for f in nuke.formats():
|
||||
if project["name"] in str(f.name()):
|
||||
|
|
@ -620,7 +708,7 @@ def get_hierarchical_attr(entity, attr, default=None):
|
|||
# dict
|
||||
# """
|
||||
#
|
||||
# node = container["_tool"]
|
||||
# node = container["_node"]
|
||||
# tile_color = node['tile_color'].value()
|
||||
# if tile_color is None:
|
||||
# return {}
|
||||
|
|
|
|||
27
pype/plugins/ftrack/publish/integrate_remove_components.py
Normal file
27
pype/plugins/ftrack/publish/integrate_remove_components.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import pyblish.api
|
||||
import os
|
||||
|
||||
|
||||
class IntegrateCleanComponentData(pyblish.api.InstancePlugin):
|
||||
"""
|
||||
Cleaning up thumbnail an mov files after they have been integrated
|
||||
"""
|
||||
|
||||
order = pyblish.api.IntegratorOrder + 0.5
|
||||
label = 'Clean component data'
|
||||
families = ["ftrack"]
|
||||
optional = True
|
||||
active = True
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
for comp in instance.data['representations']:
|
||||
self.log.debug('component {}'.format(comp))
|
||||
|
||||
if comp.get('thumbnail') or ("thumbnail" in comp.get('tags', [])):
|
||||
os.remove(comp['published_path'])
|
||||
self.log.info('Thumbnail image was erased')
|
||||
|
||||
elif comp.get('preview') or ("preview" in comp.get('tags', [])):
|
||||
os.remove(comp['published_path'])
|
||||
self.log.info('Preview mov file was erased')
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# type: render
|
||||
# if no render type node in script then first is having in name [master] for definition of main script renderer
|
||||
# colorspace setting from templates
|
||||
# dataflow setting from templates
|
||||
|
||||
# type: mask_render
|
||||
# created with shuffle gizmo for RGB separation into davinci matte
|
||||
# colorspace setting from templates
|
||||
# dataflow setting from templates
|
||||
|
||||
# type: prerender
|
||||
# backdrop with write and read
|
||||
# colorspace setting from templates
|
||||
# dataflow setting from templates
|
||||
|
||||
# type: geo
|
||||
# dataflow setting from templates
|
||||
|
|
@ -3,6 +3,7 @@ import avalon.api
|
|||
import avalon.nuke
|
||||
from pype.nuke.lib import create_write_node
|
||||
from pype import api as pype
|
||||
from pypeapp import config
|
||||
|
||||
import nuke
|
||||
|
||||
|
|
@ -30,6 +31,11 @@ class CreateWriteRender(avalon.nuke.Creator):
|
|||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CreateWriteRender, self).__init__(*args, **kwargs)
|
||||
self.presets = config.get_presets()['plugins']["nuke"]["create"].get(
|
||||
self.__class__.__name__, {}
|
||||
)
|
||||
|
||||
self.name = self.data["subset"]
|
||||
|
||||
data = OrderedDict()
|
||||
|
||||
|
|
@ -41,7 +47,6 @@ class CreateWriteRender(avalon.nuke.Creator):
|
|||
self.data = data
|
||||
|
||||
def process(self):
|
||||
self.name = self.data["subset"]
|
||||
|
||||
family = self.family
|
||||
node = 'write'
|
||||
|
|
@ -55,6 +60,16 @@ class CreateWriteRender(avalon.nuke.Creator):
|
|||
"avalon": self.data
|
||||
}
|
||||
|
||||
if self.presets.get('fpath_template'):
|
||||
self.log.info("Adding template path from preset")
|
||||
write_data.update(
|
||||
{"fpath_template": self.presets["fpath_template"]}
|
||||
)
|
||||
else:
|
||||
self.log.info("Adding template path from plugin")
|
||||
write_data.update({
|
||||
"fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}"})
|
||||
|
||||
create_write_node(self.data["subset"], write_data)
|
||||
|
||||
return
|
||||
|
|
@ -74,6 +89,9 @@ class CreateWritePrerender(avalon.nuke.Creator):
|
|||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CreateWritePrerender, self).__init__(*args, **kwargs)
|
||||
self.presets = config.get_presets()['plugins']["nuke"]["create"].get(
|
||||
self.__class__.__name__, {}
|
||||
)
|
||||
|
||||
data = OrderedDict()
|
||||
|
||||
|
|
@ -97,56 +115,16 @@ class CreateWritePrerender(avalon.nuke.Creator):
|
|||
"avalon": self.data
|
||||
}
|
||||
|
||||
if self.presets.get('fpath_template'):
|
||||
self.log.info("Adding template path from preset")
|
||||
write_data.update(
|
||||
{"fpath_template": self.presets["fpath_template"]}
|
||||
)
|
||||
else:
|
||||
self.log.info("Adding template path from plugin")
|
||||
write_data.update({
|
||||
"fpath_template": "{work}/prerenders/{subset}/{subset}.{frame}.{ext}"})
|
||||
|
||||
create_write_node(self.data["subset"], write_data)
|
||||
|
||||
return
|
||||
|
||||
|
||||
"""
|
||||
class CrateWriteStill(avalon.nuke.Creator):
|
||||
# change this to template preset
|
||||
preset = "still"
|
||||
|
||||
name = "WriteStill"
|
||||
label = "Create Write Still"
|
||||
hosts = ["nuke"]
|
||||
family = "{}_write".format(preset)
|
||||
families = preset
|
||||
icon = "image"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CrateWriteStill, self).__init__(*args, **kwargs)
|
||||
|
||||
data = OrderedDict()
|
||||
|
||||
data["family"] = self.family.split("_")[-1]
|
||||
data["families"] = self.families
|
||||
|
||||
{data.update({k: v}) for k, v in self.data.items()
|
||||
if k not in data.keys()}
|
||||
self.data = data
|
||||
|
||||
def process(self):
|
||||
self.name = self.data["subset"]
|
||||
|
||||
node_name = self.data["subset"].replace(
|
||||
"_", "_f{}_".format(nuke.frame()))
|
||||
instance = nuke.toNode(self.data["subset"])
|
||||
self.data["subset"] = node_name
|
||||
|
||||
family = self.family
|
||||
node = 'write'
|
||||
|
||||
if not instance:
|
||||
write_data = {
|
||||
"frame_range": [nuke.frame(), nuke.frame()],
|
||||
"class": node,
|
||||
"preset": self.preset,
|
||||
"avalon": self.data
|
||||
}
|
||||
|
||||
nuke.createNode("FrameHold", "first_frame {}".format(nuke.frame()))
|
||||
create_write_node(node_name, write_data)
|
||||
|
||||
return
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class SelectContainers(api.InventoryAction):
|
|||
|
||||
import avalon.nuke
|
||||
|
||||
nodes = [i["_tool"] for i in containers]
|
||||
nodes = [i["_node"] for i in containers]
|
||||
|
||||
with avalon.nuke.viewer_update_and_undo_stop():
|
||||
# clear previous_selection
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#
|
||||
# # Get tool color
|
||||
# first = containers[0]
|
||||
# tool = first["_tool"]
|
||||
# tool = first["_node"]
|
||||
# color = tool.TileColor
|
||||
#
|
||||
# if color is not None:
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
# rgb_f_table = {"R": rgb_f[0], "G": rgb_f[1], "B": rgb_f[2]}
|
||||
#
|
||||
# # Update tool
|
||||
# tool = container["_tool"]
|
||||
# tool = container["_node"]
|
||||
# tool.TileColor = rgb_f_table
|
||||
#
|
||||
# result.append(container)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import os
|
|||
import nuke
|
||||
import pyblish.api
|
||||
from avalon import io, api
|
||||
from pype.nuke.lib import get_avalon_knob_data
|
||||
from avalon.nuke.lib import get_avalon_knob_data
|
||||
|
||||
|
||||
@pyblish.api.log
|
||||
|
|
@ -34,6 +34,7 @@ class CollectNukeInstances(pyblish.api.ContextPlugin):
|
|||
|
||||
# get data from avalon knob
|
||||
avalon_knob_data = get_avalon_knob_data(node)
|
||||
self.log.debug("avalon_knob_data: {}".format(avalon_knob_data))
|
||||
if not avalon_knob_data:
|
||||
continue
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ def get_version_from_path(file):
|
|||
v: version number in string ('001')
|
||||
|
||||
"""
|
||||
pattern = re.compile(r"[\._]v([0-9]*)")
|
||||
pattern = re.compile(r"v([0-9]*)")
|
||||
try:
|
||||
v = pattern.findall(file)[0]
|
||||
return v
|
||||
|
|
|
|||
54
setup/nuke/nuke_path/atom_server.py
Normal file
54
setup/nuke/nuke_path/atom_server.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
'''
|
||||
Simple socket server using threads
|
||||
'''
|
||||
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import StringIO
|
||||
import contextlib
|
||||
|
||||
import nuke
|
||||
|
||||
HOST = ''
|
||||
PORT = 8888
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def stdoutIO(stdout=None):
|
||||
old = sys.stdout
|
||||
if stdout is None:
|
||||
stdout = StringIO.StringIO()
|
||||
sys.stdout = stdout
|
||||
yield stdout
|
||||
sys.stdout = old
|
||||
|
||||
|
||||
def _exec(data):
|
||||
with stdoutIO() as s:
|
||||
exec(data)
|
||||
return s.getvalue()
|
||||
|
||||
|
||||
def server_start():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind((HOST, PORT))
|
||||
s.listen(5)
|
||||
|
||||
while 1:
|
||||
client, address = s.accept()
|
||||
try:
|
||||
data = client.recv(4096)
|
||||
if data:
|
||||
result = nuke.executeInMainThreadWithResult(_exec, args=(data))
|
||||
client.send(str(result))
|
||||
except SystemExit:
|
||||
result = self.encode('SERVER: Shutting down...')
|
||||
client.send(str(result))
|
||||
raise
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
t = threading.Thread(None, server_start)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import atom_server
|
||||
|
||||
from pype.nuke.lib import (
|
||||
writes_version_sync,
|
||||
|
|
@ -15,5 +16,6 @@ log = Logger().get_logger(__name__, "nuke")
|
|||
nuke.addOnScriptSave(onScriptLoad)
|
||||
nuke.addOnScriptLoad(checkInventoryVersions)
|
||||
nuke.addOnScriptSave(checkInventoryVersions)
|
||||
nuke.addOnScriptSave(writes_version_sync)
|
||||
|
||||
log.info('Automatic syncing of write file knob to script version')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue