diff --git a/client/ayon_core/plugins/publish/collect_resources_path.py b/client/ayon_core/plugins/publish/collect_resources_path.py index 75199e9eec..244045c095 100644 --- a/client/ayon_core/plugins/publish/collect_resources_path.py +++ b/client/ayon_core/plugins/publish/collect_resources_path.py @@ -65,7 +65,7 @@ class CollectResourcesPath(pyblish.api.InstancePlugin): "xgen", "yeticacheUE", "tycache", - "OxRig" + "oxrig" ] def process(self, instance): diff --git a/server_addon/maya/client/ayon_maya/api/lib.py b/server_addon/maya/client/ayon_maya/api/lib.py index 2b41ffc06c..6776d26a71 100644 --- a/server_addon/maya/client/ayon_maya/api/lib.py +++ b/server_addon/maya/client/ayon_maya/api/lib.py @@ -4232,3 +4232,77 @@ def get_node_index_under_parent(node: str) -> int: return cmds.listRelatives(parent, children=True, fullPath=True).index(node) + + +def search_textures(filepath): + """Search all texture files on disk. + + This also parses to full sequences for those with dynamic patterns + like and %04d in the filename. + + Args: + filepath (str): The full path to the file, including any + dynamic patterns like or %04d + + Returns: + list: The files found on disk + + """ + filename = os.path.basename(filepath) + + # Collect full sequence if it matches a sequence pattern + if len(filename.split(".")) > 2: + + # For UDIM based textures (tiles) + if "" in filename: + sequences = get_sequence(filepath, + pattern="") + if sequences: + return sequences + + # Frame/time - Based textures (animated masks f.e) + elif "%04d" in filename: + sequences = get_sequence(filepath, + pattern="%04d") + if sequences: + return sequences + + # Assuming it is a fixed name (single file) + if os.path.exists(filepath): + return [filepath] + + return [] + + +def get_sequence(filepath, pattern="%04d"): + """Get sequence from filename. + + This will only return files if they exist on disk as it tries + to collect the sequence using the filename pattern and searching + for them on disk. + + Supports negative frame ranges like -001, 0000, 0001 and -0001, + 0000, 0001. + + Arguments: + filepath (str): The full path to filename containing the given + pattern. + pattern (str): The pattern to swap with the variable frame number. + + Returns: + list: file sequence. + + """ + import clique + + escaped = re.escape(filepath) + re_pattern = escaped.replace(pattern, "-?[0-9]+") + + source_dir = os.path.dirname(filepath) + files = [f for f in os.listdir(source_dir) + if re.match(re_pattern, f)] + + pattern = [clique.PATTERNS["frames"]] + collection, remainder = clique.assemble(files, patterns=pattern) + + return collection diff --git a/server_addon/maya/client/ayon_maya/plugins/create/create_ornatrix_cache.py b/server_addon/maya/client/ayon_maya/plugins/create/create_ornatrix_cache.py index 91cdb44440..8f57151ea8 100644 --- a/server_addon/maya/client/ayon_maya/plugins/create/create_ornatrix_cache.py +++ b/server_addon/maya/client/ayon_maya/plugins/create/create_ornatrix_cache.py @@ -8,9 +8,9 @@ from ayon_core.lib import BoolDef, NumberDef class CreateOxCache(plugin.MayaCreator): """Output for procedural plugin nodes of Ornatrix """ - identifier = "io.openpype.creators.maya.OxCache" + identifier = "io.openpype.creators.maya.oxcache" label = "Ornatrix Cache" - product_type = "OxCache" + product_type = "oxcache" icon = "pagelines" def get_instance_attr_defs(self): diff --git a/server_addon/maya/client/ayon_maya/plugins/create/create_ornatrix_rig.py b/server_addon/maya/client/ayon_maya/plugins/create/create_ornatrix_rig.py index d87dc3a153..ded7f968ff 100644 --- a/server_addon/maya/client/ayon_maya/plugins/create/create_ornatrix_rig.py +++ b/server_addon/maya/client/ayon_maya/plugins/create/create_ornatrix_rig.py @@ -9,9 +9,9 @@ from ayon_maya.api import ( class CreateOxRig(plugin.MayaCreator): """Output for Ornatrix nodes""" - identifier = "io.openpype.creators.maya.OxRig" + identifier = "io.openpype.creators.maya.oxrig" label = "Ornatrix Rig" - product_type = "OxRig" + product_type = "oxrig" icon = "usb" def create(self, product_name, instance_data, pre_create_data): diff --git a/server_addon/maya/client/ayon_maya/plugins/load/load_arnold_standin.py b/server_addon/maya/client/ayon_maya/plugins/load/load_arnold_standin.py index 8d44ce5f64..e5bcd736c6 100644 --- a/server_addon/maya/client/ayon_maya/plugins/load/load_arnold_standin.py +++ b/server_addon/maya/client/ayon_maya/plugins/load/load_arnold_standin.py @@ -34,7 +34,7 @@ class ArnoldStandinLoader(plugin.Loader): "proxyAbc", "pointcache", "usd", - "OxCache" + "oxcache" } representations = {"ass", "abc", "usda", "usdc", "usd"} diff --git a/server_addon/maya/client/ayon_maya/plugins/load/load_ornatrix_rig.py b/server_addon/maya/client/ayon_maya/plugins/load/load_ornatrix_rig.py index 20bd033717..1046dc5bf1 100644 --- a/server_addon/maya/client/ayon_maya/plugins/load/load_ornatrix_rig.py +++ b/server_addon/maya/client/ayon_maya/plugins/load/load_ornatrix_rig.py @@ -11,7 +11,7 @@ from ayon_maya.api import lib, plugin class OxRigLoader(plugin.ReferenceLoader): """This loader will load Ornatix rig.""" - product_types = {"OxRig"} + product_types = {"oxrig"} representations = {"ma"} label = "Load Ornatrix Rig" @@ -27,6 +27,13 @@ class OxRigLoader(plugin.ReferenceLoader): ): path = self.filepath_from_context(context) + # Check if the plugin for Ornatrix is available on the pc + try: + cmds.loadPlugin("Ornatrix.mll", quiet=True) + except Exception as exc: + self.log.error("Encountered exception:\n%s" % exc) + return + attach_to_root = options.get("attach_to_root", True) group_name = options["group_name"] @@ -86,7 +93,7 @@ class OxRigLoader(plugin.ReferenceLoader): node.endswith("input_SET")), None) self.log.info("Creating variant: {}".format(variant)) - creator_identifier = "io.openpype.creators.maya.OxCache" + creator_identifier = "io.openpype.creators.maya.oxcache" host = registered_host() create_context = CreateContext(host) @@ -99,7 +106,6 @@ class OxRigLoader(plugin.ReferenceLoader): pre_create_data={"use_selection": True} ) - def use_resources_textures(self, namespace, path): """Use texture maps from resources directories @@ -107,15 +113,16 @@ class OxRigLoader(plugin.ReferenceLoader): namespace (str): namespace path (str): published filepath """ - _, maya_extension = os.path.splitext(path) - settings_path = path.replace(maya_extension, ".rigsettings") + path_no_ext, _ = os.path.splitext(path) + settings_path = f"{path_no_ext}.rigsettings" with open(settings_path, "r") as fp: image_attributes = json.load(fp) - fp.close() - if image_attributes: - for image_attribute in image_attributes: - texture_attribute = "{}:{}".format( - namespace, image_attribute["texture_attribute"]) - cmds.setAttr(texture_attribute, - image_attribute["destination_file"], - type="string") + + if not image_attributes: + return + for image_attribute in image_attributes: + texture_attribute = "{}:{}".format( + namespace, image_attribute["texture_attribute"]) + cmds.setAttr(texture_attribute, + image_attribute["destination_file"], + type="string") diff --git a/server_addon/maya/client/ayon_maya/plugins/load/load_vrayproxy.py b/server_addon/maya/client/ayon_maya/plugins/load/load_vrayproxy.py index 2dc6014761..836aab6f31 100644 --- a/server_addon/maya/client/ayon_maya/plugins/load/load_vrayproxy.py +++ b/server_addon/maya/client/ayon_maya/plugins/load/load_vrayproxy.py @@ -20,7 +20,7 @@ from ayon_maya.api.plugin import get_load_color_for_product_type class VRayProxyLoader(plugin.Loader): """Load VRay Proxy with Alembic or VrayMesh.""" - product_types = {"vrayproxy", "model", "pointcache", "animation", "OxCache"} + product_types = {"vrayproxy", "model", "pointcache", "animation", "oxcache"} representations = {"vrmesh", "abc"} label = "Import VRay Proxy" diff --git a/server_addon/maya/client/ayon_maya/plugins/publish/collect_ornatrix_cache.py b/server_addon/maya/client/ayon_maya/plugins/publish/collect_ornatrix_cache.py index f9d8fce2d1..dbb793c85a 100644 --- a/server_addon/maya/client/ayon_maya/plugins/publish/collect_ornatrix_cache.py +++ b/server_addon/maya/client/ayon_maya/plugins/publish/collect_ornatrix_cache.py @@ -5,13 +5,11 @@ from maya import cmds class CollectOxCache(plugin.MayaInstancePlugin): - """Collect all information of the Ornatrix caches - - """ + """Collect all information of the Ornatrix caches""" order = pyblish.api.CollectorOrder + 0.45 label = "Collect Ornatrix Cache" - families = ["OxRig", "OxCache"] + families = ["oxrig", "oxcache"] def process(self, instance): @@ -22,8 +20,8 @@ class CollectOxCache(plugin.MayaInstancePlugin): parent = cmds.listRelatives(ox_shape, parent=True)[0] transform_data = {"name": parent, "cbId": lib.get_id(parent)} ox_cache_nodes = [ - ox_node for ox_node in cmds.listConnections(ox_shape, destination=True) - if cmds.nodeType(ox_node) == "HairFromGuidesNode" + ox_node for ox_node in cmds.listConnections( + ox_shape, destination=True, type="HairFromGuidesNode") ] # transfer cache file shape_data = { diff --git a/server_addon/maya/client/ayon_maya/plugins/publish/collect_ornatrix_rig.py b/server_addon/maya/client/ayon_maya/plugins/publish/collect_ornatrix_rig.py new file mode 100644 index 0000000000..7a00716e9e --- /dev/null +++ b/server_addon/maya/client/ayon_maya/plugins/publish/collect_ornatrix_rig.py @@ -0,0 +1,94 @@ +import os +import re + +import pyblish.api +from ayon_core.pipeline.publish import KnownPublishError +from ayon_maya.api import lib +from ayon_maya.api import plugin +from maya import cmds + + +ORNATRIX_NODES = { + "HairFromGuidesNode", "GuidesFromMeshNode", + "MeshFromStrandsNode", "SurfaceCombNode" +} + + +class CollectOxRig(plugin.MayaInstancePlugin): + """Collect all information of the Ornatrix Rig""" + + order = pyblish.api.CollectorOrder + 0.4 + label = "Collect Ornatrix Rig" + families = ["oxrig"] + + def process(self, instance): + assert "input_SET" in instance.data["setMembers"], ( + "Ornatrix Rig must have an input_SET") + + ornatrix_nodes = cmds.ls(instance[:], long=True) + self.log.debug(f"Getting ornatrix nodes: {ornatrix_nodes}") + # Force frame range for yeti cache export for the rig + # Collect any textures if used + ornatrix_resources = [] + for node in ornatrix_nodes: + # Get Yeti resources (textures) + resources = self.get_texture_resources(node) + ornatrix_resources.extend(resources) + # avoid duplicate dictionary data + instance.data["resources"] = [ + i for n, i in enumerate(ornatrix_resources) + if i not in ornatrix_resources[n + 1:] + ] + self.log.debug("{}".format(instance.data["resources"])) + start = cmds.playbackOptions(query=True, animationStartTime=True) + for key in ["frameStart", "frameEnd", + "frameStartHandle", "frameEndHandle"]: + instance.data[key] = start + + def get_texture_resources(self, node): + resources = [] + node_shape = cmds.listRelatives(node, shapes=True) + if not node_shape: + return [] + + ox_nodes = [ + ox_node for ox_node in cmds.listConnections(node_shape, destination=True) + if cmds.nodeType(ox_node) in ORNATRIX_NODES + ] + ox_image_file = [ + ox_img for ox_img in cmds.listConnections(ox_nodes, destination=False) + if cmds.nodeType(ox_img) == "file" + ] + if not ox_image_file: + return [] + + for img in ox_image_file: + texture_attr = "{}.fileTextureName".format(img) + texture = cmds.getAttr("{}.fileTextureName".format(img)) + files = [] + if os.path.isabs(texture): + self.log.debug("Texture is absolute path, ignoring " + "image search paths for: %s" % texture) + files = lib.search_textures(texture) + else: + root = os.environ["AYON_WORKDIR"] + filepath = os.path.join(root, texture) + files = lib.search_textures(filepath) + if files: + # Break out on first match in search paths.. + break + + if not files: + raise KnownPublishError( + "No texture found for: %s " + "(searched: %s)" % (texture)) + + item = { + "files": files, + "source": texture, + "texture_attribute": texture_attr + } + + resources.append(item) + + return resources diff --git a/server_addon/maya/client/ayon_maya/plugins/publish/collect_yeti_rig.py b/server_addon/maya/client/ayon_maya/plugins/publish/collect_yeti_rig.py index 7b2b0cc75e..5e17686756 100644 --- a/server_addon/maya/client/ayon_maya/plugins/publish/collect_yeti_rig.py +++ b/server_addon/maya/client/ayon_maya/plugins/publish/collect_yeti_rig.py @@ -15,12 +15,6 @@ SETTINGS = {"renderDensity", "cbId"} -ORNATRIX_NODES = { - "HairFromGuidesNode", "GuidesFromMeshNode", - "MeshFromStrandsNode", "SurfaceCombNode" -} - - class CollectYetiRig(plugin.MayaInstancePlugin): """Collect all information of the Yeti Rig""" @@ -156,11 +150,11 @@ class CollectYetiRig(plugin.MayaInstancePlugin): if os.path.isabs(texture): self.log.debug("Texture is absolute path, ignoring " "image search paths for: %s" % texture) - files = self.search_textures(texture) + files = lib.search_textures(texture) else: for root in image_search_paths: filepath = os.path.join(root, texture) - files = self.search_textures(filepath) + files = lib.search_textures(filepath) if files: # Break out on first match in search paths.. break @@ -207,7 +201,7 @@ class CollectYetiRig(plugin.MayaInstancePlugin): ref_file_name = os.path.basename(ref_file) if "%04d" in ref_file_name: - item["files"] = self.get_sequence(ref_file) + item["files"] = lib.get_sequence(ref_file) else: if os.path.exists(ref_file) and os.path.isfile(ref_file): item["files"] = [ref_file] @@ -221,173 +215,3 @@ class CollectYetiRig(plugin.MayaInstancePlugin): resources.append(item) return resources - - def search_textures(self, filepath): - """Search all texture files on disk. - - This also parses to full sequences for those with dynamic patterns - like and %04d in the filename. - - Args: - filepath (str): The full path to the file, including any - dynamic patterns like or %04d - - Returns: - list: The files found on disk - - """ - filename = os.path.basename(filepath) - - # Collect full sequence if it matches a sequence pattern - if len(filename.split(".")) > 2: - - # For UDIM based textures (tiles) - if "" in filename: - sequences = self.get_sequence(filepath, - pattern="") - if sequences: - return sequences - - # Frame/time - Based textures (animated masks f.e) - elif "%04d" in filename: - sequences = self.get_sequence(filepath, - pattern="%04d") - if sequences: - return sequences - - # Assuming it is a fixed name (single file) - if os.path.exists(filepath): - return [filepath] - - return [] - - def get_sequence(self, filepath, pattern="%04d"): - """Get sequence from filename. - - This will only return files if they exist on disk as it tries - to collect the sequence using the filename pattern and searching - for them on disk. - - Supports negative frame ranges like -001, 0000, 0001 and -0001, - 0000, 0001. - - Arguments: - filepath (str): The full path to filename containing the given - pattern. - pattern (str): The pattern to swap with the variable frame number. - - Returns: - list: file sequence. - - """ - import clique - - escaped = re.escape(filepath) - re_pattern = escaped.replace(pattern, "-?[0-9]+") - - source_dir = os.path.dirname(filepath) - files = [f for f in os.listdir(source_dir) - if re.match(re_pattern, f)] - - pattern = [clique.PATTERNS["frames"]] - collection, remainder = clique.assemble(files, patterns=pattern) - - return collection - - def _replace_tokens(self, strings): - env_re = re.compile(r"\$\{(\w+)\}") - - replaced = [] - for s in strings: - matches = re.finditer(env_re, s) - for m in matches: - try: - s = s.replace(m.group(), os.environ[m.group(1)]) - except KeyError: - msg = "Cannot find requested {} in environment".format( - m.group(1)) - self.log.error(msg) - raise RuntimeError(msg) - replaced.append(s) - return replaced - - -class CollectOxRig(CollectYetiRig): - """Collect all information of the Ornatrix Rig""" - - order = pyblish.api.CollectorOrder + 0.4 - label = "Collect Ornatrix Rig" - families = ["OxRig"] - - def process(self, instance): - assert "input_SET" in instance.data["setMembers"], ( - "Ornatrix Rig must have an input_SET") - - ornatrix_nodes = cmds.ls(instance[:], long=True) - self.log.debug(f"Getting ornatrix nodes: {ornatrix_nodes}") - # Force frame range for yeti cache export for the rig - # Collect any textures if used - ornatrix_resources = [] - for node in ornatrix_nodes: - # Get Yeti resources (textures) - resources = self.get_texture_resources(node) - ornatrix_resources.extend(resources) - # avoid duplicate dictionary data - instance.data["resources"] = [ - i for n, i in enumerate(ornatrix_resources) - if i not in ornatrix_resources[n + 1:] - ] - self.log.debug("{}".format(instance.data["resources"])) - start = cmds.playbackOptions(query=True, animationStartTime=True) - for key in ["frameStart", "frameEnd", - "frameStartHandle", "frameEndHandle"]: - instance.data[key] = start - - def get_texture_resources(self, node): - # add docstrings - resources = [] - node_shape = cmds.listRelatives(node, shapes=True) - if not node_shape: - return [] - - ox_nodes = [ - ox_node for ox_node in cmds.listConnections(node_shape, destination=True) - if cmds.nodeType(ox_node) in ORNATRIX_NODES - ] - ox_imageFile = [ - ox_img for ox_img in cmds.listConnections(ox_nodes, destination=False) - if cmds.nodeType(ox_img) == "file" - ] - if not ox_imageFile: - return [] - - for img in ox_imageFile: - texture_attr = "{}.fileTextureName".format(img) - texture = cmds.getAttr("{}.fileTextureName".format(img)) - files = [] - if os.path.isabs(texture): - self.log.debug("Texture is absolute path, ignoring " - "image search paths for: %s" % texture) - files = self.search_textures(texture) - else: - root = os.environ["AYON_WORKDIR"] - filepath = os.path.join(root, texture) - files = self.search_textures(filepath) - if files: - # Break out on first match in search paths.. - break - - if not files: - raise KnownPublishError( - "No texture found for: %s " - "(searched: %s)" % (texture)) - - item = { - "files": files, - "source": texture, - "texture_attribute": texture_attr - } - - resources.append(item) - - return resources diff --git a/server_addon/maya/client/ayon_maya/plugins/publish/extract_ornatrix_cache.py b/server_addon/maya/client/ayon_maya/plugins/publish/extract_ornatrix_cache.py index 6e5e6193e9..320d0abb69 100644 --- a/server_addon/maya/client/ayon_maya/plugins/publish/extract_ornatrix_cache.py +++ b/server_addon/maya/client/ayon_maya/plugins/publish/extract_ornatrix_cache.py @@ -12,9 +12,10 @@ class ExtractOxCache(plugin.MayaExtractorPlugin): """ label = "Extract Ornatrix Cache" - families = ["OxRig", "OxCache"] + families = ["oxrig", "oxcache"] def process(self, instance): + cmds.loadPlugin("Ornatrix.mll", quiet=True) # Define extract output file path ox_nodes = cmds.ls(instance[:], long=True) dirname = self.staging_dir(instance) diff --git a/server_addon/maya/client/ayon_maya/plugins/publish/extract_ornatrix_rig.py b/server_addon/maya/client/ayon_maya/plugins/publish/extract_ornatrix_rig.py index 77ce41f947..2bdbfa3c89 100644 --- a/server_addon/maya/client/ayon_maya/plugins/publish/extract_ornatrix_rig.py +++ b/server_addon/maya/client/ayon_maya/plugins/publish/extract_ornatrix_rig.py @@ -9,16 +9,16 @@ from ayon_maya.api import plugin from maya import cmds - class ExtractxRig(plugin.MayaExtractorPlugin): """Extract the Ornatrix rig to a Maya Scene and write the Ornatrix rig data.""" label = "Extract Ornatrix Rig" - families = ["OxRig"] + families = ["oxrig"] scene_type = "ma" def process(self, instance): """Plugin entry point.""" + cmds.loadPlugin("Ornatrix.mll", quiet=True) maya_settings = instance.context.data["project_settings"]["maya"] ext_mapping = { item["name"]: item["value"] diff --git a/server_addon/maya/client/ayon_maya/plugins/publish/validate_frame_range.py b/server_addon/maya/client/ayon_maya/plugins/publish/validate_frame_range.py index 46e1d41255..04834c21c8 100644 --- a/server_addon/maya/client/ayon_maya/plugins/publish/validate_frame_range.py +++ b/server_addon/maya/client/ayon_maya/plugins/publish/validate_frame_range.py @@ -33,7 +33,7 @@ class ValidateFrameRange(plugin.MayaInstancePlugin, "renderlayer", "review", "yeticache", - "OxCache"] + "oxcache"] optional = True actions = [RepairAction] exclude_product_types = [] diff --git a/server_addon/maya/package.py b/server_addon/maya/package.py index e0fc2ee5cf..17614ed9c1 100644 --- a/server_addon/maya/package.py +++ b/server_addon/maya/package.py @@ -1,6 +1,6 @@ name = "maya" title = "Maya" -version = "0.2.3" +version = "0.2.4" client_dir = "ayon_maya" ayon_required_addons = { diff --git a/server_addon/maya/server/settings/creators.py b/server_addon/maya/server/settings/creators.py index 5f3b850a1f..2931ed7aa2 100644 --- a/server_addon/maya/server/settings/creators.py +++ b/server_addon/maya/server/settings/creators.py @@ -205,6 +205,14 @@ class CreatorsModel(BaseSettingsModel): default_factory=BasicCreatorModel, title="Create Maya Scene" ) + CreateOxRig: BasicCreatorModel = SettingsField( + default_factory=BasicCreatorModel, + title="Create Ornatrix Rig" + ) + CreateOxCache: BasicCreatorModel = SettingsField( + default_factory=BasicCreatorModel, + title="Create Ornatrix Cache" + ) CreateRenderSetup: BasicCreatorModel = SettingsField( default_factory=BasicCreatorModel, title="Create Render Setup" @@ -373,6 +381,18 @@ DEFAULT_CREATORS_SETTINGS = { "Main" ] }, + "CreateOxRig": { + "enabled": False, + "default_variants": [ + "Main" + ] + }, + "CreateOxCache": { + "enabled": False, + "default_variants": [ + "Main" + ] + }, "CreateRenderSetup": { "enabled": True, "default_variants": [ diff --git a/server_addon/maya/server/settings/loaders.py b/server_addon/maya/server/settings/loaders.py index e7515ab5d3..6ae1d7cabf 100644 --- a/server_addon/maya/server/settings/loaders.py +++ b/server_addon/maya/server/settings/loaders.py @@ -39,7 +39,9 @@ class ColorsSetting(BaseSettingsModel): (99, 206, 220, 1.0), title="Yeti Cache:") yetiRig: ColorRGBA_uint8 = SettingsField( (0, 205, 125, 1.0), title="Yeti Rig:") - OxRig: ColorRGBA_uint8 = SettingsField( + oxCache: ColorRGBA_uint8 = SettingsField( + (156, 234, 195, 1.0), title="Ornatrix Cache:") + oxRig: ColorRGBA_uint8 = SettingsField( (206, 234, 195, 1.0), title="Ornatrix Rig:") # model: ColorRGB_float = SettingsField( # (0.82, 0.52, 0.12), title="Model:" @@ -223,6 +225,10 @@ class LoadersModel(BaseSettingsModel): default_factory=YetiRigLoaderModel, title="Yeti Rig Loader" ) + OxCacheLoader: LoaderEnabledModel = SettingsField( + default_factory=LoaderEnabledModel, + title="Ornatrix Cache Loader" + ) OxRigLoader: OxRigLoaderModel = SettingsField( default_factory=OxRigLoaderModel, title="Ornatrix Rig Loader" @@ -246,7 +252,9 @@ DEFAULT_LOADERS_SETTING = { "vrayproxy": [255, 150, 12, 1.0], "vrayscene_layer": [255, 150, 12, 1.0], "yeticache": [99, 206, 220, 1.0], - "yetiRig": [0, 205, 125, 1.0] + "yetiRig": [0, 205, 125, 1.0], + "oxCache": [156, 234, 195, 1.0], + "oxRig": [206, 234, 195, 1.0] # "model": [0.82, 0.52, 0.12], # "rig": [0.23, 0.89, 0.92], # "pointcache": [0.37, 0.82, 0.12], @@ -294,6 +302,7 @@ DEFAULT_LOADERS_SETTING = { "VRaySceneLoader": {"enabled": True}, "XgenLoader": {"enabled": True}, "YetiCacheLoader": {"enabled": True}, + "OxCacheLoader": {"enabled": True}, "YetiRigLoader": { "enabled": True, "create_cache_instance_on_load": True