mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
implement #1013 for pype 3.0
This commit is contained in:
parent
403c9fc96c
commit
1eecea34b5
11 changed files with 972 additions and 84 deletions
|
|
@ -43,17 +43,17 @@ SHAPE_ATTRS = {"castsShadows",
|
|||
"opposite"}
|
||||
|
||||
RENDER_ATTRS = {"vray": {
|
||||
"node": "vraySettings",
|
||||
"prefix": "fileNamePrefix",
|
||||
"padding": "fileNamePadding",
|
||||
"ext": "imageFormatStr"
|
||||
},
|
||||
"default": {
|
||||
"node": "defaultRenderGlobals",
|
||||
"prefix": "imageFilePrefix",
|
||||
"padding": "extensionPadding"
|
||||
}
|
||||
}
|
||||
"node": "vraySettings",
|
||||
"prefix": "fileNamePrefix",
|
||||
"padding": "fileNamePadding",
|
||||
"ext": "imageFormatStr"
|
||||
},
|
||||
"default": {
|
||||
"node": "defaultRenderGlobals",
|
||||
"prefix": "imageFilePrefix",
|
||||
"padding": "extensionPadding"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DEFAULT_MATRIX = [1.0, 0.0, 0.0, 0.0,
|
||||
|
|
@ -95,6 +95,8 @@ _alembic_options = {
|
|||
INT_FPS = {15, 24, 25, 30, 48, 50, 60, 44100, 48000}
|
||||
FLOAT_FPS = {23.98, 23.976, 29.97, 47.952, 59.94}
|
||||
|
||||
RENDERLIKE_INSTANCE_FAMILIES = ["rendering", "vrayscene"]
|
||||
|
||||
|
||||
def _get_mel_global(name):
|
||||
"""Return the value of a mel global variable"""
|
||||
|
|
@ -114,7 +116,9 @@ def matrix_equals(a, b, tolerance=1e-10):
|
|||
bool : True or False
|
||||
|
||||
"""
|
||||
return all(abs(x - y) < tolerance for x, y in zip(a, b))
|
||||
if not all(abs(x - y) < tolerance for x, y in zip(a, b)):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def float_round(num, places=0, direction=ceil):
|
||||
|
|
@ -2466,12 +2470,21 @@ class shelf():
|
|||
cmds.shelfLayout(self.name, p="ShelfLayout")
|
||||
|
||||
|
||||
def _get_render_instance():
|
||||
def _get_render_instances():
|
||||
"""Return all 'render-like' instances.
|
||||
|
||||
This returns list of instance sets that needs to receive informations
|
||||
about render layer changes.
|
||||
|
||||
Returns:
|
||||
list: list of instances
|
||||
|
||||
"""
|
||||
objectset = cmds.ls("*.id", long=True, type="objectSet",
|
||||
recursive=True, objectsOnly=True)
|
||||
|
||||
instances = []
|
||||
for objset in objectset:
|
||||
|
||||
if not cmds.attributeQuery("id", node=objset, exists=True):
|
||||
continue
|
||||
|
||||
|
|
@ -2485,16 +2498,18 @@ def _get_render_instance():
|
|||
if not has_family:
|
||||
continue
|
||||
|
||||
if cmds.getAttr("{}.family".format(objset)) == 'rendering':
|
||||
return objset
|
||||
if cmds.getAttr(
|
||||
"{}.family".format(objset)) in RENDERLIKE_INSTANCE_FAMILIES:
|
||||
instances.append(objset)
|
||||
|
||||
return None
|
||||
return instances
|
||||
|
||||
|
||||
renderItemObserverList = []
|
||||
|
||||
|
||||
class RenderSetupListObserver:
|
||||
"""Observer to catch changes in render setup layers."""
|
||||
|
||||
def listItemAdded(self, item):
|
||||
print("--- adding ...")
|
||||
|
|
@ -2505,56 +2520,95 @@ class RenderSetupListObserver:
|
|||
self._remove_render_layer(item.name())
|
||||
|
||||
def _add_render_layer(self, item):
|
||||
render_set = _get_render_instance()
|
||||
render_sets = _get_render_instances()
|
||||
layer_name = item.name()
|
||||
|
||||
if not render_set:
|
||||
return
|
||||
for render_set in render_sets:
|
||||
members = cmds.sets(render_set, query=True) or []
|
||||
|
||||
members = cmds.sets(render_set, query=True) or []
|
||||
if not "LAYER_{}".format(layer_name) in members:
|
||||
namespace_name = "_{}".format(render_set)
|
||||
if not cmds.namespace(exists=namespace_name):
|
||||
index = 1
|
||||
namespace_name = "_{}".format(render_set)
|
||||
try:
|
||||
cmds.namespace(rm=namespace_name)
|
||||
except RuntimeError:
|
||||
# namespace is not empty, so we leave it untouched
|
||||
pass
|
||||
orignal_namespace_name = namespace_name
|
||||
while(cmds.namespace(exists=namespace_name)):
|
||||
namespace_name = "{}{}".format(
|
||||
orignal_namespace_name, index)
|
||||
index += 1
|
||||
|
||||
namespace = cmds.namespace(add=namespace_name)
|
||||
|
||||
if members:
|
||||
# if set already have namespaced members, use the same
|
||||
# namespace as others.
|
||||
namespace = members[0].rpartition(":")[0]
|
||||
else:
|
||||
namespace = namespace_name
|
||||
|
||||
render_layer_set_name = "{}:{}".format(namespace, layer_name)
|
||||
if render_layer_set_name in members:
|
||||
continue
|
||||
print(" - creating set for {}".format(layer_name))
|
||||
set = cmds.sets(n="LAYER_{}".format(layer_name), empty=True)
|
||||
cmds.sets(set, forceElement=render_set)
|
||||
maya_set = cmds.sets(n=render_layer_set_name, empty=True)
|
||||
cmds.sets(maya_set, forceElement=render_set)
|
||||
rio = RenderSetupItemObserver(item)
|
||||
print("- adding observer for {}".format(item.name()))
|
||||
item.addItemObserver(rio.itemChanged)
|
||||
renderItemObserverList.append(rio)
|
||||
|
||||
def _remove_render_layer(self, layer_name):
|
||||
render_set = _get_render_instance()
|
||||
render_sets = _get_render_instances()
|
||||
|
||||
if not render_set:
|
||||
return
|
||||
for render_set in render_sets:
|
||||
members = cmds.sets(render_set, query=True)
|
||||
if not members:
|
||||
continue
|
||||
|
||||
members = cmds.sets(render_set, query=True)
|
||||
if "LAYER_{}".format(layer_name) in members:
|
||||
print(" - removing set for {}".format(layer_name))
|
||||
cmds.delete("LAYER_{}".format(layer_name))
|
||||
# all sets under set should have the same namespace
|
||||
namespace = members[0].rpartition(":")[0]
|
||||
render_layer_set_name = "{}:{}".format(namespace, layer_name)
|
||||
|
||||
if render_layer_set_name in members:
|
||||
print(" - removing set for {}".format(layer_name))
|
||||
cmds.delete(render_layer_set_name)
|
||||
|
||||
|
||||
class RenderSetupItemObserver():
|
||||
"""Handle changes in render setup items."""
|
||||
|
||||
def __init__(self, item):
|
||||
self.item = item
|
||||
self.original_name = item.name()
|
||||
|
||||
def itemChanged(self, *args, **kwargs):
|
||||
"""Item changed callback."""
|
||||
if self.item.name() == self.original_name:
|
||||
return
|
||||
|
||||
render_set = _get_render_instance()
|
||||
render_sets = _get_render_instances()
|
||||
|
||||
if not render_set:
|
||||
return
|
||||
for render_set in render_sets:
|
||||
members = cmds.sets(render_set, query=True)
|
||||
if not members:
|
||||
continue
|
||||
|
||||
members = cmds.sets(render_set, query=True)
|
||||
if "LAYER_{}".format(self.original_name) in members:
|
||||
print(" <> renaming {} to {}".format(self.original_name,
|
||||
self.item.name()))
|
||||
cmds.rename("LAYER_{}".format(self.original_name),
|
||||
"LAYER_{}".format(self.item.name()))
|
||||
self.original_name = self.item.name()
|
||||
# all sets under set should have the same namespace
|
||||
namespace = members[0].rpartition(":")[0]
|
||||
render_layer_set_name = "{}:{}".format(
|
||||
namespace, self.original_name)
|
||||
|
||||
if render_layer_set_name in members:
|
||||
print(" <> renaming {} to {}".format(self.original_name,
|
||||
self.item.name()))
|
||||
cmds.rename(render_layer_set_name,
|
||||
"{}:{}".format(
|
||||
namespace, self.item.name()))
|
||||
self.original_name = self.item.name()
|
||||
|
||||
|
||||
renderListObserver = RenderSetupListObserver()
|
||||
|
|
@ -2564,14 +2618,19 @@ def add_render_layer_change_observer():
|
|||
import maya.app.renderSetup.model.renderSetup as renderSetup
|
||||
|
||||
rs = renderSetup.instance()
|
||||
render_set = _get_render_instance()
|
||||
if not render_set:
|
||||
return
|
||||
render_sets = _get_render_instances()
|
||||
|
||||
members = cmds.sets(render_set, query=True)
|
||||
layers = rs.getRenderLayers()
|
||||
for layer in layers:
|
||||
if "LAYER_{}".format(layer.name()) in members:
|
||||
for render_set in render_sets:
|
||||
members = cmds.sets(render_set, query=True)
|
||||
if not members:
|
||||
continue
|
||||
# all sets under set should have the same namespace
|
||||
namespace = members[0].rpartition(":")[0]
|
||||
for layer in layers:
|
||||
render_layer_set_name = "{}:{}".format(namespace, layer.name())
|
||||
if render_layer_set_name not in members:
|
||||
continue
|
||||
rio = RenderSetupItemObserver(layer)
|
||||
print("- adding observer for {}".format(layer.name()))
|
||||
layer.addItemObserver(rio.itemChanged)
|
||||
|
|
|
|||
128
pype/hosts/maya/api/render_setup_tools.py
Normal file
128
pype/hosts/maya/api/render_setup_tools.py
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Export stuff in render setup layer context.
|
||||
|
||||
Export Maya nodes from Render Setup layer as if flattened in that layer instead
|
||||
of exporting the defaultRenderLayer as Maya forces by default
|
||||
|
||||
Credits: Roy Nieterau (BigRoy) / Colorbleed
|
||||
Modified for use in Pype
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import contextlib
|
||||
|
||||
from maya import cmds
|
||||
from maya.app.renderSetup.model import renderSetup
|
||||
|
||||
# from colorbleed.maya import lib
|
||||
from .lib import pairwise
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _allow_export_from_render_setup_layer():
|
||||
"""Context manager to override Maya settings to allow RS layer export"""
|
||||
try:
|
||||
|
||||
rs = renderSetup.instance()
|
||||
|
||||
# Exclude Render Setup nodes from the export
|
||||
rs._setAllRSNodesDoNotWrite(True)
|
||||
|
||||
# Disable Render Setup forcing the switch to master layer
|
||||
os.environ["MAYA_BATCH_RENDER_EXPORT"] = "1"
|
||||
|
||||
yield
|
||||
|
||||
finally:
|
||||
# Reset original state
|
||||
rs._setAllRSNodesDoNotWrite(False)
|
||||
os.environ.pop("MAYA_BATCH_RENDER_EXPORT", None)
|
||||
|
||||
|
||||
def export_in_rs_layer(path, nodes, export=None):
|
||||
"""Export nodes from Render Setup layer.
|
||||
|
||||
When exporting from Render Setup layer Maya by default
|
||||
forces a switch to the defaultRenderLayer as such making
|
||||
it impossible to export the contents of a Render Setup
|
||||
layer. Maya presents this warning message:
|
||||
# Warning: Exporting Render Setup master layer content #
|
||||
|
||||
This function however avoids the renderlayer switch and
|
||||
exports from the Render Setup layer as if the edits were
|
||||
'flattened' in the master layer.
|
||||
|
||||
It does so by:
|
||||
- Allowing export from Render Setup Layer
|
||||
- Enforce Render Setup nodes to NOT be written on export
|
||||
- Disconnect connections from any `applyOverride` nodes
|
||||
to flatten the values (so they are written correctly)*
|
||||
*Connection overrides like Shader Override and Material
|
||||
Overrides export correctly out of the box since they don't
|
||||
create an intermediate connection to an 'applyOverride' node.
|
||||
However, any scalar override (absolute or relative override)
|
||||
will get input connections in the layer so we'll break those
|
||||
to 'store' the values on the attribute itself and write value
|
||||
out instead.
|
||||
|
||||
Args:
|
||||
path (str): File path to export to.
|
||||
nodes (list): Maya nodes to export.
|
||||
export (callable, optional): Callback to be used for exporting. If
|
||||
not specified, default export to `.ma` will be called.
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
Raises:
|
||||
AssertionError: When not in a Render Setup layer an
|
||||
AssertionError is raised. This command assumes
|
||||
you are currently in a Render Setup layer.
|
||||
|
||||
"""
|
||||
rs = renderSetup.instance()
|
||||
assert rs.getVisibleRenderLayer().name() != "defaultRenderLayer", \
|
||||
("Export in Render Setup layer is only supported when in "
|
||||
"Render Setup layer")
|
||||
|
||||
# Break connection to any value overrides
|
||||
history = cmds.listHistory(nodes) or []
|
||||
nodes_all = list(
|
||||
set(cmds.ls(nodes + history, long=True, objectsOnly=True)))
|
||||
overrides = cmds.listConnections(nodes_all,
|
||||
source=True,
|
||||
destination=False,
|
||||
type="applyOverride",
|
||||
plugs=True,
|
||||
connections=True) or []
|
||||
for dest, src in pairwise(overrides):
|
||||
# Even after disconnecting the values
|
||||
# should be preserved as they were
|
||||
# Note: animated overrides would be lost for export
|
||||
cmds.disconnectAttr(src, dest)
|
||||
|
||||
# Export Selected
|
||||
with _allow_export_from_render_setup_layer():
|
||||
cmds.select(nodes, noExpand=True)
|
||||
if export:
|
||||
export()
|
||||
else:
|
||||
cmds.file(path,
|
||||
force=True,
|
||||
typ="mayaAscii",
|
||||
exportSelected=True,
|
||||
preserveReferences=False,
|
||||
channels=True,
|
||||
constraints=True,
|
||||
expressions=True,
|
||||
constructionHistory=True)
|
||||
|
||||
if overrides:
|
||||
# If we have broken override connections then Maya
|
||||
# is unaware that the Render Setup layer is in an
|
||||
# invalid state. So let's 'hard reset' the state
|
||||
# by going to default render layer and switching back
|
||||
layer = rs.getVisibleRenderLayer()
|
||||
rs.switchToLayer(None)
|
||||
rs.switchToLayer(layer)
|
||||
|
|
@ -10,6 +10,7 @@ import maya.app.renderSetup.model.renderSetup as renderSetup
|
|||
|
||||
from pype.hosts.maya.api import lib
|
||||
from pype.api import get_system_settings
|
||||
|
||||
import avalon.maya
|
||||
|
||||
|
||||
|
|
@ -86,12 +87,28 @@ class CreateRender(avalon.maya.Creator):
|
|||
"""Entry point."""
|
||||
exists = cmds.ls(self.name)
|
||||
if exists:
|
||||
return cmds.warning("%s already exists." % exists[0])
|
||||
cmds.warning("%s already exists." % exists[0])
|
||||
return
|
||||
|
||||
use_selection = self.options.get("useSelection")
|
||||
with lib.undo_chunk():
|
||||
self._create_render_settings()
|
||||
instance = super(CreateRender, self).process()
|
||||
# create namespace with instance
|
||||
index = 1
|
||||
namespace_name = "_{}".format(str(instance))
|
||||
try:
|
||||
cmds.namespace(rm=namespace_name)
|
||||
except RuntimeError:
|
||||
# namespace is not empty, so we leave it untouched
|
||||
pass
|
||||
|
||||
while(cmds.namespace(exists=namespace_name)):
|
||||
namespace_name = "_{}{}".format(str(instance), index)
|
||||
index += 1
|
||||
|
||||
namespace = cmds.namespace(add=namespace_name)
|
||||
|
||||
cmds.setAttr("{}.machineList".format(instance), lock=True)
|
||||
self._rs = renderSetup.instance()
|
||||
layers = self._rs.getRenderLayers()
|
||||
|
|
@ -99,17 +116,19 @@ class CreateRender(avalon.maya.Creator):
|
|||
print(">>> processing existing layers")
|
||||
sets = []
|
||||
for layer in layers:
|
||||
print(" - creating set for {}".format(layer.name()))
|
||||
render_set = cmds.sets(n="LAYER_{}".format(layer.name()))
|
||||
print(" - creating set for {}:{}".format(
|
||||
namespace, layer.name()))
|
||||
render_set = cmds.sets(
|
||||
n="{}:{}".format(namespace, layer.name()))
|
||||
sets.append(render_set)
|
||||
cmds.sets(sets, forceElement=instance)
|
||||
|
||||
# if no render layers are present, create default one with
|
||||
# asterix selector
|
||||
if not layers:
|
||||
rl = self._rs.createRenderLayer('Main')
|
||||
cl = rl.createCollection("defaultCollection")
|
||||
cl.getSelector().setPattern('*')
|
||||
render_layer = self._rs.createRenderLayer('Main')
|
||||
collection = render_layer.createCollection("defaultCollection")
|
||||
collection.getSelector().setPattern('*')
|
||||
|
||||
renderer = cmds.getAttr(
|
||||
'defaultRenderGlobals.currentRenderer').lower()
|
||||
|
|
|
|||
|
|
@ -1,27 +1,236 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Create instance of vrayscene."""
|
||||
import os
|
||||
import json
|
||||
import appdirs
|
||||
import requests
|
||||
|
||||
from maya import cmds
|
||||
import maya.app.renderSetup.model.renderSetup as renderSetup
|
||||
|
||||
from pype.hosts.maya.api import lib
|
||||
from pype.api import get_system_settings
|
||||
|
||||
import avalon.maya
|
||||
|
||||
|
||||
class CreateVRayScene(avalon.maya.Creator):
|
||||
"""Create Vray Scene."""
|
||||
|
||||
label = "VRay Scene"
|
||||
family = "vrayscene"
|
||||
icon = "cubes"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Entry."""
|
||||
super(CreateVRayScene, self).__init__(*args, **kwargs)
|
||||
self._rs = renderSetup.instance()
|
||||
self.data["exportOnFarm"] = False
|
||||
|
||||
# We don't need subset or asset attributes
|
||||
self.data.pop("subset", None)
|
||||
self.data.pop("asset", None)
|
||||
self.data.pop("active", None)
|
||||
def process(self):
|
||||
"""Entry point."""
|
||||
exists = cmds.ls(self.name)
|
||||
if exists:
|
||||
return cmds.warning("%s already exists." % exists[0])
|
||||
|
||||
self.data.update({
|
||||
"id": "avalon.vrayscene", # We won't be publishing this one
|
||||
"suspendRenderJob": False,
|
||||
"suspendPublishJob": False,
|
||||
"extendFrames": False,
|
||||
"pools": "",
|
||||
"framesPerTask": 1
|
||||
})
|
||||
use_selection = self.options.get("useSelection")
|
||||
with lib.undo_chunk():
|
||||
self._create_vray_instance_settings()
|
||||
instance = super(CreateVRayScene, self).process()
|
||||
|
||||
index = 1
|
||||
namespace_name = "_{}".format(str(instance))
|
||||
try:
|
||||
cmds.namespace(rm=namespace_name)
|
||||
except RuntimeError:
|
||||
# namespace is not empty, so we leave it untouched
|
||||
pass
|
||||
|
||||
while(cmds.namespace(exists=namespace_name)):
|
||||
namespace_name = "_{}{}".format(str(instance), index)
|
||||
index += 1
|
||||
|
||||
namespace = cmds.namespace(add=namespace_name)
|
||||
# create namespace with instance
|
||||
layers = self._rs.getRenderLayers()
|
||||
if use_selection:
|
||||
print(">>> processing existing layers")
|
||||
sets = []
|
||||
for layer in layers:
|
||||
print(" - creating set for {}".format(layer.name()))
|
||||
render_set = cmds.sets(
|
||||
n="{}:{}".format(namespace, layer.name()))
|
||||
sets.append(render_set)
|
||||
cmds.sets(sets, forceElement=instance)
|
||||
|
||||
# if no render layers are present, create default one with
|
||||
# asterix selector
|
||||
if not layers:
|
||||
render_layer = self._rs.createRenderLayer('Main')
|
||||
collection = render_layer.createCollection("defaultCollection")
|
||||
collection.getSelector().setPattern('*')
|
||||
|
||||
def _create_vray_instance_settings(self):
|
||||
# get pools
|
||||
pools = []
|
||||
|
||||
system_settings = get_system_settings()["modules"]
|
||||
|
||||
deadline_enabled = system_settings["deadline"]["enabled"]
|
||||
muster_enabled = system_settings["muster"]["enabled"]
|
||||
deadline_url = system_settings["deadline"]["DEADLINE_REST_URL"]
|
||||
muster_url = system_settings["muster"]["MUSTER_REST_URL"]
|
||||
|
||||
if deadline_enabled and muster_enabled:
|
||||
self.log.error(
|
||||
"Both Deadline and Muster are enabled. " "Cannot support both."
|
||||
)
|
||||
raise RuntimeError("Both Deadline and Muster are enabled")
|
||||
|
||||
if deadline_enabled:
|
||||
argument = "{}/api/pools?NamesOnly=true".format(deadline_url)
|
||||
try:
|
||||
response = self._requests_get(argument)
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
msg = 'Cannot connect to deadline web service'
|
||||
self.log.error(msg)
|
||||
raise RuntimeError('{} - {}'.format(msg, e))
|
||||
if not response.ok:
|
||||
self.log.warning("No pools retrieved")
|
||||
else:
|
||||
pools = response.json()
|
||||
self.data["primaryPool"] = pools
|
||||
# We add a string "-" to allow the user to not
|
||||
# set any secondary pools
|
||||
self.data["secondaryPool"] = ["-"] + pools
|
||||
|
||||
if muster_enabled:
|
||||
self.log.info(">>> Loading Muster credentials ...")
|
||||
self._load_credentials()
|
||||
self.log.info(">>> Getting pools ...")
|
||||
try:
|
||||
pools = self._get_muster_pools()
|
||||
except requests.exceptions.HTTPError as e:
|
||||
if e.startswith("401"):
|
||||
self.log.warning("access token expired")
|
||||
self._show_login()
|
||||
raise RuntimeError("Access token expired")
|
||||
except requests.exceptions.ConnectionError:
|
||||
self.log.error("Cannot connect to Muster API endpoint.")
|
||||
raise RuntimeError("Cannot connect to {}".format(muster_url))
|
||||
pool_names = []
|
||||
for pool in pools:
|
||||
self.log.info(" - pool: {}".format(pool["name"]))
|
||||
pool_names.append(pool["name"])
|
||||
|
||||
self.data["primaryPool"] = pool_names
|
||||
|
||||
self.data["suspendPublishJob"] = False
|
||||
self.data["priority"] = 50
|
||||
self.data["whitelist"] = False
|
||||
self.data["machineList"] = ""
|
||||
self.data["vraySceneMultipleFiles"] = False
|
||||
self.options = {"useSelection": False} # Force no content
|
||||
|
||||
def _load_credentials(self):
|
||||
"""Load Muster credentials.
|
||||
|
||||
Load Muster credentials from file and set ``MUSTER_USER``,
|
||||
``MUSTER_PASSWORD``, ``MUSTER_REST_URL`` is loaded from presets.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If loaded credentials are invalid.
|
||||
AttributeError: If ``MUSTER_REST_URL`` is not set.
|
||||
|
||||
"""
|
||||
app_dir = os.path.normpath(appdirs.user_data_dir("pype-app", "pype"))
|
||||
file_name = "muster_cred.json"
|
||||
fpath = os.path.join(app_dir, file_name)
|
||||
file = open(fpath, "r")
|
||||
muster_json = json.load(file)
|
||||
self._token = muster_json.get("token", None)
|
||||
if not self._token:
|
||||
self._show_login()
|
||||
raise RuntimeError("Invalid access token for Muster")
|
||||
file.close()
|
||||
self.MUSTER_REST_URL = os.environ.get("MUSTER_REST_URL")
|
||||
if not self.MUSTER_REST_URL:
|
||||
raise AttributeError("Muster REST API url not set")
|
||||
|
||||
def _get_muster_pools(self):
|
||||
"""Get render pools from Muster.
|
||||
|
||||
Raises:
|
||||
Exception: If pool list cannot be obtained from Muster.
|
||||
|
||||
"""
|
||||
params = {"authToken": self._token}
|
||||
api_entry = "/api/pools/list"
|
||||
response = self._requests_get(self.MUSTER_REST_URL + api_entry,
|
||||
params=params)
|
||||
if response.status_code != 200:
|
||||
if response.status_code == 401:
|
||||
self.log.warning("Authentication token expired.")
|
||||
self._show_login()
|
||||
else:
|
||||
self.log.error(
|
||||
("Cannot get pools from "
|
||||
"Muster: {}").format(response.status_code)
|
||||
)
|
||||
raise Exception("Cannot get pools from Muster")
|
||||
try:
|
||||
pools = response.json()["ResponseData"]["pools"]
|
||||
except ValueError as e:
|
||||
self.log.error("Invalid response from Muster server {}".format(e))
|
||||
raise Exception("Invalid response from Muster server")
|
||||
|
||||
return pools
|
||||
|
||||
def _show_login(self):
|
||||
# authentication token expired so we need to login to Muster
|
||||
# again to get it. We use Pype API call to show login window.
|
||||
api_url = "{}/muster/show_login".format(
|
||||
os.environ["PYPE_REST_API_URL"])
|
||||
self.log.debug(api_url)
|
||||
login_response = self._requests_post(api_url, timeout=1)
|
||||
if login_response.status_code != 200:
|
||||
self.log.error("Cannot show login form to Muster")
|
||||
raise Exception("Cannot show login form to Muster")
|
||||
|
||||
def _requests_post(self, *args, **kwargs):
|
||||
"""Wrap request post method.
|
||||
|
||||
Disabling SSL certificate validation if ``DONT_VERIFY_SSL`` environment
|
||||
variable is found. This is useful when Deadline or Muster server are
|
||||
running with self-signed certificates and their certificate is not
|
||||
added to trusted certificates on client machines.
|
||||
|
||||
Warning:
|
||||
Disabling SSL certificate validation is defeating one line
|
||||
of defense SSL is providing and it is not recommended.
|
||||
|
||||
"""
|
||||
if "verify" not in kwargs:
|
||||
kwargs["verify"] = (
|
||||
False if os.getenv("PYPE_DONT_VERIFY_SSL", True) else True
|
||||
) # noqa
|
||||
return requests.post(*args, **kwargs)
|
||||
|
||||
def _requests_get(self, *args, **kwargs):
|
||||
"""Wrap request get method.
|
||||
|
||||
Disabling SSL certificate validation if ``DONT_VERIFY_SSL`` environment
|
||||
variable is found. This is useful when Deadline or Muster server are
|
||||
running with self-signed certificates and their certificate is not
|
||||
added to trusted certificates on client machines.
|
||||
|
||||
Warning:
|
||||
Disabling SSL certificate validation is defeating one line
|
||||
of defense SSL is providing and it is not recommended.
|
||||
|
||||
"""
|
||||
if "verify" not in kwargs:
|
||||
kwargs["verify"] = (
|
||||
False if os.getenv("PYPE_DONT_VERIFY_SSL", True) else True
|
||||
) # noqa
|
||||
return requests.get(*args, **kwargs)
|
||||
|
|
|
|||
145
pype/hosts/maya/plugins/load/load_vrayscene.py
Normal file
145
pype/hosts/maya/plugins/load/load_vrayscene.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
from avalon.maya import lib
|
||||
from avalon import api
|
||||
from pype.api import config
|
||||
import os
|
||||
import maya.cmds as cmds
|
||||
|
||||
|
||||
class VRaySceneLoader(api.Loader):
|
||||
"""Load Vray scene"""
|
||||
|
||||
families = ["vrayscene_layer"]
|
||||
representations = ["vrscene"]
|
||||
|
||||
label = "Import VRay Scene"
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def load(self, context, name, namespace, data):
|
||||
|
||||
from avalon.maya.pipeline import containerise
|
||||
from pype.hosts.maya.lib import namespaced
|
||||
|
||||
try:
|
||||
family = context["representation"]["context"]["family"]
|
||||
except ValueError:
|
||||
family = "vrayscene_layer"
|
||||
|
||||
asset_name = context['asset']["name"]
|
||||
namespace = namespace or lib.unique_namespace(
|
||||
asset_name + "_",
|
||||
prefix="_" if asset_name[0].isdigit() else "",
|
||||
suffix="_",
|
||||
)
|
||||
|
||||
# Ensure V-Ray for Maya is loaded.
|
||||
cmds.loadPlugin("vrayformaya", quiet=True)
|
||||
|
||||
with lib.maintained_selection():
|
||||
cmds.namespace(addNamespace=namespace)
|
||||
with namespaced(namespace, new=False):
|
||||
nodes, group_node = self.create_vray_scene(name,
|
||||
filename=self.fname)
|
||||
|
||||
self[:] = nodes
|
||||
if not nodes:
|
||||
return
|
||||
|
||||
# colour the group node
|
||||
presets = config.get_presets(project=os.environ['AVALON_PROJECT'])
|
||||
colors = presets['plugins']['maya']['load']['colors']
|
||||
c = colors.get(family)
|
||||
if c is not None:
|
||||
cmds.setAttr("{0}.useOutlinerColor".format(group_node), 1)
|
||||
cmds.setAttr("{0}.outlinerColor".format(group_node),
|
||||
c[0], c[1], c[2])
|
||||
|
||||
return containerise(
|
||||
name=name,
|
||||
namespace=namespace,
|
||||
nodes=nodes,
|
||||
context=context,
|
||||
loader=self.__class__.__name__)
|
||||
|
||||
def update(self, container, representation):
|
||||
|
||||
node = container['objectName']
|
||||
assert cmds.objExists(node), "Missing container"
|
||||
|
||||
members = cmds.sets(node, query=True) or []
|
||||
vraymeshes = cmds.ls(members, type="VRayScene")
|
||||
assert vraymeshes, "Cannot find VRayScene in container"
|
||||
|
||||
filename = api.get_representation_path(representation)
|
||||
|
||||
for vray_mesh in vraymeshes:
|
||||
cmds.setAttr("{}.FilePath".format(vray_mesh),
|
||||
filename,
|
||||
type="string")
|
||||
|
||||
# Update metadata
|
||||
cmds.setAttr("{}.representation".format(node),
|
||||
str(representation["_id"]),
|
||||
type="string")
|
||||
|
||||
def remove(self, container):
|
||||
|
||||
# Delete container and its contents
|
||||
if cmds.objExists(container['objectName']):
|
||||
members = cmds.sets(container['objectName'], query=True) or []
|
||||
cmds.delete([container['objectName']] + members)
|
||||
|
||||
# Remove the namespace, if empty
|
||||
namespace = container['namespace']
|
||||
if cmds.namespace(exists=namespace):
|
||||
members = cmds.namespaceInfo(namespace, listNamespace=True)
|
||||
if not members:
|
||||
cmds.namespace(removeNamespace=namespace)
|
||||
else:
|
||||
self.log.warning("Namespace not deleted because it "
|
||||
"still has members: %s", namespace)
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
|
||||
def create_vray_scene(self, name, filename):
|
||||
"""Re-create the structure created by VRay to support vrscenes
|
||||
|
||||
Args:
|
||||
name(str): name of the asset
|
||||
|
||||
Returns:
|
||||
nodes(list)
|
||||
"""
|
||||
|
||||
# Create nodes
|
||||
mesh_node_name = "VRayScene_{}".format(name)
|
||||
|
||||
trans = cmds.createNode(
|
||||
"transform", name="{}".format(mesh_node_name))
|
||||
mesh = cmds.createNode(
|
||||
"mesh", name="{}_Shape".format(mesh_node_name), parent=trans)
|
||||
vray_scene = cmds.createNode(
|
||||
"VRayScene", name="{}_VRSCN".format(mesh_node_name), parent=trans)
|
||||
|
||||
cmds.connectAttr(
|
||||
"{}.outMesh".format(vray_scene), "{}.inMesh".format(mesh))
|
||||
|
||||
cmds.setAttr("{}.FilePath".format(vray_scene), filename, type="string")
|
||||
|
||||
# Create important connections
|
||||
cmds.connectAttr("time1.outTime",
|
||||
"{0}.inputTime".format(trans))
|
||||
|
||||
# Connect mesh to initialShadingGroup
|
||||
cmds.sets([mesh], forceElement="initialShadingGroup")
|
||||
|
||||
group_node = cmds.group(empty=True, name="{}_GRP".format(name))
|
||||
cmds.parent(trans, group_node)
|
||||
nodes = [trans, vray_scene, mesh, group_node]
|
||||
|
||||
# Fix: Force refresh so the mesh shows correctly after creation
|
||||
cmds.refresh()
|
||||
|
||||
return nodes, group_node
|
||||
|
|
@ -95,9 +95,17 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
|
|||
self.maya_layers = maya_render_layers
|
||||
|
||||
for layer in collected_render_layers:
|
||||
# every layer in set should start with `LAYER_` prefix
|
||||
try:
|
||||
expected_layer_name = re.search(r"^LAYER_(.*)", layer).group(1)
|
||||
if layer.startswith("LAYER_"):
|
||||
# this is support for legacy mode where render layers
|
||||
# started with `LAYER_` prefix.
|
||||
expected_layer_name = re.search(
|
||||
r"^LAYER_(.*)", layer).group(1)
|
||||
else:
|
||||
# new way is to prefix render layer name with instance
|
||||
# namespace.
|
||||
expected_layer_name = re.search(
|
||||
r"^.+:(.*)", layer).group(1)
|
||||
except IndexError:
|
||||
msg = "Invalid layer name in set [ {} ]".format(layer)
|
||||
self.log.warnig(msg)
|
||||
|
|
@ -277,10 +285,10 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
|
|||
|
||||
# handle standalone renderers
|
||||
if render_instance.data.get("vrayScene") is True:
|
||||
data["families"].append("vrayscene")
|
||||
data["families"].append("vrayscene_render")
|
||||
|
||||
if render_instance.data.get("assScene") is True:
|
||||
data["families"].append("assscene")
|
||||
data["families"].append("assscene_render")
|
||||
|
||||
# Include (optional) global settings
|
||||
# Get global overrides and translate to Deadline values
|
||||
|
|
|
|||
|
|
@ -12,11 +12,15 @@ class CollectRenderableCamera(pyblish.api.InstancePlugin):
|
|||
order = pyblish.api.CollectorOrder + 0.02
|
||||
label = "Collect Renderable Camera(s)"
|
||||
hosts = ["maya"]
|
||||
families = ["vrayscene",
|
||||
families = ["vrayscene_layer",
|
||||
"renderlayer"]
|
||||
|
||||
def process(self, instance):
|
||||
layer = instance.data["setMembers"]
|
||||
if "vrayscene_layer" in instance.data.get("families", []):
|
||||
layer = instance.data.get("layer")
|
||||
else:
|
||||
layer = instance.data["setMembers"]
|
||||
|
||||
self.log.info("layer: {}".format(layer))
|
||||
cameras = cmds.ls(type="camera", long=True)
|
||||
renderable = [c for c in cameras if
|
||||
|
|
|
|||
155
pype/hosts/maya/plugins/publish/collect_vrayscene.py
Normal file
155
pype/hosts/maya/plugins/publish/collect_vrayscene.py
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Collect Vray Scene and prepare it for extraction and publishing."""
|
||||
import re
|
||||
|
||||
import maya.app.renderSetup.model.renderSetup as renderSetup
|
||||
from maya import cmds
|
||||
|
||||
import pyblish.api
|
||||
from avalon import api
|
||||
from pype.hosts.maya import lib
|
||||
|
||||
|
||||
class CollectVrayScene(pyblish.api.InstancePlugin):
|
||||
"""Collect Vray Scene.
|
||||
|
||||
If export on farm is checked, job is created to export it.
|
||||
"""
|
||||
|
||||
order = pyblish.api.CollectorOrder + 0.01
|
||||
label = "Collect Vray Scene"
|
||||
families = ["vrayscene"]
|
||||
|
||||
def process(self, instance):
|
||||
"""Collector entry point."""
|
||||
collected_render_layers = instance.data["setMembers"]
|
||||
instance.data["remove"] = True
|
||||
context = instance.context
|
||||
|
||||
_rs = renderSetup.instance()
|
||||
# current_layer = _rs.getVisibleRenderLayer()
|
||||
|
||||
# collect all frames we are expecting to be rendered
|
||||
renderer = cmds.getAttr(
|
||||
"defaultRenderGlobals.currentRenderer"
|
||||
).lower()
|
||||
|
||||
if renderer != "vray":
|
||||
raise AssertionError("Vray is not enabled.")
|
||||
|
||||
maya_render_layers = {
|
||||
layer.name(): layer for layer in _rs.getRenderLayers()
|
||||
}
|
||||
|
||||
layer_list = []
|
||||
for layer in collected_render_layers:
|
||||
# every layer in set should start with `LAYER_` prefix
|
||||
try:
|
||||
expected_layer_name = re.search(r"^.+:(.*)", layer).group(1)
|
||||
except IndexError:
|
||||
msg = "Invalid layer name in set [ {} ]".format(layer)
|
||||
self.log.warnig(msg)
|
||||
continue
|
||||
|
||||
self.log.info("processing %s" % layer)
|
||||
# check if layer is part of renderSetup
|
||||
if expected_layer_name not in maya_render_layers:
|
||||
msg = "Render layer [ {} ] is not in " "Render Setup".format(
|
||||
expected_layer_name
|
||||
)
|
||||
self.log.warning(msg)
|
||||
continue
|
||||
|
||||
# check if layer is renderable
|
||||
if not maya_render_layers[expected_layer_name].isRenderable():
|
||||
msg = "Render layer [ {} ] is not " "renderable".format(
|
||||
expected_layer_name
|
||||
)
|
||||
self.log.warning(msg)
|
||||
continue
|
||||
|
||||
layer_name = "rs_{}".format(expected_layer_name)
|
||||
|
||||
self.log.debug(expected_layer_name)
|
||||
layer_list.append(expected_layer_name)
|
||||
|
||||
frame_start_render = int(self.get_render_attribute(
|
||||
"startFrame", layer=layer_name))
|
||||
frame_end_render = int(self.get_render_attribute(
|
||||
"endFrame", layer=layer_name))
|
||||
|
||||
if (int(context.data['frameStartHandle']) == frame_start_render
|
||||
and int(context.data['frameEndHandle']) == frame_end_render): # noqa: W503, E501
|
||||
|
||||
handle_start = context.data['handleStart']
|
||||
handle_end = context.data['handleEnd']
|
||||
frame_start = context.data['frameStart']
|
||||
frame_end = context.data['frameEnd']
|
||||
frame_start_handle = context.data['frameStartHandle']
|
||||
frame_end_handle = context.data['frameEndHandle']
|
||||
else:
|
||||
handle_start = 0
|
||||
handle_end = 0
|
||||
frame_start = frame_start_render
|
||||
frame_end = frame_end_render
|
||||
frame_start_handle = frame_start_render
|
||||
frame_end_handle = frame_end_render
|
||||
|
||||
# Get layer specific settings, might be overrides
|
||||
data = {
|
||||
"subset": expected_layer_name,
|
||||
"layer": layer_name,
|
||||
"setMembers": cmds.sets(layer, q=True) or ["*"],
|
||||
"review": False,
|
||||
"publish": True,
|
||||
"handleStart": handle_start,
|
||||
"handleEnd": handle_end,
|
||||
"frameStart": frame_start,
|
||||
"frameEnd": frame_end,
|
||||
"frameStartHandle": frame_start_handle,
|
||||
"frameEndHandle": frame_end_handle,
|
||||
"byFrameStep": int(
|
||||
self.get_render_attribute("byFrameStep",
|
||||
layer=layer_name)),
|
||||
"renderer": self.get_render_attribute("currentRenderer",
|
||||
layer=layer_name),
|
||||
# instance subset
|
||||
"family": "vrayscene_layer",
|
||||
"families": ["vrayscene_layer"],
|
||||
"asset": api.Session["AVALON_ASSET"],
|
||||
"time": api.time(),
|
||||
"author": context.data["user"],
|
||||
# Add source to allow tracing back to the scene from
|
||||
# which was submitted originally
|
||||
"source": context.data["currentFile"].replace("\\", "/"),
|
||||
"resolutionWidth": cmds.getAttr("defaultResolution.width"),
|
||||
"resolutionHeight": cmds.getAttr("defaultResolution.height"),
|
||||
"pixelAspect": cmds.getAttr("defaultResolution.pixelAspect"),
|
||||
"priority": instance.data.get("priority"),
|
||||
"useMultipleSceneFiles": instance.data.get(
|
||||
"vraySceneMultipleFiles")
|
||||
}
|
||||
|
||||
# Define nice label
|
||||
label = "{0} ({1})".format(expected_layer_name, data["asset"])
|
||||
label += " [{0}-{1}]".format(
|
||||
int(data["frameStartHandle"]), int(data["frameEndHandle"])
|
||||
)
|
||||
|
||||
instance = context.create_instance(expected_layer_name)
|
||||
instance.data["label"] = label
|
||||
instance.data.update(data)
|
||||
|
||||
def get_render_attribute(self, attr, layer):
|
||||
"""Get attribute from render options.
|
||||
|
||||
Args:
|
||||
attr (str): name of attribute to be looked up.
|
||||
|
||||
Returns:
|
||||
Attribute value
|
||||
|
||||
"""
|
||||
return lib.get_attr_in_layer(
|
||||
"defaultRenderGlobals.{}".format(attr), layer=layer
|
||||
)
|
||||
140
pype/hosts/maya/plugins/publish/extract_vrayscene.py
Normal file
140
pype/hosts/maya/plugins/publish/extract_vrayscene.py
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Extract vrayscene from specified families."""
|
||||
import os
|
||||
import re
|
||||
|
||||
import avalon.maya
|
||||
import pype.api
|
||||
from pype.hosts.maya.render_setup_tools import export_in_rs_layer
|
||||
|
||||
from maya import cmds
|
||||
|
||||
|
||||
class ExtractVrayscene(pype.api.Extractor):
|
||||
"""Extractor for vrscene."""
|
||||
|
||||
label = "VRay Scene (.vrscene)"
|
||||
hosts = ["maya"]
|
||||
families = ["vrayscene_layer"]
|
||||
|
||||
def process(self, instance):
|
||||
"""Plugin entry point."""
|
||||
if instance.data.get("exportOnFarm"):
|
||||
self.log.info("vrayscenes will be exported on farm.")
|
||||
raise NotImplementedError(
|
||||
"exporting vrayscenes is not implemented")
|
||||
|
||||
# handle sequence
|
||||
if instance.data.get("vraySceneMultipleFiles"):
|
||||
self.log.info("vrayscenes will be exported on farm.")
|
||||
raise NotImplementedError(
|
||||
"exporting vrayscene sequences not implemented yet")
|
||||
|
||||
vray_settings = cmds.ls(type="VRaySettingsNode")
|
||||
if not vray_settings:
|
||||
node = cmds.createNode("VRaySettingsNode")
|
||||
else:
|
||||
node = vray_settings[0]
|
||||
|
||||
# setMembers on vrayscene_layer shoudl contain layer name.
|
||||
layer_name = instance.data.get("layer")
|
||||
|
||||
staging_dir = self.staging_dir(instance)
|
||||
self.log.info("staging: {}".format(staging_dir))
|
||||
template = cmds.getAttr("{}.vrscene_filename".format(node))
|
||||
start_frame = instance.data.get(
|
||||
"frameStartHandle") if instance.data.get(
|
||||
"vraySceneMultipleFiles") else None
|
||||
formatted_name = self.format_vray_output_filename(
|
||||
os.path.basename(instance.data.get("source")),
|
||||
layer_name,
|
||||
template,
|
||||
start_frame
|
||||
)
|
||||
|
||||
file_path = os.path.join(
|
||||
staging_dir, "vrayscene", *formatted_name.split("/"))
|
||||
|
||||
# Write out vrscene file
|
||||
self.log.info("Writing: '%s'" % file_path)
|
||||
with avalon.maya.maintained_selection():
|
||||
if "*" not in instance.data["setMembers"]:
|
||||
self.log.info(
|
||||
"Exporting: {}".format(instance.data["setMembers"]))
|
||||
set_members = instance.data["setMembers"]
|
||||
cmds.select(set_members, noExpand=True)
|
||||
else:
|
||||
self.log.info("Exporting all ...")
|
||||
set_members = cmds.ls(
|
||||
long=True, objectsOnly=True,
|
||||
geometry=True, lights=True, cameras=True)
|
||||
cmds.select(set_members, noExpand=True)
|
||||
|
||||
self.log.info("Appending layer name {}".format(layer_name))
|
||||
set_members.append(layer_name)
|
||||
|
||||
export_in_rs_layer(
|
||||
file_path,
|
||||
set_members,
|
||||
export=lambda: cmds.file(
|
||||
file_path, type="V-Ray Scene",
|
||||
pr=True, es=True, force=True))
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
|
||||
files = file_path
|
||||
|
||||
representation = {
|
||||
'name': 'vrscene',
|
||||
'ext': 'vrscene',
|
||||
'files': os.path.basename(files),
|
||||
"stagingDir": os.path.dirname(files),
|
||||
}
|
||||
instance.data["representations"].append(representation)
|
||||
|
||||
self.log.info("Extracted instance '%s' to: %s"
|
||||
% (instance.name, staging_dir))
|
||||
|
||||
@staticmethod
|
||||
def format_vray_output_filename(
|
||||
filename, layer, template, start_frame=None):
|
||||
"""Format the expected output file of the Export job.
|
||||
|
||||
Example:
|
||||
filename: /mnt/projects/foo/shot010_v006.mb
|
||||
template: <Scene>/<Layer>/<Layer>
|
||||
result: "shot010_v006/CHARS/CHARS.vrscene"
|
||||
|
||||
Args:
|
||||
filename (str): path to scene file.
|
||||
layer (str): layer name.
|
||||
template (str): token template.
|
||||
start_frame (int, optional): start frame - if set we use
|
||||
mutliple files export mode.
|
||||
|
||||
Returns:
|
||||
str: formatted path.
|
||||
|
||||
"""
|
||||
# format template to match pythons format specs
|
||||
template = re.sub(r"<(\w+?)>", r"{\1}", template.lower())
|
||||
|
||||
# Ensure filename has no extension
|
||||
file_name, _ = os.path.splitext(filename)
|
||||
mapping = {
|
||||
"scene": file_name,
|
||||
"layer": layer
|
||||
}
|
||||
|
||||
output_path = template.format(**mapping)
|
||||
|
||||
if start_frame:
|
||||
filename_zero = "{}_{:04d}.vrscene".format(
|
||||
output_path, start_frame)
|
||||
else:
|
||||
filename_zero = "{}.vrscene".format(output_path)
|
||||
|
||||
result = filename_zero.replace("\\", "/")
|
||||
|
||||
return result
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Validate VRay Translator settings."""
|
||||
import pyblish.api
|
||||
import pype.api
|
||||
from pype.plugin import contextplugin_should_run
|
||||
|
|
@ -6,14 +8,15 @@ from maya import cmds
|
|||
|
||||
|
||||
class ValidateVRayTranslatorEnabled(pyblish.api.ContextPlugin):
|
||||
"""Validate VRay Translator settings for extracting vrscenes."""
|
||||
|
||||
order = pype.api.ValidateContentsOrder
|
||||
label = "VRay Translator Settings"
|
||||
families = ["vrayscene"]
|
||||
families = ["vrayscene_layer"]
|
||||
actions = [pype.api.RepairContextAction]
|
||||
|
||||
def process(self, context):
|
||||
|
||||
"""Plugin entry point."""
|
||||
# Workaround bug pyblish-base#250
|
||||
if not contextplugin_should_run(self, context):
|
||||
return
|
||||
|
|
@ -24,7 +27,7 @@ class ValidateVRayTranslatorEnabled(pyblish.api.ContextPlugin):
|
|||
|
||||
@classmethod
|
||||
def get_invalid(cls, context):
|
||||
|
||||
"""Get invalid instances."""
|
||||
invalid = False
|
||||
|
||||
# Get vraySettings node
|
||||
|
|
@ -34,16 +37,26 @@ class ValidateVRayTranslatorEnabled(pyblish.api.ContextPlugin):
|
|||
node = vray_settings[0]
|
||||
|
||||
if cmds.setAttr("{}.vrscene_render_on".format(node)):
|
||||
cls.log.error("Render is enabled, this should be disabled")
|
||||
cls.log.error(
|
||||
"Render is enabled, for export it should be disabled")
|
||||
invalid = True
|
||||
|
||||
if not cmds.getAttr("{}.vrscene_on".format(node)):
|
||||
cls.log.error("Export vrscene not enabled")
|
||||
invalid = True
|
||||
|
||||
if not cmds.getAttr("{}.misc_eachFrameInFile".format(node)):
|
||||
cls.log.error("Each Frame in File not enabled")
|
||||
invalid = True
|
||||
for instance in context:
|
||||
if "vrayscene_layer" not in instance.data.get("families"):
|
||||
continue
|
||||
|
||||
if instance.data.get("vraySceneMultipleFiles"):
|
||||
if not cmds.getAttr("{}.misc_eachFrameInFile".format(node)):
|
||||
cls.log.error("Each Frame in File not enabled")
|
||||
invalid = True
|
||||
else:
|
||||
if cmds.getAttr("{}.misc_eachFrameInFile".format(node)):
|
||||
cls.log.error("Each Frame in File is enabled")
|
||||
invalid = True
|
||||
|
||||
vrscene_filename = cmds.getAttr("{}.vrscene_filename".format(node))
|
||||
if vrscene_filename != "vrayscene/<Scene>/<Layer>/<Layer>":
|
||||
|
|
@ -54,7 +67,7 @@ class ValidateVRayTranslatorEnabled(pyblish.api.ContextPlugin):
|
|||
|
||||
@classmethod
|
||||
def repair(cls, context):
|
||||
|
||||
"""Repair invalid settings."""
|
||||
vray_settings = cmds.ls(type="VRaySettingsNode")
|
||||
if not vray_settings:
|
||||
node = cmds.createNode("VRaySettingsNode")
|
||||
|
|
@ -63,7 +76,14 @@ class ValidateVRayTranslatorEnabled(pyblish.api.ContextPlugin):
|
|||
|
||||
cmds.setAttr("{}.vrscene_render_on".format(node), False)
|
||||
cmds.setAttr("{}.vrscene_on".format(node), True)
|
||||
cmds.setAttr("{}.misc_eachFrameInFile".format(node), True)
|
||||
for instance in context:
|
||||
if "vrayscene" not in instance.data.get("families"):
|
||||
continue
|
||||
|
||||
if instance.data.get("vraySceneMultipleFiles"):
|
||||
cmds.setAttr("{}.misc_eachFrameInFile".format(node), True)
|
||||
else:
|
||||
cmds.setAttr("{}.misc_eachFrameInFile".format(node), False)
|
||||
cmds.setAttr("{}.vrscene_filename".format(node),
|
||||
"vrayscene/<Scene>/<Layer>/<Layer>",
|
||||
type="string")
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
|
|||
"vdbcache",
|
||||
"scene",
|
||||
"vrayproxy",
|
||||
"vrayscene_layer",
|
||||
"render",
|
||||
"prerender",
|
||||
"imagesequence",
|
||||
|
|
@ -701,7 +702,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
|
|||
'type': 'subset',
|
||||
'_id': io.ObjectId(subset["_id"])
|
||||
}, {'$set': {'data.subsetGroup':
|
||||
instance.data.get('subsetGroup')}}
|
||||
instance.data.get('subsetGroup')}}
|
||||
)
|
||||
|
||||
# Update families on subset.
|
||||
|
|
@ -878,9 +879,9 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
|
|||
path = rootless_path
|
||||
else:
|
||||
self.log.warning((
|
||||
"Could not find root path for remapping \"{}\"."
|
||||
" This may cause issues on farm."
|
||||
).format(path))
|
||||
"Could not find root path for remapping \"{}\"."
|
||||
" This may cause issues on farm."
|
||||
).format(path))
|
||||
return path
|
||||
|
||||
def get_files_info(self, instance, integrated_file_sizes):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue