Merge pull request #494 from tokejepsen/2.x/feature/nuke_build_workfile

Revamp Build Workfile in Nuke.
This commit is contained in:
Jakub Ježek 2020-08-31 16:55:24 +02:00 committed by GitHub
commit 297fcdc8da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 21 additions and 315 deletions

View file

@ -1,7 +1,6 @@
import os
import re
import sys
import getpass
from collections import OrderedDict
from avalon import api, io, lib
@ -1060,310 +1059,6 @@ def get_write_node_template_attr(node):
return avalon.nuke.lib.fix_data_for_node_create(correct_data)
class BuildWorkfile(WorkfileSettings):
"""
Building first version of workfile.
Settings are taken from presets and db. It will add all subsets
in last version for defined representaions
Arguments:
variable (type): description
"""
xpos = 0
ypos = 0
xpos_size = 80
ypos_size = 90
xpos_gap = 50
ypos_gap = 50
pos_layer = 10
def __init__(self,
root_path=None,
root_node=None,
nodes=None,
to_script=None,
**kwargs):
"""
A short description.
A bit longer description.
Argumetns:
root_path (str): description
root_node (nuke.Node): description
nodes (list): list of nuke.Node
nodes_effects (dict): dictionary with subsets
Example:
nodes_effects = {
"plateMain": {
"nodes": [
[("Class", "Reformat"),
("resize", "distort"),
("flip", True)],
[("Class", "Grade"),
("blackpoint", 0.5),
("multiply", 0.4)]
]
},
}
"""
WorkfileSettings.__init__(self,
root_node=root_node,
nodes=nodes,
**kwargs)
self.to_script = to_script
# collect data for formating
self.data_tmp = {
"project": {"name": self._project["name"],
"code": self._project["data"].get("code", "")},
"asset": self._asset or os.environ["AVALON_ASSET"],
"task": kwargs.get("task") or api.Session["AVALON_TASK"],
"hierarchy": kwargs.get("hierarchy") or pype.get_hierarchy(),
"version": kwargs.get("version", {}).get("name", 1),
"user": getpass.getuser(),
"comment": "firstBuild",
"ext": "nk"
}
# get presets from anatomy
anatomy = get_anatomy()
# format anatomy
anatomy_filled = anatomy.format(self.data_tmp)
# get dir and file for workfile
self.work_dir = anatomy_filled["work"]["folder"]
self.work_file = anatomy_filled["work"]["file"]
def save_script_as(self, path=None):
# first clear anything in open window
nuke.scriptClear()
if not path:
dir = self.work_dir
path = os.path.join(
self.work_dir,
self.work_file).replace("\\", "/")
else:
dir = os.path.dirname(path)
# check if folder is created
if not os.path.exists(dir):
os.makedirs(dir)
# save script to path
nuke.scriptSaveAs(path)
def process(self,
regex_filter=None,
version=None,
representations=["exr", "dpx", "lutJson", "mov",
"preview", "png", "jpeg", "jpg"]):
"""
A short description.
A bit longer description.
Args:
regex_filter (raw string): regex pattern to filter out subsets
version (int): define a particular version, None gets last
representations (list):
Returns:
type: description
Raises:
Exception: description
"""
if not self.to_script:
# save the script
self.save_script_as()
# create viewer and reset frame range
viewer = self.get_nodes(nodes_filter=["Viewer"])
if not viewer:
vn = nuke.createNode("Viewer")
vn["xpos"].setValue(self.xpos)
vn["ypos"].setValue(self.ypos)
else:
vn = viewer[-1]
# move position
self.position_up()
wn = self.write_create()
wn["xpos"].setValue(self.xpos)
wn["ypos"].setValue(self.ypos)
wn["render"].setValue(True)
vn.setInput(0, wn)
# adding backdrop under write
self.create_backdrop(label="Render write \n\n\n\nOUTPUT",
color='0xcc1102ff', layer=-1,
nodes=[wn])
# move position
self.position_up(4)
# set frame range for new viewer
self.reset_frame_range_handles()
# get all available representations
subsets = pype.get_subsets(self._asset,
regex_filter=regex_filter,
version=version,
representations=representations)
for name, subset in subsets.items():
log.debug("___________________")
log.debug(name)
log.debug(subset["version"])
nodes_backdrop = list()
for name, subset in subsets.items():
if "lut" in name:
continue
log.info("Building Loader to: `{}`".format(name))
version = subset["version"]
log.info("Version to: `{}`".format(version["name"]))
representations = subset["representaions"]
for repr in representations:
rn = self.read_loader(repr)
rn["xpos"].setValue(self.xpos)
rn["ypos"].setValue(self.ypos)
wn.setInput(0, rn)
# get editional nodes
lut_subset = [s for n, s in subsets.items()
if "lut{}".format(name.lower()) in n.lower()]
log.debug(">> lut_subset: `{}`".format(lut_subset))
if len(lut_subset) > 0:
lsub = lut_subset[0]
fxn = self.effect_loader(lsub["representaions"][-1])
fxn_ypos = fxn["ypos"].value()
fxn["ypos"].setValue(fxn_ypos - 100)
nodes_backdrop.append(fxn)
nodes_backdrop.append(rn)
# move position
self.position_right()
# adding backdrop under all read nodes
self.create_backdrop(label="Loaded Reads",
color='0x2d7702ff', layer=-1,
nodes=nodes_backdrop)
def read_loader(self, representation):
"""
Gets Loader plugin for image sequence or mov
Arguments:
representation (dict): avalon db entity
"""
context = representation["context"]
loader_name = "LoadSequence"
if "mov" in context["representation"]:
loader_name = "LoadMov"
loader_plugin = None
for Loader in api.discover(api.Loader):
if Loader.__name__ != loader_name:
continue
loader_plugin = Loader
return api.load(Loader=loader_plugin,
representation=representation["_id"])
def effect_loader(self, representation):
"""
Gets Loader plugin for effects
Arguments:
representation (dict): avalon db entity
"""
loader_name = "LoadLuts"
loader_plugin = None
for Loader in api.discover(api.Loader):
if Loader.__name__ != loader_name:
continue
loader_plugin = Loader
return api.load(Loader=loader_plugin,
representation=representation["_id"])
def write_create(self):
"""
Create render write
Arguments:
representation (dict): avalon db entity
"""
task = self.data_tmp["task"]
sanitized_task = re.sub('[^0-9a-zA-Z]+', '', task)
subset_name = "render{}Main".format(
sanitized_task.capitalize())
Create_name = "CreateWriteRender"
creator_plugin = None
for Creator in api.discover(api.Creator):
if Creator.__name__ != Create_name:
continue
creator_plugin = Creator
# return api.create()
return creator_plugin(subset_name, self._asset).process()
def create_backdrop(self, label="", color=None, layer=0,
nodes=None):
"""
Create Backdrop node
Arguments:
color (str): nuke compatible string with color code
layer (int): layer of node usually used (self.pos_layer - 1)
label (str): the message
nodes (list): list of nodes to be wrapped into backdrop
"""
assert isinstance(nodes, list), "`nodes` should be a list of nodes"
layer = self.pos_layer + layer
create_backdrop(label=label, color=color, layer=layer, nodes=nodes)
def position_reset(self, xpos=0, ypos=0):
self.xpos = xpos
self.ypos = ypos
def position_right(self, multiply=1):
self.xpos += (self.xpos_size * multiply) + self.xpos_gap
def position_left(self, multiply=1):
self.xpos -= (self.xpos_size * multiply) + self.xpos_gap
def position_down(self, multiply=1):
self.ypos -= (self.ypos_size * multiply) + self.ypos_gap
def position_up(self, multiply=1):
self.ypos -= (self.ypos_size * multiply) + self.ypos_gap
class ExporterReview:
"""
Base class object for generating review data from Nuke

View file

@ -2,10 +2,12 @@ import nuke
from avalon.api import Session
from pype.hosts.nuke import lib
from ...lib import BuildWorkfile
from pype.api import Logger
log = Logger().get_logger(__name__, "nuke")
def install():
menubar = nuke.menu("Nuke")
menu = menubar.findItem(Session["AVALON_LABEL"])
@ -20,7 +22,11 @@ def install():
log.debug("Changing Item: {}".format(rm_item))
# rm_item[1].setEnabled(False)
menu.removeItem(rm_item[1].name())
menu.addCommand(new_name, lambda: workfile_settings().reset_resolution(), index=(rm_item[0]))
menu.addCommand(
new_name,
lambda: workfile_settings().reset_resolution(),
index=(rm_item[0])
)
# replace reset frame range from avalon core to pype's
name = "Reset Frame Range"
@ -31,33 +37,38 @@ def install():
log.debug("Changing Item: {}".format(rm_item))
# rm_item[1].setEnabled(False)
menu.removeItem(rm_item[1].name())
menu.addCommand(new_name, lambda: workfile_settings().reset_frame_range_handles(), index=(rm_item[0]))
menu.addCommand(
new_name,
lambda: workfile_settings().reset_frame_range_handles(),
index=(rm_item[0])
)
# add colorspace menu item
name = "Set colorspace"
name = "Set Colorspace"
menu.addCommand(
name, lambda: workfile_settings().set_colorspace(),
index=(rm_item[0]+2)
index=(rm_item[0] + 2)
)
log.debug("Adding menu item: {}".format(name))
# add workfile builder menu item
name = "Build First Workfile.."
name = "Build Workfile"
menu.addCommand(
name, lambda: lib.BuildWorkfile().process(),
index=(rm_item[0]+7)
name, lambda: BuildWorkfile().process(),
index=(rm_item[0] + 7)
)
log.debug("Adding menu item: {}".format(name))
# add item that applies all setting above
name = "Apply all settings"
name = "Apply All Settings"
menu.addCommand(
name, lambda: workfile_settings().set_context_settings(), index=(rm_item[0]+3)
name,
lambda: workfile_settings().set_context_settings(),
index=(rm_item[0] + 3)
)
log.debug("Adding menu item: {}".format(name))
def uninstall():
menubar = nuke.menu("Nuke")