diff --git a/openpype/hosts/maya/plugins/create/create_multiverse_look.py b/openpype/hosts/maya/plugins/create/create_multiverse_look.py index b2b9b5bb29..44977efca0 100644 --- a/openpype/hosts/maya/plugins/create/create_multiverse_look.py +++ b/openpype/hosts/maya/plugins/create/create_multiverse_look.py @@ -12,3 +12,4 @@ class CreateMultiverseLook(plugin.Creator): def __init__(self, *args, **kwargs): super(CreateMultiverseLook, self).__init__(*args, **kwargs) self.data["fileFormat"] = ["usda", "usd"] + self.data["expectMipMap"] = True diff --git a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py index c5ea6a2253..6bf4cecc3a 100644 --- a/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py +++ b/openpype/hosts/maya/plugins/publish/collect_multiverse_look.py @@ -17,6 +17,9 @@ SHAPE_ATTRS = ["castsShadows", "opposite"] SHAPE_ATTRS = set(SHAPE_ATTRS) +COLOUR_SPACES = ['sRGB'] +MIPMAP_EXTENSIONS = ['tdl'] + def get_look_attrs(node): """Returns attributes of a node that are important for the look. @@ -103,7 +106,7 @@ def seq_to_glob(path): "": "", "#": "#", "u_v": "|", - "", #noqa - copied from collect_look.py + "", # noqa - copied from collect_look.py "": "" } @@ -189,6 +192,22 @@ def get_file_node_files(node): return [] +def get_mipmap(fname): + for colour_space in COLOUR_SPACES: + for mipmap_ext in MIPMAP_EXTENSIONS: + mipmap_fname = '.'.join([fname, colour_space, mipmap_ext]) + if os.path.exists(mipmap_fname): + return mipmap_fname + return None + + +def is_mipamp(fname): + ext = os.path.splitext(fname)[1][1:] + if ext in MIPMAP_EXTENSIONS: + return True + return False + + class CollectMultiverseLookData(pyblish.api.InstancePlugin): """Collect Multiverse Look @@ -219,6 +238,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): files = [] sets = {} instance.data["resources"] = [] + expectMipMap = instance.data["expectMipMap"] for node in nodes: self.log.info("Getting resources for '{}'".format(node)) @@ -242,7 +262,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): files = cmds.ls(history, type="file", long=True) for f in files: - resources = self.collect_resource(f) + resources = self.collect_resource(f, expectMipMap) instance.data["resources"].append(resources) elif isinstance(matOver, multiverse.MaterialSourceUsdPath): @@ -255,7 +275,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): "relationships": sets } - def collect_resource(self, node): + def collect_resource(self, node, expectMipMap): """Collect the link to the file(s) used (resource) Args: node (str): name of the node @@ -310,6 +330,7 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): source = source.replace("\\", "/") files = get_file_node_files(node) + files = self.handle_files(files, expectMipMap) if len(files) == 0: self.log.error("No valid files found from node `%s`" % node) @@ -326,3 +347,26 @@ class CollectMultiverseLookData(pyblish.api.InstancePlugin): "source": source, # required for resources "files": files, "color_space": color_space} # required for resources + + def handle_files(self, files, expectMipMap): + """This will go through all the files and make sure that they are + either already mipmapped or have a corresponding mipmap sidecar and + add that to the list.""" + if not expectMipMap: + return files + + extra_files = [] + self.log.debug("Expecting MipMaps, going to look for them.") + for fname in files: + self.log.info("Checking '{}' for mipmaps".format(fname)) + if is_mipamp(fname): + self.log.debug(" - file is already MipMap, skipping.") + continue + + mipmap = get_mipmap(fname) + if mipmap: + self.log.info(" mipmap found for '{}'".format(fname)) + extra_files.append(mipmap) + else: + self.log.warning(" no mipmap found for '{}'".format(fname)) + return files + extra_files diff --git a/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py b/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py new file mode 100644 index 0000000000..8f31cd4753 --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/validate_mvlook_contents.py @@ -0,0 +1,93 @@ +import pyblish.api +import openpype.api +import openpype.hosts.maya.api.action + +import os +import pprint + +COLOUR_SPACES = ['sRGB'] +MIPMAP_EXTENSIONS = ['tdl'] + + +class ValidateMvLookContents(pyblish.api.InstancePlugin): + order = openpype.api.ValidateContentsOrder + families = ['mvLook'] + hosts = ['maya'] + label = 'Validate mvLook Data' + actions = [openpype.hosts.maya.api.action.SelectInvalidAction] + + # Allow this validation step to be skipped when you just need to + # get things pushed through. + optional = True + + # These intents get enforced checks, other ones get warnings. + enforced_intents = ['-', 'Final'] + + def process(self, instance): + intent = instance.context.data['intent']['value'] + expectMipMap = instance.data["expectMipMap"] + enforced = True + if intent in self.enforced_intents: + self.log.info("This validation will be enforced: '{}'" + .format(intent)) + else: + enforced = False + self.log.info("This validation will NOT be enforced: '{}'" + .format(intent)) + + if not instance[:]: + raise RuntimeError("Instance is empty") + + invalid = set() + + resources = instance.data.get("resources", []) + for resource in resources: + files = resource["files"] + self.log.debug("Resouce '{}', files: [{}]".format(resource, files)) + node = resource["node"] + if len(files) == 0: + self.log.error("File node '{}' uses no or non-existing " + "files".format(node)) + invalid.add(node) + continue + for fname in files: + if not self.valid_file(fname): + self.log.error("File node '{}'/'{}' is not valid" + .format(node, fname)) + invalid.add(node) + + if expectMipMap and not self.is_or_has_mipmap(fname, files): + msg = "File node '{}'/'{}' does not have a mipmap".format( + node, fname) + if enforced: + invalid.add(node) + self.log.error(msg) + raise RuntimeError(msg) + else: + self.log.warning(msg) + + if invalid: + raise RuntimeError("'{}' has invalid look " + "content".format(instance.name)) + + def valid_file(self, fname): + self.log.debug("Checking validity of '{}'".format(fname)) + if not os.path.exists(fname): + return False + if os.path.getsize(fname) == 0: + return False + return True + + def is_or_has_mipmap(self, fname, files): + ext = os.path.splitext(fname)[1][1:] + if ext in MIPMAP_EXTENSIONS: + self.log.debug("Is a mipmap '{}'".format(fname)) + return True + + for colour_space in COLOUR_SPACES: + for mipmap_ext in MIPMAP_EXTENSIONS: + mipmap_fname = '.'.join([fname, colour_space, mipmap_ext]) + if mipmap_fname in files: + self.log.debug("Has a mipmap '{}'".format(fname)) + return True + return False