mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
Merge pull request #36 from ynput/enhancement/OP-1017_houdini-colorspaces
Enhancement: Color management for Houdini workfiles
This commit is contained in:
commit
e14c9ec369
9 changed files with 258 additions and 60 deletions
|
|
@ -811,6 +811,43 @@ def get_current_context_template_data_with_folder_attrs():
|
|||
return template_data
|
||||
|
||||
|
||||
def set_review_color_space(opengl_node, review_color_space="", log=None):
|
||||
"""Set ociocolorspace parameter for the given OpenGL node.
|
||||
|
||||
Set `ociocolorspace` parameter of the given OpenGl node
|
||||
to to the given review_color_space value.
|
||||
If review_color_space is empty, a default colorspace corresponding to
|
||||
the display & view of the current Houdini session will be used.
|
||||
|
||||
Args:
|
||||
opengl_node (hou.Node): ROP node to set its ociocolorspace parm.
|
||||
review_color_space (str): Colorspace value for ociocolorspace parm.
|
||||
log (logging.Logger): Logger to log to.
|
||||
"""
|
||||
|
||||
if log is None:
|
||||
log = self.log
|
||||
|
||||
# Set Color Correction parameter to OpenColorIO
|
||||
colorcorrect_parm = opengl_node.parm("colorcorrect")
|
||||
if colorcorrect_parm.eval() != 2:
|
||||
colorcorrect_parm.set(2)
|
||||
log.debug(
|
||||
"'Color Correction' parm on '{}' has been set to"
|
||||
" 'OpenColorIO'".format(opengl_node.path())
|
||||
)
|
||||
|
||||
opengl_node.setParms(
|
||||
{"ociocolorspace": review_color_space}
|
||||
)
|
||||
|
||||
log.debug(
|
||||
"'OCIO Colorspace' parm on '{}' has been set to "
|
||||
"the view color space '{}'"
|
||||
.format(opengl_node, review_color_space)
|
||||
)
|
||||
|
||||
|
||||
def get_context_var_changes():
|
||||
"""get context var changes."""
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
from ayon_applications import PreLaunchHook, LaunchTypes
|
||||
|
||||
|
||||
class SetDefaultDisplayView(PreLaunchHook):
|
||||
"""Set default view and default display for houdini via OpenColorIO.
|
||||
|
||||
Houdini's defaultDisplay and defaultView are set by
|
||||
setting 'OCIO_ACTIVE_DISPLAYS' and 'OCIO_ACTIVE_VIEWS'
|
||||
environment variables respectively.
|
||||
|
||||
More info: https://www.sidefx.com/docs/houdini/io/ocio.html#set-up
|
||||
"""
|
||||
|
||||
app_groups = {"houdini"}
|
||||
launch_types = {LaunchTypes.local}
|
||||
|
||||
def execute(self):
|
||||
|
||||
OCIO = self.launch_context.env.get("OCIO")
|
||||
|
||||
# This is a cheap way to skip this hook if either global color
|
||||
# management or houdini color management was disabled because the
|
||||
# OCIO var would be set by the global OCIOEnvHook
|
||||
if not OCIO:
|
||||
return
|
||||
|
||||
houdini_color_settings = \
|
||||
self.data["project_settings"]["houdini"]["imageio"]["workfile"]
|
||||
|
||||
if not houdini_color_settings["enabled"]:
|
||||
self.log.info(
|
||||
"Houdini workfile color management is disabled."
|
||||
)
|
||||
return
|
||||
|
||||
# 'OCIO_ACTIVE_DISPLAYS', 'OCIO_ACTIVE_VIEWS' are checked
|
||||
# as Admins can add them in Ayon env vars or Ayon tools.
|
||||
|
||||
default_display = houdini_color_settings["default_display"]
|
||||
if default_display:
|
||||
# get 'OCIO_ACTIVE_DISPLAYS' value if exists.
|
||||
self._set_context_env("OCIO_ACTIVE_DISPLAYS", default_display)
|
||||
|
||||
default_view = houdini_color_settings["default_view"]
|
||||
if default_view:
|
||||
# get 'OCIO_ACTIVE_VIEWS' value if exists.
|
||||
self._set_context_env("OCIO_ACTIVE_VIEWS", default_view)
|
||||
|
||||
def _set_context_env(self, env_var, default_value):
|
||||
env_value = self.launch_context.env.get(env_var, "")
|
||||
new_value = ":".join(
|
||||
key for key in [default_value, env_value] if key
|
||||
)
|
||||
self.log.info(
|
||||
"Setting {} environment to: {}"
|
||||
.format(env_var, new_value)
|
||||
)
|
||||
self.launch_context.env[env_var] = new_value
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Creator plugin for creating openGL reviews."""
|
||||
from ayon_core.hosts.houdini.api import plugin
|
||||
from ayon_core.hosts.houdini.api import lib, plugin
|
||||
from ayon_core.lib import EnumDef, BoolDef, NumberDef
|
||||
|
||||
import os
|
||||
|
|
@ -14,6 +14,13 @@ class CreateReview(plugin.HoudiniCreator):
|
|||
label = "Review"
|
||||
product_type = "review"
|
||||
icon = "video-camera"
|
||||
review_color_space = ""
|
||||
|
||||
def apply_settings(self, project_settings):
|
||||
super(CreateReview, self).apply_settings(project_settings)
|
||||
color_settings = project_settings["houdini"]["imageio"]["workfile"]
|
||||
if color_settings["enabled"]:
|
||||
self.review_color_space = color_settings.get("review_color_space")
|
||||
|
||||
def create(self, product_name, instance_data, pre_create_data):
|
||||
|
||||
|
|
@ -85,10 +92,20 @@ class CreateReview(plugin.HoudiniCreator):
|
|||
|
||||
instance_node.setParms(parms)
|
||||
|
||||
# Set OCIO Colorspace to the default output colorspace
|
||||
# Set OCIO Colorspace to the default colorspace
|
||||
# if there's OCIO
|
||||
if os.getenv("OCIO"):
|
||||
self.set_colorcorrect_to_default_view_space(instance_node)
|
||||
# Fall to the default value if cls.review_color_space is empty.
|
||||
if not self.review_color_space:
|
||||
# cls.review_color_space is an empty string
|
||||
# when the imageio/workfile setting is disabled or
|
||||
# when the Review colorspace setting is empty.
|
||||
from ayon_core.hosts.houdini.api.colorspace import get_default_display_view_colorspace # noqa
|
||||
self.review_color_space = get_default_display_view_colorspace()
|
||||
|
||||
lib.set_review_color_space(instance_node,
|
||||
self.review_color_space,
|
||||
self.log)
|
||||
|
||||
to_lock = ["id", "productType"]
|
||||
|
||||
|
|
@ -131,23 +148,3 @@ class CreateReview(plugin.HoudiniCreator):
|
|||
minimum=0.0001,
|
||||
decimals=3)
|
||||
]
|
||||
|
||||
def set_colorcorrect_to_default_view_space(self,
|
||||
instance_node):
|
||||
"""Set ociocolorspace to the default output space."""
|
||||
from ayon_core.hosts.houdini.api.colorspace import get_default_display_view_colorspace # noqa
|
||||
|
||||
# set Color Correction parameter to OpenColorIO
|
||||
instance_node.setParms({"colorcorrect": 2})
|
||||
|
||||
# Get default view space for ociocolorspace parm.
|
||||
default_view_space = get_default_display_view_colorspace()
|
||||
instance_node.setParms(
|
||||
{"ociocolorspace": default_view_space}
|
||||
)
|
||||
|
||||
self.log.debug(
|
||||
"'OCIO Colorspace' parm on '{}' has been set to "
|
||||
"the default view color space '{}'"
|
||||
.format(instance_node, default_view_space)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ from ayon_core.hosts.houdini.api.lib import render_rop, splitext
|
|||
import hou
|
||||
|
||||
|
||||
class ExtractComposite(publish.Extractor):
|
||||
class ExtractComposite(publish.Extractor,
|
||||
publish.ColormanagedPyblishPluginMixin):
|
||||
|
||||
order = pyblish.api.ExtractorOrder
|
||||
label = "Extract Composite (Image Sequence)"
|
||||
|
|
@ -45,8 +46,14 @@ class ExtractComposite(publish.Extractor):
|
|||
"frameEnd": instance.data["frameEndHandle"],
|
||||
}
|
||||
|
||||
from pprint import pformat
|
||||
|
||||
self.log.info(pformat(representation))
|
||||
if ext.lower() == "exr":
|
||||
# Inject colorspace with 'scene_linear' as that's the
|
||||
# default Houdini working colorspace and all extracted
|
||||
# OpenEXR images should be in that colorspace.
|
||||
# https://www.sidefx.com/docs/houdini/render/linear.html#image-formats
|
||||
self.set_representation_colorspace(
|
||||
representation, instance.context,
|
||||
colorspace="scene_linear"
|
||||
)
|
||||
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ from ayon_core.hosts.houdini.api.lib import render_rop
|
|||
import hou
|
||||
|
||||
|
||||
class ExtractOpenGL(publish.Extractor):
|
||||
class ExtractOpenGL(publish.Extractor,
|
||||
publish.ColormanagedPyblishPluginMixin):
|
||||
|
||||
order = pyblish.api.ExtractorOrder - 0.01
|
||||
label = "Extract OpenGL"
|
||||
|
|
@ -46,6 +47,14 @@ class ExtractOpenGL(publish.Extractor):
|
|||
"camera_name": instance.data.get("review_camera")
|
||||
}
|
||||
|
||||
if ropnode.evalParm("colorcorrect") == 2: # OpenColorIO enabled
|
||||
colorspace = ropnode.evalParm("ociocolorspace")
|
||||
# inject colorspace data
|
||||
self.set_representation_colorspace(
|
||||
representation, instance.context,
|
||||
colorspace=colorspace
|
||||
)
|
||||
|
||||
if "representations" not in instance.data:
|
||||
instance.data["representations"] = []
|
||||
instance.data["representations"].append(representation)
|
||||
|
|
|
|||
|
|
@ -4,15 +4,19 @@ from ayon_core.pipeline import (
|
|||
PublishValidationError,
|
||||
OptionalPyblishPluginMixin
|
||||
)
|
||||
from ayon_core.pipeline.publish import RepairAction
|
||||
from ayon_core.pipeline.publish import (
|
||||
RepairAction,
|
||||
get_plugin_settings,
|
||||
apply_plugin_settings_automatically
|
||||
)
|
||||
from ayon_core.hosts.houdini.api.action import SelectROPAction
|
||||
|
||||
import os
|
||||
import hou
|
||||
|
||||
|
||||
class SetDefaultViewSpaceAction(RepairAction):
|
||||
label = "Set default view colorspace"
|
||||
class ResetViewSpaceAction(RepairAction):
|
||||
label = "Reset OCIO colorspace parm"
|
||||
icon = "mdi.monitor"
|
||||
|
||||
|
||||
|
|
@ -27,9 +31,25 @@ class ValidateReviewColorspace(pyblish.api.InstancePlugin,
|
|||
families = ["review"]
|
||||
hosts = ["houdini"]
|
||||
label = "Validate Review Colorspace"
|
||||
actions = [SetDefaultViewSpaceAction, SelectROPAction]
|
||||
actions = [ResetViewSpaceAction, SelectROPAction]
|
||||
|
||||
optional = True
|
||||
review_color_space = ""
|
||||
|
||||
@classmethod
|
||||
def apply_settings(cls, project_settings):
|
||||
# Preserve automatic settings applying logic
|
||||
settings = get_plugin_settings(plugin=cls,
|
||||
project_settings=project_settings,
|
||||
log=cls.log,
|
||||
category="houdini")
|
||||
apply_plugin_settings_automatically(cls, settings, logger=cls.log)
|
||||
|
||||
# Add review color settings
|
||||
color_settings = project_settings["houdini"]["imageio"]["workfile"]
|
||||
if color_settings["enabled"]:
|
||||
cls.review_color_space = color_settings.get("review_color_space")
|
||||
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
|
|
@ -52,39 +72,54 @@ class ValidateReviewColorspace(pyblish.api.InstancePlugin,
|
|||
" 'OpenColorIO'".format(rop_node.path())
|
||||
)
|
||||
|
||||
if rop_node.evalParm("ociocolorspace") not in \
|
||||
hou.Color.ocio_spaces():
|
||||
|
||||
current_color_space = rop_node.evalParm("ociocolorspace")
|
||||
if current_color_space not in hou.Color.ocio_spaces():
|
||||
raise PublishValidationError(
|
||||
"Invalid value: Colorspace name doesn't exist.\n"
|
||||
"Check 'OCIO Colorspace' parameter on '{}' ROP"
|
||||
.format(rop_node.path())
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def repair(cls, instance):
|
||||
"""Set Default View Space Action.
|
||||
# if houdini/imageio/workfile is enabled and
|
||||
# Review colorspace setting is empty then this check should
|
||||
# actually check if the current_color_space setting equals
|
||||
# the default colorspace value.
|
||||
# However, it will make the black cmd screen show up more often
|
||||
# which is very annoying.
|
||||
if self.review_color_space and \
|
||||
self.review_color_space != current_color_space:
|
||||
|
||||
It is a helper action more than a repair action,
|
||||
used to set colorspace on opengl node to the default view.
|
||||
"""
|
||||
from ayon_core.hosts.houdini.api.colorspace import get_default_display_view_colorspace # noqa
|
||||
|
||||
rop_node = hou.node(instance.data["instance_node"])
|
||||
|
||||
if rop_node.evalParm("colorcorrect") != 2:
|
||||
rop_node.setParms({"colorcorrect": 2})
|
||||
cls.log.debug(
|
||||
"'Color Correction' parm on '{}' has been set to"
|
||||
" 'OpenColorIO'".format(rop_node.path())
|
||||
raise PublishValidationError(
|
||||
"Invalid value: Colorspace name doesn't match"
|
||||
"the Colorspace specified in settings."
|
||||
)
|
||||
|
||||
# Get default view colorspace name
|
||||
default_view_space = get_default_display_view_colorspace()
|
||||
@classmethod
|
||||
def repair(cls, instance):
|
||||
"""Reset view colorspace.
|
||||
|
||||
rop_node.setParms({"ociocolorspace": default_view_space})
|
||||
cls.log.info(
|
||||
"'OCIO Colorspace' parm on '{}' has been set to "
|
||||
"the default view color space '{}'"
|
||||
.format(rop_node, default_view_space)
|
||||
)
|
||||
It is used to set colorspace on opengl node.
|
||||
|
||||
It uses the colorspace value specified in the Houdini addon settings.
|
||||
If the value in the Houdini addon settings is empty,
|
||||
it will fall to the default colorspace.
|
||||
|
||||
Note:
|
||||
This repair action assumes that OCIO is enabled.
|
||||
As if OCIO is disabled the whole validation is skipped
|
||||
and this repair action won't show up.
|
||||
"""
|
||||
from ayon_core.hosts.houdini.api.lib import set_review_color_space
|
||||
|
||||
# Fall to the default value if cls.review_color_space is empty.
|
||||
if not cls.review_color_space:
|
||||
# cls.review_color_space is an empty string
|
||||
# when the imageio/workfile setting is disabled or
|
||||
# when the Review colorspace setting is empty.
|
||||
from ayon_core.hosts.houdini.api.colorspace import get_default_display_view_colorspace # noqa
|
||||
cls.review_color_space = get_default_display_view_colorspace()
|
||||
|
||||
rop_node = hou.node(instance.data["instance_node"])
|
||||
set_review_color_space(rop_node,
|
||||
cls.review_color_space,
|
||||
cls.log)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
name = "houdini"
|
||||
title = "Houdini"
|
||||
version = "0.2.12"
|
||||
version = "0.2.13"
|
||||
|
|
|
|||
|
|
@ -34,6 +34,34 @@ class ImageIOFileRulesModel(BaseSettingsModel):
|
|||
return value
|
||||
|
||||
|
||||
class WorkfileImageIOModel(BaseSettingsModel):
|
||||
"""Workfile settings help.
|
||||
|
||||
Empty values will be skipped, allowing any existing env vars to
|
||||
pass through as defined.
|
||||
|
||||
Note: The render space in Houdini is
|
||||
always set to the 'scene_linear' role."""
|
||||
|
||||
enabled: bool = SettingsField(False, title="Enabled")
|
||||
default_display: str = SettingsField(
|
||||
title="Default active displays",
|
||||
description="It behaves like the 'OCIO_ACTIVE_DISPLAYS' env var,"
|
||||
" Colon-separated list of displays, e.g ACES:P3"
|
||||
)
|
||||
default_view: str = SettingsField(
|
||||
title="Default active views",
|
||||
description="It behaves like the 'OCIO_ACTIVE_VIEWS' env var,"
|
||||
" Colon-separated list of views, e.g sRGB:DCDM"
|
||||
)
|
||||
review_color_space: str = SettingsField(
|
||||
title="Review colorspace",
|
||||
description="It exposes OCIO Colorspace parameter in opengl nodes."
|
||||
"if left empty, Ayon will figure out the default "
|
||||
"colorspace using your default display and default view."
|
||||
)
|
||||
|
||||
|
||||
class HoudiniImageIOModel(BaseSettingsModel):
|
||||
activate_host_color_management: bool = SettingsField(
|
||||
True, title="Enable Color Management"
|
||||
|
|
@ -46,3 +74,26 @@ class HoudiniImageIOModel(BaseSettingsModel):
|
|||
default_factory=ImageIOFileRulesModel,
|
||||
title="File Rules"
|
||||
)
|
||||
workfile: WorkfileImageIOModel = SettingsField(
|
||||
default_factory=WorkfileImageIOModel,
|
||||
title="Workfile"
|
||||
)
|
||||
|
||||
|
||||
DEFAULT_IMAGEIO_SETTINGS = {
|
||||
"activate_host_color_management": False,
|
||||
"ocio_config": {
|
||||
"override_global_config": False,
|
||||
"filepath": []
|
||||
},
|
||||
"file_rules": {
|
||||
"activate_host_rules": False,
|
||||
"rules": []
|
||||
},
|
||||
"workfile": {
|
||||
"enabled": False,
|
||||
"default_display": "ACES",
|
||||
"default_view": "sRGB",
|
||||
"review_color_space": ""
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@ from .general import (
|
|||
GeneralSettingsModel,
|
||||
DEFAULT_GENERAL_SETTINGS
|
||||
)
|
||||
from .imageio import HoudiniImageIOModel
|
||||
from .imageio import (
|
||||
HoudiniImageIOModel,
|
||||
DEFAULT_IMAGEIO_SETTINGS
|
||||
)
|
||||
from .shelves import ShelvesModel
|
||||
from .create import (
|
||||
CreatePluginsModel,
|
||||
|
|
@ -40,6 +43,7 @@ class HoudiniSettings(BaseSettingsModel):
|
|||
|
||||
DEFAULT_VALUES = {
|
||||
"general": DEFAULT_GENERAL_SETTINGS,
|
||||
"imageio": DEFAULT_IMAGEIO_SETTINGS,
|
||||
"shelves": [],
|
||||
"create": DEFAULT_HOUDINI_CREATE_SETTINGS,
|
||||
"publish": DEFAULT_HOUDINI_PUBLISH_SETTINGS
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue