mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge branch 'develop' into feature/906-hiero-convert-to-pype3
This commit is contained in:
commit
00cedfc873
396 changed files with 2791 additions and 1915 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -13,4 +13,4 @@
|
|||
url = https://bitbucket.org/ftrack/ftrack-python-api.git
|
||||
[submodule "pype/modules/ftrack/python2_vendor/arrow"]
|
||||
path = pype/modules/ftrack/python2_vendor/arrow
|
||||
url = git@github.com:arrow-py/arrow.git
|
||||
url = git@github.com:arrow-py/arrow.git
|
||||
10
pype/api.py
10
pype/api.py
|
|
@ -26,6 +26,14 @@ from .lib.mongo import (
|
|||
get_default_components
|
||||
)
|
||||
|
||||
from .lib.applications import (
|
||||
ApplicationManager
|
||||
)
|
||||
|
||||
from .lib.avalon_context import (
|
||||
BuildWorkfile
|
||||
)
|
||||
|
||||
from . import resources
|
||||
|
||||
from .plugin import (
|
||||
|
|
@ -63,6 +71,8 @@ __all__ = [
|
|||
"decompose_url",
|
||||
"compose_url",
|
||||
"get_default_components",
|
||||
"ApplicationManager",
|
||||
"BuildWorkfile",
|
||||
|
||||
# Resources
|
||||
"resources",
|
||||
|
|
|
|||
|
|
@ -20,16 +20,23 @@ class AfterEffectsPrelaunchHook(PreLaunchHook):
|
|||
while self.launch_context.launch_args:
|
||||
remainders.append(self.launch_context.launch_args.pop(0))
|
||||
|
||||
workfile_path = self.data["last_workfile_path"]
|
||||
if not os.path.exists(workfile_path):
|
||||
workfile_path = ""
|
||||
|
||||
new_launch_args = [
|
||||
self.python_executable(),
|
||||
"-c",
|
||||
(
|
||||
"import avalon.aftereffects;"
|
||||
"avalon.aftereffects.launch(\"{}\")"
|
||||
).format(aftereffects_executable)
|
||||
"avalon.aftereffects.launch(\"{}\", \"{}\")"
|
||||
).format(
|
||||
aftereffects_executable.replace("\\", "\\\\"),
|
||||
workfile_path.replace("\\", "\\\\")
|
||||
)
|
||||
]
|
||||
|
||||
# Append as whole list as these areguments should not be separated
|
||||
# Append as whole list as these arguments should not be separated
|
||||
self.launch_context.launch_args.append(new_launch_args)
|
||||
|
||||
if remainders:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class HarmonyPrelaunchHook(PreLaunchHook):
|
|||
(
|
||||
"import avalon.harmony;"
|
||||
"avalon.harmony.launch(\"{}\")"
|
||||
).format(harmony_executable)
|
||||
).format(harmony_executable.replace("\\", "\\\\"))
|
||||
]
|
||||
|
||||
# Append as whole list as these areguments should not be separated
|
||||
|
|
|
|||
|
|
@ -20,13 +20,20 @@ class PhotoshopPrelaunchHook(PreLaunchHook):
|
|||
while self.launch_context.launch_args:
|
||||
remainders.append(self.launch_context.launch_args.pop(0))
|
||||
|
||||
workfile_path = self.data["last_workfile_path"]
|
||||
if not os.path.exists(workfile_path):
|
||||
workfile_path = ""
|
||||
|
||||
new_launch_args = [
|
||||
self.python_executable(),
|
||||
"-c",
|
||||
(
|
||||
"import avalon.photoshop;"
|
||||
"avalon.photoshop.launch(\"{}\")"
|
||||
).format(photoshop_executable)
|
||||
"avalon.photoshop.launch(\"{}\", \"{}\")"
|
||||
).format(
|
||||
photoshop_executable.replace("\\", "\\\\"),
|
||||
workfile_path.replace("\\", "\\\\")
|
||||
)
|
||||
]
|
||||
|
||||
# Append as whole list as these areguments should not be separated
|
||||
|
|
|
|||
BIN
pype/hosts/aftereffects/template.aep
Normal file
BIN
pype/hosts/aftereffects/template.aep
Normal file
Binary file not shown.
|
|
@ -1,60 +0,0 @@
|
|||
import os
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from avalon import api as avalon
|
||||
from pyblish import api as pyblish
|
||||
|
||||
import bpy
|
||||
|
||||
from pype import PLUGINS_DIR
|
||||
|
||||
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "blender", "publish")
|
||||
LOAD_PATH = os.path.join(PLUGINS_DIR, "blender", "load")
|
||||
CREATE_PATH = os.path.join(PLUGINS_DIR, "blender", "create")
|
||||
|
||||
ORIGINAL_EXCEPTHOOK = sys.excepthook
|
||||
|
||||
|
||||
def pype_excepthook_handler(*args):
|
||||
traceback.print_exception(*args)
|
||||
|
||||
|
||||
def install():
|
||||
"""Install Blender configuration for Avalon."""
|
||||
sys.excepthook = pype_excepthook_handler
|
||||
pyblish.register_plugin_path(str(PUBLISH_PATH))
|
||||
avalon.register_plugin_path(avalon.Loader, str(LOAD_PATH))
|
||||
avalon.register_plugin_path(avalon.Creator, str(CREATE_PATH))
|
||||
|
||||
avalon.on("new", on_new)
|
||||
avalon.on("open", on_open)
|
||||
|
||||
|
||||
def uninstall():
|
||||
"""Uninstall Blender configuration for Avalon."""
|
||||
sys.excepthook = ORIGINAL_EXCEPTHOOK
|
||||
pyblish.deregister_plugin_path(str(PUBLISH_PATH))
|
||||
avalon.deregister_plugin_path(avalon.Loader, str(LOAD_PATH))
|
||||
avalon.deregister_plugin_path(avalon.Creator, str(CREATE_PATH))
|
||||
|
||||
|
||||
def set_start_end_frames():
|
||||
from avalon import io
|
||||
|
||||
asset_name = io.Session["AVALON_ASSET"]
|
||||
asset_doc = io.find_one({
|
||||
"type": "asset",
|
||||
"name": asset_name
|
||||
})
|
||||
|
||||
bpy.context.scene.frame_start = asset_doc["data"]["frameStart"]
|
||||
bpy.context.scene.frame_end = asset_doc["data"]["frameEnd"]
|
||||
|
||||
|
||||
def on_new(arg1, arg2):
|
||||
set_start_end_frames()
|
||||
|
||||
|
||||
def on_open(arg1, arg2):
|
||||
set_start_end_frames()
|
||||
63
pype/hosts/blender/api/__init__.py
Normal file
63
pype/hosts/blender/api/__init__.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import os
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import bpy
|
||||
|
||||
from avalon import api as avalon
|
||||
from pyblish import api as pyblish
|
||||
|
||||
import pype.hosts.blender
|
||||
|
||||
HOST_DIR = os.path.dirname(os.path.abspath(pype.hosts.blender.__file__))
|
||||
PLUGINS_DIR = os.path.join(HOST_DIR, "plugins")
|
||||
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish")
|
||||
LOAD_PATH = os.path.join(PLUGINS_DIR, "load")
|
||||
CREATE_PATH = os.path.join(PLUGINS_DIR, "create")
|
||||
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
|
||||
|
||||
ORIGINAL_EXCEPTHOOK = sys.excepthook
|
||||
|
||||
|
||||
def pype_excepthook_handler(*args):
|
||||
traceback.print_exception(*args)
|
||||
|
||||
|
||||
def install():
|
||||
"""Install Blender configuration for Avalon."""
|
||||
sys.excepthook = pype_excepthook_handler
|
||||
pyblish.register_plugin_path(str(PUBLISH_PATH))
|
||||
avalon.register_plugin_path(avalon.Loader, str(LOAD_PATH))
|
||||
avalon.register_plugin_path(avalon.Creator, str(CREATE_PATH))
|
||||
|
||||
avalon.on("new", on_new)
|
||||
avalon.on("open", on_open)
|
||||
|
||||
|
||||
def uninstall():
|
||||
"""Uninstall Blender configuration for Avalon."""
|
||||
sys.excepthook = ORIGINAL_EXCEPTHOOK
|
||||
pyblish.deregister_plugin_path(str(PUBLISH_PATH))
|
||||
avalon.deregister_plugin_path(avalon.Loader, str(LOAD_PATH))
|
||||
avalon.deregister_plugin_path(avalon.Creator, str(CREATE_PATH))
|
||||
|
||||
|
||||
def set_start_end_frames():
|
||||
from avalon import io
|
||||
|
||||
asset_name = io.Session["AVALON_ASSET"]
|
||||
asset_doc = io.find_one({
|
||||
"type": "asset",
|
||||
"name": asset_name
|
||||
})
|
||||
|
||||
bpy.context.scene.frame_start = asset_doc["data"]["frameStart"]
|
||||
bpy.context.scene.frame_end = asset_doc["data"]["frameEnd"]
|
||||
|
||||
|
||||
def on_new(arg1, arg2):
|
||||
set_start_end_frames()
|
||||
|
||||
|
||||
def on_open(arg1, arg2):
|
||||
set_start_end_frames()
|
||||
|
|
@ -2,7 +2,7 @@ import bpy
|
|||
|
||||
import pyblish.api
|
||||
|
||||
from ...action import get_errored_instances_from_context
|
||||
from pype.api import get_errored_instances_from_context
|
||||
|
||||
|
||||
class SelectInvalidAction(pyblish.api.Action):
|
||||
|
|
@ -4,7 +4,7 @@ import bpy
|
|||
|
||||
from avalon import api
|
||||
from avalon.blender import Creator, lib
|
||||
import pype.hosts.blender.plugin
|
||||
import pype.hosts.blender.api.plugin
|
||||
|
||||
|
||||
class CreateAction(Creator):
|
||||
|
|
@ -19,7 +19,7 @@ class CreateAction(Creator):
|
|||
|
||||
asset = self.data["asset"]
|
||||
subset = self.data["subset"]
|
||||
name = pype.hosts.blender.plugin.asset_name(asset, subset)
|
||||
name = pype.hosts.blender.api.plugin.asset_name(asset, subset)
|
||||
collection = bpy.data.collections.new(name=name)
|
||||
bpy.context.scene.collection.children.link(collection)
|
||||
self.data['task'] = api.Session.get('AVALON_TASK')
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
import bpy
|
||||
|
||||
from avalon import api, blender
|
||||
import pype.hosts.blender.plugin
|
||||
import pype.hosts.blender.api.plugin
|
||||
|
||||
|
||||
class CreateAnimation(blender.Creator):
|
||||
|
|
@ -17,7 +17,7 @@ class CreateAnimation(blender.Creator):
|
|||
def process(self):
|
||||
asset = self.data["asset"]
|
||||
subset = self.data["subset"]
|
||||
name = pype.hosts.blender.plugin.asset_name(asset, subset)
|
||||
name = pype.hosts.blender.api.plugin.asset_name(asset, subset)
|
||||
collection = bpy.data.collections.new(name=name)
|
||||
bpy.context.scene.collection.children.link(collection)
|
||||
self.data['task'] = api.Session.get('AVALON_TASK')
|
||||
|
|
@ -4,7 +4,7 @@ import bpy
|
|||
|
||||
from avalon import api
|
||||
from avalon.blender import Creator, lib
|
||||
import pype.hosts.blender.plugin
|
||||
import pype.hosts.blender.api.plugin
|
||||
|
||||
|
||||
class CreateCamera(Creator):
|
||||
|
|
@ -19,7 +19,7 @@ class CreateCamera(Creator):
|
|||
|
||||
asset = self.data["asset"]
|
||||
subset = self.data["subset"]
|
||||
name = pype.hosts.blender.plugin.asset_name(asset, subset)
|
||||
name = pype.hosts.blender.api.plugin.asset_name(asset, subset)
|
||||
collection = bpy.data.collections.new(name=name)
|
||||
bpy.context.scene.collection.children.link(collection)
|
||||
self.data['task'] = api.Session.get('AVALON_TASK')
|
||||
|
|
@ -4,7 +4,7 @@ import bpy
|
|||
|
||||
from avalon import api
|
||||
from avalon.blender import Creator, lib
|
||||
import pype.hosts.blender.plugin
|
||||
import pype.hosts.blender.api.plugin
|
||||
|
||||
|
||||
class CreateLayout(Creator):
|
||||
|
|
@ -19,7 +19,7 @@ class CreateLayout(Creator):
|
|||
|
||||
asset = self.data["asset"]
|
||||
subset = self.data["subset"]
|
||||
name = pype.hosts.blender.plugin.asset_name(asset, subset)
|
||||
name = pype.hosts.blender.api.plugin.asset_name(asset, subset)
|
||||
collection = bpy.data.collections.new(name=name)
|
||||
bpy.context.scene.collection.children.link(collection)
|
||||
self.data['task'] = api.Session.get('AVALON_TASK')
|
||||
|
|
@ -4,7 +4,7 @@ import bpy
|
|||
|
||||
from avalon import api
|
||||
from avalon.blender import Creator, lib
|
||||
import pype.hosts.blender.plugin
|
||||
import pype.hosts.blender.api.plugin
|
||||
|
||||
|
||||
class CreateModel(Creator):
|
||||
|
|
@ -19,7 +19,7 @@ class CreateModel(Creator):
|
|||
|
||||
asset = self.data["asset"]
|
||||
subset = self.data["subset"]
|
||||
name = pype.hosts.blender.plugin.asset_name(asset, subset)
|
||||
name = pype.hosts.blender.api.plugin.asset_name(asset, subset)
|
||||
collection = bpy.data.collections.new(name=name)
|
||||
bpy.context.scene.collection.children.link(collection)
|
||||
self.data['task'] = api.Session.get('AVALON_TASK')
|
||||
|
|
@ -4,7 +4,7 @@ import bpy
|
|||
|
||||
from avalon import api
|
||||
from avalon.blender import Creator, lib
|
||||
import pype.hosts.blender.plugin
|
||||
import pype.hosts.blender.api.plugin
|
||||
|
||||
|
||||
class CreateRig(Creator):
|
||||
|
|
@ -19,7 +19,7 @@ class CreateRig(Creator):
|
|||
|
||||
asset = self.data["asset"]
|
||||
subset = self.data["subset"]
|
||||
name = pype.hosts.blender.plugin.asset_name(asset, subset)
|
||||
name = pype.hosts.blender.api.plugin.asset_name(asset, subset)
|
||||
collection = bpy.data.collections.new(name=name)
|
||||
bpy.context.scene.collection.children.link(collection)
|
||||
self.data['task'] = api.Session.get('AVALON_TASK')
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import bpy
|
||||
|
||||
from avalon import api, blender
|
||||
import pype.hosts.blender.plugin
|
||||
import pype.hosts.blender.api.plugin
|
||||
|
||||
class CreateSetDress(blender.Creator):
|
||||
"""A grouped package of loaded content"""
|
||||
|
|
@ -15,7 +15,7 @@ class CreateSetDress(blender.Creator):
|
|||
def process(self):
|
||||
asset = self.data["asset"]
|
||||
subset = self.data["subset"]
|
||||
name = pype.hosts.blender.plugin.asset_name(asset, subset)
|
||||
name = pype.hosts.blender.api.plugin.asset_name(asset, subset)
|
||||
collection = bpy.data.collections.new(name=name)
|
||||
bpy.context.scene.collection.children.link(collection)
|
||||
self.data['task'] = api.Session.get('AVALON_TASK')
|
||||
|
|
@ -7,12 +7,12 @@ from typing import Dict, List, Optional
|
|||
|
||||
from avalon import api, blender
|
||||
import bpy
|
||||
import pype.hosts.blender.plugin
|
||||
import pype.hosts.blender.api.plugin
|
||||
|
||||
logger = logging.getLogger("pype").getChild("blender").getChild("load_action")
|
||||
|
||||
|
||||
class BlendActionLoader(pype.hosts.blender.plugin.AssetLoader):
|
||||
class BlendActionLoader(pype.hosts.blender.api.plugin.AssetLoader):
|
||||
"""Load action from a .blend file.
|
||||
|
||||
Warning:
|
||||
|
|
@ -42,8 +42,8 @@ class BlendActionLoader(pype.hosts.blender.plugin.AssetLoader):
|
|||
libpath = self.fname
|
||||
asset = context["asset"]["name"]
|
||||
subset = context["subset"]["name"]
|
||||
lib_container = pype.hosts.blender.plugin.asset_name(asset, subset)
|
||||
container_name = pype.hosts.blender.plugin.asset_name(
|
||||
lib_container = pype.hosts.blender.api.plugin.asset_name(asset, subset)
|
||||
container_name = pype.hosts.blender.api.plugin.asset_name(
|
||||
asset, subset, namespace
|
||||
)
|
||||
|
||||
|
|
@ -149,7 +149,7 @@ class BlendActionLoader(pype.hosts.blender.plugin.AssetLoader):
|
|||
assert libpath.is_file(), (
|
||||
f"The file doesn't exist: {libpath}"
|
||||
)
|
||||
assert extension in pype.hosts.blender.plugin.VALID_EXTENSIONS, (
|
||||
assert extension in pype.hosts.blender.api.plugin.VALID_EXTENSIONS, (
|
||||
f"Unsupported file: {libpath}"
|
||||
)
|
||||
|
||||
|
|
@ -7,14 +7,14 @@ from typing import Dict, List, Optional
|
|||
|
||||
from avalon import api, blender
|
||||
import bpy
|
||||
import pype.hosts.blender.plugin
|
||||
import pype.hosts.blender.api.plugin
|
||||
|
||||
|
||||
logger = logging.getLogger("pype").getChild(
|
||||
"blender").getChild("load_animation")
|
||||
|
||||
|
||||
class BlendAnimationLoader(pype.hosts.blender.plugin.AssetLoader):
|
||||
class BlendAnimationLoader(pype.hosts.blender.api.plugin.AssetLoader):
|
||||
"""Load animations from a .blend file.
|
||||
|
||||
Warning:
|
||||
|
|
@ -105,8 +105,8 @@ class BlendAnimationLoader(pype.hosts.blender.plugin.AssetLoader):
|
|||
libpath = self.fname
|
||||
asset = context["asset"]["name"]
|
||||
subset = context["subset"]["name"]
|
||||
lib_container = pype.hosts.blender.plugin.asset_name(asset, subset)
|
||||
container_name = pype.hosts.blender.plugin.asset_name(
|
||||
lib_container = pype.hosts.blender.api.plugin.asset_name(asset, subset)
|
||||
container_name = pype.hosts.blender.api.plugin.asset_name(
|
||||
asset, subset, namespace
|
||||
)
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ class BlendAnimationLoader(pype.hosts.blender.plugin.AssetLoader):
|
|||
assert libpath.is_file(), (
|
||||
f"The file doesn't exist: {libpath}"
|
||||
)
|
||||
assert extension in pype.hosts.blender.plugin.VALID_EXTENSIONS, (
|
||||
assert extension in pype.hosts.blender.api.plugin.VALID_EXTENSIONS, (
|
||||
f"Unsupported file: {libpath}"
|
||||
)
|
||||
|
||||
|
|
@ -7,12 +7,12 @@ from typing import Dict, List, Optional
|
|||
|
||||
from avalon import api, blender
|
||||
import bpy
|
||||
import pype.hosts.blender.plugin
|
||||
import pype.hosts.blender.api.plugin
|
||||
|
||||
logger = logging.getLogger("pype").getChild("blender").getChild("load_camera")
|
||||
|
||||
|
||||
class BlendCameraLoader(pype.hosts.blender.plugin.AssetLoader):
|
||||
class BlendCameraLoader(pype.hosts.blender.api.plugin.AssetLoader):
|
||||
"""Load a camera from a .blend file.
|
||||
|
||||
Warning:
|
||||
|
|
@ -92,8 +92,8 @@ class BlendCameraLoader(pype.hosts.blender.plugin.AssetLoader):
|
|||
libpath = self.fname
|
||||
asset = context["asset"]["name"]
|
||||
subset = context["subset"]["name"]
|
||||
lib_container = pype.hosts.blender.plugin.asset_name(asset, subset)
|
||||
container_name = pype.hosts.blender.plugin.asset_name(
|
||||
lib_container = pype.hosts.blender.api.plugin.asset_name(asset, subset)
|
||||
container_name = pype.hosts.blender.api.plugin.asset_name(
|
||||
asset, subset, namespace
|
||||
)
|
||||
|
||||
|
|
@ -162,7 +162,7 @@ class BlendCameraLoader(pype.hosts.blender.plugin.AssetLoader):
|
|||
assert libpath.is_file(), (
|
||||
f"The file doesn't exist: {libpath}"
|
||||
)
|
||||
assert extension in pype.hosts.blender.plugin.VALID_EXTENSIONS, (
|
||||
assert extension in pype.hosts.blender.api.plugin.VALID_EXTENSIONS, (
|
||||
f"Unsupported file: {libpath}"
|
||||
)
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ from typing import Dict, List, Optional
|
|||
|
||||
from avalon import api, blender, pipeline
|
||||
import bpy
|
||||
import pype.hosts.blender.plugin as plugin
|
||||
import pype.hosts.blender.api.plugin as plugin
|
||||
|
||||
|
||||
class BlendLayoutLoader(plugin.AssetLoader):
|
||||
|
|
@ -7,7 +7,7 @@ from typing import Dict, List, Optional
|
|||
|
||||
from avalon import api, blender
|
||||
import bpy
|
||||
import pype.hosts.blender.plugin as plugin
|
||||
import pype.hosts.blender.api.plugin as plugin
|
||||
|
||||
|
||||
class BlendModelLoader(plugin.AssetLoader):
|
||||
|
|
@ -7,7 +7,7 @@ from typing import Dict, List, Optional
|
|||
|
||||
from avalon import api, blender
|
||||
import bpy
|
||||
import pype.hosts.blender.plugin as plugin
|
||||
import pype.hosts.blender.api.plugin as plugin
|
||||
|
||||
|
||||
class BlendRigLoader(plugin.AssetLoader):
|
||||
0
pype/hosts/blender/plugins/publish/__init__.py
Normal file
0
pype/hosts/blender/plugins/publish/__init__.py
Normal file
|
|
@ -1,7 +1,7 @@
|
|||
import os
|
||||
|
||||
import pype.api
|
||||
import pype.hosts.blender.plugin
|
||||
import pype.hosts.blender.api.plugin
|
||||
|
||||
import bpy
|
||||
|
||||
|
|
@ -61,7 +61,8 @@ class ExtractABC(pype.api.Extractor):
|
|||
except:
|
||||
continue
|
||||
|
||||
new_context = pype.hosts.blender.plugin.create_blender_context(active=selected[0], selected=selected)
|
||||
new_context = pype.hosts.blender.api.plugin.create_blender_context(
|
||||
active=selected[0], selected=selected)
|
||||
|
||||
# We set the scale of the scene for the export
|
||||
scene.unit_settings.scale_length = 0.01
|
||||
|
|
@ -6,6 +6,7 @@ import pyblish.api
|
|||
|
||||
import bpy
|
||||
|
||||
|
||||
class ExtractSetDress(pype.api.Extractor):
|
||||
"""Extract setdress."""
|
||||
|
||||
|
|
@ -21,17 +22,20 @@ class ExtractSetDress(pype.api.Extractor):
|
|||
json_data = []
|
||||
|
||||
for i in instance.context:
|
||||
collection = i.data.get('name')
|
||||
collection = i.data.get("name")
|
||||
container = None
|
||||
for obj in bpy.data.collections[collection].objects:
|
||||
if obj.type == 'ARMATURE':
|
||||
container_name = obj.get('avalon').get('container_name')
|
||||
if obj.type == "ARMATURE":
|
||||
container_name = obj.get("avalon").get("container_name")
|
||||
container = bpy.data.collections[container_name]
|
||||
if container:
|
||||
json_dict = {}
|
||||
json_dict['subset'] = i.data.get('subset')
|
||||
json_dict['container'] = container.name
|
||||
json_dict['instance_name'] = container.get('avalon').get('instance_name')
|
||||
json_dict = {
|
||||
"subset": i.data.get("subset"),
|
||||
"container": container.name,
|
||||
}
|
||||
json_dict["instance_name"] = container.get("avalon").get(
|
||||
"instance_name"
|
||||
)
|
||||
json_data.append(json_dict)
|
||||
|
||||
if "representations" not in instance.data:
|
||||
|
|
@ -44,13 +48,14 @@ class ExtractSetDress(pype.api.Extractor):
|
|||
json.dump(json_data, fp=file, indent=2)
|
||||
|
||||
json_representation = {
|
||||
'name': 'json',
|
||||
'ext': 'json',
|
||||
'files': json_filename,
|
||||
"name": "json",
|
||||
"ext": "json",
|
||||
"files": json_filename,
|
||||
"stagingDir": stagingdir,
|
||||
}
|
||||
instance.data["representations"].append(json_representation)
|
||||
|
||||
self.log.info("Extracted instance '{}' to: {}".format(
|
||||
instance.name, json_representation))
|
||||
|
||||
self.log.info(
|
||||
"Extracted instance '{}' to: {}".format(instance.name,
|
||||
json_representation)
|
||||
)
|
||||
|
|
@ -1,47 +1,47 @@
|
|||
import os
|
||||
import avalon.blender.workio
|
||||
|
||||
import pype.api
|
||||
|
||||
|
||||
class ExtractBlend(pype.api.Extractor):
|
||||
"""Extract a blend file."""
|
||||
|
||||
label = "Extract Blend"
|
||||
hosts = ["blender"]
|
||||
families = ["model", "camera", "rig", "action", "layout", "animation"]
|
||||
optional = True
|
||||
|
||||
def process(self, instance):
|
||||
# Define extract output file path
|
||||
|
||||
stagingdir = self.staging_dir(instance)
|
||||
filename = f"{instance.name}.blend"
|
||||
filepath = os.path.join(stagingdir, filename)
|
||||
|
||||
# Perform extraction
|
||||
self.log.info("Performing extraction..")
|
||||
|
||||
# Just save the file to a temporary location. At least for now it's no
|
||||
# problem to have (possibly) extra stuff in the file.
|
||||
avalon.blender.workio.save_file(filepath, copy=True)
|
||||
#
|
||||
# # Store reference for integration
|
||||
# if "files" not in instance.data:
|
||||
# instance.data["files"] = list()
|
||||
#
|
||||
# # instance.data["files"].append(filename)
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
||||
representation = {
|
||||
'name': 'blend',
|
||||
'ext': 'blend',
|
||||
'files': filename,
|
||||
"stagingDir": stagingdir,
|
||||
}
|
||||
instance.data["representations"].append(representation)
|
||||
|
||||
self.log.info("Extracted instance '%s' to: %s",
|
||||
instance.name, representation)
|
||||
import os
|
||||
import avalon.blender.workio
|
||||
|
||||
import pype.api
|
||||
|
||||
|
||||
class ExtractBlend(pype.api.Extractor):
|
||||
"""Extract a blend file."""
|
||||
|
||||
label = "Extract Blend"
|
||||
hosts = ["blender"]
|
||||
families = ["model", "camera", "rig", "action", "layout", "animation"]
|
||||
optional = True
|
||||
|
||||
def process(self, instance):
|
||||
# Define extract output file path
|
||||
|
||||
stagingdir = self.staging_dir(instance)
|
||||
filename = f"{instance.name}.blend"
|
||||
filepath = os.path.join(stagingdir, filename)
|
||||
|
||||
# Perform extraction
|
||||
self.log.info("Performing extraction..")
|
||||
|
||||
# Just save the file to a temporary location. At least for now it's no
|
||||
# problem to have (possibly) extra stuff in the file.
|
||||
avalon.blender.workio.save_file(filepath, copy=True)
|
||||
#
|
||||
# # Store reference for integration
|
||||
# if "files" not in instance.data:
|
||||
# instance.data["files"] = list()
|
||||
#
|
||||
# # instance.data["files"].append(filename)
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
||||
representation = {
|
||||
'name': 'blend',
|
||||
'ext': 'blend',
|
||||
'files': filename,
|
||||
"stagingDir": stagingdir,
|
||||
}
|
||||
instance.data["representations"].append(representation)
|
||||
|
||||
self.log.info("Extracted instance '%s' to: %s",
|
||||
instance.name, representation)
|
||||
|
|
@ -3,7 +3,7 @@ from typing import List
|
|||
import bpy
|
||||
|
||||
import pyblish.api
|
||||
import pype.hosts.blender.action
|
||||
import pype.hosts.blender.api.action
|
||||
|
||||
|
||||
class ValidateMeshHasUvs(pyblish.api.InstancePlugin):
|
||||
|
|
@ -14,7 +14,7 @@ class ValidateMeshHasUvs(pyblish.api.InstancePlugin):
|
|||
families = ["model"]
|
||||
category = "geometry"
|
||||
label = "Mesh Has UV's"
|
||||
actions = [pype.hosts.blender.action.SelectInvalidAction]
|
||||
actions = [pype.hosts.blender.api.action.SelectInvalidAction]
|
||||
optional = True
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -3,7 +3,7 @@ from typing import List
|
|||
import bpy
|
||||
|
||||
import pyblish.api
|
||||
import pype.hosts.blender.action
|
||||
import pype.hosts.blender.api.action
|
||||
|
||||
|
||||
class ValidateMeshNoNegativeScale(pyblish.api.Validator):
|
||||
|
|
@ -13,7 +13,7 @@ class ValidateMeshNoNegativeScale(pyblish.api.Validator):
|
|||
hosts = ["blender"]
|
||||
families = ["model"]
|
||||
label = "Mesh No Negative Scale"
|
||||
actions = [pype.hosts.blender.action.SelectInvalidAction]
|
||||
actions = [pype.hosts.blender.api.action.SelectInvalidAction]
|
||||
|
||||
@staticmethod
|
||||
def get_invalid(instance) -> List:
|
||||
3
pype/hosts/blender/startup/init.py
Normal file
3
pype/hosts/blender/startup/init.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from pype.hosts.blender import api
|
||||
|
||||
api.install()
|
||||
|
|
@ -1 +0,0 @@
|
|||
kwargs = None
|
||||
1
pype/hosts/celaction/api/__init__.py
Normal file
1
pype/hosts/celaction/api/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
kwargs = None
|
||||
|
|
@ -11,18 +11,19 @@ import pyblish.util
|
|||
|
||||
from pype.api import Logger
|
||||
import pype
|
||||
from pype.hosts import celaction
|
||||
import pype.hosts.celaction
|
||||
from pype.hosts.celaction import api as celaction
|
||||
|
||||
log = Logger().get_logger("Celaction_cli_publisher")
|
||||
|
||||
publish_host = "celaction"
|
||||
|
||||
PUBLISH_PATH = os.path.join(pype.PLUGINS_DIR, publish_host, "publish")
|
||||
|
||||
PUBLISH_PATHS = [
|
||||
PUBLISH_PATH,
|
||||
os.path.join(pype.PLUGINS_DIR, "ftrack", "publish")
|
||||
]
|
||||
HOST_DIR = os.path.dirname(os.path.abspath(pype.hosts.celaction.__file__))
|
||||
PLUGINS_DIR = os.path.join(HOST_DIR, "plugins")
|
||||
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish")
|
||||
LOAD_PATH = os.path.join(PLUGINS_DIR, "load")
|
||||
CREATE_PATH = os.path.join(PLUGINS_DIR, "create")
|
||||
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
|
||||
|
||||
|
||||
def cli():
|
||||
0
pype/hosts/celaction/hooks/__init__.py
Normal file
0
pype/hosts/celaction/hooks/__init__.py
Normal file
|
|
@ -2,15 +2,12 @@ import os
|
|||
import shutil
|
||||
import winreg
|
||||
from pype.lib import PreLaunchHook
|
||||
from pype.hosts import celaction
|
||||
from pype.hosts.celaction import api as celaction
|
||||
|
||||
|
||||
class CelactionPrelaunchHook(PreLaunchHook):
|
||||
"""
|
||||
This hook will check if current workfile path has Unreal
|
||||
project inside. IF not, it initialize it and finally it pass
|
||||
path to the project by environment variable to Unreal launcher
|
||||
shell script.
|
||||
Bootstrap celacion with pype
|
||||
"""
|
||||
workfile_ext = "scn"
|
||||
app_groups = ["celaction"]
|
||||
|
|
@ -37,7 +34,7 @@ class CelactionPrelaunchHook(PreLaunchHook):
|
|||
"Software\\CelAction\\CelAction2D\\User Settings", 0,
|
||||
winreg.KEY_ALL_ACCESS)
|
||||
|
||||
# TODO: change to root path and pyblish standalone to premiere way
|
||||
# TODO: change to pype executable
|
||||
pype_root_path = os.getenv("PYPE_SETUP_PATH")
|
||||
path = os.path.join(pype_root_path, "pype.bat")
|
||||
|
||||
|
|
@ -94,11 +91,12 @@ class CelactionPrelaunchHook(PreLaunchHook):
|
|||
if not os.path.exists(workfile_path):
|
||||
# TODO add ability to set different template workfile path via
|
||||
# settings
|
||||
pype_celaction_dir = os.path.dirname(
|
||||
pype_celaction_dir = os.path.dirname(os.path.dirname(
|
||||
os.path.abspath(celaction.__file__)
|
||||
)
|
||||
))
|
||||
template_path = os.path.join(
|
||||
pype_celaction_dir,
|
||||
"resources",
|
||||
"celaction_template_scene.scn"
|
||||
)
|
||||
|
||||
0
pype/hosts/celaction/plugins/__init__.py
Normal file
0
pype/hosts/celaction/plugins/__init__.py
Normal file
|
|
@ -1,126 +1,126 @@
|
|||
import os
|
||||
import collections
|
||||
|
||||
import pyblish.api
|
||||
from avalon import io
|
||||
|
||||
from pprint import pformat
|
||||
|
||||
|
||||
class AppendCelactionAudio(pyblish.api.ContextPlugin):
|
||||
|
||||
label = "Colect Audio for publishing"
|
||||
order = pyblish.api.CollectorOrder + 0.1
|
||||
|
||||
def process(self, context):
|
||||
self.log.info('Collecting Audio Data')
|
||||
asset_doc = context.data["assetEntity"]
|
||||
|
||||
# get all available representations
|
||||
subsets = self.get_subsets(
|
||||
asset_doc,
|
||||
representations=["audio", "wav"]
|
||||
)
|
||||
self.log.info(f"subsets is: {pformat(subsets)}")
|
||||
|
||||
if not subsets.get("audioMain"):
|
||||
raise AttributeError("`audioMain` subset does not exist")
|
||||
|
||||
reprs = subsets.get("audioMain", {}).get("representations", [])
|
||||
self.log.info(f"reprs is: {pformat(reprs)}")
|
||||
|
||||
repr = next((r for r in reprs), None)
|
||||
if not repr:
|
||||
raise "Missing `audioMain` representation"
|
||||
self.log.info(f"represetation is: {repr}")
|
||||
|
||||
audio_file = repr.get('data', {}).get('path', "")
|
||||
|
||||
if os.path.exists(audio_file):
|
||||
context.data["audioFile"] = audio_file
|
||||
self.log.info(
|
||||
'audio_file: {}, has been added to context'.format(audio_file))
|
||||
else:
|
||||
self.log.warning("Couldn't find any audio file on Ftrack.")
|
||||
|
||||
def get_subsets(self, asset_doc, representations):
|
||||
"""
|
||||
Query subsets with filter on name.
|
||||
|
||||
The method will return all found subsets and its defined version
|
||||
and subsets. Version could be specified with number. Representation
|
||||
can be filtered.
|
||||
|
||||
Arguments:
|
||||
asset_doct (dict): Asset (shot) mongo document
|
||||
representations (list): list for all representations
|
||||
|
||||
Returns:
|
||||
dict: subsets with version and representaions in keys
|
||||
"""
|
||||
|
||||
# Query all subsets for asset
|
||||
subset_docs = io.find({
|
||||
"type": "subset",
|
||||
"parent": asset_doc["_id"]
|
||||
})
|
||||
# Collect all subset ids
|
||||
subset_ids = [
|
||||
subset_doc["_id"]
|
||||
for subset_doc in subset_docs
|
||||
]
|
||||
|
||||
# Check if we found anything
|
||||
assert subset_ids, (
|
||||
"No subsets found. Check correct filter. "
|
||||
"Try this for start `r'.*'`: asset: `{}`"
|
||||
).format(asset_doc["name"])
|
||||
|
||||
# Last version aggregation
|
||||
pipeline = [
|
||||
# Find all versions of those subsets
|
||||
{"$match": {
|
||||
"type": "version",
|
||||
"parent": {"$in": subset_ids}
|
||||
}},
|
||||
# Sorting versions all together
|
||||
{"$sort": {"name": 1}},
|
||||
# Group them by "parent", but only take the last
|
||||
{"$group": {
|
||||
"_id": "$parent",
|
||||
"_version_id": {"$last": "$_id"},
|
||||
"name": {"$last": "$name"}
|
||||
}}
|
||||
]
|
||||
last_versions_by_subset_id = dict()
|
||||
for doc in io.aggregate(pipeline):
|
||||
doc["parent"] = doc["_id"]
|
||||
doc["_id"] = doc.pop("_version_id")
|
||||
last_versions_by_subset_id[doc["parent"]] = doc
|
||||
|
||||
version_docs_by_id = {}
|
||||
for version_doc in last_versions_by_subset_id.values():
|
||||
version_docs_by_id[version_doc["_id"]] = version_doc
|
||||
|
||||
repre_docs = io.find({
|
||||
"type": "representation",
|
||||
"parent": {"$in": list(version_docs_by_id.keys())},
|
||||
"name": {"$in": representations}
|
||||
})
|
||||
repre_docs_by_version_id = collections.defaultdict(list)
|
||||
for repre_doc in repre_docs:
|
||||
version_id = repre_doc["parent"]
|
||||
repre_docs_by_version_id[version_id].append(repre_doc)
|
||||
|
||||
output_dict = {}
|
||||
for version_id, repre_docs in repre_docs_by_version_id.items():
|
||||
version_doc = version_docs_by_id[version_id]
|
||||
subset_id = version_doc["parent"]
|
||||
subset_doc = last_versions_by_subset_id[subset_id]
|
||||
# Store queried docs by subset name
|
||||
output_dict[subset_doc["name"]] = {
|
||||
"representations": repre_docs,
|
||||
"version": version_doc
|
||||
}
|
||||
|
||||
return output_dict
|
||||
import os
|
||||
import collections
|
||||
|
||||
import pyblish.api
|
||||
from avalon import io
|
||||
|
||||
from pprint import pformat
|
||||
|
||||
|
||||
class AppendCelactionAudio(pyblish.api.ContextPlugin):
|
||||
|
||||
label = "Colect Audio for publishing"
|
||||
order = pyblish.api.CollectorOrder + 0.1
|
||||
|
||||
def process(self, context):
|
||||
self.log.info('Collecting Audio Data')
|
||||
asset_doc = context.data["assetEntity"]
|
||||
|
||||
# get all available representations
|
||||
subsets = self.get_subsets(
|
||||
asset_doc,
|
||||
representations=["audio", "wav"]
|
||||
)
|
||||
self.log.info(f"subsets is: {pformat(subsets)}")
|
||||
|
||||
if not subsets.get("audioMain"):
|
||||
raise AttributeError("`audioMain` subset does not exist")
|
||||
|
||||
reprs = subsets.get("audioMain", {}).get("representations", [])
|
||||
self.log.info(f"reprs is: {pformat(reprs)}")
|
||||
|
||||
repr = next((r for r in reprs), None)
|
||||
if not repr:
|
||||
raise "Missing `audioMain` representation"
|
||||
self.log.info(f"represetation is: {repr}")
|
||||
|
||||
audio_file = repr.get('data', {}).get('path', "")
|
||||
|
||||
if os.path.exists(audio_file):
|
||||
context.data["audioFile"] = audio_file
|
||||
self.log.info(
|
||||
'audio_file: {}, has been added to context'.format(audio_file))
|
||||
else:
|
||||
self.log.warning("Couldn't find any audio file on Ftrack.")
|
||||
|
||||
def get_subsets(self, asset_doc, representations):
|
||||
"""
|
||||
Query subsets with filter on name.
|
||||
|
||||
The method will return all found subsets and its defined version
|
||||
and subsets. Version could be specified with number. Representation
|
||||
can be filtered.
|
||||
|
||||
Arguments:
|
||||
asset_doct (dict): Asset (shot) mongo document
|
||||
representations (list): list for all representations
|
||||
|
||||
Returns:
|
||||
dict: subsets with version and representaions in keys
|
||||
"""
|
||||
|
||||
# Query all subsets for asset
|
||||
subset_docs = io.find({
|
||||
"type": "subset",
|
||||
"parent": asset_doc["_id"]
|
||||
})
|
||||
# Collect all subset ids
|
||||
subset_ids = [
|
||||
subset_doc["_id"]
|
||||
for subset_doc in subset_docs
|
||||
]
|
||||
|
||||
# Check if we found anything
|
||||
assert subset_ids, (
|
||||
"No subsets found. Check correct filter. "
|
||||
"Try this for start `r'.*'`: asset: `{}`"
|
||||
).format(asset_doc["name"])
|
||||
|
||||
# Last version aggregation
|
||||
pipeline = [
|
||||
# Find all versions of those subsets
|
||||
{"$match": {
|
||||
"type": "version",
|
||||
"parent": {"$in": subset_ids}
|
||||
}},
|
||||
# Sorting versions all together
|
||||
{"$sort": {"name": 1}},
|
||||
# Group them by "parent", but only take the last
|
||||
{"$group": {
|
||||
"_id": "$parent",
|
||||
"_version_id": {"$last": "$_id"},
|
||||
"name": {"$last": "$name"}
|
||||
}}
|
||||
]
|
||||
last_versions_by_subset_id = dict()
|
||||
for doc in io.aggregate(pipeline):
|
||||
doc["parent"] = doc["_id"]
|
||||
doc["_id"] = doc.pop("_version_id")
|
||||
last_versions_by_subset_id[doc["parent"]] = doc
|
||||
|
||||
version_docs_by_id = {}
|
||||
for version_doc in last_versions_by_subset_id.values():
|
||||
version_docs_by_id[version_doc["_id"]] = version_doc
|
||||
|
||||
repre_docs = io.find({
|
||||
"type": "representation",
|
||||
"parent": {"$in": list(version_docs_by_id.keys())},
|
||||
"name": {"$in": representations}
|
||||
})
|
||||
repre_docs_by_version_id = collections.defaultdict(list)
|
||||
for repre_doc in repre_docs:
|
||||
version_id = repre_doc["parent"]
|
||||
repre_docs_by_version_id[version_id].append(repre_doc)
|
||||
|
||||
output_dict = {}
|
||||
for version_id, repre_docs in repre_docs_by_version_id.items():
|
||||
version_doc = version_docs_by_id[version_id]
|
||||
subset_id = version_doc["parent"]
|
||||
subset_doc = last_versions_by_subset_id[subset_id]
|
||||
# Store queried docs by subset name
|
||||
output_dict[subset_doc["name"]] = {
|
||||
"representations": repre_docs,
|
||||
"version": version_doc
|
||||
}
|
||||
|
||||
return output_dict
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
import pyblish.api
|
||||
from pype.hosts import celaction
|
||||
|
||||
|
||||
class CollectCelactionCliKwargs(pyblish.api.Collector):
|
||||
""" Collects all keyword arguments passed from the terminal """
|
||||
|
||||
label = "Collect Celaction Cli Kwargs"
|
||||
order = pyblish.api.Collector.order - 0.1
|
||||
|
||||
def process(self, context):
|
||||
kwargs = celaction.kwargs.copy()
|
||||
|
||||
self.log.info("Storing kwargs: %s" % kwargs)
|
||||
context.set_data("kwargs", kwargs)
|
||||
|
||||
# get kwargs onto context data as keys with values
|
||||
for k, v in kwargs.items():
|
||||
self.log.info(f"Setting `{k}` to instance.data with value: `{v}`")
|
||||
if k in ["frameStart", "frameEnd"]:
|
||||
context.data[k] = kwargs[k] = int(v)
|
||||
else:
|
||||
context.data[k] = v
|
||||
import pyblish.api
|
||||
from pype.hosts.celaction import api as celaction
|
||||
|
||||
|
||||
class CollectCelactionCliKwargs(pyblish.api.Collector):
|
||||
""" Collects all keyword arguments passed from the terminal """
|
||||
|
||||
label = "Collect Celaction Cli Kwargs"
|
||||
order = pyblish.api.Collector.order - 0.1
|
||||
|
||||
def process(self, context):
|
||||
kwargs = celaction.kwargs.copy()
|
||||
|
||||
self.log.info("Storing kwargs: %s" % kwargs)
|
||||
context.set_data("kwargs", kwargs)
|
||||
|
||||
# get kwargs onto context data as keys with values
|
||||
for k, v in kwargs.items():
|
||||
self.log.info(f"Setting `{k}` to instance.data with value: `{v}`")
|
||||
if k in ["frameStart", "frameEnd"]:
|
||||
context.data[k] = kwargs[k] = int(v)
|
||||
else:
|
||||
context.data[k] = v
|
||||
|
|
@ -1,96 +1,96 @@
|
|||
import os
|
||||
from avalon import api
|
||||
import pyblish.api
|
||||
|
||||
|
||||
class CollectCelactionInstances(pyblish.api.ContextPlugin):
|
||||
""" Adds the celaction render instances """
|
||||
|
||||
label = "Collect Celaction Instances"
|
||||
order = pyblish.api.CollectorOrder + 0.1
|
||||
|
||||
def process(self, context):
|
||||
task = api.Session["AVALON_TASK"]
|
||||
current_file = context.data["currentFile"]
|
||||
staging_dir = os.path.dirname(current_file)
|
||||
scene_file = os.path.basename(current_file)
|
||||
version = context.data["version"]
|
||||
asset_entity = context.data["assetEntity"]
|
||||
project_entity = context.data["projectEntity"]
|
||||
|
||||
shared_instance_data = {
|
||||
"asset": asset_entity["name"],
|
||||
"frameStart": asset_entity["data"]["frameStart"],
|
||||
"frameEnd": asset_entity["data"]["frameEnd"],
|
||||
"handleStart": asset_entity["data"]["handleStart"],
|
||||
"handleEnd": asset_entity["data"]["handleEnd"],
|
||||
"fps": asset_entity["data"]["fps"],
|
||||
"resolutionWidth": asset_entity["data"].get(
|
||||
"resolutionWidth",
|
||||
project_entity["data"]["resolutionWidth"]),
|
||||
"resolutionHeight": asset_entity["data"].get(
|
||||
"resolutionHeight",
|
||||
project_entity["data"]["resolutionHeight"]),
|
||||
"pixelAspect": 1,
|
||||
"step": 1,
|
||||
"version": version
|
||||
}
|
||||
|
||||
celaction_kwargs = context.data.get("kwargs", {})
|
||||
|
||||
if celaction_kwargs:
|
||||
shared_instance_data.update(celaction_kwargs)
|
||||
|
||||
# workfile instance
|
||||
family = "workfile"
|
||||
subset = family + task.capitalize()
|
||||
# Create instance
|
||||
instance = context.create_instance(subset)
|
||||
|
||||
# creating instance data
|
||||
instance.data.update({
|
||||
"subset": subset,
|
||||
"label": scene_file,
|
||||
"family": family,
|
||||
"families": [family, "ftrack"],
|
||||
"representations": list()
|
||||
})
|
||||
|
||||
# adding basic script data
|
||||
instance.data.update(shared_instance_data)
|
||||
|
||||
# creating representation
|
||||
representation = {
|
||||
'name': 'scn',
|
||||
'ext': 'scn',
|
||||
'files': scene_file,
|
||||
"stagingDir": staging_dir,
|
||||
}
|
||||
|
||||
instance.data["representations"].append(representation)
|
||||
|
||||
self.log.info('Publishing Celaction workfile')
|
||||
|
||||
# render instance
|
||||
family = "render.farm"
|
||||
subset = f"render{task}Main"
|
||||
instance = context.create_instance(name=subset)
|
||||
# getting instance state
|
||||
instance.data["publish"] = True
|
||||
|
||||
# add assetEntity data into instance
|
||||
instance.data.update({
|
||||
"label": "{} - farm".format(subset),
|
||||
"family": family,
|
||||
"families": [family],
|
||||
"subset": subset
|
||||
})
|
||||
|
||||
# adding basic script data
|
||||
instance.data.update(shared_instance_data)
|
||||
|
||||
self.log.info('Publishing Celaction render instance')
|
||||
self.log.debug(f"Instance data: `{instance.data}`")
|
||||
|
||||
for i in context:
|
||||
self.log.debug(f"{i.data['families']}")
|
||||
import os
|
||||
from avalon import api
|
||||
import pyblish.api
|
||||
|
||||
|
||||
class CollectCelactionInstances(pyblish.api.ContextPlugin):
|
||||
""" Adds the celaction render instances """
|
||||
|
||||
label = "Collect Celaction Instances"
|
||||
order = pyblish.api.CollectorOrder + 0.1
|
||||
|
||||
def process(self, context):
|
||||
task = api.Session["AVALON_TASK"]
|
||||
current_file = context.data["currentFile"]
|
||||
staging_dir = os.path.dirname(current_file)
|
||||
scene_file = os.path.basename(current_file)
|
||||
version = context.data["version"]
|
||||
asset_entity = context.data["assetEntity"]
|
||||
project_entity = context.data["projectEntity"]
|
||||
|
||||
shared_instance_data = {
|
||||
"asset": asset_entity["name"],
|
||||
"frameStart": asset_entity["data"]["frameStart"],
|
||||
"frameEnd": asset_entity["data"]["frameEnd"],
|
||||
"handleStart": asset_entity["data"]["handleStart"],
|
||||
"handleEnd": asset_entity["data"]["handleEnd"],
|
||||
"fps": asset_entity["data"]["fps"],
|
||||
"resolutionWidth": asset_entity["data"].get(
|
||||
"resolutionWidth",
|
||||
project_entity["data"]["resolutionWidth"]),
|
||||
"resolutionHeight": asset_entity["data"].get(
|
||||
"resolutionHeight",
|
||||
project_entity["data"]["resolutionHeight"]),
|
||||
"pixelAspect": 1,
|
||||
"step": 1,
|
||||
"version": version
|
||||
}
|
||||
|
||||
celaction_kwargs = context.data.get("kwargs", {})
|
||||
|
||||
if celaction_kwargs:
|
||||
shared_instance_data.update(celaction_kwargs)
|
||||
|
||||
# workfile instance
|
||||
family = "workfile"
|
||||
subset = family + task.capitalize()
|
||||
# Create instance
|
||||
instance = context.create_instance(subset)
|
||||
|
||||
# creating instance data
|
||||
instance.data.update({
|
||||
"subset": subset,
|
||||
"label": scene_file,
|
||||
"family": family,
|
||||
"families": [family, "ftrack"],
|
||||
"representations": list()
|
||||
})
|
||||
|
||||
# adding basic script data
|
||||
instance.data.update(shared_instance_data)
|
||||
|
||||
# creating representation
|
||||
representation = {
|
||||
'name': 'scn',
|
||||
'ext': 'scn',
|
||||
'files': scene_file,
|
||||
"stagingDir": staging_dir,
|
||||
}
|
||||
|
||||
instance.data["representations"].append(representation)
|
||||
|
||||
self.log.info('Publishing Celaction workfile')
|
||||
|
||||
# render instance
|
||||
family = "render.farm"
|
||||
subset = f"render{task}Main"
|
||||
instance = context.create_instance(name=subset)
|
||||
# getting instance state
|
||||
instance.data["publish"] = True
|
||||
|
||||
# add assetEntity data into instance
|
||||
instance.data.update({
|
||||
"label": "{} - farm".format(subset),
|
||||
"family": family,
|
||||
"families": [family],
|
||||
"subset": subset
|
||||
})
|
||||
|
||||
# adding basic script data
|
||||
instance.data.update(shared_instance_data)
|
||||
|
||||
self.log.info('Publishing Celaction render instance')
|
||||
self.log.debug(f"Instance data: `{instance.data}`")
|
||||
|
||||
for i in context:
|
||||
self.log.debug(f"{i.data['families']}")
|
||||
|
|
@ -1,20 +1,20 @@
|
|||
import shutil
|
||||
import pype
|
||||
import pyblish.api
|
||||
|
||||
|
||||
class VersionUpScene(pyblish.api.ContextPlugin):
|
||||
order = pyblish.api.IntegratorOrder + 0.5
|
||||
label = 'Version Up Scene'
|
||||
families = ['workfile']
|
||||
optional = True
|
||||
active = True
|
||||
|
||||
def process(self, context):
|
||||
current_file = context.data.get('currentFile')
|
||||
v_up = pype.lib.version_up(current_file)
|
||||
self.log.debug('Current file is: {}'.format(current_file))
|
||||
self.log.debug('Version up: {}'.format(v_up))
|
||||
|
||||
shutil.copy2(current_file, v_up)
|
||||
self.log.info('Scene saved into new version: {}'.format(v_up))
|
||||
import shutil
|
||||
import pype
|
||||
import pyblish.api
|
||||
|
||||
|
||||
class VersionUpScene(pyblish.api.ContextPlugin):
|
||||
order = pyblish.api.IntegratorOrder + 0.5
|
||||
label = 'Version Up Scene'
|
||||
families = ['workfile']
|
||||
optional = True
|
||||
active = True
|
||||
|
||||
def process(self, context):
|
||||
current_file = context.data.get('currentFile')
|
||||
v_up = pype.lib.version_up(current_file)
|
||||
self.log.debug('Current file is: {}'.format(current_file))
|
||||
self.log.debug('Version up: {}'.format(v_up))
|
||||
|
||||
shutil.copy2(current_file, v_up)
|
||||
self.log.info('Scene saved into new version: {}'.format(v_up))
|
||||
|
|
@ -9,7 +9,7 @@ import avalon.tools.sceneinventory
|
|||
import pyblish.api
|
||||
|
||||
from pype import lib
|
||||
from pype.api import get_current_project_settings
|
||||
from pype.api import (get_current_project_settings)
|
||||
|
||||
|
||||
def set_scene_settings(settings):
|
||||
|
|
@ -48,20 +48,13 @@ def get_asset_settings():
|
|||
"resolutionWidth": resolution_width,
|
||||
"resolutionHeight": resolution_height
|
||||
}
|
||||
settings = get_current_project_settings()
|
||||
|
||||
try:
|
||||
skip_resolution_check = (
|
||||
get_current_project_settings()
|
||||
["harmony"]
|
||||
["general"]
|
||||
["skip_resolution_check"]
|
||||
)
|
||||
skip_timelines_check = (
|
||||
get_current_project_settings()
|
||||
["harmony"]
|
||||
["general"]
|
||||
["skip_timelines_check"]
|
||||
)
|
||||
skip_resolution_check = \
|
||||
settings["harmony"]["general"]["skip_resolution_check"]
|
||||
skip_timelines_check = \
|
||||
settings["harmony"]["general"]["skip_timelines_check"]
|
||||
except KeyError:
|
||||
skip_resolution_check = []
|
||||
skip_timelines_check = []
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
var LD_OPENHARMONY_PATH = System.getenv('LIB_OPENHARMONY_PATH');
|
||||
include(LD_OPENHARMONY_PATH + '/openHarmony.js');
|
||||
this.__proto__['$'] = $;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -79,7 +79,8 @@ PypeHarmony.getSceneSettings = function() {
|
|||
scene.getStopFrame(),
|
||||
sound.getSoundtrackAll().path(),
|
||||
scene.defaultResolutionX(),
|
||||
scene.defaultResolutionY()
|
||||
scene.defaultResolutionY(),
|
||||
scene.defaultResolutionFOV()
|
||||
];
|
||||
};
|
||||
|
||||
|
|
@ -200,3 +201,16 @@ PypeHarmony.getDependencies = function(_node) {
|
|||
}
|
||||
return dependencies;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* return version of running Harmony instance.
|
||||
* @function
|
||||
* @return {array} [major_version, minor_version]
|
||||
*/
|
||||
PypeHarmony.getVersion = function() {
|
||||
return [
|
||||
about.getMajorVersion(),
|
||||
about.getMinorVersion()
|
||||
];
|
||||
};
|
||||
|
|
|
|||
52
pype/hosts/harmony/js/publish/CollectFarmRender.js
Normal file
52
pype/hosts/harmony/js/publish/CollectFarmRender.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* global PypeHarmony:writable, include */
|
||||
// ***************************************************************************
|
||||
// * CollectFarmRender *
|
||||
// ***************************************************************************
|
||||
|
||||
|
||||
// check if PypeHarmony is defined and if not, load it.
|
||||
if (typeof PypeHarmony !== 'undefined') {
|
||||
var PYPE_HARMONY_JS = System.getenv('PYPE_HARMONY_JS');
|
||||
include(PYPE_HARMONY_JS + '/pype_harmony.js');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @namespace
|
||||
* @classdesc Image Sequence loader JS code.
|
||||
*/
|
||||
var CollectFarmRender = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Get information important for render output.
|
||||
* @function
|
||||
* @param node {String} node name.
|
||||
* @return {array} array of render info.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* var ret = [
|
||||
* file_prefix, // like foo/bar-
|
||||
* type, // PNG4, ...
|
||||
* leading_zeros, // 3 - for 0001
|
||||
* start // start frame
|
||||
* ]
|
||||
*/
|
||||
CollectFarmRender.prototype.getRenderNodeSettings = function(n) {
|
||||
// this will return
|
||||
var output = [
|
||||
node.getTextAttr(
|
||||
n, frame.current(), 'DRAWING_NAME'),
|
||||
node.getTextAttr(
|
||||
n, frame.current(), 'DRAWING_TYPE'),
|
||||
node.getTextAttr(
|
||||
n, frame.current(), 'LEADING_ZEROS'),
|
||||
node.getTextAttr(n, frame.current(), 'START')
|
||||
];
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
// add self to Pype Loaders
|
||||
PypeHarmony.Publish.CollectFarmRender = new CollectFarmRender();
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
import os
|
||||
import logging
|
||||
|
||||
import hou
|
||||
|
||||
from pyblish import api as pyblish
|
||||
|
||||
from avalon import api as avalon
|
||||
from avalon.houdini import pipeline as houdini
|
||||
|
||||
from pype.hosts.houdini import lib
|
||||
|
||||
from pype.lib import any_outdated
|
||||
from pype import PLUGINS_DIR
|
||||
|
||||
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "houdini", "publish")
|
||||
LOAD_PATH = os.path.join(PLUGINS_DIR, "houdini", "load")
|
||||
CREATE_PATH = os.path.join(PLUGINS_DIR, "houdini", "create")
|
||||
|
||||
log = logging.getLogger("pype.hosts.houdini")
|
||||
|
||||
|
||||
def install():
|
||||
|
||||
pyblish.register_plugin_path(PUBLISH_PATH)
|
||||
avalon.register_plugin_path(avalon.Loader, LOAD_PATH)
|
||||
avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
|
||||
|
||||
log.info("Installing callbacks ... ")
|
||||
avalon.on("init", on_init)
|
||||
avalon.before("save", before_save)
|
||||
avalon.on("save", on_save)
|
||||
avalon.on("open", on_open)
|
||||
|
||||
pyblish.register_callback("instanceToggled", on_pyblish_instance_toggled)
|
||||
|
||||
log.info("Setting default family states for loader..")
|
||||
avalon.data["familiesStateToggled"] = ["imagesequence"]
|
||||
|
||||
|
||||
def on_init(*args):
|
||||
houdini.on_houdini_initialize()
|
||||
|
||||
|
||||
def before_save(*args):
|
||||
return lib.validate_fps()
|
||||
|
||||
|
||||
def on_save(*args):
|
||||
|
||||
avalon.logger.info("Running callback on save..")
|
||||
|
||||
nodes = lib.get_id_required_nodes()
|
||||
for node, new_id in lib.generate_ids(nodes):
|
||||
lib.set_id(node, new_id, overwrite=False)
|
||||
|
||||
|
||||
def on_open(*args):
|
||||
|
||||
avalon.logger.info("Running callback on open..")
|
||||
|
||||
if any_outdated():
|
||||
from ..widgets import popup
|
||||
|
||||
log.warning("Scene has outdated content.")
|
||||
|
||||
# Get main window
|
||||
parent = hou.ui.mainQtWindow()
|
||||
if parent is None:
|
||||
log.info("Skipping outdated content pop-up "
|
||||
"because Maya window can't be found.")
|
||||
else:
|
||||
|
||||
# Show outdated pop-up
|
||||
def _on_show_inventory():
|
||||
import avalon.tools.sceneinventory as tool
|
||||
tool.show(parent=parent)
|
||||
|
||||
dialog = popup.Popup(parent=parent)
|
||||
dialog.setWindowTitle("Maya scene has outdated content")
|
||||
dialog.setMessage("There are outdated containers in "
|
||||
"your Maya scene.")
|
||||
dialog.on_show.connect(_on_show_inventory)
|
||||
dialog.show()
|
||||
|
||||
|
||||
def on_pyblish_instance_toggled(instance, new_value, old_value):
|
||||
"""Toggle saver tool passthrough states on instance toggles."""
|
||||
|
||||
nodes = instance[:]
|
||||
if not nodes:
|
||||
return
|
||||
|
||||
# Assume instance node is first node
|
||||
instance_node = nodes[0]
|
||||
|
||||
if instance_node.isBypassed() != (not old_value):
|
||||
print("%s old bypass state didn't match old instance state, "
|
||||
"updating anyway.." % instance_node.path())
|
||||
|
||||
instance_node.bypass(not new_value)
|
||||
103
pype/hosts/houdini/api/__init__.py
Normal file
103
pype/hosts/houdini/api/__init__.py
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import os
|
||||
import logging
|
||||
|
||||
import hou
|
||||
|
||||
from pyblish import api as pyblish
|
||||
|
||||
from avalon import api as avalon
|
||||
from avalon.houdini import pipeline as houdini
|
||||
|
||||
import pype.hosts.houdini
|
||||
from pype.hosts.houdini.api import lib
|
||||
|
||||
from pype.lib import any_outdated
|
||||
|
||||
log = logging.getLogger("pype.hosts.houdini")
|
||||
|
||||
HOST_DIR = os.path.dirname(os.path.abspath(pype.hosts.houdini.__file__))
|
||||
PLUGINS_DIR = os.path.join(HOST_DIR, "plugins")
|
||||
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish")
|
||||
LOAD_PATH = os.path.join(PLUGINS_DIR, "load")
|
||||
CREATE_PATH = os.path.join(PLUGINS_DIR, "create")
|
||||
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
|
||||
|
||||
def install():
|
||||
|
||||
pyblish.register_plugin_path(PUBLISH_PATH)
|
||||
avalon.register_plugin_path(avalon.Loader, LOAD_PATH)
|
||||
avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
|
||||
|
||||
log.info("Installing callbacks ... ")
|
||||
avalon.on("init", on_init)
|
||||
avalon.before("save", before_save)
|
||||
avalon.on("save", on_save)
|
||||
avalon.on("open", on_open)
|
||||
|
||||
pyblish.register_callback("instanceToggled", on_pyblish_instance_toggled)
|
||||
|
||||
log.info("Setting default family states for loader..")
|
||||
avalon.data["familiesStateToggled"] = ["imagesequence"]
|
||||
|
||||
|
||||
def on_init(*args):
|
||||
houdini.on_houdini_initialize()
|
||||
|
||||
|
||||
def before_save(*args):
|
||||
return lib.validate_fps()
|
||||
|
||||
|
||||
def on_save(*args):
|
||||
|
||||
avalon.logger.info("Running callback on save..")
|
||||
|
||||
nodes = lib.get_id_required_nodes()
|
||||
for node, new_id in lib.generate_ids(nodes):
|
||||
lib.set_id(node, new_id, overwrite=False)
|
||||
|
||||
|
||||
def on_open(*args):
|
||||
|
||||
avalon.logger.info("Running callback on open..")
|
||||
|
||||
if any_outdated():
|
||||
from ..widgets import popup
|
||||
|
||||
log.warning("Scene has outdated content.")
|
||||
|
||||
# Get main window
|
||||
parent = hou.ui.mainQtWindow()
|
||||
if parent is None:
|
||||
log.info("Skipping outdated content pop-up "
|
||||
"because Maya window can't be found.")
|
||||
else:
|
||||
|
||||
# Show outdated pop-up
|
||||
def _on_show_inventory():
|
||||
import avalon.tools.sceneinventory as tool
|
||||
tool.show(parent=parent)
|
||||
|
||||
dialog = popup.Popup(parent=parent)
|
||||
dialog.setWindowTitle("Maya scene has outdated content")
|
||||
dialog.setMessage("There are outdated containers in "
|
||||
"your Maya scene.")
|
||||
dialog.on_show.connect(_on_show_inventory)
|
||||
dialog.show()
|
||||
|
||||
|
||||
def on_pyblish_instance_toggled(instance, new_value, old_value):
|
||||
"""Toggle saver tool passthrough states on instance toggles."""
|
||||
|
||||
nodes = instance[:]
|
||||
if not nodes:
|
||||
return
|
||||
|
||||
# Assume instance node is first node
|
||||
instance_node = nodes[0]
|
||||
|
||||
if instance_node.isBypassed() != (not old_value):
|
||||
print("%s old bypass state didn't match old instance state, "
|
||||
"updating anyway.." % instance_node.path())
|
||||
|
||||
instance_node.bypass(not new_value)
|
||||
|
|
@ -2,7 +2,7 @@ import os
|
|||
import re
|
||||
|
||||
import pyblish.api
|
||||
from pype.hosts.houdini import lib
|
||||
from pype.hosts.houdini.api import lib
|
||||
|
||||
|
||||
class CollectFrames(pyblish.api.InstancePlugin):
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import pyblish.api
|
||||
|
||||
from pype.hosts.houdini import lib
|
||||
from pype.hosts.houdini.api import lib
|
||||
|
||||
|
||||
class ValidateAnimationSettings(pyblish.api.InstancePlugin):
|
||||
|
|
@ -1,217 +0,0 @@
|
|||
import os
|
||||
import logging
|
||||
import weakref
|
||||
|
||||
from maya import utils, cmds
|
||||
|
||||
from avalon import api as avalon, pipeline, maya
|
||||
from avalon.maya.pipeline import IS_HEADLESS
|
||||
from avalon.tools import workfiles
|
||||
from pyblish import api as pyblish
|
||||
|
||||
from ...lib import any_outdated
|
||||
from pype import PLUGINS_DIR
|
||||
|
||||
from . import menu
|
||||
from . import lib
|
||||
|
||||
log = logging.getLogger("pype.hosts.maya")
|
||||
|
||||
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "maya", "publish")
|
||||
LOAD_PATH = os.path.join(PLUGINS_DIR, "maya", "load")
|
||||
CREATE_PATH = os.path.join(PLUGINS_DIR, "maya", "create")
|
||||
|
||||
|
||||
def install():
|
||||
pyblish.register_plugin_path(PUBLISH_PATH)
|
||||
avalon.register_plugin_path(avalon.Loader, LOAD_PATH)
|
||||
avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
|
||||
log.info(PUBLISH_PATH)
|
||||
menu.install()
|
||||
|
||||
log.info("Installing callbacks ... ")
|
||||
avalon.on("init", on_init)
|
||||
|
||||
# Callbacks below are not required for headless mode, the `init` however
|
||||
# is important to load referenced Alembics correctly at rendertime.
|
||||
if IS_HEADLESS:
|
||||
log.info("Running in headless mode, skipping Colorbleed Maya "
|
||||
"save/open/new callback installation..")
|
||||
return
|
||||
|
||||
avalon.on("save", on_save)
|
||||
avalon.on("open", on_open)
|
||||
avalon.on("new", on_new)
|
||||
avalon.before("save", on_before_save)
|
||||
|
||||
log.info("Overriding existing event 'taskChanged'")
|
||||
override_event("taskChanged", on_task_changed)
|
||||
|
||||
log.info("Setting default family states for loader..")
|
||||
avalon.data["familiesStateToggled"] = ["imagesequence"]
|
||||
|
||||
|
||||
def uninstall():
|
||||
pyblish.deregister_plugin_path(PUBLISH_PATH)
|
||||
avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH)
|
||||
avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH)
|
||||
|
||||
menu.uninstall()
|
||||
|
||||
|
||||
def override_event(event, callback):
|
||||
"""
|
||||
Override existing event callback
|
||||
Args:
|
||||
event (str): name of the event
|
||||
callback (function): callback to be triggered
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
"""
|
||||
|
||||
ref = weakref.WeakSet()
|
||||
ref.add(callback)
|
||||
|
||||
pipeline._registered_event_handlers[event] = ref
|
||||
|
||||
|
||||
def on_init(_):
|
||||
avalon.logger.info("Running callback on init..")
|
||||
|
||||
def safe_deferred(fn):
|
||||
"""Execute deferred the function in a try-except"""
|
||||
|
||||
def _fn():
|
||||
"""safely call in deferred callback"""
|
||||
try:
|
||||
fn()
|
||||
except Exception as exc:
|
||||
print(exc)
|
||||
|
||||
try:
|
||||
utils.executeDeferred(_fn)
|
||||
except Exception as exc:
|
||||
print(exc)
|
||||
|
||||
# Force load Alembic so referenced alembics
|
||||
# work correctly on scene open
|
||||
cmds.loadPlugin("AbcImport", quiet=True)
|
||||
cmds.loadPlugin("AbcExport", quiet=True)
|
||||
|
||||
# Force load objExport plug-in (requested by artists)
|
||||
cmds.loadPlugin("objExport", quiet=True)
|
||||
|
||||
from .customize import (
|
||||
override_component_mask_commands,
|
||||
override_toolbox_ui
|
||||
)
|
||||
safe_deferred(override_component_mask_commands)
|
||||
|
||||
launch_workfiles = os.environ.get("WORKFILES_STARTUP")
|
||||
|
||||
if launch_workfiles:
|
||||
safe_deferred(launch_workfiles_app)
|
||||
|
||||
if not IS_HEADLESS:
|
||||
safe_deferred(override_toolbox_ui)
|
||||
|
||||
|
||||
def launch_workfiles_app(*args):
|
||||
workfiles.show(os.environ["AVALON_WORKDIR"])
|
||||
|
||||
|
||||
def on_before_save(return_code, _):
|
||||
"""Run validation for scene's FPS prior to saving"""
|
||||
return lib.validate_fps()
|
||||
|
||||
|
||||
def on_save(_):
|
||||
"""Automatically add IDs to new nodes
|
||||
|
||||
Any transform of a mesh, without an existing ID, is given one
|
||||
automatically on file save.
|
||||
"""
|
||||
|
||||
avalon.logger.info("Running callback on save..")
|
||||
|
||||
# # Update current task for the current scene
|
||||
# update_task_from_path(cmds.file(query=True, sceneName=True))
|
||||
|
||||
# Generate ids of the current context on nodes in the scene
|
||||
nodes = lib.get_id_required_nodes(referenced_nodes=False)
|
||||
for node, new_id in lib.generate_ids(nodes):
|
||||
lib.set_id(node, new_id, overwrite=False)
|
||||
|
||||
|
||||
def on_open(_):
|
||||
"""On scene open let's assume the containers have changed."""
|
||||
|
||||
from avalon.vendor.Qt import QtWidgets
|
||||
from ...widgets import popup
|
||||
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya import lib;lib.remove_render_layer_observer()")
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya import lib;lib.add_render_layer_observer()")
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya import lib;lib.add_render_layer_change_observer()")
|
||||
# # Update current task for the current scene
|
||||
# update_task_from_path(cmds.file(query=True, sceneName=True))
|
||||
|
||||
# Validate FPS after update_task_from_path to
|
||||
# ensure it is using correct FPS for the asset
|
||||
lib.validate_fps()
|
||||
lib.fix_incompatible_containers()
|
||||
|
||||
if any_outdated():
|
||||
log.warning("Scene has outdated content.")
|
||||
|
||||
# Find maya main window
|
||||
top_level_widgets = {w.objectName(): w for w in
|
||||
QtWidgets.QApplication.topLevelWidgets()}
|
||||
parent = top_level_widgets.get("MayaWindow", None)
|
||||
|
||||
if parent is None:
|
||||
log.info("Skipping outdated content pop-up "
|
||||
"because Maya window can't be found.")
|
||||
else:
|
||||
|
||||
# Show outdated pop-up
|
||||
def _on_show_inventory():
|
||||
import avalon.tools.sceneinventory as tool
|
||||
tool.show(parent=parent)
|
||||
|
||||
dialog = popup.Popup(parent=parent)
|
||||
dialog.setWindowTitle("Maya scene has outdated content")
|
||||
dialog.setMessage("There are outdated containers in "
|
||||
"your Maya scene.")
|
||||
dialog.on_show.connect(_on_show_inventory)
|
||||
dialog.show()
|
||||
|
||||
|
||||
def on_new(_):
|
||||
"""Set project resolution and fps when create a new file"""
|
||||
avalon.logger.info("Running callback on new..")
|
||||
with maya.suspended_refresh():
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya import lib;lib.remove_render_layer_observer()")
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya import lib;lib.add_render_layer_observer()")
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya import lib;lib.add_render_layer_change_observer()")
|
||||
lib.set_context_settings()
|
||||
|
||||
|
||||
def on_task_changed(*args):
|
||||
"""Wrapped function of app initialize and maya's on task changed"""
|
||||
# Run
|
||||
maya.pipeline._on_task_changed()
|
||||
with maya.suspended_refresh():
|
||||
lib.set_context_settings()
|
||||
lib.update_content_on_context_change()
|
||||
|
||||
lib.show_message("Context was changed",
|
||||
("Context was changed to {}".format(
|
||||
avalon.Session["AVALON_ASSET"])))
|
||||
226
pype/hosts/maya/api/__init__.py
Normal file
226
pype/hosts/maya/api/__init__.py
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
import os
|
||||
import logging
|
||||
import weakref
|
||||
|
||||
from maya import utils, cmds
|
||||
|
||||
from avalon import api as avalon
|
||||
from avalon import pipeline
|
||||
from avalon.maya import suspended_refresh
|
||||
from avalon.maya.pipeline import IS_HEADLESS, _on_task_changed
|
||||
from avalon.tools import workfiles
|
||||
from pyblish import api as pyblish
|
||||
from pype.lib import any_outdated
|
||||
import pype.hosts.maya
|
||||
from . import menu, lib
|
||||
|
||||
log = logging.getLogger("pype.hosts.maya")
|
||||
|
||||
HOST_DIR = os.path.dirname(os.path.abspath(pype.hosts.maya.__file__))
|
||||
PLUGINS_DIR = os.path.join(HOST_DIR, "plugins")
|
||||
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish")
|
||||
LOAD_PATH = os.path.join(PLUGINS_DIR, "load")
|
||||
CREATE_PATH = os.path.join(PLUGINS_DIR, "create")
|
||||
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
|
||||
|
||||
|
||||
def install():
|
||||
pyblish.register_plugin_path(PUBLISH_PATH)
|
||||
avalon.register_plugin_path(avalon.Loader, LOAD_PATH)
|
||||
avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
|
||||
log.info(PUBLISH_PATH)
|
||||
menu.install()
|
||||
|
||||
log.info("Installing callbacks ... ")
|
||||
avalon.on("init", on_init)
|
||||
|
||||
# Callbacks below are not required for headless mode, the `init` however
|
||||
# is important to load referenced Alembics correctly at rendertime.
|
||||
if IS_HEADLESS:
|
||||
log.info("Running in headless mode, skipping Maya "
|
||||
"save/open/new callback installation..")
|
||||
return
|
||||
|
||||
avalon.on("save", on_save)
|
||||
avalon.on("open", on_open)
|
||||
avalon.on("new", on_new)
|
||||
avalon.before("save", on_before_save)
|
||||
|
||||
log.info("Overriding existing event 'taskChanged'")
|
||||
override_event("taskChanged", on_task_changed)
|
||||
|
||||
log.info("Setting default family states for loader..")
|
||||
avalon.data["familiesStateToggled"] = ["imagesequence"]
|
||||
|
||||
|
||||
def uninstall():
|
||||
pyblish.deregister_plugin_path(PUBLISH_PATH)
|
||||
avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH)
|
||||
avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH)
|
||||
|
||||
menu.uninstall()
|
||||
|
||||
|
||||
def override_event(event, callback):
|
||||
"""
|
||||
Override existing event callback
|
||||
Args:
|
||||
event (str): name of the event
|
||||
callback (function): callback to be triggered
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
"""
|
||||
|
||||
ref = weakref.WeakSet()
|
||||
ref.add(callback)
|
||||
|
||||
pipeline._registered_event_handlers[event] = ref
|
||||
|
||||
|
||||
def on_init(_):
|
||||
avalon.logger.info("Running callback on init..")
|
||||
|
||||
def safe_deferred(fn):
|
||||
"""Execute deferred the function in a try-except"""
|
||||
|
||||
def _fn():
|
||||
"""safely call in deferred callback"""
|
||||
try:
|
||||
fn()
|
||||
except Exception as exc:
|
||||
print(exc)
|
||||
|
||||
try:
|
||||
utils.executeDeferred(_fn)
|
||||
except Exception as exc:
|
||||
print(exc)
|
||||
|
||||
# Force load Alembic so referenced alembics
|
||||
# work correctly on scene open
|
||||
cmds.loadPlugin("AbcImport", quiet=True)
|
||||
cmds.loadPlugin("AbcExport", quiet=True)
|
||||
|
||||
# Force load objExport plug-in (requested by artists)
|
||||
cmds.loadPlugin("objExport", quiet=True)
|
||||
|
||||
from .customize import (
|
||||
override_component_mask_commands,
|
||||
override_toolbox_ui
|
||||
)
|
||||
safe_deferred(override_component_mask_commands)
|
||||
|
||||
launch_workfiles = os.environ.get("WORKFILES_STARTUP")
|
||||
|
||||
if launch_workfiles:
|
||||
safe_deferred(launch_workfiles_app)
|
||||
|
||||
if not IS_HEADLESS:
|
||||
safe_deferred(override_toolbox_ui)
|
||||
|
||||
|
||||
def launch_workfiles_app():
|
||||
workfiles.show(os.environ["AVALON_WORKDIR"])
|
||||
|
||||
|
||||
def on_before_save(return_code, _):
|
||||
"""Run validation for scene's FPS prior to saving"""
|
||||
return lib.validate_fps()
|
||||
|
||||
|
||||
def on_save(_):
|
||||
"""Automatically add IDs to new nodes
|
||||
|
||||
Any transform of a mesh, without an existing ID, is given one
|
||||
automatically on file save.
|
||||
"""
|
||||
|
||||
avalon.logger.info("Running callback on save..")
|
||||
|
||||
# # Update current task for the current scene
|
||||
# update_task_from_path(cmds.file(query=True, sceneName=True))
|
||||
|
||||
# Generate ids of the current context on nodes in the scene
|
||||
nodes = lib.get_id_required_nodes(referenced_nodes=False)
|
||||
for node, new_id in lib.generate_ids(nodes):
|
||||
lib.set_id(node, new_id, overwrite=False)
|
||||
|
||||
|
||||
def on_open(_):
|
||||
"""On scene open let's assume the containers have changed."""
|
||||
|
||||
from avalon.vendor.Qt import QtWidgets
|
||||
from ...widgets import popup
|
||||
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya.api import lib;"
|
||||
"lib.remove_render_layer_observer()")
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya.api import lib;"
|
||||
"lib.add_render_layer_observer()")
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya.api import lib;"
|
||||
"lib.add_render_layer_change_observer()")
|
||||
# # Update current task for the current scene
|
||||
# update_task_from_path(cmds.file(query=True, sceneName=True))
|
||||
|
||||
# Validate FPS after update_task_from_path to
|
||||
# ensure it is using correct FPS for the asset
|
||||
lib.validate_fps()
|
||||
lib.fix_incompatible_containers()
|
||||
|
||||
if any_outdated():
|
||||
log.warning("Scene has outdated content.")
|
||||
|
||||
# Find maya main window
|
||||
top_level_widgets = {w.objectName(): w for w in
|
||||
QtWidgets.QApplication.topLevelWidgets()}
|
||||
parent = top_level_widgets.get("MayaWindow", None)
|
||||
|
||||
if parent is None:
|
||||
log.info("Skipping outdated content pop-up "
|
||||
"because Maya window can't be found.")
|
||||
else:
|
||||
|
||||
# Show outdated pop-up
|
||||
def _on_show_inventory():
|
||||
import avalon.tools.sceneinventory as tool
|
||||
tool.show(parent=parent)
|
||||
|
||||
dialog = popup.Popup(parent=parent)
|
||||
dialog.setWindowTitle("Maya scene has outdated content")
|
||||
dialog.setMessage("There are outdated containers in "
|
||||
"your Maya scene.")
|
||||
dialog.on_show.connect(_on_show_inventory)
|
||||
dialog.show()
|
||||
|
||||
|
||||
def on_new(_):
|
||||
"""Set project resolution and fps when create a new file"""
|
||||
avalon.logger.info("Running callback on new..")
|
||||
with suspended_refresh():
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya.api import lib;"
|
||||
"lib.remove_render_layer_observer()")
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya.api import lib;"
|
||||
"lib.add_render_layer_observer()")
|
||||
cmds.evalDeferred(
|
||||
"from pype.hosts.maya.api import lib;"
|
||||
"lib.add_render_layer_change_observer()")
|
||||
lib.set_context_settings()
|
||||
|
||||
|
||||
def on_task_changed(*args):
|
||||
"""Wrapped function of app initialize and maya's on task changed"""
|
||||
# Run
|
||||
_on_task_changed()
|
||||
with suspended_refresh():
|
||||
lib.set_context_settings()
|
||||
lib.update_content_on_context_change()
|
||||
|
||||
lib.show_message(
|
||||
"Context was changed",
|
||||
("Context was changed to {}".format(avalon.Session["AVALON_ASSET"])),
|
||||
)
|
||||
|
|
@ -4,7 +4,7 @@ from __future__ import absolute_import
|
|||
import pyblish.api
|
||||
|
||||
|
||||
from ...action import get_errored_instances_from_context
|
||||
from pype.api import get_errored_instances_from_context
|
||||
|
||||
|
||||
class GenerateUUIDsOnInvalidAction(pyblish.api.Action):
|
||||
|
|
@ -29,8 +29,8 @@ Attributes:
|
|||
token in image prefixes.
|
||||
RENDERER_NAMES (dict): Renderer names mapping between reported name and
|
||||
*human readable* name.
|
||||
ImagePrefixes (dict): Mapping between renderers and their respective
|
||||
image prefix atrribute names.
|
||||
IMAGE_PREFIXES (dict): Mapping between renderers and their respective
|
||||
image prefix attribute names.
|
||||
|
||||
Todo:
|
||||
Determine `multipart` from render instance.
|
||||
|
|
@ -44,7 +44,7 @@ from abc import ABCMeta, abstractmethod
|
|||
|
||||
import six
|
||||
|
||||
import pype.hosts.maya.lib as lib
|
||||
import pype.hosts.maya.api.lib as lib
|
||||
|
||||
from maya import cmds
|
||||
import maya.app.renderSetup.model.renderSetup as renderSetup
|
||||
|
|
@ -78,7 +78,7 @@ RENDERER_NAMES = {
|
|||
}
|
||||
|
||||
# not sure about the renderman image prefix
|
||||
ImagePrefixes = {
|
||||
IMAGE_PREFIXES = {
|
||||
"mentalray": "defaultRenderGlobals.imageFilePrefix",
|
||||
"vray": "vraySettings.fileNamePrefix",
|
||||
"arnold": "defaultRenderGlobals.imageFilePrefix",
|
||||
|
|
@ -123,22 +123,22 @@ class ExpectedFiles:
|
|||
if renderer.lower() == "arnold":
|
||||
return self._get_files(ExpectedFilesArnold(layer,
|
||||
self._render_instance))
|
||||
elif renderer.lower() == "vray":
|
||||
if renderer.lower() == "vray":
|
||||
return self._get_files(ExpectedFilesVray(
|
||||
layer, self._render_instance))
|
||||
elif renderer.lower() == "redshift":
|
||||
if renderer.lower() == "redshift":
|
||||
return self._get_files(ExpectedFilesRedshift(
|
||||
layer, self._render_instance))
|
||||
elif renderer.lower() == "mentalray":
|
||||
if renderer.lower() == "mentalray":
|
||||
return self._get_files(ExpectedFilesMentalray(
|
||||
layer, self._render_instance))
|
||||
elif renderer.lower() == "renderman":
|
||||
if renderer.lower() == "renderman":
|
||||
return self._get_files(ExpectedFilesRenderman(
|
||||
layer, self._render_instance))
|
||||
else:
|
||||
raise UnsupportedRendererException(
|
||||
"unsupported {}".format(renderer)
|
||||
)
|
||||
|
||||
raise UnsupportedRendererException(
|
||||
"unsupported {}".format(renderer)
|
||||
)
|
||||
|
||||
def _get_files(self, renderer):
|
||||
files = renderer.get_files()
|
||||
|
|
@ -169,9 +169,9 @@ class AExpectedFiles:
|
|||
@abstractmethod
|
||||
def get_aovs(self):
|
||||
"""To be implemented by renderer class."""
|
||||
pass
|
||||
|
||||
def sanitize_camera_name(self, camera):
|
||||
@staticmethod
|
||||
def sanitize_camera_name(camera):
|
||||
"""Sanitize camera name.
|
||||
|
||||
Remove Maya illegal characters from camera name.
|
||||
|
|
@ -187,8 +187,7 @@ class AExpectedFiles:
|
|||
test_camera_01
|
||||
|
||||
"""
|
||||
sanitized = re.sub('[^0-9a-zA-Z_]+', '_', camera)
|
||||
return sanitized
|
||||
return re.sub('[^0-9a-zA-Z_]+', '_', camera)
|
||||
|
||||
def get_renderer_prefix(self):
|
||||
"""Return prefix for specific renderer.
|
||||
|
|
@ -201,12 +200,12 @@ class AExpectedFiles:
|
|||
Raises:
|
||||
:exc:`UnsupportedRendererException`: If we requested image
|
||||
prefix for renderer we know nothing about.
|
||||
See :data:`ImagePrefixes` for mapping of renderers and
|
||||
See :data:`IMAGE_PREFIXES` for mapping of renderers and
|
||||
image prefixes.
|
||||
|
||||
"""
|
||||
try:
|
||||
file_prefix = cmds.getAttr(ImagePrefixes[self.renderer])
|
||||
file_prefix = cmds.getAttr(IMAGE_PREFIXES[self.renderer])
|
||||
except KeyError:
|
||||
raise UnsupportedRendererException(
|
||||
"Unsupported renderer {}".format(self.renderer)
|
||||
|
|
@ -218,62 +217,32 @@ class AExpectedFiles:
|
|||
# ____________________/ ____________________________________________/
|
||||
# 1 - get scene name /__________________/
|
||||
# ____________________/
|
||||
scene_dir, scene_basename = os.path.split(cmds.file(q=True, loc=True))
|
||||
_, scene_basename = os.path.split(cmds.file(q=True, loc=True))
|
||||
scene_name, _ = os.path.splitext(scene_basename)
|
||||
|
||||
# ______________________________________________
|
||||
# ____________________/ ____________________________________________/
|
||||
# 2 - detect renderer /__________________/
|
||||
# ____________________/
|
||||
renderer = self.renderer
|
||||
|
||||
# ________________________________________________
|
||||
# __________________/ ______________________________________________/
|
||||
# 3 - image prefix /__________________/
|
||||
# __________________/
|
||||
file_prefix = self.get_renderer_prefix()
|
||||
|
||||
if not file_prefix:
|
||||
raise RuntimeError("Image prefix not set")
|
||||
|
||||
default_ext = cmds.getAttr("defaultRenderGlobals.imfPluginKey")
|
||||
|
||||
# ________________________________________________
|
||||
# __________________/ ______________________________________________/
|
||||
# 4 - get renderable cameras_____________/
|
||||
# __________________/
|
||||
|
||||
# if we have <camera> token in prefix path we'll expect output for
|
||||
# every renderable camera in layer.
|
||||
|
||||
renderable_cameras = self.get_renderable_cameras()
|
||||
# ________________________________________________
|
||||
# __________________/ ______________________________________________/
|
||||
# 5 - get AOVs /____________________/
|
||||
# __________________/
|
||||
|
||||
enabled_aovs = self.get_aovs()
|
||||
|
||||
layer_name = self.layer
|
||||
if self.layer.startswith("rs_"):
|
||||
layer_name = self.layer[3:]
|
||||
start_frame = int(self.get_render_attribute("startFrame"))
|
||||
end_frame = int(self.get_render_attribute("endFrame"))
|
||||
frame_step = int(self.get_render_attribute("byFrameStep"))
|
||||
padding = int(self.get_render_attribute("extensionPadding"))
|
||||
|
||||
scene_data = {
|
||||
"frameStart": start_frame,
|
||||
"frameEnd": end_frame,
|
||||
"frameStep": frame_step,
|
||||
"padding": padding,
|
||||
"cameras": renderable_cameras,
|
||||
"frameStart": int(self.get_render_attribute("startFrame")),
|
||||
"frameEnd": int(self.get_render_attribute("endFrame")),
|
||||
"frameStep": int(self.get_render_attribute("byFrameStep")),
|
||||
"padding": int(self.get_render_attribute("extensionPadding")),
|
||||
# if we have <camera> token in prefix path we'll expect output for
|
||||
# every renderable camera in layer.
|
||||
"cameras": self.get_renderable_cameras(),
|
||||
"sceneName": scene_name,
|
||||
"layerName": layer_name,
|
||||
"renderer": renderer,
|
||||
"defaultExt": default_ext,
|
||||
"renderer": self.renderer,
|
||||
"defaultExt": cmds.getAttr("defaultRenderGlobals.imfPluginKey"),
|
||||
"filePrefix": file_prefix,
|
||||
"enabledAOVs": enabled_aovs,
|
||||
"enabledAOVs": self.get_aovs(),
|
||||
}
|
||||
return scene_data
|
||||
|
||||
|
|
@ -296,9 +265,9 @@ class AExpectedFiles:
|
|||
file_prefix = re.sub(regex, value, file_prefix)
|
||||
|
||||
for frame in range(
|
||||
int(layer_data["frameStart"]),
|
||||
int(layer_data["frameEnd"]) + 1,
|
||||
int(layer_data["frameStep"]),
|
||||
int(layer_data["frameStart"]),
|
||||
int(layer_data["frameEnd"]) + 1,
|
||||
int(layer_data["frameStep"]),
|
||||
):
|
||||
expected_files.append(
|
||||
"{}.{}.{}".format(
|
||||
|
|
@ -331,9 +300,9 @@ class AExpectedFiles:
|
|||
|
||||
aov_files = []
|
||||
for frame in range(
|
||||
int(layer_data["frameStart"]),
|
||||
int(layer_data["frameEnd"]) + 1,
|
||||
int(layer_data["frameStep"]),
|
||||
int(layer_data["frameStart"]),
|
||||
int(layer_data["frameEnd"]) + 1,
|
||||
int(layer_data["frameStep"]),
|
||||
):
|
||||
aov_files.append(
|
||||
"{}.{}.{}".format(
|
||||
|
|
@ -388,14 +357,13 @@ class AExpectedFiles:
|
|||
|
||||
renderable_cameras = []
|
||||
for cam in cam_parents:
|
||||
renderable = False
|
||||
if self.maya_is_true(cmds.getAttr("{}.renderable".format(cam))):
|
||||
renderable = True
|
||||
renderable_cameras.append(cam)
|
||||
|
||||
return renderable_cameras
|
||||
|
||||
def maya_is_true(self, attr_val):
|
||||
@staticmethod
|
||||
def maya_is_true(attr_val):
|
||||
"""Whether a Maya attr evaluates to True.
|
||||
|
||||
When querying an attribute value from an ambiguous object the
|
||||
|
|
@ -411,12 +379,13 @@ class AExpectedFiles:
|
|||
"""
|
||||
if isinstance(attr_val, types.BooleanType):
|
||||
return attr_val
|
||||
elif isinstance(attr_val, (types.ListType, types.GeneratorType)):
|
||||
if isinstance(attr_val, (types.ListType, types.GeneratorType)):
|
||||
return any(attr_val)
|
||||
else:
|
||||
return bool(attr_val)
|
||||
|
||||
def get_layer_overrides(self, attr, layer):
|
||||
return bool(attr_val)
|
||||
|
||||
@staticmethod
|
||||
def get_layer_overrides(attr):
|
||||
"""Get overrides for attribute on given render layer.
|
||||
|
||||
Args:
|
||||
|
|
@ -491,8 +460,8 @@ class ExpectedFilesArnold(AExpectedFiles):
|
|||
enabled_aovs = []
|
||||
try:
|
||||
if not (
|
||||
cmds.getAttr("defaultArnoldRenderOptions.aovMode")
|
||||
and not cmds.getAttr("defaultArnoldDriver.mergeAOVs") # noqa: W503, E501
|
||||
cmds.getAttr("defaultArnoldRenderOptions.aovMode")
|
||||
and not cmds.getAttr("defaultArnoldDriver.mergeAOVs") # noqa: W503, E501
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
|
|
@ -508,7 +477,14 @@ class ExpectedFilesArnold(AExpectedFiles):
|
|||
# AOVs are set to be rendered separately. We should expect
|
||||
# <RenderPass> token in path.
|
||||
|
||||
ai_aovs = [n for n in cmds.ls(type="aiAOV")]
|
||||
# handle aovs from references
|
||||
use_ref_aovs = self.render_instance.data.get(
|
||||
"useReferencedAovs", False) or False
|
||||
|
||||
ai_aovs = cmds.ls(type="aiAOV")
|
||||
if not use_ref_aovs:
|
||||
ref_aovs = cmds.ls(type="aiAOV", referencedNodes=True)
|
||||
ai_aovs = list(set(ai_aovs) - set(ref_aovs))
|
||||
|
||||
for aov in ai_aovs:
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov)))
|
||||
|
|
@ -523,7 +499,7 @@ class ExpectedFilesArnold(AExpectedFiles):
|
|||
raise AOVError(msg)
|
||||
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enabled".format(aov), self.layer
|
||||
"{}.enabled".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
if enabled:
|
||||
|
|
@ -567,7 +543,7 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
"""Override to get vray specific extension."""
|
||||
layer_data = super(ExpectedFilesVray, self)._get_layer_data()
|
||||
default_ext = cmds.getAttr("vraySettings.imageFormatStr")
|
||||
if default_ext == "exr (multichannel)" or default_ext == "exr (deep)":
|
||||
if default_ext in ["exr (multichannel)", "exr (deep)"]:
|
||||
default_ext = "exr"
|
||||
layer_data["defaultExt"] = default_ext
|
||||
layer_data["padding"] = cmds.getAttr("vraySettings.fileNamePadding")
|
||||
|
|
@ -587,11 +563,11 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
# remove 'beauty' from filenames as vray doesn't output it
|
||||
update = {}
|
||||
if layer_data.get("enabledAOVs"):
|
||||
for aov, seq in expected_files[0].items():
|
||||
for aov, seqs in expected_files[0].items():
|
||||
if aov.startswith("beauty"):
|
||||
new_list = []
|
||||
for f in seq:
|
||||
new_list.append(f.replace("_beauty", ""))
|
||||
for seq in seqs:
|
||||
new_list.append(seq.replace("_beauty", ""))
|
||||
update[aov] = new_list
|
||||
|
||||
expected_files[0].update(update)
|
||||
|
|
@ -609,8 +585,8 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
try:
|
||||
# really? do we set it in vray just by selecting multichannel exr?
|
||||
if (
|
||||
cmds.getAttr("vraySettings.imageFormatStr")
|
||||
== "exr (multichannel)" # noqa: W503
|
||||
cmds.getAttr("vraySettings.imageFormatStr")
|
||||
== "exr (multichannel)" # noqa: W503
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
|
|
@ -624,7 +600,7 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
return enabled_aovs
|
||||
|
||||
default_ext = cmds.getAttr("vraySettings.imageFormatStr")
|
||||
if default_ext == "exr (multichannel)" or default_ext == "exr (deep)":
|
||||
if default_ext in ["exr (multichannel)", "exr (deep)"]:
|
||||
default_ext = "exr"
|
||||
|
||||
# add beauty as default
|
||||
|
|
@ -634,7 +610,7 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
|
||||
# handle aovs from references
|
||||
use_ref_aovs = self.render_instance.data.get(
|
||||
"vrayUseReferencedAovs", False) or False
|
||||
"useReferencedAovs", False) or False
|
||||
|
||||
# this will have list of all aovs no matter if they are coming from
|
||||
# reference or not.
|
||||
|
|
@ -650,18 +626,18 @@ class ExpectedFilesVray(AExpectedFiles):
|
|||
for aov in vr_aovs:
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov)))
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enabled".format(aov), "rs_{}".format(self.layer)
|
||||
"{}.enabled".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
|
||||
if enabled:
|
||||
# todo: find how vray set format for AOVs
|
||||
enabled_aovs.append(
|
||||
(self._get_vray_aov_name(aov), default_ext))
|
||||
|
||||
return enabled_aovs
|
||||
|
||||
def _get_vray_aov_name(self, node):
|
||||
@staticmethod
|
||||
def _get_vray_aov_name(node):
|
||||
"""Get AOVs name from Vray.
|
||||
|
||||
Args:
|
||||
|
|
@ -762,8 +738,8 @@ class ExpectedFilesRedshift(AExpectedFiles):
|
|||
if aov[0].lower() == "cryptomatte":
|
||||
aov_name = aov[0]
|
||||
expected_files.append(
|
||||
{aov_name: self._generate_single_file_sequence(
|
||||
layer_data, aov_name=aov_name)})
|
||||
{aov_name: self._generate_single_file_sequence(layer_data)}
|
||||
)
|
||||
|
||||
return expected_files
|
||||
|
||||
|
|
@ -778,7 +754,7 @@ class ExpectedFilesRedshift(AExpectedFiles):
|
|||
|
||||
try:
|
||||
if self.maya_is_true(
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
|
|
@ -794,13 +770,13 @@ class ExpectedFilesRedshift(AExpectedFiles):
|
|||
default_ext = self.ext_mapping[
|
||||
cmds.getAttr("redshiftOptions.imageFormat")
|
||||
]
|
||||
rs_aovs = [n for n in cmds.ls(type="RedshiftAOV")]
|
||||
rs_aovs = cmds.ls(type="RedshiftAOV", referencedNodes=False)
|
||||
|
||||
# todo: find out how to detect multichannel exr for redshift
|
||||
for aov in rs_aovs:
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enabled".format(aov)))
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enabled".format(aov), self.layer
|
||||
"{}.enabled".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
|
||||
|
|
@ -809,7 +785,7 @@ class ExpectedFilesRedshift(AExpectedFiles):
|
|||
# is in the list of AOVs that renderer cannot (or will not)
|
||||
# merge into final exr.
|
||||
if self.maya_is_true(
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
):
|
||||
if cmds.getAttr("%s.name" % aov) in self.unmerged_aovs:
|
||||
enabled_aovs.append(
|
||||
|
|
@ -821,7 +797,7 @@ class ExpectedFilesRedshift(AExpectedFiles):
|
|||
)
|
||||
|
||||
if self.maya_is_true(
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
cmds.getAttr("redshiftOptions.exrForceMultilayer")
|
||||
):
|
||||
# AOVs are merged in mutli-channel file
|
||||
self.multipart = True
|
||||
|
|
@ -859,7 +835,7 @@ class ExpectedFilesRenderman(AExpectedFiles):
|
|||
|
||||
enabled = self.maya_is_true(cmds.getAttr("{}.enable".format(aov)))
|
||||
for override in self.get_layer_overrides(
|
||||
"{}.enable".format(aov), self.layer
|
||||
"{}.enable".format(aov)
|
||||
):
|
||||
enabled = self.maya_is_true(override)
|
||||
|
||||
|
|
@ -908,6 +884,7 @@ class ExpectedFilesMentalray(AExpectedFiles):
|
|||
:exc:`UnimplementedRendererException`: as it is not implemented.
|
||||
|
||||
"""
|
||||
super(ExpectedFilesMentalray, self).__init__(layer, render_instance)
|
||||
raise UnimplementedRendererException("Mentalray not implemented")
|
||||
|
||||
def get_aovs(self):
|
||||
|
|
@ -923,8 +900,6 @@ class ExpectedFilesMentalray(AExpectedFiles):
|
|||
class AOVError(Exception):
|
||||
"""Custom exception for determining AOVs."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class UnsupportedRendererException(Exception):
|
||||
"""Custom exception.
|
||||
|
|
@ -932,13 +907,9 @@ class UnsupportedRendererException(Exception):
|
|||
Raised when requesting data from unsupported renderer.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class UnimplementedRendererException(Exception):
|
||||
"""Custom exception.
|
||||
|
||||
Raised when requesting data from renderer that is not implemented yet.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
|
@ -114,9 +114,7 @@ def matrix_equals(a, b, tolerance=1e-10):
|
|||
bool : True or False
|
||||
|
||||
"""
|
||||
if not all(abs(x - y) < tolerance for x, y in zip(a, b)):
|
||||
return False
|
||||
return True
|
||||
return all(abs(x - y) < tolerance for x, y in zip(a, b))
|
||||
|
||||
|
||||
def float_round(num, places=0, direction=ceil):
|
||||
|
|
@ -1084,7 +1082,7 @@ def get_id_required_nodes(referenced_nodes=False, nodes=None):
|
|||
|
||||
# Check if plugin nodes are available for Maya by checking if the plugin
|
||||
# is loaded
|
||||
if cmds.pluginInfo("pgYetiMaya", query=True, loaded=True):
|
||||
if cmds.pluginInfo("pgYetiMaya", query=True, loaded=True):
|
||||
types.append("pgYetiMaya")
|
||||
|
||||
# We *always* ignore intermediate shapes, so we filter them out directly
|
||||
|
|
@ -4,7 +4,7 @@ import logging
|
|||
|
||||
from avalon.vendor.Qt import QtWidgets, QtGui
|
||||
from avalon.maya import pipeline
|
||||
from ...lib import BuildWorkfile
|
||||
from pype.api import BuildWorkfile
|
||||
import maya.cmds as cmds
|
||||
|
||||
self = sys.modules[__name__]
|
||||
|
|
@ -9,7 +9,7 @@ from maya import cmds
|
|||
|
||||
from avalon import api, io
|
||||
from avalon.maya.lib import unique_namespace
|
||||
from pype.hosts.maya.lib import matrix_equals
|
||||
from pype.hosts.maya.api.lib import matrix_equals
|
||||
|
||||
log = logging.getLogger("PackageLoader")
|
||||
|
||||
0
pype/hosts/maya/plugins/__init__.py
Normal file
0
pype/hosts/maya/plugins/__init__.py
Normal file
|
|
@ -1,5 +1,5 @@
|
|||
import avalon.maya
|
||||
from pype.hosts.maya import lib
|
||||
from pype.hosts.maya.api import lib
|
||||
|
||||
|
||||
class CreateAnimation(avalon.maya.Creator):
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
from collections import OrderedDict
|
||||
|
||||
import avalon.maya
|
||||
from pype.hosts.maya import lib
|
||||
from pype.hosts.maya.api import lib
|
||||
|
||||
from maya import cmds
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import avalon.maya
|
||||
from pype.hosts.maya import lib
|
||||
from pype.hosts.maya.api import lib
|
||||
|
||||
|
||||
class CreateCamera(avalon.maya.Creator):
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import avalon.maya
|
||||
from pype.hosts.maya import lib
|
||||
from pype.hosts.maya.api import lib
|
||||
|
||||
|
||||
class CreateLook(avalon.maya.Creator):
|
||||
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