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 os
import re import re
import sys import sys
import getpass
from collections import OrderedDict from collections import OrderedDict
from avalon import api, io, lib 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) 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: class ExporterReview:
""" """
Base class object for generating review data from Nuke Base class object for generating review data from Nuke

View file

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