mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
Merged in feature/PYPE-433-deadline-publish-with-correct-c (pull request #403)
Nuke to Deadline submission Approved-by: Milan Kolar <milan@orbi.tools>
This commit is contained in:
commit
033e3e4ff5
13 changed files with 583 additions and 238 deletions
171
pype/nuke/lib.py
171
pype/nuke/lib.py
|
|
@ -6,6 +6,7 @@ from collections import OrderedDict
|
|||
|
||||
from avalon import api, io, lib
|
||||
import avalon.nuke
|
||||
from avalon.nuke import lib as anlib
|
||||
import pype.api as pype
|
||||
|
||||
import nuke
|
||||
|
|
@ -1195,6 +1196,176 @@ class BuildWorkfile(WorkfileSettings):
|
|||
def position_up(self, multiply=1):
|
||||
self.ypos -= (self.ypos_size * multiply) + self.ypos_gap
|
||||
|
||||
|
||||
class Exporter_review_lut:
|
||||
"""
|
||||
Generator object for review lut from Nuke
|
||||
|
||||
Args:
|
||||
klass (pyblish.plugin): pyblish plugin parent
|
||||
|
||||
|
||||
"""
|
||||
_temp_nodes = []
|
||||
data = dict({
|
||||
"representations": list()
|
||||
})
|
||||
|
||||
def __init__(self,
|
||||
klass,
|
||||
instance,
|
||||
name=None,
|
||||
ext=None,
|
||||
cube_size=None,
|
||||
lut_size=None,
|
||||
lut_style=None):
|
||||
|
||||
self.log = klass.log
|
||||
self.instance = instance
|
||||
|
||||
self.name = name or "baked_lut"
|
||||
self.ext = ext or "cube"
|
||||
self.cube_size = cube_size or 32
|
||||
self.lut_size = lut_size or 1024
|
||||
self.lut_style = lut_style or "linear"
|
||||
|
||||
self.stagingDir = self.instance.data["stagingDir"]
|
||||
self.collection = self.instance.data.get("collection", None)
|
||||
|
||||
# set frame start / end and file name to self
|
||||
self.get_file_info()
|
||||
|
||||
self.log.info("File info was set...")
|
||||
|
||||
self.file = self.fhead + self.name + ".{}".format(self.ext)
|
||||
self.path = os.path.join(self.stagingDir, self.file).replace("\\", "/")
|
||||
|
||||
def generate_lut(self):
|
||||
# ---------- start nodes creation
|
||||
|
||||
# CMSTestPattern
|
||||
cms_node = nuke.createNode("CMSTestPattern")
|
||||
cms_node["cube_size"].setValue(self.cube_size)
|
||||
# connect
|
||||
self._temp_nodes.append(cms_node)
|
||||
self.previous_node = cms_node
|
||||
self.log.debug("CMSTestPattern... `{}`".format(self._temp_nodes))
|
||||
|
||||
# Node View Process
|
||||
ipn = self.get_view_process_node()
|
||||
if ipn is not None:
|
||||
# connect
|
||||
ipn.setInput(0, self.previous_node)
|
||||
self._temp_nodes.append(ipn)
|
||||
self.previous_node = ipn
|
||||
self.log.debug("ViewProcess... `{}`".format(self._temp_nodes))
|
||||
|
||||
# OCIODisplay
|
||||
dag_node = nuke.createNode("OCIODisplay")
|
||||
# connect
|
||||
dag_node.setInput(0, self.previous_node)
|
||||
self._temp_nodes.append(dag_node)
|
||||
self.previous_node = dag_node
|
||||
self.log.debug("OCIODisplay... `{}`".format(self._temp_nodes))
|
||||
|
||||
# GenerateLUT
|
||||
gen_lut_node = nuke.createNode("GenerateLUT")
|
||||
gen_lut_node["file"].setValue(self.path)
|
||||
gen_lut_node["file_type"].setValue(".{}".format(self.ext))
|
||||
gen_lut_node["lut1d"].setValue(self.lut_size)
|
||||
gen_lut_node["style1d"].setValue(self.lut_style)
|
||||
# connect
|
||||
gen_lut_node.setInput(0, self.previous_node)
|
||||
self._temp_nodes.append(gen_lut_node)
|
||||
self.log.debug("GenerateLUT... `{}`".format(self._temp_nodes))
|
||||
|
||||
# ---------- end nodes creation
|
||||
|
||||
# Export lut file
|
||||
nuke.execute(
|
||||
gen_lut_node.name(),
|
||||
int(self.first_frame),
|
||||
int(self.first_frame))
|
||||
|
||||
self.log.info("Exported...")
|
||||
|
||||
# ---------- generate representation data
|
||||
self.get_representation_data()
|
||||
|
||||
self.log.debug("Representation... `{}`".format(self.data))
|
||||
|
||||
# ---------- Clean up
|
||||
for node in self._temp_nodes:
|
||||
nuke.delete(node)
|
||||
self.log.info("Deleted nodes...")
|
||||
|
||||
return self.data
|
||||
|
||||
def get_file_info(self):
|
||||
if self.collection:
|
||||
self.log.debug("Collection: `{}`".format(self.collection))
|
||||
# get path
|
||||
self.fname = os.path.basename(self.collection.format(
|
||||
"{head}{padding}{tail}"))
|
||||
self.fhead = self.collection.format("{head}")
|
||||
|
||||
# get first and last frame
|
||||
self.first_frame = min(self.collection.indexes)
|
||||
self.last_frame = max(self.collection.indexes)
|
||||
else:
|
||||
self.fname = os.path.basename(self.instance.data.get("path", None))
|
||||
self.fhead = os.path.splitext(self.fname)[0] + "."
|
||||
self.first_frame = self.instance.data.get("frameStart", None)
|
||||
self.last_frame = self.instance.data.get("frameEnd", None)
|
||||
|
||||
if "#" in self.fhead:
|
||||
self.fhead = self.fhead.replace("#", "")[:-1]
|
||||
|
||||
def get_representation_data(self):
|
||||
|
||||
repre = {
|
||||
'name': self.name,
|
||||
'ext': self.ext,
|
||||
'files': self.file,
|
||||
"stagingDir": self.stagingDir,
|
||||
"anatomy_template": "publish",
|
||||
"tags": [self.name.replace("_", "-")]
|
||||
}
|
||||
|
||||
self.data["representations"].append(repre)
|
||||
|
||||
def get_view_process_node(self):
|
||||
"""
|
||||
Will get any active view process.
|
||||
|
||||
Arguments:
|
||||
self (class): in object definition
|
||||
|
||||
Returns:
|
||||
nuke.Node: copy node of Input Process node
|
||||
"""
|
||||
anlib.reset_selection()
|
||||
ipn_orig = None
|
||||
for v in [n for n in nuke.allNodes()
|
||||
if "Viewer" in n.Class()]:
|
||||
ip = v['input_process'].getValue()
|
||||
ipn = v['input_process_node'].getValue()
|
||||
if "VIEWER_INPUT" not in ipn and ip:
|
||||
ipn_orig = nuke.toNode(ipn)
|
||||
ipn_orig.setSelected(True)
|
||||
|
||||
if ipn_orig:
|
||||
# copy selected to clipboard
|
||||
nuke.nodeCopy('%clipboard%')
|
||||
# reset selection
|
||||
anlib.reset_selection()
|
||||
# paste node and selection is on it only
|
||||
nuke.nodePaste('%clipboard%')
|
||||
# assign to variable
|
||||
ipn = nuke.selectedNode()
|
||||
|
||||
return ipn
|
||||
|
||||
def get_dependent_nodes(nodes):
|
||||
"""Get all dependent nodes connected to the list of nodes.
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin):
|
|||
label = "RenderedFrames"
|
||||
|
||||
def process(self, context):
|
||||
pixel_aspect = 1
|
||||
lut_path = None
|
||||
if os.environ.get("PYPE_PUBLISH_PATHS"):
|
||||
paths = os.environ["PYPE_PUBLISH_PATHS"].split(os.pathsep)
|
||||
self.log.info("Collecting paths: {}".format(paths))
|
||||
|
|
@ -144,6 +146,12 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin):
|
|||
self.log.info("setting session using metadata")
|
||||
api.Session.update(session)
|
||||
os.environ.update(session)
|
||||
instance = metadata.get("instance")
|
||||
if instance:
|
||||
instance_family = instance.get("family")
|
||||
pixel_aspect = instance.get("pixelAspect", 1)
|
||||
lut_path = instance.get("lutPath", None)
|
||||
|
||||
|
||||
else:
|
||||
# Search in directory
|
||||
|
|
@ -181,6 +189,8 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin):
|
|||
families.append("ftrack")
|
||||
if "review" not in families:
|
||||
families.append("review")
|
||||
if "write" in instance_family:
|
||||
families.append("write")
|
||||
|
||||
for collection in collections:
|
||||
instance = context.create_instance(str(collection))
|
||||
|
|
@ -197,6 +207,11 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin):
|
|||
start = data.get("frameStart", indices[0])
|
||||
end = data.get("frameEnd", indices[-1])
|
||||
|
||||
self.log.debug("Collected pixel_aspect:\n"
|
||||
"{}".format(pixel_aspect))
|
||||
self.log.debug("type pixel_aspect:\n"
|
||||
"{}".format(type(pixel_aspect)))
|
||||
|
||||
# root = os.path.normpath(root)
|
||||
# self.log.info("Source: {}}".format(data.get("source", "")))
|
||||
|
||||
|
|
@ -212,8 +227,11 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin):
|
|||
"frameStart": start,
|
||||
"frameEnd": end,
|
||||
"fps": fps,
|
||||
"source": data.get('source', '')
|
||||
"source": data.get('source', ''),
|
||||
"pixelAspect": pixel_aspect,
|
||||
})
|
||||
if lut_path:
|
||||
instance.data.update({"lutPath": lut_path})
|
||||
instance.append(collection)
|
||||
instance.context.data['fps'] = fps
|
||||
|
||||
|
|
|
|||
|
|
@ -85,3 +85,6 @@ class CollectTemplates(pyblish.api.InstancePlugin):
|
|||
instance.data["assumedDestination"] = os.path.dirname(
|
||||
(anatomy.format(template_data))["publish"]["path"]
|
||||
)
|
||||
self.log.info("Assumed Destination has been created...")
|
||||
self.log.debug("__ assumedTemplateData: `{}`".format(instance.data["assumedTemplateData"]))
|
||||
self.log.debug("__ template: `{}`".format(instance.data["template"]))
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import os
|
||||
|
||||
import math
|
||||
import pyblish.api
|
||||
import clique
|
||||
import pype.api
|
||||
from pypeapp import config
|
||||
|
||||
|
||||
class ExtractReview(pyblish.api.InstancePlugin):
|
||||
|
|
@ -22,16 +21,19 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
families = ["review"]
|
||||
hosts = ["nuke", "maya", "shell"]
|
||||
|
||||
outputs = {}
|
||||
ext_filter = []
|
||||
|
||||
def process(self, instance):
|
||||
# adding plugin attributes from presets
|
||||
publish_presets = config.get_presets()["plugins"]["global"]["publish"]
|
||||
plugin_attrs = publish_presets[self.__class__.__name__]
|
||||
output_profiles = plugin_attrs.get("outputs", {})
|
||||
|
||||
output_profiles = self.outputs or {}
|
||||
|
||||
inst_data = instance.data
|
||||
fps = inst_data.get("fps")
|
||||
start_frame = inst_data.get("frameStart")
|
||||
|
||||
resolution_height = instance.data.get("resolutionHeight", 1080)
|
||||
resolution_width = instance.data.get("resolutionWidth", 1920)
|
||||
pixel_aspect = instance.data.get("pixelAspect", 1)
|
||||
self.log.debug("Families In: `{}`".format(instance.data["families"]))
|
||||
|
||||
# get representation and loop them
|
||||
|
|
@ -40,7 +42,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
# filter out mov and img sequences
|
||||
representations_new = representations[:]
|
||||
for repre in representations:
|
||||
if repre['ext'] in plugin_attrs["ext_filter"]:
|
||||
if repre['ext'] in self.ext_filter:
|
||||
tags = repre.get("tags", [])
|
||||
|
||||
self.log.info("Try repre: {}".format(repre))
|
||||
|
|
@ -92,8 +94,9 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
self.log.info("p_tags: `{}`".format(p_tags))
|
||||
# add families
|
||||
[instance.data["families"].append(t)
|
||||
for t in p_tags
|
||||
if t not in instance.data["families"]]
|
||||
for t in p_tags
|
||||
if t not in instance.data["families"]]
|
||||
|
||||
# add to
|
||||
[new_tags.append(t) for t in p_tags
|
||||
if t not in new_tags]
|
||||
|
|
@ -147,14 +150,16 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
)
|
||||
|
||||
output_args = []
|
||||
output_args.extend(profile.get('codec', []))
|
||||
codec_args = profile.get('codec', [])
|
||||
output_args.extend(codec_args)
|
||||
# preset's output data
|
||||
output_args.extend(profile.get('output', []))
|
||||
|
||||
# letter_box
|
||||
# TODO: add to documentation
|
||||
lb = profile.get('letter_box', None)
|
||||
if lb:
|
||||
lb = profile.get('letter_box', 0)
|
||||
if lb is not 0:
|
||||
if "reformat" not in p_tags:
|
||||
lb /= pixel_aspect
|
||||
output_args.append(
|
||||
"-filter:v drawbox=0:0:iw:round((ih-(iw*(1/{0})))/2):t=fill:c=black,drawbox=0:ih-round((ih-(iw*(1/{0})))/2):iw:round((ih-(iw*(1/{0})))/2):t=fill:c=black".format(lb))
|
||||
|
||||
|
|
@ -163,6 +168,65 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
|
||||
# output filename
|
||||
output_args.append(full_output_path)
|
||||
|
||||
self.log.debug("__ pixel_aspect: `{}`".format(pixel_aspect))
|
||||
self.log.debug("__ resolution_width: `{}`".format(resolution_width))
|
||||
self.log.debug("__ resolution_height: `{}`".format(resolution_height))
|
||||
# scaling none square pixels and 1920 width
|
||||
if "reformat" in p_tags:
|
||||
width_scale = 1920
|
||||
width_half_pad = 0
|
||||
res_w = int(float(resolution_width) * pixel_aspect)
|
||||
height_half_pad = int((
|
||||
(res_w - 1920) / (
|
||||
res_w * .01) * (
|
||||
1080 * .01)) / 2
|
||||
)
|
||||
height_scale = 1080 - (height_half_pad * 2)
|
||||
if height_scale > 1080:
|
||||
height_half_pad = 0
|
||||
height_scale = 1080
|
||||
width_half_pad = (1920 - (float(resolution_width) * (1080 / float(resolution_height))) ) / 2
|
||||
width_scale = int(1920 - (width_half_pad * 2))
|
||||
|
||||
self.log.debug("__ width_scale: `{}`".format(width_scale))
|
||||
self.log.debug("__ width_half_pad: `{}`".format(width_half_pad))
|
||||
self.log.debug("__ height_scale: `{}`".format(height_scale))
|
||||
self.log.debug("__ height_half_pad: `{}`".format(height_half_pad))
|
||||
|
||||
|
||||
scaling_arg = "scale={0}x{1}:flags=lanczos,pad=1920:1080:{2}:{3}:black,setsar=1".format(
|
||||
width_scale, height_scale, width_half_pad, height_half_pad
|
||||
)
|
||||
|
||||
vf_back = self.add_video_filter_args(
|
||||
output_args, scaling_arg)
|
||||
# add it to output_args
|
||||
output_args.insert(0, vf_back)
|
||||
|
||||
# baking lut file application
|
||||
lut_path = instance.data.get("lutPath")
|
||||
if lut_path and ("bake-lut" in p_tags):
|
||||
# removing Gama info as it is all baked in lut
|
||||
gamma = next((g for g in input_args
|
||||
if "-gamma" in g), None)
|
||||
if gamma:
|
||||
input_args.remove(gamma)
|
||||
|
||||
# create lut argument
|
||||
lut_arg = "lut3d=file='{}'".format(
|
||||
lut_path.replace(
|
||||
"\\", "/").replace(":/", "\\:/")
|
||||
)
|
||||
lut_arg += ",colormatrix=bt601:bt709"
|
||||
|
||||
vf_back = self.add_video_filter_args(
|
||||
output_args, lut_arg)
|
||||
# add it to output_args
|
||||
output_args.insert(0, vf_back)
|
||||
self.log.info("Added Lut to ffmpeg command")
|
||||
self.log.debug("_ output_args: `{}`".format(output_args))
|
||||
|
||||
mov_args = [
|
||||
os.path.join(
|
||||
os.environ.get(
|
||||
|
|
@ -185,7 +249,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
'files': repr_file,
|
||||
"tags": new_tags,
|
||||
"outputName": name,
|
||||
"codec": profile.get('codec', [])
|
||||
"codec": codec_args
|
||||
})
|
||||
if repre_new.get('preview'):
|
||||
repre_new.pop("preview")
|
||||
|
|
@ -209,3 +273,40 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
instance.data["representations"] = representations_new
|
||||
|
||||
self.log.debug("Families Out: `{}`".format(instance.data["families"]))
|
||||
|
||||
def add_video_filter_args(self, args, inserting_arg):
|
||||
"""
|
||||
Fixing video filter argumets to be one long string
|
||||
|
||||
Args:
|
||||
args (list): list of string arguments
|
||||
inserting_arg (str): string argument we want to add
|
||||
(without flag `-vf`)
|
||||
|
||||
Returns:
|
||||
str: long joined argument to be added back to list of arguments
|
||||
|
||||
"""
|
||||
# find all video format settings
|
||||
vf_settings = [p for p in args
|
||||
for v in ["-filter:v", "-vf"]
|
||||
if v in p]
|
||||
self.log.debug("_ vf_settings: `{}`".format(vf_settings))
|
||||
|
||||
# remove them from output args list
|
||||
for p in vf_settings:
|
||||
self.log.debug("_ remove p: `{}`".format(p))
|
||||
args.remove(p)
|
||||
self.log.debug("_ args: `{}`".format(args))
|
||||
|
||||
# strip them from all flags
|
||||
vf_fixed = [p.replace("-vf ", "").replace("-filter:v ", "")
|
||||
for p in vf_settings]
|
||||
|
||||
self.log.debug("_ vf_fixed: `{}`".format(vf_fixed))
|
||||
vf_fixed.insert(0, inserting_arg)
|
||||
self.log.debug("_ vf_fixed: `{}`".format(vf_fixed))
|
||||
# create new video filter setting
|
||||
vf_back = "-vf " + ",".join(vf_fixed)
|
||||
|
||||
return vf_back
|
||||
|
|
|
|||
|
|
@ -414,7 +414,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
|
|||
}
|
||||
|
||||
if sequence_repre and repre.get("frameStart"):
|
||||
representation['context']['frame'] = src_padding_exp % repre.get("frameStart")
|
||||
representation['context']['frame'] = src_padding_exp % int(repre.get("frameStart"))
|
||||
|
||||
self.log.debug("__ representation: {}".format(representation))
|
||||
destination_list.append(dst)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ class ValidateFfmpegInstallef(pyblish.api.Validator):
|
|||
return True
|
||||
|
||||
def process(self, instance):
|
||||
self.log.info("ffmpeg path: `{}`".format(
|
||||
os.environ.get("FFMPEG_PATH", "")))
|
||||
if self.is_tool(
|
||||
os.path.join(
|
||||
os.environ.get("FFMPEG_PATH", ""), "ffmpeg")) is False:
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ class CollectNukeInstances(pyblish.api.ContextPlugin):
|
|||
self.log.debug("asset_data: {}".format(asset_data["data"]))
|
||||
instances = []
|
||||
|
||||
root = nuke.root()
|
||||
|
||||
self.log.debug("nuke.allNodes(): {}".format(nuke.allNodes()))
|
||||
for node in nuke.allNodes():
|
||||
|
||||
|
|
@ -34,7 +36,7 @@ class CollectNukeInstances(pyblish.api.ContextPlugin):
|
|||
|
||||
# get data from avalon knob
|
||||
self.log.debug("node[name]: {}".format(node['name'].value()))
|
||||
avalon_knob_data = get_avalon_knob_data(node)
|
||||
avalon_knob_data = get_avalon_knob_data(node, ["avalon:", "ak:"])
|
||||
|
||||
self.log.debug("avalon_knob_data: {}".format(avalon_knob_data))
|
||||
|
||||
|
|
@ -86,6 +88,12 @@ class CollectNukeInstances(pyblish.api.ContextPlugin):
|
|||
family = avalon_knob_data["family"]
|
||||
families = [avalon_knob_data["families"]]
|
||||
|
||||
# Get format
|
||||
format = root['format'].value()
|
||||
resolution_width = format.width()
|
||||
resolution_height = format.height()
|
||||
pixel_aspect = format.pixelAspect()
|
||||
|
||||
if node.Class() not in "Read":
|
||||
if node["render"].value():
|
||||
self.log.info("flagged for render")
|
||||
|
|
@ -111,7 +119,10 @@ class CollectNukeInstances(pyblish.api.ContextPlugin):
|
|||
"avalonKnob": avalon_knob_data,
|
||||
"publish": node.knob('publish').value(),
|
||||
"step": 1,
|
||||
"fps": nuke.root()['fps'].value()
|
||||
"fps": nuke.root()['fps'].value(),
|
||||
"resolutionWidth": resolution_width,
|
||||
"resolutionHeight": resolution_height,
|
||||
"pixelAspect": pixel_aspect,
|
||||
|
||||
})
|
||||
|
||||
|
|
@ -119,5 +130,4 @@ class CollectNukeInstances(pyblish.api.ContextPlugin):
|
|||
instances.append(instance)
|
||||
|
||||
context.data["instances"] = instances
|
||||
|
||||
self.log.debug("context: {}".format(context))
|
||||
|
|
|
|||
|
|
@ -76,7 +76,8 @@ class CollectNukeWrites(pyblish.api.InstancePlugin):
|
|||
}
|
||||
|
||||
try:
|
||||
collected_frames = os.listdir(output_dir)
|
||||
collected_frames = [f for f in os.listdir(output_dir)
|
||||
if ext in f]
|
||||
if collected_frames:
|
||||
representation['frameStart'] = "%0{}d".format(
|
||||
len(str(last_frame))) % first_frame
|
||||
|
|
@ -99,7 +100,7 @@ class CollectNukeWrites(pyblish.api.InstancePlugin):
|
|||
"subset": instance.data["subset"],
|
||||
"fps": instance.context.data["fps"]
|
||||
}
|
||||
|
||||
instance.data["family"] = "write"
|
||||
group_node = [x for x in instance if x.Class() == "Group"][0]
|
||||
deadlineChunkSize = 1
|
||||
if "deadlineChunkSize" in group_node.knobs():
|
||||
|
|
|
|||
|
|
@ -1,187 +0,0 @@
|
|||
import os
|
||||
import nuke
|
||||
import pyblish.api
|
||||
import pype
|
||||
|
||||
class ExtractReviewData(pype.api.Extractor):
|
||||
"""Extracts movie and thumbnail with baked in luts
|
||||
|
||||
must be run after extract_render_local.py
|
||||
|
||||
"""
|
||||
|
||||
order = pyblish.api.ExtractorOrder + 0.01
|
||||
label = "Extract Review Data"
|
||||
|
||||
families = ["review"]
|
||||
hosts = ["nuke"]
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
# Store selection
|
||||
selection = [i for i in nuke.allNodes() if i["selected"].getValue()]
|
||||
# Deselect all nodes to prevent external connections
|
||||
[i["selected"].setValue(False) for i in nuke.allNodes()]
|
||||
self.log.debug("creating staging dir:")
|
||||
self.staging_dir(instance)
|
||||
|
||||
self.log.debug("instance: {}".format(instance))
|
||||
self.log.debug("instance.data[families]: {}".format(
|
||||
instance.data["families"]))
|
||||
|
||||
if "still" not in instance.data["families"]:
|
||||
self.render_review_representation(instance,
|
||||
representation="mov")
|
||||
self.render_review_representation(instance,
|
||||
representation="jpeg")
|
||||
else:
|
||||
self.render_review_representation(instance, representation="jpeg")
|
||||
|
||||
# Restore selection
|
||||
[i["selected"].setValue(False) for i in nuke.allNodes()]
|
||||
[i["selected"].setValue(True) for i in selection]
|
||||
|
||||
def render_review_representation(self,
|
||||
instance,
|
||||
representation="mov"):
|
||||
|
||||
assert instance.data['representations'][0]['files'], "Instance data files should't be empty!"
|
||||
|
||||
temporary_nodes = []
|
||||
stagingDir = instance.data[
|
||||
'representations'][0]["stagingDir"].replace("\\", "/")
|
||||
self.log.debug("StagingDir `{0}`...".format(stagingDir))
|
||||
|
||||
collection = instance.data.get("collection", None)
|
||||
|
||||
if collection:
|
||||
# get path
|
||||
fname = os.path.basename(collection.format(
|
||||
"{head}{padding}{tail}"))
|
||||
fhead = collection.format("{head}")
|
||||
|
||||
# get first and last frame
|
||||
first_frame = min(collection.indexes)
|
||||
last_frame = max(collection.indexes)
|
||||
else:
|
||||
fname = os.path.basename(instance.data.get("path", None))
|
||||
fhead = os.path.splitext(fname)[0] + "."
|
||||
first_frame = instance.data.get("frameStart", None)
|
||||
last_frame = instance.data.get("frameEnd", None)
|
||||
|
||||
rnode = nuke.createNode("Read")
|
||||
|
||||
rnode["file"].setValue(
|
||||
os.path.join(stagingDir, fname).replace("\\", "/"))
|
||||
|
||||
rnode["first"].setValue(first_frame)
|
||||
rnode["origfirst"].setValue(first_frame)
|
||||
rnode["last"].setValue(last_frame)
|
||||
rnode["origlast"].setValue(last_frame)
|
||||
temporary_nodes.append(rnode)
|
||||
previous_node = rnode
|
||||
|
||||
# get input process and connect it to baking
|
||||
ipn = self.get_view_process_node()
|
||||
if ipn is not None:
|
||||
ipn.setInput(0, previous_node)
|
||||
previous_node = ipn
|
||||
temporary_nodes.append(ipn)
|
||||
|
||||
reformat_node = nuke.createNode("Reformat")
|
||||
|
||||
ref_node = self.nodes.get("Reformat", None)
|
||||
if ref_node:
|
||||
for k, v in ref_node:
|
||||
self.log.debug("k,v: {0}:{1}".format(k,v))
|
||||
if isinstance(v, unicode):
|
||||
v = str(v)
|
||||
reformat_node[k].setValue(v)
|
||||
|
||||
reformat_node.setInput(0, previous_node)
|
||||
previous_node = reformat_node
|
||||
temporary_nodes.append(reformat_node)
|
||||
|
||||
dag_node = nuke.createNode("OCIODisplay")
|
||||
dag_node.setInput(0, previous_node)
|
||||
previous_node = dag_node
|
||||
temporary_nodes.append(dag_node)
|
||||
|
||||
# create write node
|
||||
write_node = nuke.createNode("Write")
|
||||
|
||||
if representation in "mov":
|
||||
file = fhead + "baked.mov"
|
||||
name = "baked"
|
||||
path = os.path.join(stagingDir, file).replace("\\", "/")
|
||||
self.log.debug("Path: {}".format(path))
|
||||
instance.data["baked_colorspace_movie"] = path
|
||||
write_node["file"].setValue(path)
|
||||
write_node["file_type"].setValue("mov")
|
||||
write_node["raw"].setValue(1)
|
||||
write_node.setInput(0, previous_node)
|
||||
temporary_nodes.append(write_node)
|
||||
tags = ["review", "delete"]
|
||||
|
||||
elif representation in "jpeg":
|
||||
file = fhead + "jpeg"
|
||||
name = "thumbnail"
|
||||
path = os.path.join(stagingDir, file).replace("\\", "/")
|
||||
instance.data["thumbnail"] = path
|
||||
write_node["file"].setValue(path)
|
||||
write_node["file_type"].setValue("jpeg")
|
||||
write_node["raw"].setValue(1)
|
||||
write_node.setInput(0, previous_node)
|
||||
temporary_nodes.append(write_node)
|
||||
tags = ["thumbnail"]
|
||||
|
||||
# retime for
|
||||
first_frame = int(last_frame) / 2
|
||||
last_frame = int(last_frame) / 2
|
||||
|
||||
repre = {
|
||||
'name': name,
|
||||
'ext': representation,
|
||||
'files': file,
|
||||
"stagingDir": stagingDir,
|
||||
"frameStart": first_frame,
|
||||
"frameEnd": last_frame,
|
||||
"anatomy_template": "render",
|
||||
"tags": tags
|
||||
}
|
||||
instance.data["representations"].append(repre)
|
||||
|
||||
# Render frames
|
||||
nuke.execute(write_node.name(), int(first_frame), int(last_frame))
|
||||
|
||||
self.log.debug("representations: {}".format(instance.data["representations"]))
|
||||
|
||||
# Clean up
|
||||
for node in temporary_nodes:
|
||||
nuke.delete(node)
|
||||
|
||||
def get_view_process_node(self):
|
||||
|
||||
# Select only the target node
|
||||
if nuke.selectedNodes():
|
||||
[n.setSelected(False) for n in nuke.selectedNodes()]
|
||||
|
||||
ipn_orig = None
|
||||
for v in [n for n in nuke.allNodes()
|
||||
if "Viewer" in n.Class()]:
|
||||
ip = v['input_process'].getValue()
|
||||
ipn = v['input_process_node'].getValue()
|
||||
if "VIEWER_INPUT" not in ipn and ip:
|
||||
ipn_orig = nuke.toNode(ipn)
|
||||
ipn_orig.setSelected(True)
|
||||
|
||||
if ipn_orig:
|
||||
nuke.nodeCopy('%clipboard%')
|
||||
|
||||
[n.setSelected(False) for n in nuke.selectedNodes()] # Deselect all
|
||||
|
||||
nuke.nodePaste('%clipboard%')
|
||||
|
||||
ipn = nuke.selectedNode()
|
||||
|
||||
return ipn
|
||||
58
pype/plugins/nuke/publish/extract_review_data_lut.py
Normal file
58
pype/plugins/nuke/publish/extract_review_data_lut.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import os
|
||||
import pyblish.api
|
||||
from avalon.nuke import lib as anlib
|
||||
from pype.nuke import lib as pnlib
|
||||
import pype
|
||||
reload(pnlib)
|
||||
|
||||
|
||||
class ExtractReviewLutData(pype.api.Extractor):
|
||||
"""Extracts movie and thumbnail with baked in luts
|
||||
|
||||
must be run after extract_render_local.py
|
||||
|
||||
"""
|
||||
|
||||
order = pyblish.api.ExtractorOrder + 0.005
|
||||
label = "Extract Review Data Lut"
|
||||
|
||||
families = ["review"]
|
||||
hosts = ["nuke"]
|
||||
|
||||
def process(self, instance):
|
||||
families = instance.data["families"]
|
||||
self.log.info("Creating staging dir...")
|
||||
if "representations" in instance.data:
|
||||
staging_dir = instance.data[
|
||||
"representations"][0]["stagingDir"].replace("\\", "/")
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
instance.data["representations"][0]["tags"] = ["review"]
|
||||
else:
|
||||
instance.data["representations"] = []
|
||||
# get output path
|
||||
render_path = instance.data['path']
|
||||
staging_dir = os.path.normpath(os.path.dirname(render_path))
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
|
||||
self.log.info(
|
||||
"StagingDir `{0}`...".format(instance.data["stagingDir"]))
|
||||
|
||||
with anlib.maintained_selection():
|
||||
exporter = pnlib.Exporter_review_lut(
|
||||
self, instance
|
||||
)
|
||||
data = exporter.generate_lut()
|
||||
|
||||
# assign to representations
|
||||
instance.data["lutPath"] = os.path.join(
|
||||
exporter.stagingDir, exporter.file).replace("\\", "/")
|
||||
instance.data["representations"] += data["representations"]
|
||||
|
||||
if "render.farm" in families:
|
||||
instance.data["families"].remove("review")
|
||||
instance.data["families"].remove("ftrack")
|
||||
|
||||
self.log.debug(
|
||||
"_ lutPath: {}".format(instance.data["lutPath"]))
|
||||
self.log.debug(
|
||||
"_ representations: {}".format(instance.data["representations"]))
|
||||
174
pype/plugins/nuke/publish/extract_thumbnail.py
Normal file
174
pype/plugins/nuke/publish/extract_thumbnail.py
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
import os
|
||||
import nuke
|
||||
from avalon.nuke import lib as anlib
|
||||
import pyblish.api
|
||||
import pype
|
||||
|
||||
|
||||
class ExtractThumbnail(pype.api.Extractor):
|
||||
"""Extracts movie and thumbnail with baked in luts
|
||||
|
||||
must be run after extract_render_local.py
|
||||
|
||||
"""
|
||||
|
||||
order = pyblish.api.ExtractorOrder + 0.01
|
||||
label = "Extract Thumbnail"
|
||||
|
||||
families = ["review", "render.farm"]
|
||||
hosts = ["nuke"]
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
with anlib.maintained_selection():
|
||||
self.log.debug("instance: {}".format(instance))
|
||||
self.log.debug("instance.data[families]: {}".format(
|
||||
instance.data["families"]))
|
||||
|
||||
self.render_thumbnail(instance)
|
||||
|
||||
def render_thumbnail(self, instance):
|
||||
node = instance[0] # group node
|
||||
self.log.info("Creating staging dir...")
|
||||
if "representations" in instance.data:
|
||||
staging_dir = instance.data[
|
||||
"representations"][0]["stagingDir"].replace("\\", "/")
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
instance.data["representations"][0]["tags"] = ["review"]
|
||||
else:
|
||||
instance.data["representations"] = []
|
||||
# get output path
|
||||
render_path = instance.data['path']
|
||||
staging_dir = os.path.normpath(os.path.dirname(render_path))
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
|
||||
self.log.info(
|
||||
"StagingDir `{0}`...".format(instance.data["stagingDir"]))
|
||||
|
||||
temporary_nodes = []
|
||||
collection = instance.data.get("collection", None)
|
||||
|
||||
if collection:
|
||||
# get path
|
||||
fname = os.path.basename(collection.format(
|
||||
"{head}{padding}{tail}"))
|
||||
fhead = collection.format("{head}")
|
||||
|
||||
# get first and last frame
|
||||
first_frame = min(collection.indexes)
|
||||
last_frame = max(collection.indexes)
|
||||
else:
|
||||
fname = os.path.basename(instance.data.get("path", None))
|
||||
fhead = os.path.splitext(fname)[0] + "."
|
||||
first_frame = instance.data.get("frameStart", None)
|
||||
last_frame = instance.data.get("frameEnd", None)
|
||||
|
||||
if "#" in fhead:
|
||||
fhead = fhead.replace("#", "")[:-1]
|
||||
|
||||
path_render = os.path.join(staging_dir, fname).replace("\\", "/")
|
||||
# check if file exist otherwise connect to write node
|
||||
if os.path.isfile(path_render):
|
||||
rnode = nuke.createNode("Read")
|
||||
|
||||
rnode["file"].setValue(path_render)
|
||||
|
||||
rnode["first"].setValue(first_frame)
|
||||
rnode["origfirst"].setValue(first_frame)
|
||||
rnode["last"].setValue(last_frame)
|
||||
rnode["origlast"].setValue(last_frame)
|
||||
temporary_nodes.append(rnode)
|
||||
previous_node = rnode
|
||||
else:
|
||||
previous_node = node
|
||||
|
||||
# get input process and connect it to baking
|
||||
ipn = self.get_view_process_node()
|
||||
if ipn is not None:
|
||||
ipn.setInput(0, previous_node)
|
||||
previous_node = ipn
|
||||
temporary_nodes.append(ipn)
|
||||
|
||||
reformat_node = nuke.createNode("Reformat")
|
||||
|
||||
ref_node = self.nodes.get("Reformat", None)
|
||||
if ref_node:
|
||||
for k, v in ref_node:
|
||||
self.log.debug("k, v: {0}:{1}".format(k, v))
|
||||
if isinstance(v, unicode):
|
||||
v = str(v)
|
||||
reformat_node[k].setValue(v)
|
||||
|
||||
reformat_node.setInput(0, previous_node)
|
||||
previous_node = reformat_node
|
||||
temporary_nodes.append(reformat_node)
|
||||
|
||||
dag_node = nuke.createNode("OCIODisplay")
|
||||
dag_node.setInput(0, previous_node)
|
||||
previous_node = dag_node
|
||||
temporary_nodes.append(dag_node)
|
||||
|
||||
# create write node
|
||||
write_node = nuke.createNode("Write")
|
||||
file = fhead + "jpeg"
|
||||
name = "thumbnail"
|
||||
path = os.path.join(staging_dir, file).replace("\\", "/")
|
||||
instance.data["thumbnail"] = path
|
||||
write_node["file"].setValue(path)
|
||||
write_node["file_type"].setValue("jpeg")
|
||||
write_node["raw"].setValue(1)
|
||||
write_node.setInput(0, previous_node)
|
||||
temporary_nodes.append(write_node)
|
||||
tags = ["thumbnail"]
|
||||
|
||||
# retime for
|
||||
first_frame = int(last_frame) / 2
|
||||
last_frame = int(last_frame) / 2
|
||||
|
||||
repre = {
|
||||
'name': name,
|
||||
'ext': "jpeg",
|
||||
'files': file,
|
||||
"stagingDir": staging_dir,
|
||||
"frameStart": first_frame,
|
||||
"frameEnd": last_frame,
|
||||
"anatomy_template": "render",
|
||||
"tags": tags
|
||||
}
|
||||
instance.data["representations"].append(repre)
|
||||
|
||||
# Render frames
|
||||
nuke.execute(write_node.name(), int(first_frame), int(last_frame))
|
||||
|
||||
self.log.debug(
|
||||
"representations: {}".format(instance.data["representations"]))
|
||||
|
||||
# Clean up
|
||||
for node in temporary_nodes:
|
||||
nuke.delete(node)
|
||||
|
||||
def get_view_process_node(self):
|
||||
|
||||
# Select only the target node
|
||||
if nuke.selectedNodes():
|
||||
[n.setSelected(False) for n in nuke.selectedNodes()]
|
||||
|
||||
ipn_orig = None
|
||||
for v in [n for n in nuke.allNodes()
|
||||
if "Viewer" in n.Class()]:
|
||||
ip = v['input_process'].getValue()
|
||||
ipn = v['input_process_node'].getValue()
|
||||
if "VIEWER_INPUT" not in ipn and ip:
|
||||
ipn_orig = nuke.toNode(ipn)
|
||||
ipn_orig.setSelected(True)
|
||||
|
||||
if ipn_orig:
|
||||
nuke.nodeCopy('%clipboard%')
|
||||
|
||||
[n.setSelected(False) for n in nuke.selectedNodes()] # Deselect all
|
||||
|
||||
nuke.nodePaste('%clipboard%')
|
||||
|
||||
ipn = nuke.selectedNode()
|
||||
|
||||
return ipn
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
import os
|
||||
import json
|
||||
import getpass
|
||||
|
||||
import nuke
|
||||
|
||||
|
||||
from avalon import api
|
||||
from avalon.vendor import requests
|
||||
import re
|
||||
|
|
@ -27,40 +25,36 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin):
|
|||
|
||||
def process(self, instance):
|
||||
|
||||
node = None
|
||||
for x in instance:
|
||||
if x.Class() == "Write":
|
||||
node = x
|
||||
|
||||
if node is None:
|
||||
return
|
||||
node = instance[0]
|
||||
# for x in instance:
|
||||
# if x.Class() == "Write":
|
||||
# node = x
|
||||
#
|
||||
# if node is None:
|
||||
# return
|
||||
|
||||
DEADLINE_REST_URL = os.environ.get("DEADLINE_REST_URL",
|
||||
"http://localhost:8082")
|
||||
assert DEADLINE_REST_URL, "Requires DEADLINE_REST_URL"
|
||||
|
||||
context = instance.context
|
||||
workspace = os.path.dirname(context.data["currentFile"])
|
||||
filepath = None
|
||||
|
||||
# get path
|
||||
path = nuke.filename(node)
|
||||
output_dir = instance.data['outputDir']
|
||||
# get output path
|
||||
render_path = instance.data['path']
|
||||
render_dir = os.path.normpath(os.path.dirname(render_path))
|
||||
|
||||
filepath = context.data["currentFile"]
|
||||
script_path = context.data["currentFile"]
|
||||
|
||||
self.log.debug(filepath)
|
||||
|
||||
filename = os.path.basename(filepath)
|
||||
script_name = os.path.basename(script_path)
|
||||
comment = context.data.get("comment", "")
|
||||
dirname = os.path.join(workspace, "renders")
|
||||
|
||||
deadline_user = context.data.get("deadlineUser", getpass.getuser())
|
||||
jobname = "%s - %s" % (filename, instance.name)
|
||||
jobname = "%s - %s" % (script_name, instance.name)
|
||||
ver = re.search(r"\d+\.\d+", context.data.get("hostVersion"))
|
||||
|
||||
try:
|
||||
# Ensure render folder exists
|
||||
os.makedirs(dirname)
|
||||
os.makedirs(render_dir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
|
@ -71,7 +65,7 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin):
|
|||
payload = {
|
||||
"JobInfo": {
|
||||
# Top-level group name
|
||||
"BatchName": filename,
|
||||
"BatchName": script_name,
|
||||
|
||||
# Job name, as seen in Monitor
|
||||
"Name": jobname,
|
||||
|
|
@ -95,20 +89,20 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin):
|
|||
},
|
||||
"PluginInfo": {
|
||||
# Input
|
||||
"SceneFile": filepath,
|
||||
"SceneFile": script_path,
|
||||
|
||||
# Output directory and filename
|
||||
"OutputFilePath": dirname.replace("\\", "/"),
|
||||
"OutputFilePath": render_dir.replace("\\", "/"),
|
||||
# "OutputFilePrefix": render_variables["filename_prefix"],
|
||||
|
||||
# Mandatory for Deadline
|
||||
"Version": ver.group(),
|
||||
|
||||
# Resolve relative references
|
||||
"ProjectPath": workspace,
|
||||
|
||||
"ProjectPath": script_path,
|
||||
"AWSAssetFile0": render_path,
|
||||
# Only the specific write node is rendered.
|
||||
"WriteNode": instance[0].name()
|
||||
"WriteNode": node.name()
|
||||
},
|
||||
|
||||
# Mandatory for Deadline, may be empty
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class ValidateRenderedFrames(pyblish.api.InstancePlugin):
|
|||
""" Validates file output. """
|
||||
|
||||
order = pyblish.api.ValidatorOrder + 0.1
|
||||
families = ["render.no"]
|
||||
families = ["render"]
|
||||
|
||||
label = "Validate rendered frame"
|
||||
hosts = ["nuke", "nukestudio"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue