From bc9633233baf2a1e3550a03f1dae5b05ab732f8f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 9 Aug 2019 19:29:57 +0200 Subject: [PATCH] feat(nks): adding retiming and timewarping implementation --- .../nuke/publish/collect_asset_info.py | 4 +- .../publish/collect_calculate_retime.py | 121 ++++++++++++++++++ .../publish/collect_frame_ranges.py | 7 +- .../nukestudio/publish/collect_plates.py | 34 ++++- .../nukestudio/publish/collect_tag_retime.py | 32 +++++ 5 files changed, 190 insertions(+), 8 deletions(-) create mode 100644 pype/plugins/nukestudio/publish/collect_calculate_retime.py create mode 100644 pype/plugins/nukestudio/publish/collect_tag_retime.py diff --git a/pype/plugins/nuke/publish/collect_asset_info.py b/pype/plugins/nuke/publish/collect_asset_info.py index 4bfcb0ab00..76b93ef3d0 100644 --- a/pype/plugins/nuke/publish/collect_asset_info.py +++ b/pype/plugins/nuke/publish/collect_asset_info.py @@ -1,4 +1,3 @@ -import nuke from avalon import api, io import pyblish.api @@ -19,5 +18,6 @@ class CollectAssetInfo(pyblish.api.ContextPlugin): self.log.info("asset_data: {}".format(asset_data)) context.data['handles'] = int(asset_data["data"].get("handles", 0)) - context.data["handleStart"] = int(asset_data["data"].get("handleStart", 0)) + context.data["handleStart"] = int(asset_data["data"].get( + "handleStart", 0)) context.data["handleEnd"] = int(asset_data["data"].get("handleEnd", 0)) diff --git a/pype/plugins/nukestudio/publish/collect_calculate_retime.py b/pype/plugins/nukestudio/publish/collect_calculate_retime.py new file mode 100644 index 0000000000..a97b43a4ce --- /dev/null +++ b/pype/plugins/nukestudio/publish/collect_calculate_retime.py @@ -0,0 +1,121 @@ +from pyblish import api +import hiero +import math + + +class CollectCalculateRetime(api.InstancePlugin): + """Calculate Retiming of selected track items.""" + + order = api.CollectorOrder + 0.02 + label = "Collect Calculate Retiming" + hosts = ["nukestudio"] + families = ['retime'] + + def process(self, instance): + margin_in = instance.data["retimeMarginIn"] + margin_out = instance.data["retimeMarginOut"] + self.log.debug("margin_in: '{0}', margin_out: '{1}'".format(margin_in, margin_out)) + + handle_start = instance.data["handleStart"] + handle_end = instance.data["handleEnd"] + + track_item = instance.data["item"] + + # define basic clip frame range variables + timeline_in = int(track_item.timelineIn()) + timeline_out = int(track_item.timelineOut()) + source_in = int(track_item.sourceIn()) + source_out = int(track_item.sourceOut()) + speed = track_item.playbackSpeed() + self.log.debug("_BEFORE: \n timeline_in: `{0}`,\n timeline_out: `{1}`,\ + \n source_in: `{2}`,\n source_out: `{3}`,\n speed: `{4}`,\n handle_start: `{5}`,\n handle_end: `{6}`".format( + timeline_in, + timeline_out, + source_in, + source_out, + speed, + handle_start, + handle_end + )) + + # loop withing subtrack items + source_in_change = 0 + source_out_change = 0 + for s_track_item in track_item.linkedItems(): + if isinstance(s_track_item, hiero.core.EffectTrackItem) \ + and "TimeWarp" in s_track_item.node().Class(): + + # adding timewarp attribute to instance + if not instance.data.get("timeWarpNodes", None): + instance.data["timeWarpNodes"] = list() + + # ignore item if not enabled + if s_track_item.isEnabled(): + node = s_track_item.node() + name = node["name"].value() + look_up = node["lookup"].value() + animated = node["lookup"].isAnimated() + if animated: + look_up = [((node["lookup"].getValueAt(i)) - i) + for i in range((timeline_in - handle_start), (timeline_out + handle_end) + 1) + ] + # calculate differnce + diff_in = (node["lookup"].getValueAt( + timeline_in)) - timeline_in + diff_out = (node["lookup"].getValueAt( + timeline_out)) - timeline_out + + # calculate source + source_in_change += diff_in + source_out_change += diff_out + + # calculate speed + speed_in = (node["lookup"].getValueAt(timeline_in) / ( + float(timeline_in) * .01)) * .01 + speed_out = (node["lookup"].getValueAt(timeline_out) / ( + float(timeline_out) * .01)) * .01 + + # calculate handles + handle_start = int( + math.ceil( + (handle_start * speed_in * 1000) / 1000.0) + ) + + handle_end = int( + math.ceil( + (handle_end * speed_out * 1000) / 1000.0) + ) + self.log.debug( + ("diff_in, diff_out", diff_in, diff_out)) + self.log.debug( + ("source_in_change, source_out_change", source_in_change, source_out_change)) + + instance.data["timeWarpNodes"].append({"Class": "TimeWarp", + "name": name, + "lookup": look_up}) + + self.log.debug((source_in_change, source_out_change)) + # recalculate handles by the speed + handle_start *= speed + handle_end *= speed + self.log.debug("speed: handle_start: '{0}', handle_end: '{1}'".format(handle_start, handle_end)) + + source_in += int(source_in_change) + source_out += int(source_out_change * speed) + handle_start += (margin_in) + handle_end += (margin_out) + self.log.debug("margin: handle_start: '{0}', handle_end: '{1}'".format(handle_start, handle_end)) + + # add all data to Instance + instance.data["sourceIn"] = source_in + instance.data["sourceOut"] = source_out + instance.data["sourceInH"] = int(source_in - math.ceil( + (handle_start * 1000) / 1000.0)) + instance.data["sourceOutH"] = int(source_out + math.ceil( + (handle_end * 1000) / 1000.0)) + instance.data["speed"] = speed + + self.log.debug("timeWarpNodes: {}".format(instance.data["timeWarpNodes"])) + self.log.debug("sourceIn: {}".format(instance.data["sourceIn"])) + self.log.debug("sourceOut: {}".format(instance.data["sourceOut"])) + self.log.debug("speed: {}".format(instance.data["speed"])) diff --git a/pype/plugins/nukestudio/publish/collect_frame_ranges.py b/pype/plugins/nukestudio/publish/collect_frame_ranges.py index 392dbba68b..38224f683d 100644 --- a/pype/plugins/nukestudio/publish/collect_frame_ranges.py +++ b/pype/plugins/nukestudio/publish/collect_frame_ranges.py @@ -1,5 +1,6 @@ import pyblish.api + class CollectClipFrameRanges(pyblish.api.InstancePlugin): """Collect all frame range data: source(In,Out), timeline(In,Out), edit_(in, out), f(start, end)""" @@ -15,8 +16,10 @@ class CollectClipFrameRanges(pyblish.api.InstancePlugin): handle_start = instance.data["handleStart"] handle_end = instance.data["handleEnd"] - source_in_h = instance.data["sourceIn"] - handle_start - source_out_h = instance.data["sourceOut"] + handle_end + source_in_h = instance.data("sourceInH", + instance.data("sourceIn") - handle_start) + source_out_h = instance.data("sourceOutH", + instance.data("sourceOut") + handle_end) timeline_in = instance.data["clipIn"] timeline_out = instance.data["clipOut"] diff --git a/pype/plugins/nukestudio/publish/collect_plates.py b/pype/plugins/nukestudio/publish/collect_plates.py index c9e6305062..9843307f14 100644 --- a/pype/plugins/nukestudio/publish/collect_plates.py +++ b/pype/plugins/nukestudio/publish/collect_plates.py @@ -137,7 +137,6 @@ class CollectPlatesData(api.InstancePlugin): "subset": name, "fps": instance.context.data["fps"] }) - instance.data["versionData"] = version_data try: basename, ext = os.path.splitext(source_file) @@ -156,9 +155,11 @@ class CollectPlatesData(api.InstancePlugin): start_frame = source_first_frame + instance.data["sourceInH"] duration = instance.data["sourceOutH"] - instance.data["sourceInH"] end_frame = start_frame + duration + self.log.debug("start_frame: `{}`".format(start_frame)) + self.log.debug("end_frame: `{}`".format(end_frame)) files = [file % i for i in range(start_frame, (end_frame + 1), 1)] except Exception as e: - self.log.debug("Exception in file: {}".format(e)) + self.log.warning("Exception in file: {}".format(e)) head, ext = os.path.splitext(source_file) ext = ext[1:] files = source_file @@ -207,16 +208,41 @@ class CollectPlatesData(api.InstancePlugin): thumb_representation) # adding representation for plates + frame_start = instance.data["frameStart"] - \ + instance.data["handleStart"] + frame_end = instance.data["frameEnd"] + instance.data["handleEnd"] + + # exception for retimes + if instance.data.get("retime"): + source_in_h = instance.data["sourceInH"] + source_in = instance.data["sourceIn"] + source_handle_start = source_in_h - source_in + frame_start = instance.data["frameStart"] + source_handle_start + duration = instance.data["sourceOutH"] - instance.data["sourceInH"] + frame_end = frame_start + duration + plates_representation = { 'files': files, 'stagingDir': staging_dir, 'name': ext, 'ext': ext, - "frameStart": instance.data["frameStart"] - instance.data["handleStart"], - "frameEnd": instance.data["frameEnd"] + instance.data["handleEnd"], + "frameStart": frame_start, + "frameEnd": frame_end, } instance.data["representations"].append(plates_representation) + # deal with retimed clip + if instance.data.get("retime"): + version_data.update({ + "retime": True, + "speed": instance.data.get("speed", 1), + "timewarps": instance.data.get("timeWarpNodes", []), + "frameStart": frame_start, + "frameEnd": frame_end, + }) + + instance.data["versionData"] = version_data + # testing families family = instance.data["family"] families = instance.data["families"] diff --git a/pype/plugins/nukestudio/publish/collect_tag_retime.py b/pype/plugins/nukestudio/publish/collect_tag_retime.py new file mode 100644 index 0000000000..32e49e1b2a --- /dev/null +++ b/pype/plugins/nukestudio/publish/collect_tag_retime.py @@ -0,0 +1,32 @@ +from pyblish import api + + +class CollectTagRetime(api.InstancePlugin): + """Collect Retiming from Tags of selected track items.""" + + order = api.CollectorOrder + 0.014 + label = "Collect Retiming Tag" + hosts = ["nukestudio"] + families = ['clip'] + + def process(self, instance): + # gets tags + tags = instance.data["tags"] + + for t in tags: + t_metadata = dict(t["metadata"]) + t_family = t_metadata.get("tag.family", "") + + # gets only task family tags and collect labels + if "retiming" in t_family: + margin_in = t_metadata.get("tag.marginIn", "") + margin_out = t_metadata.get("tag.marginOut", "") + + instance.data["retimeMarginIn"] = int(margin_in) + instance.data["retimeMarginOut"] = int(margin_out) + instance.data["retime"] = True + + self.log.info("retimeMarginIn: `{}`".format(margin_in)) + self.log.info("retimeMarginOut: `{}`".format(margin_out)) + + instance.data["families"] += ["retime"]