Merge pull request #4340 from tokejepsen/enchancement/OP-2630_acescg_maya

This commit is contained in:
Jakub Ježek 2023-02-23 21:51:15 +01:00 committed by GitHub
commit f037074747
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 237 additions and 87 deletions

View file

@ -15,7 +15,7 @@ from math import ceil
from six import string_types
from maya import cmds, mel
import maya.api.OpenMaya as om
from maya.api import OpenMaya
from openpype.client import (
get_project,
@ -3509,3 +3509,56 @@ def write_xgen_file(data, filepath):
with open(filepath, "w") as f:
f.writelines(lines)
def get_color_management_preferences():
"""Get and resolve OCIO preferences."""
data = {
# Is color management enabled.
"enabled": cmds.colorManagementPrefs(
query=True, cmEnabled=True
),
"rendering_space": cmds.colorManagementPrefs(
query=True, renderingSpaceName=True
),
"output_transform": cmds.colorManagementPrefs(
query=True, outputTransformName=True
),
"output_transform_enabled": cmds.colorManagementPrefs(
query=True, outputTransformEnabled=True
),
"view_transform": cmds.colorManagementPrefs(
query=True, viewTransformName=True
)
}
# Split view and display from view_transform. view_transform comes in
# format of "{view} ({display})".
regex = re.compile(r"^(?P<view>.+) \((?P<display>.+)\)$")
match = regex.match(data["view_transform"])
data.update({
"display": match.group("display"),
"view": match.group("view")
})
# Get config absolute path.
path = cmds.colorManagementPrefs(
query=True, configFilePath=True
)
# The OCIO config supports a custom <MAYA_RESOURCES> token.
maya_resources_token = "<MAYA_RESOURCES>"
maya_resources_path = OpenMaya.MGlobal.getAbsolutePathToResources()
path = path.replace(maya_resources_token, maya_resources_path)
data["config"] = path
return data
def get_color_management_output_transform():
preferences = get_color_management_preferences()
colorspace = preferences["rendering_space"]
if preferences["output_transform_enabled"]:
colorspace = preferences["output_transform"]
return colorspace

View file

@ -46,6 +46,7 @@ import attr
from . import lib
from . import lib_rendersetup
from openpype.pipeline.colorspace import get_ocio_config_views
from maya import cmds, mel
@ -127,6 +128,7 @@ class RenderProduct(object):
"""
productName = attr.ib()
ext = attr.ib() # extension
colorspace = attr.ib() # colorspace
aov = attr.ib(default=None) # source aov
driver = attr.ib(default=None) # source driver
multipart = attr.ib(default=False) # multichannel file
@ -562,6 +564,9 @@ class RenderProductsArnold(ARenderProducts):
]
for ai_driver in ai_drivers:
colorspace = self._get_colorspace(
ai_driver + ".colorManagement"
)
# todo: check aiAOVDriver.prefix as it could have
# a custom path prefix set for this driver
@ -599,12 +604,15 @@ class RenderProductsArnold(ARenderProducts):
global_aov = self._get_attr(aov, "globalAov")
if global_aov:
for camera in cameras:
product = RenderProduct(productName=name,
ext=ext,
aov=aov_name,
driver=ai_driver,
multipart=self.multipart,
camera=camera)
product = RenderProduct(
productName=name,
ext=ext,
aov=aov_name,
driver=ai_driver,
multipart=self.multipart,
camera=camera,
colorspace=colorspace
)
products.append(product)
all_light_groups = self._get_attr(aov, "lightGroups")
@ -612,13 +620,16 @@ class RenderProductsArnold(ARenderProducts):
# All light groups is enabled. A single multipart
# Render Product
for camera in cameras:
product = RenderProduct(productName=name + "_lgroups",
ext=ext,
aov=aov_name,
driver=ai_driver,
# Always multichannel output
multipart=True,
camera=camera)
product = RenderProduct(
productName=name + "_lgroups",
ext=ext,
aov=aov_name,
driver=ai_driver,
# Always multichannel output
multipart=True,
camera=camera,
colorspace=colorspace
)
products.append(product)
else:
value = self._get_attr(aov, "lightGroupsList")
@ -634,12 +645,36 @@ class RenderProductsArnold(ARenderProducts):
aov=aov_name,
driver=ai_driver,
ext=ext,
camera=camera
camera=camera,
colorspace=colorspace
)
products.append(product)
return products
def _get_colorspace(self, attribute):
"""Resolve colorspace from Arnold settings."""
def _view_transform():
preferences = lib.get_color_management_preferences()
views_data = get_ocio_config_views(preferences["config"])
view_data = views_data[
"{}/{}".format(preferences["display"], preferences["view"])
]
return view_data["colorspace"]
def _raw():
preferences = lib.get_color_management_preferences()
return preferences["rendering_space"]
resolved_values = {
"Raw": _raw,
"Use View Transform": _view_transform,
# Default. Same as Maya Preferences.
"Use Output Transform": lib.get_color_management_output_transform
}
return resolved_values[self._get_attr(attribute)]()
def get_render_products(self):
"""Get all AOVs.
@ -668,11 +703,19 @@ class RenderProductsArnold(ARenderProducts):
]
default_ext = self._get_attr("defaultRenderGlobals.imfPluginKey")
beauty_products = [RenderProduct(
productName="beauty",
ext=default_ext,
driver="defaultArnoldDriver",
camera=camera) for camera in cameras]
colorspace = self._get_colorspace(
"defaultArnoldDriver.colorManagement"
)
beauty_products = [
RenderProduct(
productName="beauty",
ext=default_ext,
driver="defaultArnoldDriver",
camera=camera,
colorspace=colorspace
) for camera in cameras
]
# AOVs > Legacy > Maya Render View > Mode
aovs_enabled = bool(
self._get_attr("defaultArnoldRenderOptions.aovMode")
@ -825,6 +868,7 @@ class RenderProductsVray(ARenderProducts):
productName="",
ext=default_ext,
camera=camera,
colorspace=lib.get_color_management_output_transform(),
multipart=self.multipart
)
)
@ -880,10 +924,13 @@ class RenderProductsVray(ARenderProducts):
aov_name = self._get_vray_aov_name(aov)
for camera in cameras:
product = RenderProduct(productName=aov_name,
ext=default_ext,
aov=aov,
camera=camera)
product = RenderProduct(
productName=aov_name,
ext=default_ext,
aov=aov,
camera=camera,
colorspace=lib.get_color_management_output_transform()
)
products.append(product)
return products
@ -1367,7 +1414,12 @@ class RenderProductsMayaHardware(ARenderProducts):
products = []
for cam in self.get_renderable_cameras():
product = RenderProduct(productName="beauty", ext=ext, camera=cam)
product = RenderProduct(
productName="beauty",
ext=ext,
camera=cam,
colorspace=lib.get_color_management_output_transform()
)
products.append(product)
return products

View file

@ -23,7 +23,8 @@ class RenderSettings(object):
'vray': 'vraySettings.fileNamePrefix',
'arnold': 'defaultRenderGlobals.imageFilePrefix',
'renderman': 'rmanGlobals.imageFileFormat',
'redshift': 'defaultRenderGlobals.imageFilePrefix'
'redshift': 'defaultRenderGlobals.imageFilePrefix',
'mayahardware2': 'defaultRenderGlobals.imageFilePrefix'
}
_image_prefixes = {

View file

@ -269,7 +269,7 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
self.log.info(full_exp_files)
self.log.info("collecting layer: {}".format(layer_name))
# Get layer specific settings, might be overrides
colorspace_data = lib.get_color_management_preferences()
data = {
"subset": expected_layer_name,
"attachTo": attach_to,
@ -323,6 +323,9 @@ class CollectMayaRender(pyblish.api.ContextPlugin):
"renderSetupIncludeLights": render_instance.data.get(
"renderSetupIncludeLights"
),
"colorspaceConfig": colorspace_data["config"],
"colorspaceDisplay": colorspace_data["display"],
"colorspaceView": colorspace_data["view"],
"strict_error_checking": render_instance.data.get(
"strict_error_checking", True
)

View file

@ -7,12 +7,13 @@ from openpype.hosts.maya.api import MayaHost
from maya import cmds
host = MayaHost()
install_host(host)
print("Starting OpenPype usersetup...")
# Open Workfile Post Initialization.
key = "OPENPYPE_OPEN_WORKFILE_POST_INITIALIZATION"
if bool(int(os.environ.get(key, "0"))):

View file

@ -434,7 +434,9 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
self.log.info(
"Finished copying %i files" % len(resource_files))
def _create_instances_for_aov(self, instance_data, exp_files):
def _create_instances_for_aov(
self, instance_data, exp_files, additional_data
):
"""Create instance for each AOV found.
This will create new instance for every aov it can detect in expected
@ -536,6 +538,14 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
else:
files = os.path.basename(col)
# Copy render product "colorspace" data to representation.
colorspace = ""
products = additional_data["renderProducts"].layer_data.products
for product in products:
if product.productName == aov:
colorspace = product.colorspace
break
rep = {
"name": ext,
"ext": ext,
@ -545,7 +555,16 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
# If expectedFile are absolute, we need only filenames
"stagingDir": staging,
"fps": new_instance.get("fps"),
"tags": ["review"] if preview else []
"tags": ["review"] if preview else [],
"colorspaceData": {
"colorspace": colorspace,
"config": {
"path": additional_data["colorspaceConfig"],
"template": additional_data["colorspaceTemplate"]
},
"display": additional_data["display"],
"view": additional_data["view"]
}
}
# support conversion from tiled to scanline
@ -569,7 +588,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
self.log.debug("instances:{}".format(instances))
return instances
def _get_representations(self, instance, exp_files):
def _get_representations(self, instance, exp_files, additional_data):
"""Create representations for file sequences.
This will return representations of expected files if they are not
@ -914,6 +933,16 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
self.log.info(data.get("expectedFiles"))
additional_data = {
"renderProducts": instance.data["renderProducts"],
"colorspaceConfig": instance.data["colorspaceConfig"],
"display": instance.data["colorspaceDisplay"],
"view": instance.data["colorspaceView"],
"colorspaceTemplate": instance.data["colorspaceConfig"].replace(
str(context.data["anatomy"].roots["work"]), "{root[work]}"
)
}
if isinstance(data.get("expectedFiles")[0], dict):
# we cannot attach AOVs to other subsets as we consider every
# AOV subset of its own.
@ -928,7 +957,9 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
# there are multiple renderable cameras in scene)
instances = self._create_instances_for_aov(
instance_skeleton_data,
data.get("expectedFiles"))
data.get("expectedFiles"),
additional_data
)
self.log.info("got {} instance{}".format(
len(instances),
"s" if len(instances) > 1 else ""))

View file

@ -198,41 +198,19 @@ def validate_imageio_colorspace_in_config(config_path, colorspace_name):
return True
def get_ocio_config_colorspaces(config_path):
"""Get all colorspace data
Wrapper function for aggregating all names and its families.
Families can be used for building menu and submenus in gui.
Args:
config_path (str): path leading to config.ocio file
Returns:
dict: colorspace and family in couple
"""
if sys.version_info[0] == 2:
return get_colorspace_data_subprocess(config_path)
from ..scripts.ocio_wrapper import _get_colorspace_data
return _get_colorspace_data(config_path)
def get_colorspace_data_subprocess(config_path):
"""Get colorspace data via subprocess
def get_data_subprocess(config_path, data_type):
"""Get data via subprocess
Wrapper for Python 2 hosts.
Args:
config_path (str): path leading to config.ocio file
Returns:
dict: colorspace and family in couple
"""
with _make_temp_json_file() as tmp_json_path:
# Prepare subprocess arguments
args = [
"run", get_ocio_config_script_path(),
"config", "get_colorspace",
"config", data_type,
"--in_path", config_path,
"--out_path", tmp_json_path
@ -251,6 +229,47 @@ def get_colorspace_data_subprocess(config_path):
return json.loads(return_json_data)
def compatible_python():
"""Only 3.9 or higher can directly use PyOpenColorIO in ocio_wrapper"""
compatible = False
if sys.version[0] == 3 and sys.version[1] >= 9:
compatible = True
return compatible
def get_ocio_config_colorspaces(config_path):
"""Get all colorspace data
Wrapper function for aggregating all names and its families.
Families can be used for building menu and submenus in gui.
Args:
config_path (str): path leading to config.ocio file
Returns:
dict: colorspace and family in couple
"""
if compatible_python():
from ..scripts.ocio_wrapper import _get_colorspace_data
return _get_colorspace_data(config_path)
else:
return get_colorspace_data_subprocess(config_path)
def get_colorspace_data_subprocess(config_path):
"""Get colorspace data via subprocess
Wrapper for Python 2 hosts.
Args:
config_path (str): path leading to config.ocio file
Returns:
dict: colorspace and family in couple
"""
return get_data_subprocess(config_path, "get_colorspace")
def get_ocio_config_views(config_path):
"""Get all viewer data
@ -263,12 +282,12 @@ def get_ocio_config_views(config_path):
Returns:
dict: `display/viewer` and viewer data
"""
if sys.version_info[0] == 2:
if compatible_python():
from ..scripts.ocio_wrapper import _get_views_data
return _get_views_data(config_path)
else:
return get_views_data_subprocess(config_path)
from ..scripts.ocio_wrapper import _get_views_data
return _get_views_data(config_path)
def get_views_data_subprocess(config_path):
"""Get viewers data via subprocess
@ -281,27 +300,7 @@ def get_views_data_subprocess(config_path):
Returns:
dict: `display/viewer` and viewer data
"""
with _make_temp_json_file() as tmp_json_path:
# Prepare subprocess arguments
args = [
"run", get_ocio_config_script_path(),
"config", "get_views",
"--in_path", config_path,
"--out_path", tmp_json_path
]
log.info("Executing: {}".format(" ".join(args)))
process_kwargs = {
"logger": log,
"env": {}
}
run_openpype_process(*args, **process_kwargs)
# return all colorspaces
return_json_data = open(tmp_json_path).read()
return json.loads(return_json_data)
return get_data_subprocess(config_path, "get_views")
def get_imageio_config(

View file

@ -157,11 +157,21 @@ def _get_views_data(config_path):
config = ocio.Config().CreateFromFile(str(config_path))
return {
f"{d}/{v}": {"display": d, "view": v}
for d in config.getDisplays()
for v in config.getViews(d)
}
data = {}
for display in config.getDisplays():
for view in config.getViews(display):
colorspace = config.getDisplayViewColorSpaceName(display, view)
# Special token. See https://opencolorio.readthedocs.io/en/latest/guides/authoring/authoring.html#shared-views # noqa
if colorspace == "<USE_DISPLAY_NAME>":
colorspace = display
data[f"{display}/{view}"] = {
"display": display,
"view": view,
"colorspace": colorspace
}
return data
if __name__ == '__main__':