mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-02 00:44:52 +01:00
Merge branch '2.x/develop' into feature/tvpaint_creators
This commit is contained in:
commit
c2a340fab3
5 changed files with 172 additions and 46 deletions
39
pype/lib.py
39
pype/lib.py
|
|
@ -864,10 +864,10 @@ class BuildWorkfile:
|
|||
current_task_name = io.Session["AVALON_TASK"]
|
||||
|
||||
# Load workfile presets for task
|
||||
build_presets = self.get_build_presets(current_task_name)
|
||||
self.build_presets = self.get_build_presets(current_task_name)
|
||||
|
||||
# Skip if there are any presets for task
|
||||
if not build_presets:
|
||||
if not self.build_presets:
|
||||
log.warning(
|
||||
"Current task `{}` does not have any loading preset.".format(
|
||||
current_task_name
|
||||
|
|
@ -876,9 +876,9 @@ class BuildWorkfile:
|
|||
return
|
||||
|
||||
# Get presets for loading current asset
|
||||
current_context_profiles = build_presets.get("current_context")
|
||||
current_context_profiles = self.build_presets.get("current_context")
|
||||
# Get presets for loading linked assets
|
||||
link_context_profiles = build_presets.get("linked_assets")
|
||||
link_context_profiles = self.build_presets.get("linked_assets")
|
||||
# Skip if both are missing
|
||||
if not current_context_profiles and not link_context_profiles:
|
||||
log.warning("Current task `{}` has empty loading preset.".format(
|
||||
|
|
@ -1231,7 +1231,36 @@ class BuildWorkfile:
|
|||
:rtype: list
|
||||
"""
|
||||
loaded_containers = []
|
||||
for subset_id, repres in repres_by_subset_id.items():
|
||||
|
||||
# Get subset id order from build presets.
|
||||
build_presets = self.build_presets.get("current_context", [])
|
||||
build_presets += self.build_presets.get("linked_assets", [])
|
||||
subset_ids_ordered = []
|
||||
for preset in build_presets:
|
||||
for preset_family in preset["families"]:
|
||||
for id, subset in subsets_by_id.items():
|
||||
if preset_family not in subset["data"].get("families", []):
|
||||
continue
|
||||
|
||||
subset_ids_ordered.append(id)
|
||||
|
||||
# Order representations from subsets.
|
||||
print("repres_by_subset_id", repres_by_subset_id)
|
||||
representations_ordered = []
|
||||
representations = []
|
||||
for id in subset_ids_ordered:
|
||||
for subset_id, repres in repres_by_subset_id.items():
|
||||
if repres in representations:
|
||||
continue
|
||||
|
||||
if id == subset_id:
|
||||
representations_ordered.append((subset_id, repres))
|
||||
representations.append(repres)
|
||||
|
||||
print("representations", representations)
|
||||
|
||||
# Load ordered reprensentations.
|
||||
for subset_id, repres in representations_ordered:
|
||||
subset_name = subsets_by_id[subset_id]["name"]
|
||||
|
||||
profile = profiles_per_subset_id[subset_id]
|
||||
|
|
|
|||
|
|
@ -157,6 +157,11 @@ class ExtractBurnin(pype.api.Extractor):
|
|||
filled_anatomy = anatomy.format_all(burnin_data)
|
||||
burnin_data["anatomy"] = filled_anatomy.get_solved()
|
||||
|
||||
# Add source camera name to burnin data
|
||||
camera_name = repre.get("camera_name")
|
||||
if camera_name:
|
||||
burnin_data["camera_name"] = camera_name
|
||||
|
||||
first_output = True
|
||||
|
||||
files_to_delete = []
|
||||
|
|
|
|||
|
|
@ -4,14 +4,70 @@ import maya.cmds as cmds
|
|||
from avalon import api, io
|
||||
from avalon.maya.pipeline import containerise
|
||||
from avalon.maya import lib
|
||||
from Qt import QtWidgets
|
||||
from Qt import QtWidgets, QtCore
|
||||
|
||||
|
||||
class CameraWindow(QtWidgets.QDialog):
|
||||
|
||||
def __init__(self, cameras):
|
||||
super(CameraWindow, self).__init__()
|
||||
self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint)
|
||||
|
||||
self.camera = None
|
||||
|
||||
self.widgets = {
|
||||
"label": QtWidgets.QLabel("Select camera for image plane."),
|
||||
"list": QtWidgets.QListWidget(),
|
||||
"warning": QtWidgets.QLabel("No cameras selected!"),
|
||||
"buttons": QtWidgets.QWidget(),
|
||||
"okButton": QtWidgets.QPushButton("Ok"),
|
||||
"cancelButton": QtWidgets.QPushButton("Cancel")
|
||||
}
|
||||
|
||||
# Build warning.
|
||||
self.widgets["warning"].setVisible(False)
|
||||
self.widgets["warning"].setStyleSheet("color: red")
|
||||
|
||||
# Build list.
|
||||
for camera in cameras:
|
||||
self.widgets["list"].addItem(camera)
|
||||
|
||||
# Build buttons.
|
||||
layout = QtWidgets.QHBoxLayout(self.widgets["buttons"])
|
||||
layout.addWidget(self.widgets["okButton"])
|
||||
layout.addWidget(self.widgets["cancelButton"])
|
||||
|
||||
# Build layout.
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.addWidget(self.widgets["label"])
|
||||
layout.addWidget(self.widgets["list"])
|
||||
layout.addWidget(self.widgets["buttons"])
|
||||
layout.addWidget(self.widgets["warning"])
|
||||
|
||||
self.widgets["okButton"].pressed.connect(self.on_ok_pressed)
|
||||
self.widgets["cancelButton"].pressed.connect(self.on_cancel_pressed)
|
||||
self.widgets["list"].itemPressed.connect(self.on_list_itemPressed)
|
||||
|
||||
def on_list_itemPressed(self, item):
|
||||
self.camera = item.text()
|
||||
|
||||
def on_ok_pressed(self):
|
||||
if self.camera is None:
|
||||
self.widgets["warning"].setVisible(True)
|
||||
return
|
||||
|
||||
self.close()
|
||||
|
||||
def on_cancel_pressed(self):
|
||||
self.camera = None
|
||||
self.close()
|
||||
|
||||
|
||||
class ImagePlaneLoader(api.Loader):
|
||||
"""Specific loader of plate for image planes on selected camera."""
|
||||
|
||||
families = ["plate", "render"]
|
||||
label = "Create imagePlane on selected camera."
|
||||
label = "Load imagePlane."
|
||||
representations = ["mov", "exr", "preview", "png"]
|
||||
icon = "image"
|
||||
color = "orange"
|
||||
|
|
@ -26,43 +82,24 @@ class ImagePlaneLoader(api.Loader):
|
|||
suffix="_",
|
||||
)
|
||||
|
||||
# Getting camera from selection.
|
||||
selection = pc.ls(selection=True)
|
||||
|
||||
# Get camera from user selection.
|
||||
camera = None
|
||||
default_cameras = [
|
||||
"frontShape", "perspShape", "sideShape", "topShape"
|
||||
]
|
||||
cameras = [
|
||||
x for x in pc.ls(type="camera") if x.name() not in default_cameras
|
||||
]
|
||||
camera_names = {x.getParent().name(): x for x in cameras}
|
||||
camera_names["Create new camera."] = "create_camera"
|
||||
window = CameraWindow(camera_names.keys())
|
||||
window.exec_()
|
||||
camera = camera_names[window.camera]
|
||||
|
||||
if len(selection) > 1:
|
||||
QtWidgets.QMessageBox.critical(
|
||||
None,
|
||||
"Error!",
|
||||
"Multiple nodes selected. Please select only one.",
|
||||
QtWidgets.QMessageBox.Ok
|
||||
)
|
||||
return
|
||||
if camera == "create_camera":
|
||||
camera = pc.createNode("camera")
|
||||
|
||||
if len(selection) < 1:
|
||||
result = QtWidgets.QMessageBox.critical(
|
||||
None,
|
||||
"Error!",
|
||||
"No camera selected. Do you want to create a camera?",
|
||||
QtWidgets.QMessageBox.Ok,
|
||||
QtWidgets.QMessageBox.Cancel
|
||||
)
|
||||
if result == QtWidgets.QMessageBox.Ok:
|
||||
camera = pc.createNode("camera")
|
||||
else:
|
||||
return
|
||||
else:
|
||||
relatives = pc.listRelatives(selection[0], shapes=True)
|
||||
if pc.ls(relatives, type="camera"):
|
||||
camera = selection[0]
|
||||
else:
|
||||
QtWidgets.QMessageBox.critical(
|
||||
None,
|
||||
"Error!",
|
||||
"Selected node is not a camera.",
|
||||
QtWidgets.QMessageBox.Ok
|
||||
)
|
||||
if camera is None:
|
||||
return
|
||||
|
||||
try:
|
||||
|
|
@ -100,10 +137,16 @@ class ImagePlaneLoader(api.Loader):
|
|||
# Ensure OpenEXRLoader plugin is loaded.
|
||||
pc.loadPlugin("OpenEXRLoader.mll", quiet=True)
|
||||
|
||||
message = (
|
||||
"Hold image sequence on first frame?"
|
||||
"\n{} files available.".format(
|
||||
len(context["representation"]["files"])
|
||||
)
|
||||
)
|
||||
reply = QtWidgets.QMessageBox.information(
|
||||
None,
|
||||
"Frame Hold.",
|
||||
"Hold image sequence on first frame?",
|
||||
message,
|
||||
QtWidgets.QMessageBox.Ok,
|
||||
QtWidgets.QMessageBox.Cancel
|
||||
)
|
||||
|
|
|
|||
|
|
@ -110,6 +110,9 @@ class ExtractPlayblast(pype.api.Extractor):
|
|||
if not instance.data.get("keepImages"):
|
||||
tags.append("delete")
|
||||
|
||||
# Add camera node name to representation data
|
||||
camera_node_name = pm.ls(camera)[0].getTransform().getName()
|
||||
|
||||
representation = {
|
||||
'name': 'png',
|
||||
'ext': 'png',
|
||||
|
|
@ -119,7 +122,8 @@ class ExtractPlayblast(pype.api.Extractor):
|
|||
"frameEnd": end,
|
||||
'fps': fps,
|
||||
'preview': True,
|
||||
'tags': tags
|
||||
'tags': tags,
|
||||
'camera_name': camera_node_name
|
||||
}
|
||||
instance.data["representations"].append(representation)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from avalon import api
|
||||
from avalon.tvpaint import lib
|
||||
from avalon.vendor import qargparse
|
||||
from avalon.tvpaint import CommunicatorWrapper
|
||||
|
||||
|
||||
class ImportImage(api.Loader):
|
||||
|
|
@ -16,11 +17,54 @@ class ImportImage(api.Loader):
|
|||
import_script = (
|
||||
"filepath = \"{}\"\n"
|
||||
"layer_name = \"{}\"\n"
|
||||
"tv_loadsequence filepath \"preload\" PARSE layer_id\n"
|
||||
"tv_loadsequence filepath {}PARSE layer_id\n"
|
||||
"tv_layerrename layer_id layer_name"
|
||||
)
|
||||
|
||||
defaults = {
|
||||
"stretch": True,
|
||||
"timestretch": True,
|
||||
"preload": True
|
||||
}
|
||||
|
||||
options = [
|
||||
qargparse.Boolean(
|
||||
"stretch",
|
||||
label="Stretch to project size",
|
||||
default=True,
|
||||
help="Stretch loaded image/s to project resolution?"
|
||||
),
|
||||
qargparse.Boolean(
|
||||
"timestretch",
|
||||
label="Stretch to timeline length",
|
||||
default=True,
|
||||
help="Clip loaded image/s to timeline length?"
|
||||
),
|
||||
qargparse.Boolean(
|
||||
"preload",
|
||||
label="Preload loaded image/s",
|
||||
default=True,
|
||||
help="Preload image/s?"
|
||||
)
|
||||
]
|
||||
|
||||
def load(self, context, name, namespace, options):
|
||||
stretch = options.get("stretch", self.defaults["stretch"])
|
||||
timestretch = options.get("timestretch", self.defaults["timestretch"])
|
||||
preload = options.get("preload", self.defaults["preload"])
|
||||
|
||||
load_options = []
|
||||
if stretch:
|
||||
load_options.append("\"STRETCH\"")
|
||||
if timestretch:
|
||||
load_options.append("\"TIMESTRETCH\"")
|
||||
if preload:
|
||||
load_options.append("\"PRELOAD\"")
|
||||
|
||||
load_options_str = ""
|
||||
for load_option in load_options:
|
||||
load_options_str += (load_option + " ")
|
||||
|
||||
# Prepare layer name
|
||||
asset_name = context["asset"]["name"]
|
||||
version_name = context["version"]["name"]
|
||||
|
|
@ -33,6 +77,7 @@ class ImportImage(api.Loader):
|
|||
# - filename mus not contain backwards slashes
|
||||
george_script = self.import_script.format(
|
||||
self.fname.replace("\\", "/"),
|
||||
layer_name
|
||||
layer_name,
|
||||
load_options_str
|
||||
)
|
||||
return lib.execute_george_through_file(george_script)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue