mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-26 05:42:15 +01:00
Merge branch 'feature/1376-hiero-publish-color-and-transformation-soft-effects' into feature/1377-hiero-publish-with-retiming
This commit is contained in:
commit
4d93fd705b
10 changed files with 212 additions and 46 deletions
|
|
@ -214,7 +214,9 @@ def get_track_items(
|
|||
# add all if no track_type is defined
|
||||
return_list.append(track_item)
|
||||
|
||||
return return_list
|
||||
# return output list but make sure all items are TrackItems
|
||||
return [_i for _i in return_list
|
||||
if type(_i) == hiero.core.TrackItem]
|
||||
|
||||
|
||||
def get_track_item_pype_tag(track_item):
|
||||
|
|
|
|||
|
|
@ -52,10 +52,11 @@ class ExtractClipEffects(openpype.api.Extractor):
|
|||
instance.data["representations"] = list()
|
||||
|
||||
transfer_data = [
|
||||
"handleStart", "handleEnd", "sourceIn", "sourceOut",
|
||||
"frameStart", "frameEnd", "sourceInH", "sourceOutH",
|
||||
"clipIn", "clipOut", "clipInH", "clipOutH", "asset", "track",
|
||||
"version"
|
||||
"handleStart", "handleEnd",
|
||||
"sourceStart", "sourceStartH", "sourceEnd", "sourceEndH",
|
||||
"frameStart", "frameEnd",
|
||||
"clipIn", "clipOut", "clipInH", "clipOutH",
|
||||
"asset", "version"
|
||||
]
|
||||
|
||||
# pass data to version
|
||||
|
|
@ -5,7 +5,7 @@ import pyblish.api
|
|||
class PreCollectClipEffects(pyblish.api.InstancePlugin):
|
||||
"""Collect soft effects instances."""
|
||||
|
||||
order = pyblish.api.CollectorOrder - 0.508
|
||||
order = pyblish.api.CollectorOrder - 0.579
|
||||
label = "Pre-collect Clip Effects Instances"
|
||||
families = ["clip"]
|
||||
|
||||
|
|
@ -24,7 +24,8 @@ class PreCollectClipEffects(pyblish.api.InstancePlugin):
|
|||
self.clip_in_h = self.clip_in - self.handle_start
|
||||
self.clip_out_h = self.clip_out + self.handle_end
|
||||
|
||||
track = instance.data["trackItem"]
|
||||
track_item = instance.data["item"]
|
||||
track = track_item.parent()
|
||||
track_index = track.trackIndex()
|
||||
tracks_effect_items = instance.context.data.get("tracksEffectItems")
|
||||
clip_effect_items = instance.data.get("clipEffectItems")
|
||||
|
|
@ -112,7 +113,12 @@ class PreCollectClipEffects(pyblish.api.InstancePlugin):
|
|||
node = sitem.node()
|
||||
node_serialized = self.node_serialisation(node)
|
||||
node_name = sitem.name()
|
||||
node_class = re.sub(r"\d+", "", node_name)
|
||||
|
||||
if "_" in node_name:
|
||||
node_class = re.sub(r"(?:_)[_0-9]+", "", node_name) # more numbers
|
||||
else:
|
||||
node_class = re.sub(r"\d+", "", node_name) # one number
|
||||
|
||||
# collect timelineIn/Out
|
||||
effect_t_in = int(sitem.timelineIn())
|
||||
effect_t_out = int(sitem.timelineOut())
|
||||
|
|
@ -121,6 +127,7 @@ class PreCollectClipEffects(pyblish.api.InstancePlugin):
|
|||
return
|
||||
|
||||
self.log.debug("node_name: `{}`".format(node_name))
|
||||
self.log.debug("node_class: `{}`".format(node_class))
|
||||
|
||||
return {node_name: {
|
||||
"class": node_class,
|
||||
|
|
@ -2,6 +2,9 @@ import pyblish
|
|||
import openpype
|
||||
from openpype.hosts.hiero import api as phiero
|
||||
from openpype.hosts.hiero.otio import hiero_export
|
||||
import hiero
|
||||
|
||||
from compiler.ast import flatten
|
||||
|
||||
# # developer reload modules
|
||||
from pprint import pformat
|
||||
|
|
@ -14,18 +17,40 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
|
|||
label = "Precollect Instances"
|
||||
hosts = ["hiero"]
|
||||
|
||||
audio_track_items = []
|
||||
|
||||
def process(self, context):
|
||||
otio_timeline = context.data["otioTimeline"]
|
||||
self.otio_timeline = context.data["otioTimeline"]
|
||||
|
||||
selected_timeline_items = phiero.get_track_items(
|
||||
selected=True, check_enabled=True, check_tagged=True)
|
||||
selected=True, check_tagged=True, check_enabled=True)
|
||||
|
||||
# only return enabled track items
|
||||
if not selected_timeline_items:
|
||||
selected_timeline_items = phiero.get_track_items(
|
||||
check_enabled=True, check_tagged=True)
|
||||
|
||||
self.log.info(
|
||||
"Processing enabled track items: {}".format(
|
||||
selected_timeline_items))
|
||||
|
||||
# add all tracks subtreck effect items to context
|
||||
all_tracks = hiero.ui.activeSequence().videoTracks()
|
||||
tracks_effect_items = self.collect_sub_track_items(all_tracks)
|
||||
context.data["tracksEffectItems"] = tracks_effect_items
|
||||
|
||||
# process all sellected timeline track items
|
||||
for track_item in selected_timeline_items:
|
||||
|
||||
data = {}
|
||||
clip_name = track_item.name()
|
||||
source_clip = track_item.source()
|
||||
|
||||
# get clips subtracks and anotations
|
||||
annotations = self.clip_annotations(source_clip)
|
||||
subtracks = self.clip_subtrack(track_item)
|
||||
self.log.debug("Annotations: {}".format(annotations))
|
||||
self.log.debug(">> Subtracks: {}".format(subtracks))
|
||||
|
||||
# get openpype tag data
|
||||
tag_data = phiero.get_track_item_pype_data(track_item)
|
||||
|
|
@ -76,12 +101,15 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
|
|||
"item": track_item,
|
||||
"families": families,
|
||||
"publish": tag_data["publish"],
|
||||
"fps": context.data["fps"]
|
||||
"fps": context.data["fps"],
|
||||
|
||||
# clip's effect
|
||||
"clipEffectItems": subtracks,
|
||||
"clipAnnotations": annotations
|
||||
})
|
||||
|
||||
# otio clip data
|
||||
otio_data = self.get_otio_clip_instance_data(
|
||||
otio_timeline, track_item) or {}
|
||||
otio_data = self.get_otio_clip_instance_data(track_item) or {}
|
||||
self.log.debug("__ otio_data: {}".format(pformat(otio_data)))
|
||||
data.update(otio_data)
|
||||
self.log.debug("__ data: {}".format(pformat(data)))
|
||||
|
|
@ -185,6 +213,10 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
|
|||
item = data.get("item")
|
||||
clip_name = item.name()
|
||||
|
||||
# test if any audio clips
|
||||
if not self.test_any_audio(item):
|
||||
return
|
||||
|
||||
asset = data["asset"]
|
||||
subset = "audioMain"
|
||||
|
||||
|
|
@ -215,7 +247,28 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
|
|||
self.log.debug(
|
||||
"_ instance.data: {}".format(pformat(instance.data)))
|
||||
|
||||
def get_otio_clip_instance_data(self, otio_timeline, track_item):
|
||||
def test_any_audio(self, track_item):
|
||||
# collect all audio tracks to class variable
|
||||
if not self.audio_track_items:
|
||||
for otio_clip in self.otio_timeline.each_clip():
|
||||
if otio_clip.parent().kind != "Audio":
|
||||
continue
|
||||
self.audio_track_items.append(otio_clip)
|
||||
|
||||
# get track item timeline range
|
||||
timeline_range = self.create_otio_time_range_from_timeline_item_data(
|
||||
track_item)
|
||||
|
||||
# loop trough audio track items and search for overlaping clip
|
||||
for otio_audio in self.audio_track_items:
|
||||
parent_range = otio_audio.range_in_parent()
|
||||
|
||||
# if any overaling clip found then return True
|
||||
if openpype.lib.is_overlapping_otio_ranges(
|
||||
parent_range, timeline_range, strict=False):
|
||||
return True
|
||||
|
||||
def get_otio_clip_instance_data(self, track_item):
|
||||
"""
|
||||
Return otio objects for timeline, track and clip
|
||||
|
||||
|
|
@ -231,7 +284,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
|
|||
ti_track_name = track_item.parent().name()
|
||||
timeline_range = self.create_otio_time_range_from_timeline_item_data(
|
||||
track_item)
|
||||
for otio_clip in otio_timeline.each_clip():
|
||||
for otio_clip in self.otio_timeline.each_clip():
|
||||
track_name = otio_clip.parent().name
|
||||
parent_range = otio_clip.range_in_parent()
|
||||
if ti_track_name not in track_name:
|
||||
|
|
@ -258,3 +311,76 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
|
|||
|
||||
return hiero_export.create_otio_time_range(
|
||||
frame_start, frame_duration, fps)
|
||||
|
||||
@staticmethod
|
||||
def collect_sub_track_items(tracks):
|
||||
"""
|
||||
Returns dictionary with track index as key and list of subtracks
|
||||
"""
|
||||
# collect all subtrack items
|
||||
sub_track_items = {}
|
||||
for track in tracks:
|
||||
items = track.items()
|
||||
|
||||
# skip if no clips on track > need track with effect only
|
||||
if items:
|
||||
continue
|
||||
|
||||
# skip all disabled tracks
|
||||
if not track.isEnabled():
|
||||
continue
|
||||
|
||||
track_index = track.trackIndex()
|
||||
_sub_track_items = flatten(track.subTrackItems())
|
||||
|
||||
# continue only if any subtrack items are collected
|
||||
if len(_sub_track_items) < 1:
|
||||
continue
|
||||
|
||||
enabled_sti = []
|
||||
# loop all found subtrack items and check if they are enabled
|
||||
for _sti in _sub_track_items:
|
||||
# checking if not enabled
|
||||
if not _sti.isEnabled():
|
||||
continue
|
||||
if isinstance(_sti, hiero.core.Annotation):
|
||||
continue
|
||||
# collect the subtrack item
|
||||
enabled_sti.append(_sti)
|
||||
|
||||
# continue only if any subtrack items are collected
|
||||
if len(enabled_sti) < 1:
|
||||
continue
|
||||
|
||||
# add collection of subtrackitems to dict
|
||||
sub_track_items[track_index] = enabled_sti
|
||||
|
||||
return sub_track_items
|
||||
|
||||
@staticmethod
|
||||
def clip_annotations(clip):
|
||||
"""
|
||||
Returns list of Clip's hiero.core.Annotation
|
||||
"""
|
||||
annotations = []
|
||||
subTrackItems = flatten(clip.subTrackItems())
|
||||
annotations += [item for item in subTrackItems if isinstance(
|
||||
item, hiero.core.Annotation)]
|
||||
return annotations
|
||||
|
||||
@staticmethod
|
||||
def clip_subtrack(clip):
|
||||
"""
|
||||
Returns list of Clip's hiero.core.SubTrackItem
|
||||
"""
|
||||
subtracks = []
|
||||
subTrackItems = flatten(clip.parent().subTrackItems())
|
||||
for item in subTrackItems:
|
||||
# avoid all anotation
|
||||
if isinstance(item, hiero.core.Annotation):
|
||||
continue
|
||||
# # avoid all not anaibled
|
||||
if not item.isEnabled():
|
||||
continue
|
||||
subtracks.append(item)
|
||||
return subtracks
|
||||
|
|
|
|||
|
|
@ -75,10 +75,26 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin):
|
|||
"activeProject": project,
|
||||
"otioTimeline": otio_timeline,
|
||||
"currentFile": curent_file,
|
||||
"fps": fps,
|
||||
"colorspace": self.get_colorspace(project),
|
||||
"fps": fps
|
||||
}
|
||||
context.data.update(context_data)
|
||||
|
||||
self.log.info("Creating instance: {}".format(instance))
|
||||
self.log.debug("__ instance.data: {}".format(pformat(instance.data)))
|
||||
self.log.debug("__ context_data: {}".format(pformat(context_data)))
|
||||
|
||||
def get_colorspace(self, project):
|
||||
# get workfile's colorspace properties
|
||||
return {
|
||||
"useOCIOEnvironmentOverride": project.useOCIOEnvironmentOverride(),
|
||||
"lutSetting16Bit": project.lutSetting16Bit(),
|
||||
"lutSetting8Bit": project.lutSetting8Bit(),
|
||||
"lutSettingFloat": project.lutSettingFloat(),
|
||||
"lutSettingLog": project.lutSettingLog(),
|
||||
"lutSettingViewer": project.lutSettingViewer(),
|
||||
"lutSettingWorkingSpace": project.lutSettingWorkingSpace(),
|
||||
"lutUseOCIOForExport": project.lutUseOCIOForExport(),
|
||||
"ocioConfigName": project.ocioConfigName(),
|
||||
"ocioConfigPath": project.ocioConfigPath()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,18 +4,19 @@ import json
|
|||
from collections import OrderedDict
|
||||
|
||||
|
||||
class LoadLuts(api.Loader):
|
||||
class LoadEffects(api.Loader):
|
||||
"""Loading colorspace soft effect exported from nukestudio"""
|
||||
|
||||
representations = ["lutJson"]
|
||||
families = ["lut"]
|
||||
representations = ["effectJson"]
|
||||
families = ["effect"]
|
||||
|
||||
label = "Load Luts - nodes"
|
||||
label = "Load Effects - nodes"
|
||||
order = 0
|
||||
icon = "cc"
|
||||
color = style.colors.light
|
||||
ignore_attr = ["useLifetime"]
|
||||
|
||||
|
||||
def load(self, context, name, namespace, data):
|
||||
"""
|
||||
Loading function to get the soft effects to particular read node
|
||||
|
|
@ -66,15 +67,15 @@ class LoadLuts(api.Loader):
|
|||
for key, value in json.load(f).iteritems()}
|
||||
|
||||
# get correct order of nodes by positions on track and subtrack
|
||||
nodes_order = self.reorder_nodes(json_f["effects"])
|
||||
nodes_order = self.reorder_nodes(json_f)
|
||||
|
||||
# adding nodes to node graph
|
||||
# just in case we are in group lets jump out of it
|
||||
nuke.endGroup()
|
||||
|
||||
GN = nuke.createNode("Group")
|
||||
|
||||
GN["name"].setValue(object_name)
|
||||
GN = nuke.createNode(
|
||||
"Group",
|
||||
"name {}_1".format(object_name))
|
||||
|
||||
# adding content to the group node
|
||||
with GN:
|
||||
|
|
@ -186,7 +187,7 @@ class LoadLuts(api.Loader):
|
|||
for key, value in json.load(f).iteritems()}
|
||||
|
||||
# get correct order of nodes by positions on track and subtrack
|
||||
nodes_order = self.reorder_nodes(json_f["effects"])
|
||||
nodes_order = self.reorder_nodes(json_f)
|
||||
|
||||
# adding nodes to node graph
|
||||
# just in case we are in group lets jump out of it
|
||||
|
|
@ -266,7 +267,11 @@ class LoadLuts(api.Loader):
|
|||
None: if nothing found
|
||||
"""
|
||||
search_name = "{0}_{1}".format(asset, subset)
|
||||
node = [n for n in nuke.allNodes() if search_name in n["name"].value()]
|
||||
|
||||
node = [
|
||||
n for n in nuke.allNodes(filter="Read")
|
||||
if search_name in n["file"].value()
|
||||
]
|
||||
if len(node) > 0:
|
||||
rn = node[0]
|
||||
else:
|
||||
|
|
@ -286,8 +291,10 @@ class LoadLuts(api.Loader):
|
|||
|
||||
def reorder_nodes(self, data):
|
||||
new_order = OrderedDict()
|
||||
trackNums = [v["trackIndex"] for k, v in data.items()]
|
||||
subTrackNums = [v["subTrackIndex"] for k, v in data.items()]
|
||||
trackNums = [v["trackIndex"] for k, v in data.items()
|
||||
if isinstance(v, dict)]
|
||||
subTrackNums = [v["subTrackIndex"] for k, v in data.items()
|
||||
if isinstance(v, dict)]
|
||||
|
||||
for trackIndex in range(
|
||||
min(trackNums), max(trackNums) + 1):
|
||||
|
|
@ -300,6 +307,7 @@ class LoadLuts(api.Loader):
|
|||
|
||||
def get_item(self, data, trackIndex, subTrackIndex):
|
||||
return {key: val for key, val in data.items()
|
||||
if isinstance(val, dict)
|
||||
if subTrackIndex == val["subTrackIndex"]
|
||||
if trackIndex == val["trackIndex"]}
|
||||
|
||||
|
|
@ -5,13 +5,13 @@ from collections import OrderedDict
|
|||
from openpype.hosts.nuke.api import lib
|
||||
|
||||
|
||||
class LoadLutsInputProcess(api.Loader):
|
||||
class LoadEffectsInputProcess(api.Loader):
|
||||
"""Loading colorspace soft effect exported from nukestudio"""
|
||||
|
||||
representations = ["lutJson"]
|
||||
families = ["lut"]
|
||||
representations = ["effectJson"]
|
||||
families = ["effect"]
|
||||
|
||||
label = "Load Luts - Input Process"
|
||||
label = "Load Effects - Input Process"
|
||||
order = 0
|
||||
icon = "eye"
|
||||
color = style.colors.alert
|
||||
|
|
@ -67,15 +67,15 @@ class LoadLutsInputProcess(api.Loader):
|
|||
for key, value in json.load(f).iteritems()}
|
||||
|
||||
# get correct order of nodes by positions on track and subtrack
|
||||
nodes_order = self.reorder_nodes(json_f["effects"])
|
||||
nodes_order = self.reorder_nodes(json_f)
|
||||
|
||||
# adding nodes to node graph
|
||||
# just in case we are in group lets jump out of it
|
||||
nuke.endGroup()
|
||||
|
||||
GN = nuke.createNode("Group")
|
||||
|
||||
GN["name"].setValue(object_name)
|
||||
GN = nuke.createNode(
|
||||
"Group",
|
||||
"name {}_1".format(object_name))
|
||||
|
||||
# adding content to the group node
|
||||
with GN:
|
||||
|
|
@ -190,7 +190,7 @@ class LoadLutsInputProcess(api.Loader):
|
|||
for key, value in json.load(f).iteritems()}
|
||||
|
||||
# get correct order of nodes by positions on track and subtrack
|
||||
nodes_order = self.reorder_nodes(json_f["effects"])
|
||||
nodes_order = self.reorder_nodes(json_f)
|
||||
|
||||
# adding nodes to node graph
|
||||
# just in case we are in group lets jump out of it
|
||||
|
|
@ -304,8 +304,10 @@ class LoadLutsInputProcess(api.Loader):
|
|||
|
||||
def reorder_nodes(self, data):
|
||||
new_order = OrderedDict()
|
||||
trackNums = [v["trackIndex"] for k, v in data.items()]
|
||||
subTrackNums = [v["subTrackIndex"] for k, v in data.items()]
|
||||
trackNums = [v["trackIndex"] for k, v in data.items()
|
||||
if isinstance(v, dict)]
|
||||
subTrackNums = [v["subTrackIndex"] for k, v in data.items()
|
||||
if isinstance(v, dict)]
|
||||
|
||||
for trackIndex in range(
|
||||
min(trackNums), max(trackNums) + 1):
|
||||
|
|
@ -318,6 +320,7 @@ class LoadLutsInputProcess(api.Loader):
|
|||
|
||||
def get_item(self, data, trackIndex, subTrackIndex):
|
||||
return {key: val for key, val in data.items()
|
||||
if isinstance(val, dict)
|
||||
if subTrackIndex == val["subTrackIndex"]
|
||||
if trackIndex == val["trackIndex"]}
|
||||
|
||||
|
|
@ -39,7 +39,6 @@ class CollectResourcesPath(pyblish.api.InstancePlugin):
|
|||
"rig",
|
||||
"plate",
|
||||
"look",
|
||||
"lut",
|
||||
"yetiRig",
|
||||
"yeticache",
|
||||
"nukenodes",
|
||||
|
|
@ -52,7 +51,8 @@ class CollectResourcesPath(pyblish.api.InstancePlugin):
|
|||
"fbx",
|
||||
"textures",
|
||||
"action",
|
||||
"background"
|
||||
"background",
|
||||
"effect"
|
||||
]
|
||||
|
||||
def process(self, instance):
|
||||
|
|
|
|||
|
|
@ -40,12 +40,15 @@ class ExtractOtioAudioTracks(pyblish.api.ContextPlugin):
|
|||
# get sequence
|
||||
otio_timeline = context.data["otioTimeline"]
|
||||
|
||||
# temp file
|
||||
audio_temp_fpath = self.create_temp_file("audio")
|
||||
|
||||
# get all audio inputs from otio timeline
|
||||
audio_inputs = self.get_audio_track_items(otio_timeline)
|
||||
|
||||
if not audio_inputs:
|
||||
return
|
||||
|
||||
# temp file
|
||||
audio_temp_fpath = self.create_temp_file("audio")
|
||||
|
||||
# create empty audio with longest duration
|
||||
empty = self.create_empty(audio_inputs)
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
|
|||
"rig",
|
||||
"plate",
|
||||
"look",
|
||||
"lut",
|
||||
"audio",
|
||||
"yetiRig",
|
||||
"yeticache",
|
||||
|
|
@ -97,7 +96,8 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
|
|||
"editorial",
|
||||
"background",
|
||||
"camerarig",
|
||||
"redshiftproxy"
|
||||
"redshiftproxy",
|
||||
"effect"
|
||||
]
|
||||
exclude_families = ["clip"]
|
||||
db_representation_context_keys = [
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue