mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
fix the positional arguments
This commit is contained in:
commit
8d9dbb616d
176 changed files with 1236 additions and 514 deletions
|
|
@ -31,6 +31,7 @@ from .addon import ApplicationsAddon
|
|||
|
||||
|
||||
__all__ = (
|
||||
"APPLICATIONS_ADDON_ROOT",
|
||||
"DEFAULT_ENV_SUBGROUP",
|
||||
"PLATFORM_NAMES",
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import os
|
|||
import sys
|
||||
import code
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
import acre
|
||||
|
|
@ -11,7 +12,7 @@ import acre
|
|||
from ayon_core import AYON_CORE_ROOT
|
||||
from ayon_core.addon import AddonsManager
|
||||
from ayon_core.settings import get_general_environments
|
||||
from ayon_core.lib import initialize_ayon_connection
|
||||
from ayon_core.lib import initialize_ayon_connection, is_running_from_build
|
||||
|
||||
from .cli_commands import Commands
|
||||
|
||||
|
|
@ -167,16 +168,27 @@ def run(script):
|
|||
|
||||
if not script:
|
||||
print("Error: missing path to script file.")
|
||||
return
|
||||
|
||||
# Remove first argument if it is the same as AYON executable
|
||||
# - Forward compatibility with future AYON versions.
|
||||
# - Current AYON launcher keeps the arguments with first argument but
|
||||
# future versions might remove it.
|
||||
first_arg = sys.argv[0]
|
||||
if is_running_from_build():
|
||||
comp_path = os.getenv("AYON_EXECUTABLE")
|
||||
else:
|
||||
comp_path = os.path.join(os.environ["AYON_ROOT"], "start.py")
|
||||
# Compare paths and remove first argument if it is the same as AYON
|
||||
if Path(first_arg).resolve() == Path(comp_path).resolve():
|
||||
sys.argv.pop(0)
|
||||
|
||||
args = sys.argv
|
||||
args.remove("run")
|
||||
args.remove(script)
|
||||
sys.argv = args
|
||||
# Remove 'run' command from sys.argv
|
||||
sys.argv.remove("run")
|
||||
|
||||
args_string = " ".join(args[1:])
|
||||
print(f"... running: {script} {args_string}")
|
||||
runpy.run_path(script, run_name="__main__", )
|
||||
args_string = " ".join(sys.argv[1:])
|
||||
print(f"... running: {script} {args_string}")
|
||||
runpy.run_path(script, run_name="__main__")
|
||||
|
||||
|
||||
@main_cli.command()
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class BackgroundLoader(api.AfterEffectsLoader):
|
|||
"""
|
||||
label = "Load JSON Background"
|
||||
product_types = {"background"}
|
||||
representations = ["json"]
|
||||
representations = {"json"}
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
stub = self.get_stub()
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class FileLoader(api.AfterEffectsLoader):
|
|||
"review",
|
||||
"audio",
|
||||
}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
stub = self.get_stub()
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class AppendBlendLoader(plugin.AssetLoader):
|
|||
so you could also use it as a new base.
|
||||
"""
|
||||
|
||||
representations = ["blend"]
|
||||
representations = {"blend"}
|
||||
product_types = {"workfile"}
|
||||
|
||||
label = "Append Workfile"
|
||||
|
|
@ -68,7 +68,7 @@ class ImportBlendLoader(plugin.AssetLoader):
|
|||
so you could also use it as a new base.
|
||||
"""
|
||||
|
||||
representations = ["blend"]
|
||||
representations = {"blend"}
|
||||
product_types = {"workfile"}
|
||||
|
||||
label = "Import Workfile"
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class CacheModelLoader(plugin.AssetLoader):
|
|||
At least for now it only supports Alembic files.
|
||||
"""
|
||||
product_types = {"model", "pointcache", "animation"}
|
||||
representations = ["abc"]
|
||||
representations = {"abc"}
|
||||
|
||||
label = "Load Alembic"
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class BlendActionLoader(plugin.AssetLoader):
|
|||
"""
|
||||
|
||||
product_types = {"action"}
|
||||
representations = ["blend"]
|
||||
representations = {"blend"}
|
||||
|
||||
label = "Link Action"
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class BlendAnimationLoader(plugin.AssetLoader):
|
|||
"""
|
||||
|
||||
product_types = {"animation"}
|
||||
representations = ["blend"]
|
||||
representations = {"blend"}
|
||||
|
||||
label = "Link Animation"
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class AudioLoader(plugin.AssetLoader):
|
|||
"""Load audio in Blender."""
|
||||
|
||||
product_types = {"audio"}
|
||||
representations = ["wav"]
|
||||
representations = {"wav"}
|
||||
|
||||
label = "Load Audio"
|
||||
icon = "volume-up"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class BlendLoader(plugin.AssetLoader):
|
|||
"""Load assets from a .blend file."""
|
||||
|
||||
product_types = {"model", "rig", "layout", "camera"}
|
||||
representations = ["blend"]
|
||||
representations = {"blend"}
|
||||
|
||||
label = "Append Blend"
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class BlendSceneLoader(plugin.AssetLoader):
|
|||
"""Load assets from a .blend file."""
|
||||
|
||||
product_types = {"blendScene"}
|
||||
representations = ["blend"]
|
||||
representations = {"blend"}
|
||||
|
||||
label = "Append Blend"
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class AbcCameraLoader(plugin.AssetLoader):
|
|||
"""
|
||||
|
||||
product_types = {"camera"}
|
||||
representations = ["abc"]
|
||||
representations = {"abc"}
|
||||
|
||||
label = "Load Camera (ABC)"
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class FbxCameraLoader(plugin.AssetLoader):
|
|||
"""
|
||||
|
||||
product_types = {"camera"}
|
||||
representations = ["fbx"]
|
||||
representations = {"fbx"}
|
||||
|
||||
label = "Load Camera (FBX)"
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class FbxModelLoader(plugin.AssetLoader):
|
|||
"""
|
||||
|
||||
product_types = {"model", "rig"}
|
||||
representations = ["fbx"]
|
||||
representations = {"fbx"}
|
||||
|
||||
label = "Load FBX"
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class JsonLayoutLoader(plugin.AssetLoader):
|
|||
"""Load layout published from Unreal."""
|
||||
|
||||
product_types = {"layout"}
|
||||
representations = ["json"]
|
||||
representations = {"json"}
|
||||
|
||||
label = "Load Layout"
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class BlendLookLoader(plugin.AssetLoader):
|
|||
"""
|
||||
|
||||
product_types = {"look"}
|
||||
representations = ["json"]
|
||||
representations = {"json"}
|
||||
|
||||
label = "Load Look"
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class LoadClip(opfapi.ClipLoader):
|
|||
"""
|
||||
|
||||
product_types = {"render2d", "source", "plate", "render", "review"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = set(
|
||||
ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class LoadClipBatch(opfapi.ClipLoader):
|
|||
"""
|
||||
|
||||
product_types = {"render2d", "source", "plate", "render", "review"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = set(
|
||||
ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ from ayon_core.pipeline import (
|
|||
AVALON_INSTANCE_ID,
|
||||
AYON_INSTANCE_ID,
|
||||
)
|
||||
from ayon_core.pipeline.workfile import get_workdir
|
||||
from ayon_api import (
|
||||
get_project,
|
||||
get_folder_by_path,
|
||||
get_task_by_name
|
||||
)
|
||||
|
||||
|
||||
class GenericCreateSaver(Creator):
|
||||
|
|
@ -125,6 +131,8 @@ class GenericCreateSaver(Creator):
|
|||
product_name = data["productName"]
|
||||
if (
|
||||
original_product_name != product_name
|
||||
or tool.GetData("openpype.task") != data["task"]
|
||||
or tool.GetData("openpype.folderPath") != data["folderPath"]
|
||||
or original_format != data["creator_attributes"]["image_format"]
|
||||
):
|
||||
self._configure_saver_tool(data, tool, product_name)
|
||||
|
|
@ -145,7 +153,30 @@ class GenericCreateSaver(Creator):
|
|||
folder_path = formatting_data["folderPath"]
|
||||
folder_name = folder_path.rsplit("/", 1)[-1]
|
||||
|
||||
workdir = os.path.normpath(os.getenv("AYON_WORKDIR"))
|
||||
# If the folder path and task do not match the current context then the
|
||||
# workdir is not just the `AYON_WORKDIR`. Hence, we need to actually
|
||||
# compute the resulting workdir
|
||||
if (
|
||||
data["folderPath"] == self.create_context.get_current_folder_path()
|
||||
and data["task"] == self.create_context.get_current_task_name()
|
||||
):
|
||||
workdir = os.path.normpath(os.getenv("AYON_WORKDIR"))
|
||||
else:
|
||||
# TODO: Optimize this logic
|
||||
project_name = self.create_context.get_current_project_name()
|
||||
project_entity = get_project(project_name)
|
||||
folder_entity = get_folder_by_path(project_name,
|
||||
data["folderPath"])
|
||||
task_entity = get_task_by_name(project_name,
|
||||
folder_id=folder_entity["id"],
|
||||
task_name=data["task"])
|
||||
workdir = get_workdir(
|
||||
project_entity=project_entity,
|
||||
folder_entity=folder_entity,
|
||||
task_entity=task_entity,
|
||||
host_name=self.create_context.host_name,
|
||||
)
|
||||
|
||||
formatting_data.update({
|
||||
"workdir": workdir,
|
||||
"frame": "0" * frame_padding,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
import os
|
||||
from ayon_core.lib import PreLaunchHook
|
||||
from ayon_core.hosts.fusion import FUSION_HOST_DIR
|
||||
|
||||
|
||||
class FusionLaunchMenuHook(PreLaunchHook):
|
||||
"""Launch AYON menu on start of Fusion"""
|
||||
app_groups = ["fusion"]
|
||||
order = 9
|
||||
|
||||
def execute(self):
|
||||
# Prelaunch hook is optional
|
||||
settings = self.data["project_settings"][self.host_name]
|
||||
if not settings["hooks"]["FusionLaunchMenuHook"]["enabled"]:
|
||||
return
|
||||
|
||||
variant = self.application.name
|
||||
if variant.isnumeric():
|
||||
version = int(variant)
|
||||
if version < 18:
|
||||
print("Skipping launch of OpenPype menu on Fusion start "
|
||||
"because Fusion version below 18.0 does not support "
|
||||
"/execute argument on launch. "
|
||||
f"Version detected: {version}")
|
||||
return
|
||||
else:
|
||||
print(f"Application variant is not numeric: {variant}. "
|
||||
"Validation for Fusion version 18+ for /execute "
|
||||
"prelaunch argument skipped.")
|
||||
|
||||
path = os.path.join(FUSION_HOST_DIR,
|
||||
"deploy",
|
||||
"MenuScripts",
|
||||
"launch_menu.py").replace("\\", "/")
|
||||
script = f"fusion:RunScript('{path}')"
|
||||
self.launch_context.launch_args.extend(["/execute", script])
|
||||
|
|
@ -17,7 +17,7 @@ class FusionSetFrameRangeLoader(load.LoaderPlugin):
|
|||
"pointcache",
|
||||
"render",
|
||||
}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = {"*"}
|
||||
|
||||
label = "Set frame range"
|
||||
|
|
@ -54,7 +54,7 @@ class FusionSetFrameRangeWithHandlesLoader(load.LoaderPlugin):
|
|||
"pointcache",
|
||||
"render",
|
||||
}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
|
||||
label = "Set frame range (with handles)"
|
||||
order = 12
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class FusionLoadAlembicMesh(load.LoaderPlugin):
|
|||
"""Load Alembic mesh into Fusion"""
|
||||
|
||||
product_types = {"pointcache", "model"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = {"abc"}
|
||||
|
||||
label = "Load alembic mesh"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class FusionLoadFBXMesh(load.LoaderPlugin):
|
|||
"""Load FBX mesh into Fusion"""
|
||||
|
||||
product_types = {"*"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = {
|
||||
"3ds",
|
||||
"amc",
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ class FusionLoadSequence(load.LoaderPlugin):
|
|||
"image",
|
||||
"online",
|
||||
}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = set(
|
||||
ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class FusionLoadUSD(load.LoaderPlugin):
|
|||
"""
|
||||
|
||||
product_types = {"*"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = {"usd", "usda", "usdz"}
|
||||
|
||||
label = "Load USD"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class FusionLoadWorkfile(load.LoaderPlugin):
|
|||
"""Load the content of a workfile into Fusion"""
|
||||
|
||||
product_types = {"workfile"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = {"comp"}
|
||||
|
||||
label = "Load Workfile"
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ class ImageSequenceLoader(load.LoaderPlugin):
|
|||
"reference",
|
||||
"review",
|
||||
}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = {"jpeg", "png", "jpg"}
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class ImportAudioLoader(load.LoaderPlugin):
|
|||
"""Import audio."""
|
||||
|
||||
product_types = {"shot", "audio"}
|
||||
representations = ["wav"]
|
||||
representations = {"wav"}
|
||||
label = "Import Audio"
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ class BackgroundLoader(load.LoaderPlugin):
|
|||
Stores the imported asset in a container named after the asset.
|
||||
"""
|
||||
product_types = {"background"}
|
||||
representations = ["json"]
|
||||
representations = {"json"}
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class ImageSequenceLoader(load.LoaderPlugin):
|
|||
"reference",
|
||||
"review",
|
||||
}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = {"jpeg", "png", "jpg"}
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class ImportPaletteLoader(load.LoaderPlugin):
|
|||
"""Import palettes."""
|
||||
|
||||
product_types = {"palette", "harmony.palette"}
|
||||
representations = ["plt"]
|
||||
representations = {"plt"}
|
||||
label = "Import Palette"
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class TemplateLoader(load.LoaderPlugin):
|
|||
"""
|
||||
|
||||
product_types = {"template", "workfile"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
label = "Load Template"
|
||||
icon = "gift"
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class ImportTemplateLoader(load.LoaderPlugin):
|
|||
"""Import templates."""
|
||||
|
||||
product_types = {"harmony.template", "workfile"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
label = "Import Template"
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
|
|
@ -61,5 +61,5 @@ class ImportWorkfileLoader(ImportTemplateLoader):
|
|||
"""Import workfiles."""
|
||||
|
||||
product_types = {"workfile"}
|
||||
representations = ["zip"]
|
||||
representations = {"zip"}
|
||||
label = "Import Workfile"
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ class CreateShotClip(phiero.Creator):
|
|||
"value": ["<track_name>", "main", "bg", "fg", "bg",
|
||||
"animatic"],
|
||||
"type": "QComboBox",
|
||||
"label": "pRODUCT Name",
|
||||
"label": "Product Name",
|
||||
"target": "ui",
|
||||
"toolTip": "chose product name pattern, if <track_name> is selected, name of track layer will be used", # noqa
|
||||
"order": 0},
|
||||
|
|
@ -159,7 +159,7 @@ class CreateShotClip(phiero.Creator):
|
|||
"type": "QCheckBox",
|
||||
"label": "Include audio",
|
||||
"target": "tag",
|
||||
"toolTip": "Process productS with corresponding audio", # noqa
|
||||
"toolTip": "Process products with corresponding audio", # noqa
|
||||
"order": 3},
|
||||
"sourceResolution": {
|
||||
"value": False,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class LoadClip(phiero.SequenceLoader):
|
|||
"""
|
||||
|
||||
product_types = {"render2d", "source", "plate", "render", "review"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = set(
|
||||
ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class LoadEffects(load.LoaderPlugin):
|
|||
"""Loading colorspace soft effect exported from nukestudio"""
|
||||
|
||||
product_types = {"effect"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extension = {"json"}
|
||||
|
||||
label = "Load Effects"
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import pyblish.api
|
|||
from ayon_core.pipeline import publish
|
||||
|
||||
|
||||
class ExtractThumnail(publish.Extractor):
|
||||
class ExtractThumbnail(publish.Extractor):
|
||||
"""
|
||||
Extractor for track item's tumnails
|
||||
Extractor for track item's tumbnails
|
||||
"""
|
||||
|
||||
label = "Extract Thumnail"
|
||||
label = "Extract Thumbnail"
|
||||
order = pyblish.api.ExtractorOrder
|
||||
families = ["plate", "take"]
|
||||
hosts = ["hiero"]
|
||||
|
|
@ -48,7 +48,7 @@ class ExtractThumnail(publish.Extractor):
|
|||
self.log.debug(
|
||||
"__ thumb_path: `{}`, frame: `{}`".format(thumbnail, thumb_frame))
|
||||
|
||||
self.log.info("Thumnail was generated to: {}".format(thumb_path))
|
||||
self.log.info("Thumbnail was generated to: {}".format(thumb_path))
|
||||
thumb_representation = {
|
||||
'files': thumb_file,
|
||||
'stagingDir': staging_dir,
|
||||
|
|
|
|||
|
|
@ -1001,6 +1001,82 @@ def add_self_publish_button(node):
|
|||
node.setParmTemplateGroup(template)
|
||||
|
||||
|
||||
def get_scene_viewer():
|
||||
"""
|
||||
Return an instance of a visible viewport.
|
||||
|
||||
There may be many, some could be closed, any visible are current
|
||||
|
||||
Returns:
|
||||
Optional[hou.SceneViewer]: A scene viewer, if any.
|
||||
"""
|
||||
panes = hou.ui.paneTabs()
|
||||
panes = [x for x in panes if x.type() == hou.paneTabType.SceneViewer]
|
||||
panes = sorted(panes, key=lambda x: x.isCurrentTab())
|
||||
if panes:
|
||||
return panes[-1]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def sceneview_snapshot(
|
||||
sceneview,
|
||||
filepath="$HIP/thumbnails/$HIPNAME.$F4.jpg",
|
||||
frame_start=None,
|
||||
frame_end=None):
|
||||
"""Take a snapshot of your scene view.
|
||||
|
||||
It takes snapshot of your scene view for the given frame range.
|
||||
So, it's capable of generating snapshots image sequence.
|
||||
It works in different Houdini context e.g. Objects, Solaris
|
||||
|
||||
Example:
|
||||
This is how the function can be used::
|
||||
|
||||
from ayon_core.hosts.houdini.api import lib
|
||||
sceneview = hou.ui.paneTabOfType(hou.paneTabType.SceneViewer)
|
||||
lib.sceneview_snapshot(sceneview)
|
||||
|
||||
Notes:
|
||||
.png output will render poorly, so use .jpg.
|
||||
|
||||
How it works:
|
||||
Get the current sceneviewer (may be more than one or hidden)
|
||||
and screengrab the perspective viewport to a file in the
|
||||
publish location to be picked up with the publish.
|
||||
|
||||
Credits:
|
||||
https://www.sidefx.com/forum/topic/42808/?page=1#post-354796
|
||||
|
||||
Args:
|
||||
sceneview (hou.SceneViewer): The scene view pane from which you want
|
||||
to take a snapshot.
|
||||
filepath (str): thumbnail filepath. it expects `$F4` token
|
||||
when frame_end is bigger than frame_star other wise
|
||||
each frame will override its predecessor.
|
||||
frame_start (int): the frame at which snapshot starts
|
||||
frame_end (int): the frame at which snapshot ends
|
||||
"""
|
||||
|
||||
if frame_start is None:
|
||||
frame_start = hou.frame()
|
||||
if frame_end is None:
|
||||
frame_end = frame_start
|
||||
|
||||
if not isinstance(sceneview, hou.SceneViewer):
|
||||
log.debug("Wrong Input. {} is not of type hou.SceneViewer."
|
||||
.format(sceneview))
|
||||
return
|
||||
viewport = sceneview.curViewport()
|
||||
|
||||
flip_settings = sceneview.flipbookSettings().stash()
|
||||
flip_settings.frameRange((frame_start, frame_end))
|
||||
flip_settings.output(filepath)
|
||||
flip_settings.outputToMPlay(False)
|
||||
sceneview.flipbook(viewport, flip_settings)
|
||||
log.debug("A snapshot of sceneview has been saved to: {}".format(filepath))
|
||||
|
||||
|
||||
def update_content_on_context_change():
|
||||
"""Update all Creator instances to current asset"""
|
||||
host = registered_host()
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class SetFrameRangeLoader(load.LoaderPlugin):
|
|||
"vdbcache",
|
||||
"usd",
|
||||
}
|
||||
representations = ["abc", "vdb", "usd"]
|
||||
representations = {"abc", "vdb", "usd"}
|
||||
|
||||
label = "Set frame range"
|
||||
order = 11
|
||||
|
|
@ -52,7 +52,7 @@ class SetFrameRangeWithHandlesLoader(load.LoaderPlugin):
|
|||
"vdbcache",
|
||||
"usd",
|
||||
}
|
||||
representations = ["abc", "vdb", "usd"]
|
||||
representations = {"abc", "vdb", "usd"}
|
||||
|
||||
label = "Set frame range (with handles)"
|
||||
order = 12
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class AbcLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"model", "animation", "pointcache", "gpuCache"}
|
||||
label = "Load Alembic"
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = {"abc"}
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class AbcArchiveLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"model", "animation", "pointcache", "gpuCache"}
|
||||
label = "Load Alembic as Archive"
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = {"abc"}
|
||||
order = -5
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class AssLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"ass"}
|
||||
label = "Load Arnold Procedural"
|
||||
representations = ["ass"]
|
||||
representations = {"ass"}
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ class BgeoLoader(load.LoaderPlugin):
|
|||
|
||||
label = "Load bgeo"
|
||||
product_types = {"model", "pointcache", "bgeo"}
|
||||
representations = [
|
||||
representations = {
|
||||
"bgeo", "bgeosc", "bgeogz",
|
||||
"bgeo.sc", "bgeo.gz", "bgeo.lzma", "bgeo.bz2"]
|
||||
"bgeo.sc", "bgeo.gz", "bgeo.lzma", "bgeo.bz2"}
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ class CameraLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"camera"}
|
||||
label = "Load Camera (abc)"
|
||||
representations = ["abc"]
|
||||
representations = {"abc"}
|
||||
order = -10
|
||||
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class FbxLoader(load.LoaderPlugin):
|
|||
order = -10
|
||||
|
||||
product_types = {"*"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
extensions = {"fbx"}
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class FilePathLoader(load.LoaderPlugin):
|
|||
icon = "link"
|
||||
color = "white"
|
||||
product_types = {"*"}
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class HdaLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"hda"}
|
||||
label = "Load Hda"
|
||||
representations = ["hda"]
|
||||
representations = {"hda"}
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ class ImageLoader(load.LoaderPlugin):
|
|||
"online",
|
||||
}
|
||||
label = "Load Image (COP2)"
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
order = -10
|
||||
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class RedshiftProxyLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"redshiftproxy"}
|
||||
label = "Load Redshift Proxy"
|
||||
representations = ["rs"]
|
||||
representations = {"rs"}
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class USDSublayerLoader(load.LoaderPlugin):
|
|||
"usdCamera",
|
||||
}
|
||||
label = "Sublayer USD"
|
||||
representations = ["usd", "usda", "usdlc", "usdnc", "abc"]
|
||||
representations = {"usd", "usda", "usdlc", "usdnc", "abc"}
|
||||
order = 1
|
||||
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class USDReferenceLoader(load.LoaderPlugin):
|
|||
"usdCamera",
|
||||
}
|
||||
label = "Reference USD"
|
||||
representations = ["usd", "usda", "usdlc", "usdnc", "abc"]
|
||||
representations = {"usd", "usda", "usdlc", "usdnc", "abc"}
|
||||
order = -8
|
||||
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class SopUsdImportLoader(load.LoaderPlugin):
|
|||
|
||||
label = "Load USD to SOPs"
|
||||
product_types = {"*"}
|
||||
representations = ["usd"]
|
||||
representations = {"usd"}
|
||||
order = -6
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class VdbLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"vdbcache"}
|
||||
label = "Load VDB"
|
||||
representations = ["vdb"]
|
||||
representations = {"vdb"}
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class ShowInUsdview(load.LoaderPlugin):
|
|||
"""Open USD file in usdview"""
|
||||
|
||||
label = "Show in usdview"
|
||||
representations = ["*"]
|
||||
representations = {"*"}
|
||||
product_types = {"*"}
|
||||
extensions = {"usd", "usda", "usdlc", "usdnc", "abc"}
|
||||
order = 15
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
import pyblish.api
|
||||
import tempfile
|
||||
from ayon_core.pipeline import publish
|
||||
from ayon_core.hosts.houdini.api import lib
|
||||
from ayon_core.hosts.houdini.api.pipeline import IS_HEADLESS
|
||||
|
||||
|
||||
class ExtractActiveViewThumbnail(publish.Extractor):
|
||||
"""Set instance thumbnail to a screengrab of current active viewport.
|
||||
|
||||
This makes it so that if an instance does not have a thumbnail set yet that
|
||||
it will get a thumbnail of the currently active view at the time of
|
||||
publishing as a fallback.
|
||||
|
||||
"""
|
||||
order = pyblish.api.ExtractorOrder + 0.49
|
||||
label = "Extract Active View Thumbnail"
|
||||
families = ["workfile"]
|
||||
hosts = ["houdini"]
|
||||
|
||||
def process(self, instance):
|
||||
if IS_HEADLESS:
|
||||
self.log.debug(
|
||||
"Skip extraction of active view thumbnail, due to being in"
|
||||
"headless mode."
|
||||
)
|
||||
return
|
||||
|
||||
thumbnail = instance.data.get("thumbnailPath")
|
||||
if thumbnail:
|
||||
# A thumbnail was already set for this instance
|
||||
return
|
||||
|
||||
view_thumbnail = self.get_view_thumbnail(instance)
|
||||
if not view_thumbnail:
|
||||
return
|
||||
self.log.debug("Setting instance thumbnail path to: {}"
|
||||
.format(view_thumbnail)
|
||||
)
|
||||
instance.data["thumbnailPath"] = view_thumbnail
|
||||
|
||||
def get_view_thumbnail(self, instance):
|
||||
|
||||
sceneview = lib.get_scene_viewer()
|
||||
if sceneview is None:
|
||||
self.log.debug("Skipping Extract Active View Thumbnail"
|
||||
" because no scene view was detected.")
|
||||
return
|
||||
|
||||
with tempfile.NamedTemporaryFile("w", suffix=".jpg", delete=False) as tmp:
|
||||
lib.sceneview_snapshot(sceneview, tmp.name)
|
||||
thumbnail_path = tmp.name
|
||||
|
||||
instance.context.data["cleanupFullPaths"].append(thumbnail_path)
|
||||
return thumbnail_path
|
||||
|
|
@ -19,7 +19,7 @@ class FbxLoader(load.LoaderPlugin):
|
|||
"""Fbx Loader."""
|
||||
|
||||
product_types = {"camera"}
|
||||
representations = ["fbx"]
|
||||
representations = {"fbx"}
|
||||
order = -9
|
||||
icon = "code-fork"
|
||||
color = "white"
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class MaxSceneLoader(load.LoaderPlugin):
|
|||
"model",
|
||||
}
|
||||
|
||||
representations = ["max"]
|
||||
representations = {"max"}
|
||||
order = -8
|
||||
icon = "code-fork"
|
||||
color = "green"
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class ModelAbcLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"model"}
|
||||
label = "Load Model with Alembic"
|
||||
representations = ["abc"]
|
||||
representations = {"abc"}
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class FbxModelLoader(load.LoaderPlugin):
|
|||
"""Fbx Model Loader."""
|
||||
|
||||
product_types = {"model"}
|
||||
representations = ["fbx"]
|
||||
representations = {"fbx"}
|
||||
order = -9
|
||||
icon = "code-fork"
|
||||
color = "white"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class ObjLoader(load.LoaderPlugin):
|
|||
"""Obj Loader."""
|
||||
|
||||
product_types = {"model"}
|
||||
representations = ["obj"]
|
||||
representations = {"obj"}
|
||||
order = -9
|
||||
icon = "code-fork"
|
||||
color = "white"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class ModelUSDLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"model"}
|
||||
label = "Load Model(USD)"
|
||||
representations = ["usda"]
|
||||
representations = {"usda"}
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class AbcLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"camera", "animation", "pointcache"}
|
||||
label = "Load Alembic"
|
||||
representations = ["abc"]
|
||||
representations = {"abc"}
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class OxAbcLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"camera", "animation", "pointcache"}
|
||||
label = "Load Alembic with Ornatrix"
|
||||
representations = ["abc"]
|
||||
representations = {"abc"}
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class PointCloudLoader(load.LoaderPlugin):
|
|||
"""Point Cloud Loader."""
|
||||
|
||||
product_types = {"pointcloud"}
|
||||
representations = ["prt"]
|
||||
representations = {"prt"}
|
||||
order = -8
|
||||
icon = "code-fork"
|
||||
color = "green"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class RedshiftProxyLoader(load.LoaderPlugin):
|
|||
|
||||
label = "Load Redshift Proxy"
|
||||
product_types = {"redshiftproxy"}
|
||||
representations = ["rs"]
|
||||
representations = {"rs"}
|
||||
order = -9
|
||||
icon = "code-fork"
|
||||
color = "white"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class TyCacheLoader(load.LoaderPlugin):
|
|||
"""TyCache Loader."""
|
||||
|
||||
product_types = {"tycache"}
|
||||
representations = ["tyc"]
|
||||
representations = {"tyc"}
|
||||
order = -8
|
||||
icon = "code-fork"
|
||||
color = "green"
|
||||
|
|
|
|||
|
|
@ -38,15 +38,15 @@ class ValidateInstanceInContext(pyblish.api.InstancePlugin,
|
|||
context_label = "{} > {}".format(*context)
|
||||
instance_label = "{} > {}".format(folderPath, task)
|
||||
message = (
|
||||
"Instance '{}' publishes to different context than current "
|
||||
"context: {}. Current context: {}".format(
|
||||
"Instance '{}' publishes to different folder or task "
|
||||
"than current context: {}. Current context: {}".format(
|
||||
instance.name, instance_label, context_label
|
||||
)
|
||||
)
|
||||
raise PublishValidationError(
|
||||
message=message,
|
||||
description=(
|
||||
"## Publishing to a different context data\n"
|
||||
"## Publishing to a different context folder or task\n"
|
||||
"There are publish instances present which are publishing "
|
||||
"into a different folder path or task than your current context.\n\n"
|
||||
"Usually this is not what you want but there can be cases "
|
||||
|
|
|
|||
|
|
@ -22,15 +22,15 @@ class MayaAddon(AYONAddon, IHostAddon):
|
|||
if norm_path not in new_python_paths:
|
||||
new_python_paths.append(norm_path)
|
||||
|
||||
# add vendor path
|
||||
new_python_paths.append(
|
||||
os.path.join(MAYA_ROOT_DIR, "vendor", "python")
|
||||
)
|
||||
env["PYTHONPATH"] = os.pathsep.join(new_python_paths)
|
||||
|
||||
# Set default environments
|
||||
envs = {
|
||||
"AYON_LOG_NO_COLORS": "1",
|
||||
# For python module 'qtpy'
|
||||
"QT_API": "PySide2",
|
||||
# For python module 'Qt'
|
||||
"QT_PREFERRED_BINDING": "PySide2"
|
||||
}
|
||||
for key, value in envs.items():
|
||||
env[key] = value
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ from ayon_core.pipeline import (
|
|||
AYON_CONTAINER_ID,
|
||||
)
|
||||
from ayon_core.lib import NumberDef
|
||||
from ayon_core.pipeline.context_tools import get_current_folder_entity
|
||||
from ayon_core.pipeline.context_tools import get_current_task_entity
|
||||
from ayon_core.pipeline.create import CreateContext
|
||||
from ayon_core.lib.profiles_filtering import filter_profiles
|
||||
|
||||
|
|
@ -1519,24 +1519,30 @@ def extract_alembic(file,
|
|||
|
||||
|
||||
# region ID
|
||||
def get_id_required_nodes(referenced_nodes=False, nodes=None):
|
||||
"""Filter out any node which are locked (reference) or readOnly
|
||||
def get_id_required_nodes(referenced_nodes=False,
|
||||
nodes=None,
|
||||
existing_ids=True):
|
||||
"""Return nodes that should receive a `cbId` attribute.
|
||||
|
||||
This includes only mesh and curve nodes, parent transforms of the shape
|
||||
nodes, file texture nodes and object sets (including shading engines).
|
||||
|
||||
This filters out any node which is locked, referenced, read-only,
|
||||
intermediate object.
|
||||
|
||||
Args:
|
||||
referenced_nodes (bool): set True to filter out reference nodes
|
||||
referenced_nodes (bool): set True to include referenced nodes
|
||||
nodes (list, Optional): nodes to consider
|
||||
existing_ids (bool): set True to include nodes with `cbId` attribute
|
||||
|
||||
Returns:
|
||||
nodes (set): list of filtered nodes
|
||||
"""
|
||||
|
||||
lookup = None
|
||||
if nodes is None:
|
||||
# Consider all nodes
|
||||
nodes = cmds.ls()
|
||||
else:
|
||||
# Build a lookup for the only allowed nodes in output based
|
||||
# on `nodes` input of the function (+ ensure long names)
|
||||
lookup = set(cmds.ls(nodes, long=True))
|
||||
if nodes is not None and not nodes:
|
||||
# User supplied an empty `nodes` list to check so all we can
|
||||
# do is return the empty result
|
||||
return set()
|
||||
|
||||
def _node_type_exists(node_type):
|
||||
try:
|
||||
|
|
@ -1545,63 +1551,142 @@ def get_id_required_nodes(referenced_nodes=False, nodes=None):
|
|||
except RuntimeError:
|
||||
return False
|
||||
|
||||
def iterate(maya_iterator):
|
||||
while not maya_iterator.isDone():
|
||||
yield maya_iterator.thisNode()
|
||||
maya_iterator.next()
|
||||
|
||||
# `readOnly` flag is obsolete as of Maya 2016 therefore we explicitly
|
||||
# remove default nodes and reference nodes
|
||||
camera_shapes = ["frontShape", "sideShape", "topShape", "perspShape"]
|
||||
default_camera_shapes = {
|
||||
"frontShape", "sideShape", "topShape", "perspShape"
|
||||
}
|
||||
|
||||
ignore = set()
|
||||
if not referenced_nodes:
|
||||
ignore |= set(cmds.ls(long=True, referencedNodes=True))
|
||||
|
||||
# list all defaultNodes to filter out from the rest
|
||||
ignore |= set(cmds.ls(long=True, defaultNodes=True))
|
||||
ignore |= set(cmds.ls(camera_shapes, long=True))
|
||||
|
||||
# Remove Turtle from the result of `cmds.ls` if Turtle is loaded
|
||||
# TODO: This should be a less specific check for a single plug-in.
|
||||
if _node_type_exists("ilrBakeLayer"):
|
||||
ignore |= set(cmds.ls(type="ilrBakeLayer", long=True))
|
||||
|
||||
# Establish set of nodes types to include
|
||||
types = ["objectSet", "file", "mesh", "nurbsCurve", "nurbsSurface"]
|
||||
# The filtered types do not include transforms because we only want the
|
||||
# parent transforms that have a child shape that we filtered to, so we
|
||||
# include the parents here
|
||||
types = ["mesh", "nurbsCurve", "nurbsSurface", "file", "objectSet"]
|
||||
|
||||
# Check if plugin nodes are available for Maya by checking if the plugin
|
||||
# is loaded
|
||||
if cmds.pluginInfo("pgYetiMaya", query=True, loaded=True):
|
||||
types.append("pgYetiMaya")
|
||||
|
||||
# We *always* ignore intermediate shapes, so we filter them out directly
|
||||
nodes = cmds.ls(nodes, type=types, long=True, noIntermediate=True)
|
||||
iterator_type = OpenMaya.MIteratorType()
|
||||
# This tries to be closest matching API equivalents of `types` variable
|
||||
iterator_type.filterList = [
|
||||
OpenMaya.MFn.kMesh, # mesh
|
||||
OpenMaya.MFn.kNurbsSurface, # nurbsSurface
|
||||
OpenMaya.MFn.kNurbsCurve, # nurbsCurve
|
||||
OpenMaya.MFn.kFileTexture, # file
|
||||
OpenMaya.MFn.kSet, # objectSet
|
||||
OpenMaya.MFn.kPluginShape # pgYetiMaya
|
||||
]
|
||||
it = OpenMaya.MItDependencyNodes(iterator_type)
|
||||
|
||||
# The items which need to pass the id to their parent
|
||||
# Add the collected transform to the nodes
|
||||
dag = cmds.ls(nodes, type="dagNode", long=True) # query only dag nodes
|
||||
transforms = cmds.listRelatives(dag,
|
||||
parent=True,
|
||||
fullPath=True) or []
|
||||
fn_dep = OpenMaya.MFnDependencyNode()
|
||||
fn_dag = OpenMaya.MFnDagNode()
|
||||
result = set()
|
||||
|
||||
nodes = set(nodes)
|
||||
nodes |= set(transforms)
|
||||
def _should_include_parents(obj):
|
||||
"""Whether to include parents of obj in output"""
|
||||
if not obj.hasFn(OpenMaya.MFn.kShape):
|
||||
return False
|
||||
|
||||
nodes -= ignore # Remove the ignored nodes
|
||||
if not nodes:
|
||||
return nodes
|
||||
fn_dag.setObject(obj)
|
||||
if fn_dag.isIntermediateObject:
|
||||
return False
|
||||
|
||||
# Ensure only nodes from the input `nodes` are returned when a
|
||||
# filter was applied on function call because we also iterated
|
||||
# to parents and alike
|
||||
if lookup is not None:
|
||||
nodes &= lookup
|
||||
# Skip default cameras
|
||||
if (
|
||||
obj.hasFn(OpenMaya.MFn.kCamera) and
|
||||
fn_dag.name() in default_camera_shapes
|
||||
):
|
||||
return False
|
||||
|
||||
# Avoid locked nodes
|
||||
nodes_list = list(nodes)
|
||||
locked = cmds.lockNode(nodes_list, query=True, lock=True)
|
||||
for node, lock in zip(nodes_list, locked):
|
||||
if lock:
|
||||
log.warning("Skipping locked node: %s" % node)
|
||||
nodes.remove(node)
|
||||
return True
|
||||
|
||||
return nodes
|
||||
def _add_to_result_if_valid(obj):
|
||||
"""Add to `result` if the object should be included"""
|
||||
fn_dep.setObject(obj)
|
||||
if not existing_ids and fn_dep.hasAttribute("cbId"):
|
||||
return
|
||||
|
||||
if not referenced_nodes and fn_dep.isFromReferencedFile:
|
||||
return
|
||||
|
||||
if fn_dep.isDefaultNode:
|
||||
return
|
||||
|
||||
if fn_dep.isLocked:
|
||||
return
|
||||
|
||||
# Skip default cameras
|
||||
if (
|
||||
obj.hasFn(OpenMaya.MFn.kCamera) and
|
||||
fn_dep.name() in default_camera_shapes
|
||||
):
|
||||
return
|
||||
|
||||
if obj.hasFn(OpenMaya.MFn.kDagNode):
|
||||
# DAG nodes
|
||||
fn_dag.setObject(obj)
|
||||
|
||||
# Skip intermediate objects
|
||||
if fn_dag.isIntermediateObject:
|
||||
return
|
||||
|
||||
# DAG nodes can be instanced and thus may have multiple paths.
|
||||
# We need to identify each path
|
||||
paths = OpenMaya.MDagPath.getAllPathsTo(obj)
|
||||
for dag in paths:
|
||||
path = dag.fullPathName()
|
||||
result.add(path)
|
||||
else:
|
||||
# Dependency node
|
||||
path = fn_dep.name()
|
||||
result.add(path)
|
||||
|
||||
for obj in iterate(it):
|
||||
# For any non-intermediate shape node always include the parent
|
||||
# even if we exclude the shape itself (e.g. when locked, default)
|
||||
if _should_include_parents(obj):
|
||||
fn_dag.setObject(obj)
|
||||
parents = [
|
||||
fn_dag.parent(index) for index in range(fn_dag.parentCount())
|
||||
]
|
||||
for parent_obj in parents:
|
||||
_add_to_result_if_valid(parent_obj)
|
||||
|
||||
_add_to_result_if_valid(obj)
|
||||
|
||||
if not result:
|
||||
return result
|
||||
|
||||
# Exclude some additional types
|
||||
exclude_types = []
|
||||
if _node_type_exists("ilrBakeLayer"):
|
||||
# Remove Turtle from the result if Turtle is loaded
|
||||
exclude_types.append("ilrBakeLayer")
|
||||
|
||||
if exclude_types:
|
||||
exclude_nodes = set(cmds.ls(nodes, long=True, type=exclude_types))
|
||||
if exclude_nodes:
|
||||
result -= exclude_nodes
|
||||
|
||||
# Filter to explicit input nodes if provided
|
||||
if nodes is not None:
|
||||
# The amount of input nodes to filter to can be large and querying
|
||||
# many nodes can be slow in Maya. As such we want to try and reduce
|
||||
# it as much as possible, so we include the type filter to try and
|
||||
# reduce the result of `maya.cmds.ls` here.
|
||||
nodes = set(cmds.ls(nodes, long=True, type=types + ["dagNode"]))
|
||||
if nodes:
|
||||
result &= nodes
|
||||
else:
|
||||
return set()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_id(node):
|
||||
|
|
@ -2629,21 +2714,21 @@ def reset_frame_range(playback=True, render=True, fps=True):
|
|||
def reset_scene_resolution():
|
||||
"""Apply the scene resolution from the project definition
|
||||
|
||||
scene resolution can be overwritten by an folder if the folder.attrib
|
||||
contains any information regarding scene resolution .
|
||||
The scene resolution will be retrieved from the current task entity's
|
||||
attributes.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
folder_attributes = get_current_folder_entity()["attrib"]
|
||||
task_attributes = get_current_task_entity(fields={"attrib"})["attrib"]
|
||||
|
||||
# Set resolution
|
||||
width = folder_attributes.get("resolutionWidth", 1920)
|
||||
height = folder_attributes.get("resolutionHeight", 1080)
|
||||
pixelAspect = folder_attributes.get("pixelAspect", 1)
|
||||
width = task_attributes.get("resolutionWidth", 1920)
|
||||
height = task_attributes.get("resolutionHeight", 1080)
|
||||
pixel_aspect = task_attributes.get("pixelAspect", 1)
|
||||
|
||||
set_scene_resolution(width, height, pixelAspect)
|
||||
set_scene_resolution(width, height, pixel_aspect)
|
||||
|
||||
|
||||
def set_context_settings(
|
||||
|
|
@ -3129,7 +3214,7 @@ def load_capture_preset(data):
|
|||
return options
|
||||
|
||||
|
||||
def get_attr_in_layer(attr, layer):
|
||||
def get_attr_in_layer(attr, layer, as_string=True):
|
||||
"""Return attribute value in specified renderlayer.
|
||||
|
||||
Same as cmds.getAttr but this gets the attribute's value in a
|
||||
|
|
@ -3147,6 +3232,7 @@ def get_attr_in_layer(attr, layer):
|
|||
Args:
|
||||
attr (str): attribute name, ex. "node.attribute"
|
||||
layer (str): layer name
|
||||
as_string (bool): whether attribute should convert to a string value
|
||||
|
||||
Returns:
|
||||
The return value from `maya.cmds.getAttr`
|
||||
|
|
@ -3156,7 +3242,8 @@ def get_attr_in_layer(attr, layer):
|
|||
try:
|
||||
if cmds.mayaHasRenderSetup():
|
||||
from . import lib_rendersetup
|
||||
return lib_rendersetup.get_attr_in_layer(attr, layer)
|
||||
return lib_rendersetup.get_attr_in_layer(
|
||||
attr, layer, as_string=as_string)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
|
@ -3164,7 +3251,7 @@ def get_attr_in_layer(attr, layer):
|
|||
current_layer = cmds.editRenderLayerGlobals(query=True,
|
||||
currentRenderLayer=True)
|
||||
if layer == current_layer:
|
||||
return cmds.getAttr(attr)
|
||||
return cmds.getAttr(attr, asString=as_string)
|
||||
|
||||
connections = cmds.listConnections(attr,
|
||||
plugs=True,
|
||||
|
|
@ -3215,7 +3302,7 @@ def get_attr_in_layer(attr, layer):
|
|||
value *= conversion
|
||||
return value
|
||||
|
||||
return cmds.getAttr(attr)
|
||||
return cmds.getAttr(attr, asString=as_string)
|
||||
|
||||
|
||||
def fix_incompatible_containers():
|
||||
|
|
@ -3244,33 +3331,46 @@ def update_content_on_context_change():
|
|||
"""
|
||||
This will update scene content to match new folder on context change
|
||||
"""
|
||||
scene_sets = cmds.listSets(allSets=True)
|
||||
folder_entity = get_current_folder_entity()
|
||||
folder_attributes = folder_entity["attrib"]
|
||||
new_folder_path = folder_entity["path"]
|
||||
for s in scene_sets:
|
||||
try:
|
||||
if cmds.getAttr("{}.id".format(s)) in {
|
||||
AYON_INSTANCE_ID, AVALON_INSTANCE_ID
|
||||
}:
|
||||
attr = cmds.listAttr(s)
|
||||
print(s)
|
||||
if "folderPath" in attr:
|
||||
print(
|
||||
" - setting folder to: [ {} ]".format(new_folder_path)
|
||||
)
|
||||
cmds.setAttr(
|
||||
"{}.folderPath".format(s),
|
||||
new_folder_path, type="string"
|
||||
)
|
||||
if "frameStart" in attr:
|
||||
cmds.setAttr("{}.frameStart".format(s),
|
||||
folder_attributes["frameStart"])
|
||||
if "frameEnd" in attr:
|
||||
cmds.setAttr("{}.frameEnd".format(s),
|
||||
folder_attributes["frameEnd"],)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
host = registered_host()
|
||||
create_context = CreateContext(host)
|
||||
folder_entity = get_current_task_entity(fields={"attrib"})
|
||||
|
||||
instance_values = {
|
||||
"folderPath": create_context.get_current_folder_path(),
|
||||
"task": create_context.get_current_task_name(),
|
||||
}
|
||||
creator_attribute_values = {
|
||||
"frameStart": folder_entity["attrib"]["frameStart"],
|
||||
"frameEnd": folder_entity["attrib"]["frameEnd"],
|
||||
}
|
||||
|
||||
has_changes = False
|
||||
for instance in create_context.instances:
|
||||
for key, value in instance_values.items():
|
||||
if key not in instance or instance[key] == value:
|
||||
continue
|
||||
|
||||
# Update instance value
|
||||
print(f"Updating {instance.product_name} {key} to: {value}")
|
||||
instance[key] = value
|
||||
has_changes = True
|
||||
|
||||
creator_attributes = instance.creator_attributes
|
||||
for key, value in creator_attribute_values.items():
|
||||
if (
|
||||
key not in creator_attributes
|
||||
or creator_attributes[key] == value
|
||||
):
|
||||
continue
|
||||
|
||||
# Update instance creator attribute value
|
||||
print(f"Updating {instance.product_name} {key} to: {value}")
|
||||
instance[key] = value
|
||||
has_changes = True
|
||||
|
||||
if has_changes:
|
||||
create_context.save_changes()
|
||||
|
||||
|
||||
def show_message(title, msg):
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ class ARenderProducts:
|
|||
"""
|
||||
return self._get_attr("defaultRenderGlobals", attribute)
|
||||
|
||||
def _get_attr(self, node_attr, attribute=None):
|
||||
def _get_attr(self, node_attr, attribute=None, as_string=True):
|
||||
"""Return the value of the attribute in the renderlayer
|
||||
|
||||
For readability this allows passing in the attribute in two ways.
|
||||
|
|
@ -317,7 +317,7 @@ class ARenderProducts:
|
|||
else:
|
||||
plug = "{}.{}".format(node_attr, attribute)
|
||||
|
||||
return lib.get_attr_in_layer(plug, layer=self.layer)
|
||||
return lib.get_attr_in_layer(plug, layer=self.layer, as_string=as_string)
|
||||
|
||||
@staticmethod
|
||||
def extract_separator(file_prefix):
|
||||
|
|
@ -1133,9 +1133,24 @@ class RenderProductsRedshift(ARenderProducts):
|
|||
aovs = list(set(aovs) - set(ref_aovs))
|
||||
|
||||
products = []
|
||||
global_aov_enabled = bool(
|
||||
self._get_attr("redshiftOptions.aovGlobalEnableMode", as_string=False)
|
||||
)
|
||||
colorspace = lib.get_color_management_output_transform()
|
||||
if not global_aov_enabled:
|
||||
# only beauty output
|
||||
for camera in cameras:
|
||||
products.insert(0,
|
||||
RenderProduct(productName="",
|
||||
ext=ext,
|
||||
multipart=self.multipart,
|
||||
camera=camera,
|
||||
colorspace=colorspace))
|
||||
return products
|
||||
|
||||
light_groups_enabled = False
|
||||
has_beauty_aov = False
|
||||
colorspace = lib.get_color_management_output_transform()
|
||||
|
||||
for aov in aovs:
|
||||
enabled = self._get_attr(aov, "enabled")
|
||||
if not enabled:
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ def get_rendersetup_layer(layer):
|
|||
if conn.endswith(".legacyRenderLayer")), None)
|
||||
|
||||
|
||||
def get_attr_in_layer(node_attr, layer):
|
||||
def get_attr_in_layer(node_attr, layer, as_string=True):
|
||||
"""Return attribute value in Render Setup layer.
|
||||
|
||||
This will only work for attributes which can be
|
||||
|
|
@ -124,7 +124,7 @@ def get_attr_in_layer(node_attr, layer):
|
|||
node = history_overrides[-1] if history_overrides else override
|
||||
node_attr_ = node + ".original"
|
||||
|
||||
return get_attribute(node_attr_, asString=True)
|
||||
return get_attribute(node_attr_, asString=as_string)
|
||||
|
||||
layer = get_rendersetup_layer(layer)
|
||||
rs = renderSetup.instance()
|
||||
|
|
@ -144,7 +144,7 @@ def get_attr_in_layer(node_attr, layer):
|
|||
# we will let it error out.
|
||||
rs.switchToLayer(current_layer)
|
||||
|
||||
return get_attribute(node_attr, asString=True)
|
||||
return get_attribute(node_attr, asString=as_string)
|
||||
|
||||
overrides = get_attr_overrides(node_attr, layer)
|
||||
default_layer_value = get_default_layer_value(node_attr)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import os
|
||||
import json
|
||||
import logging
|
||||
from functools import partial
|
||||
|
||||
|
|
@ -214,8 +215,18 @@ def install(project_settings):
|
|||
)
|
||||
return
|
||||
|
||||
config = project_settings["maya"]["scriptsmenu"]["definition"]
|
||||
_menu = project_settings["maya"]["scriptsmenu"]["name"]
|
||||
menu_settings = project_settings["maya"]["scriptsmenu"]
|
||||
menu_name = menu_settings["name"]
|
||||
config = menu_settings["definition"]
|
||||
|
||||
if menu_settings.get("definition_type") == "definition_json":
|
||||
data = menu_settings["definition_json"]
|
||||
try:
|
||||
config = json.loads(data)
|
||||
except json.JSONDecodeError as exc:
|
||||
print("Skipping studio menu, error decoding JSON definition.")
|
||||
log.error(exc)
|
||||
return
|
||||
|
||||
if not config:
|
||||
log.warning("Skipping studio menu, no definition found.")
|
||||
|
|
@ -223,8 +234,8 @@ def install(project_settings):
|
|||
|
||||
# run the launcher for Maya menu
|
||||
studio_menu = launchformaya.main(
|
||||
title=_menu.title(),
|
||||
objectName=_menu.title().lower().replace(" ", "_")
|
||||
title=menu_name.title(),
|
||||
objectName=menu_name.title().lower().replace(" ", "_")
|
||||
)
|
||||
|
||||
# apply configuration
|
||||
|
|
|
|||
|
|
@ -580,7 +580,8 @@ def on_save():
|
|||
_remove_workfile_lock()
|
||||
|
||||
# Generate ids of the current context on nodes in the scene
|
||||
nodes = lib.get_id_required_nodes(referenced_nodes=False)
|
||||
nodes = lib.get_id_required_nodes(referenced_nodes=False,
|
||||
existing_ids=False)
|
||||
for node, new_id in lib.generate_ids(nodes):
|
||||
lib.set_id(node, new_id, overwrite=False)
|
||||
|
||||
|
|
@ -653,10 +654,6 @@ def on_task_changed():
|
|||
"Can't set project for new context because path does not exist: {}"
|
||||
).format(workdir))
|
||||
|
||||
with lib.suspended_refresh():
|
||||
lib.set_context_settings()
|
||||
lib.update_content_on_context_change()
|
||||
|
||||
global _about_to_save
|
||||
if not lib.IS_HEADLESS and _about_to_save:
|
||||
# Let's prompt the user to update the context settings or not
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ class MayaPlaceholderLoadPlugin(PlaceholderPlugin, PlaceholderLoadMixin):
|
|||
if not container:
|
||||
return
|
||||
|
||||
roots = cmds.sets(container, q=True)
|
||||
roots = cmds.sets(container, q=True) or []
|
||||
ref_node = None
|
||||
try:
|
||||
ref_node = get_reference_node(roots)
|
||||
|
|
|
|||
|
|
@ -40,8 +40,15 @@ class CreateRenderlayer(plugin.RenderlayerCreator):
|
|||
def create(self, product_name, instance_data, pre_create_data):
|
||||
# Only allow a single render instance to exist
|
||||
if self._get_singleton_node():
|
||||
raise CreatorError("A Render instance already exists - only "
|
||||
"one can be configured.")
|
||||
raise CreatorError(
|
||||
"A Render instance already exists - only one can be "
|
||||
"configured.\n\n"
|
||||
"To render multiple render layers, create extra Render Setup "
|
||||
"Layers via Maya's Render Setup UI.\n"
|
||||
"Then refresh the publisher to detect the new layers for "
|
||||
"rendering.\n\n"
|
||||
"With a render instance present all Render Setup layers in "
|
||||
"your workfile are renderable instances.")
|
||||
|
||||
# Apply default project render settings on create
|
||||
if self.render_settings.get("apply_render_settings"):
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class AbcLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
|
|||
"camera",
|
||||
"pointcache",
|
||||
}
|
||||
representations = ["abc"]
|
||||
representations = {"abc"}
|
||||
|
||||
label = "Reference animation"
|
||||
order = -10
|
||||
|
|
@ -81,7 +81,7 @@ class FbxLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
|
|||
"animation",
|
||||
"camera",
|
||||
}
|
||||
representations = ["fbx"]
|
||||
representations = {"fbx"}
|
||||
|
||||
label = "Reference animation"
|
||||
order = -10
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class SetFrameRangeLoader(load.LoaderPlugin):
|
|||
"proxyAbc",
|
||||
"pointcache",
|
||||
}
|
||||
representations = ["abc"]
|
||||
representations = {"abc"}
|
||||
|
||||
label = "Set frame range"
|
||||
order = 11
|
||||
|
|
@ -54,7 +54,7 @@ class SetFrameRangeWithHandlesLoader(load.LoaderPlugin):
|
|||
"proxyAbc",
|
||||
"pointcache",
|
||||
}
|
||||
representations = ["abc"]
|
||||
representations = {"abc"}
|
||||
|
||||
label = "Set frame range (with handles)"
|
||||
order = 12
|
||||
|
|
@ -94,7 +94,7 @@ class ImportMayaLoader(ayon_core.hosts.maya.api.plugin.Loader):
|
|||
so you could also use it as a new base.
|
||||
|
||||
"""
|
||||
representations = ["ma", "mb", "obj"]
|
||||
representations = {"ma", "mb", "obj"}
|
||||
product_types = {
|
||||
"model",
|
||||
"pointcache",
|
||||
|
|
@ -125,6 +125,11 @@ class ImportMayaLoader(ayon_core.hosts.maya.api.plugin.Loader):
|
|||
)
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def apply_settings(cls, project_settings):
|
||||
super(ImportMayaLoader, cls).apply_settings(project_settings)
|
||||
cls.enabled = cls.load_settings["import_loader"].get("enabled", True)
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
import maya.cmds as cmds
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class ArnoldStandinLoader(load.LoaderPlugin):
|
|||
product_types = {
|
||||
"ass", "animation", "model", "proxyAbc", "pointcache", "usd"
|
||||
}
|
||||
representations = ["ass", "abc", "usda", "usdc", "usd"]
|
||||
representations = {"ass", "abc", "usda", "usdc", "usd"}
|
||||
|
||||
label = "Load as Arnold standin"
|
||||
order = -5
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from ayon_core.hosts.maya.api import setdress
|
|||
class AssemblyLoader(load.LoaderPlugin):
|
||||
|
||||
product_types = {"assembly"}
|
||||
representations = ["json"]
|
||||
representations = {"json"}
|
||||
|
||||
label = "Load Set Dress"
|
||||
order = -9
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class AudioLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"audio"}
|
||||
label = "Load audio"
|
||||
representations = ["wav"]
|
||||
representations = {"wav"}
|
||||
icon = "volume-up"
|
||||
color = "orange"
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class GpuCacheLoader(load.LoaderPlugin):
|
|||
"""Load Alembic as gpuCache"""
|
||||
|
||||
product_types = {"model", "animation", "proxyAbc", "pointcache"}
|
||||
representations = ["abc", "gpu_cache"]
|
||||
representations = {"abc", "gpu_cache"}
|
||||
|
||||
label = "Load Gpu Cache"
|
||||
order = -5
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ class FileNodeLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"image", "plate", "render"}
|
||||
label = "Load file node"
|
||||
representations = ["exr", "tif", "png", "jpg"]
|
||||
representations = {"exr", "tif", "png", "jpg"}
|
||||
icon = "image"
|
||||
color = "orange"
|
||||
order = 2
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ class ImagePlaneLoader(load.LoaderPlugin):
|
|||
|
||||
product_types = {"image", "plate", "render"}
|
||||
label = "Load imagePlane"
|
||||
representations = ["mov", "exr", "preview", "png", "jpg"]
|
||||
representations = {"mov", "exr", "preview", "png", "jpg"}
|
||||
icon = "image"
|
||||
color = "orange"
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ class ImagePlaneLoader(load.LoaderPlugin):
|
|||
plug = "{}.{}".format(image_plane_shape, attr)
|
||||
cmds.setAttr(plug, value)
|
||||
|
||||
movie_representations = ["mov", "preview"]
|
||||
movie_representations = {"mov", "preview"}
|
||||
if context["representation"]["name"] in movie_representations:
|
||||
cmds.setAttr(image_plane_shape + ".type", 2)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class LookLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
|
|||
"""Specific loader for lookdev"""
|
||||
|
||||
product_types = {"look"}
|
||||
representations = ["ma"]
|
||||
representations = {"ma"}
|
||||
|
||||
label = "Reference look"
|
||||
order = -10
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class MatchmoveLoader(load.LoaderPlugin):
|
|||
"""
|
||||
|
||||
product_types = {"matchmove"}
|
||||
representations = ["py", "mel"]
|
||||
representations = {"py", "mel"}
|
||||
defaults = ["Camera", "Object", "Mocap"]
|
||||
|
||||
label = "Run matchmove script"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class MayaUsdLoader(load.LoaderPlugin):
|
|||
"""Read USD data in a Maya USD Proxy"""
|
||||
|
||||
product_types = {"model", "usd", "pointcache", "animation"}
|
||||
representations = ["usd", "usda", "usdc", "usdz", "abc"]
|
||||
representations = {"usd", "usda", "usdc", "usdz", "abc"}
|
||||
|
||||
label = "Load USD to Maya Proxy"
|
||||
order = -1
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class MultiverseUsdLoader(load.LoaderPlugin):
|
|||
"pointcache",
|
||||
"animation",
|
||||
}
|
||||
representations = ["usd", "usda", "usdc", "usdz", "abc"]
|
||||
representations = {"usd", "usda", "usdc", "usdz", "abc"}
|
||||
|
||||
label = "Load USD to Multiverse"
|
||||
order = -10
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class MultiverseUsdOverLoader(load.LoaderPlugin):
|
|||
"""Reference file"""
|
||||
|
||||
product_types = {"mvUsdOverride"}
|
||||
representations = ["usda", "usd", "udsz"]
|
||||
representations = {"usda", "usd", "udsz"}
|
||||
|
||||
label = "Load Usd Override into Compound"
|
||||
order = -10
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class RedshiftProxyLoader(load.LoaderPlugin):
|
|||
"""Load Redshift proxy"""
|
||||
|
||||
product_types = {"redshiftproxy"}
|
||||
representations = ["rs"]
|
||||
representations = {"rs"}
|
||||
|
||||
label = "Import Redshift Proxy"
|
||||
order = -10
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class ReferenceLoader(plugin.ReferenceLoader):
|
|||
"matchmove",
|
||||
}
|
||||
|
||||
representations = ["ma", "abc", "fbx", "mb"]
|
||||
representations = {"ma", "abc", "fbx", "mb"}
|
||||
|
||||
label = "Reference"
|
||||
order = -10
|
||||
|
|
@ -269,7 +269,7 @@ class MayaUSDReferenceLoader(ReferenceLoader):
|
|||
|
||||
label = "Reference Maya USD"
|
||||
product_types = {"usd"}
|
||||
representations = ["usd"]
|
||||
representations = {"usd"}
|
||||
extensions = {"usd", "usda", "usdc"}
|
||||
|
||||
options = ReferenceLoader.options + [
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class RenderSetupLoader(load.LoaderPlugin):
|
|||
"""Load json preset for RenderSetup overwriting current one."""
|
||||
|
||||
product_types = {"rendersetup"}
|
||||
representations = ["json"]
|
||||
representations = {"json"}
|
||||
defaults = ['Main']
|
||||
|
||||
label = "Load RenderSetup template"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class LoadVDBtoArnold(load.LoaderPlugin):
|
|||
"""Load OpenVDB for Arnold in aiVolume"""
|
||||
|
||||
product_types = {"vdbcache"}
|
||||
representations = ["vdb"]
|
||||
representations = {"vdb"}
|
||||
|
||||
label = "Load VDB to Arnold"
|
||||
icon = "cloud"
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class LoadVDBtoRedShift(load.LoaderPlugin):
|
|||
"""
|
||||
|
||||
product_types = {"vdbcache"}
|
||||
representations = ["vdb"]
|
||||
representations = {"vdb"}
|
||||
|
||||
label = "Load VDB to RedShift"
|
||||
icon = "cloud"
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class LoadVDBtoVRay(load.LoaderPlugin):
|
|||
"""Load OpenVDB in a V-Ray Volume Grid"""
|
||||
|
||||
product_types = {"vdbcache"}
|
||||
representations = ["vdb"]
|
||||
representations = {"vdb"}
|
||||
|
||||
label = "Load VDB to VRay"
|
||||
icon = "cloud"
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class VRayProxyLoader(load.LoaderPlugin):
|
|||
"""Load VRay Proxy with Alembic or VrayMesh."""
|
||||
|
||||
product_types = {"vrayproxy", "model", "pointcache", "animation"}
|
||||
representations = ["vrmesh", "abc"]
|
||||
representations = {"vrmesh", "abc"}
|
||||
|
||||
label = "Import VRay Proxy"
|
||||
order = -10
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class VRaySceneLoader(load.LoaderPlugin):
|
|||
"""Load Vray scene"""
|
||||
|
||||
product_types = {"vrayscene_layer"}
|
||||
representations = ["vrscene"]
|
||||
representations = {"vrscene"}
|
||||
|
||||
label = "Import VRay Scene"
|
||||
order = -10
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class XgenLoader(ayon_core.hosts.maya.api.plugin.ReferenceLoader):
|
|||
"""Load Xgen as reference"""
|
||||
|
||||
product_types = {"xgen"}
|
||||
representations = ["ma", "mb"]
|
||||
representations = {"ma", "mb"}
|
||||
|
||||
label = "Reference Xgen"
|
||||
icon = "code-fork"
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class YetiCacheLoader(load.LoaderPlugin):
|
|||
"""Load Yeti Cache with one or more Yeti nodes"""
|
||||
|
||||
product_types = {"yeticache", "yetiRig"}
|
||||
representations = ["fur"]
|
||||
representations = {"fur"}
|
||||
|
||||
label = "Load Yeti Cache"
|
||||
order = -9
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ class YetiRigLoader(plugin.ReferenceLoader):
|
|||
"""This loader will load Yeti rig."""
|
||||
|
||||
product_types = {"yetiRig"}
|
||||
representations = ["ma"]
|
||||
representations = {"ma"}
|
||||
|
||||
label = "Load Yeti Rig"
|
||||
order = -9
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import json
|
||||
|
||||
from maya import cmds
|
||||
|
||||
import pyblish.api
|
||||
|
|
@ -11,18 +9,24 @@ class CollectFileDependencies(pyblish.api.ContextPlugin):
|
|||
label = "Collect File Dependencies"
|
||||
order = pyblish.api.CollectorOrder - 0.49
|
||||
hosts = ["maya"]
|
||||
families = ["renderlayer"]
|
||||
|
||||
@classmethod
|
||||
def apply_settings(cls, project_settings, system_settings):
|
||||
# Disable plug-in if not used for deadline submission anyway
|
||||
settings = project_settings["deadline"]["publish"]["MayaSubmitDeadline"] # noqa
|
||||
cls.enabled = settings.get("asset_dependencies", True)
|
||||
|
||||
def process(self, context):
|
||||
dependencies = []
|
||||
dependencies = set()
|
||||
for node in cmds.ls(type="file"):
|
||||
path = cmds.getAttr("{}.{}".format(node, "fileTextureName"))
|
||||
if path not in dependencies:
|
||||
dependencies.append(path)
|
||||
dependencies.add(path)
|
||||
|
||||
for node in cmds.ls(type="AlembicNode"):
|
||||
path = cmds.getAttr("{}.{}".format(node, "abc_File"))
|
||||
if path not in dependencies:
|
||||
dependencies.append(path)
|
||||
dependencies.add(path)
|
||||
|
||||
context.data["fileDependencies"] = dependencies
|
||||
self.log.debug(json.dumps(dependencies, indent=4))
|
||||
context.data["fileDependencies"] = list(dependencies)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue