mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-26 13:52:15 +01:00
Expanding the scope of mvLook to publish mipmapped textures too, like TDL's
generated by 3delight. During collection, we check to see if the TDL's exist beside the original texture, and if they do they get added to the collection. Validation of these will depend on the publish intent and whether `expectMipMap` is True in the publish set. If mipmaps are expected and the intent is correct, the mipmaps will be published along with the original file, which will accelerate rendering, since 3dl will find that TDL and use it instead of having to generate it.
This commit is contained in:
parent
fe40624135
commit
eff55dfce4
3 changed files with 141 additions and 3 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
|||
"<uvtile>": "<uvtile>",
|
||||
"#": "#",
|
||||
"u<u>_v<v>": "<u>|<v>",
|
||||
"<frame0": "<frame0\d+>", #noqa - copied from collect_look.py
|
||||
"<frame0": "<frame0\d+>", # noqa - copied from collect_look.py
|
||||
"<f>": "<f>"
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue