Set color space from publish using representation color space data or falling back to imageio settings file rules in OP settings

This commit is contained in:
Roy Nieterau 2023-03-06 15:26:55 +01:00 committed by Milan Kolar
parent 1c5b821688
commit 4ac950aa60

View file

@ -1,16 +1,24 @@
import os
import copy
from openpype.lib import EnumDef
from openpype.pipeline import (
load,
get_representation_context
)
from openpype.lib import EnumDef
from openpype.pipeline.load.utils import get_representation_path_from_context
from openpype.pipeline.colorspace import (
get_imageio_colorspace_from_filepath,
get_imageio_config,
get_imageio_file_rules
)
from openpype.settings import get_project_settings
from openpype.hosts.maya.api.pipeline import containerise
from openpype.hosts.maya.api.lib import (
unique_namespace,
namespaced
)
from openpype.pipeline.load.utils import get_representation_path_from_context
from maya import cmds
@ -83,7 +91,6 @@ def create_stencil():
class FileNodeLoader(load.LoaderPlugin):
"""File node loader."""
# TODO: Implement color space manamagent OCIO (set correct color space)
families = ["image", "plate", "render"]
label = "Load file node"
@ -107,7 +114,6 @@ class FileNodeLoader(load.LoaderPlugin):
def load(self, context, name, namespace, data):
path = self._format_path(context)
asset = context['asset']['name']
namespace = namespace or unique_namespace(
asset + "_",
@ -115,10 +121,6 @@ class FileNodeLoader(load.LoaderPlugin):
suffix="_",
)
repre_context = context["representation"]["context"]
has_frames = repre_context.get("frame") is not None
has_udim = repre_context.get("udim") is not None
with namespaced(namespace, new=True) as namespace:
# Create the nodes within the namespace
nodes = {
@ -126,31 +128,14 @@ class FileNodeLoader(load.LoaderPlugin):
"projection": create_projection,
"stencil": create_stencil
}[data.get("mode", "texture")]()
file_node = cmds.ls(nodes, type="file")[0]
# Set UV tiling mode if UDIM tiles
if has_udim:
cmds.setAttr(file_node + ".uvTilingMode", 3) # UDIM-tiles
file_node = cmds.ls(nodes, type="file")[0]
# Enable sequence if publish has `startFrame` and `endFrame` and
# `startFrame != endFrame`
if has_frames:
is_sequence = self._is_sequence(context)
if is_sequence:
# When enabling useFrameExtension maya automatically
# connects an expression to <file>.frameExtension to set
# the current frame. However, this expression is generated
# with some delay and thus it'll show a warning if frame 0
# doesn't exist because we're explicitly setting the <f>
# token.
cmds.setAttr(file_node + ".useFrameExtension", True)
self._apply_representation_context(context, file_node)
# Set the file node path attribute
cmds.setAttr(file_node + ".fileTextureName", path, type="string")
# For ease of access for the user select all the nodes and select
# the file node last so that UI shows its attributes by default
cmds.select(list(nodes) + [file_node], replace=True)
# For ease of access for the user select all the nodes and select
# the file node last so that UI shows its attributes by default
cmds.select(list(nodes) + [file_node], replace=True)
return containerise(
name=name,
@ -167,7 +152,7 @@ class FileNodeLoader(load.LoaderPlugin):
members = cmds.sets(container['objectName'], query=True)
file_node = cmds.ls(members, type="file")[0]
cmds.setAttr(file_node + ".fileTextureName", path, type="string")
self._apply_representation_context(context, file_node)
# Update representation
cmds.setAttr(
@ -191,6 +176,51 @@ class FileNodeLoader(load.LoaderPlugin):
except RuntimeError:
pass
def _apply_representation_context(self, context, file_node):
"""Update the file node to match the context.
This sets the file node's attributes for:
- file path
- udim tiling mode (if it is an udim tile)
- use frame extension (if it is a sequence)
- colorspace
"""
repre_context = context["representation"]["context"]
has_frames = repre_context.get("frame") is not None
has_udim = repre_context.get("udim") is not None
# Set UV tiling mode if UDIM tiles
if has_udim:
cmds.setAttr(file_node + ".uvTilingMode", 3) # UDIM-tiles
else:
cmds.setAttr(file_node + ".uvTilingMode", 0) # off
# Enable sequence if publish has `startFrame` and `endFrame` and
# `startFrame != endFrame`
if has_frames and self._is_sequence(context):
# When enabling useFrameExtension maya automatically
# connects an expression to <file>.frameExtension to set
# the current frame. However, this expression is generated
# with some delay and thus it'll show a warning if frame 0
# doesn't exist because we're explicitly setting the <f>
# token.
cmds.setAttr(file_node + ".useFrameExtension", True)
else:
cmds.setAttr(file_node + ".useFrameExtension", False)
# Set the file node path attribute
path = self._format_path(context)
cmds.setAttr(file_node + ".fileTextureName", path, type="string")
# Set colorspace
colorspace = self._get_colorspace(context)
if colorspace:
cmds.setAttr(file_node + ".colorSpace", colorspace, type="string")
else:
self.log.debug("Unknown colorspace - setting colorspace skipped.")
def _is_sequence(self, context):
"""Check whether frameStart and frameEnd are not the same."""
version = context.get("version", {})
@ -213,6 +243,54 @@ class FileNodeLoader(load.LoaderPlugin):
return False
def _get_colorspace(self, context):
"""Return colorspace of the file to load.
Retrieves the explicit colorspace from the publish. If no colorspace
data is stored with published content then project imageio settings
are used to make an assumption of the colorspace based on the file
rules. If no file rules match then None is returned.
Returns:
str or None: The colorspace of the file or None if not detected.
"""
# We can't apply color spaces if management is not enabled
if not cmds.colorManagementPrefs(query=True, cmEnabled=True):
return
representation = context["representation"]
colorspace_data = representation.get("data", {}).get("colorspaceData")
if colorspace_data:
return colorspace_data["colorspace"]
# Assume colorspace from filepath based on project settings
project_name = context["project"]["name"]
host_name = os.environ.get("AVALON_APP")
project_settings = get_project_settings(project_name)
config_data = get_imageio_config(
project_name, host_name,
project_settings=project_settings
)
file_rules = get_imageio_file_rules(
project_name, host_name,
project_settings=project_settings
)
path = get_representation_path_from_context(context)
colorspace = get_imageio_colorspace_from_filepath(
path=path,
host_name=host_name,
project_name=project_name,
config_data=config_data,
file_rules=file_rules,
project_settings=project_settings
)
return colorspace
def _format_path(self, context):
"""Format the path with correct tokens for frames and udim tiles."""