mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
Remove plugins for instancer family - there is no instancer family?
This commit is contained in:
parent
11e89c100e
commit
d223be1a88
2 changed files with 0 additions and 242 deletions
|
|
@ -1,75 +0,0 @@
|
|||
import maya.cmds as cmds
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.hosts.maya.api import lib
|
||||
from ayon_core.pipeline.publish import PublishValidationError
|
||||
|
||||
|
||||
class ValidateInstancerContent(pyblish.api.InstancePlugin):
|
||||
"""Validates that all meshes in the instance have object IDs.
|
||||
|
||||
This skips a check on intermediate objects because we consider them
|
||||
not important.
|
||||
"""
|
||||
order = pyblish.api.ValidatorOrder
|
||||
label = 'Instancer Content'
|
||||
families = ['instancer']
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
error = False
|
||||
members = instance.data['setMembers']
|
||||
export_members = instance.data['exactExportMembers']
|
||||
|
||||
self.log.debug("Contents {0}".format(members))
|
||||
|
||||
if not len(members) == len(cmds.ls(members, type="instancer")):
|
||||
self.log.error("Instancer can only contain instancers")
|
||||
error = True
|
||||
|
||||
# TODO: Implement better check for particles are cached
|
||||
if not cmds.ls(export_members, type="nucleus"):
|
||||
self.log.error("Instancer must have a connected nucleus")
|
||||
error = True
|
||||
|
||||
if not cmds.ls(export_members, type="cacheFile"):
|
||||
self.log.error("Instancer must be cached")
|
||||
error = True
|
||||
|
||||
hidden = self.check_geometry_hidden(export_members)
|
||||
if not hidden:
|
||||
error = True
|
||||
self.log.error("Instancer input geometry must be hidden "
|
||||
"the scene. Invalid: {0}".format(hidden))
|
||||
|
||||
# Ensure all in one group
|
||||
parents = cmds.listRelatives(members,
|
||||
allParents=True,
|
||||
fullPath=True) or []
|
||||
roots = list(set(cmds.ls(parents, assemblies=True, long=True)))
|
||||
if len(roots) > 1:
|
||||
self.log.error("Instancer should all be contained in a single "
|
||||
"group. Current roots: {0}".format(roots))
|
||||
error = True
|
||||
|
||||
if error:
|
||||
raise PublishValidationError(
|
||||
"Instancer Content is invalid. See log.")
|
||||
|
||||
def check_geometry_hidden(self, export_members):
|
||||
|
||||
# Ensure all instanced geometry is hidden
|
||||
shapes = cmds.ls(export_members,
|
||||
dag=True,
|
||||
shapes=True,
|
||||
noIntermediate=True)
|
||||
meshes = cmds.ls(shapes, type="mesh")
|
||||
|
||||
visible = [node for node in meshes
|
||||
if lib.is_visible(node,
|
||||
displayLayer=False,
|
||||
intermediateObject=False)]
|
||||
if visible:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
import os
|
||||
import re
|
||||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.pipeline.publish import PublishValidationError
|
||||
|
||||
|
||||
def is_cache_resource(resource):
|
||||
"""Return whether resource is a cacheFile resource"""
|
||||
required = set(["maya", "node", "cacheFile"])
|
||||
tags = resource.get("tags", [])
|
||||
return required.issubset(tags)
|
||||
|
||||
|
||||
def valdidate_files(files):
|
||||
for f in files:
|
||||
assert os.path.exists(f)
|
||||
assert f.endswith(".mcx") or f.endswith(".mcc")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def filter_ticks(files):
|
||||
tick_files = set()
|
||||
ticks = set()
|
||||
for path in files:
|
||||
match = re.match(".+Tick([0-9]+).mcx$", os.path.basename(path))
|
||||
if match:
|
||||
tick_files.add(path)
|
||||
num = match.group(1)
|
||||
ticks.add(int(num))
|
||||
|
||||
return tick_files, ticks
|
||||
|
||||
|
||||
class ValidateInstancerFrameRanges(pyblish.api.InstancePlugin):
|
||||
"""Validates all instancer particle systems are cached correctly.
|
||||
|
||||
This means they should have the files/frames as required by the start-end
|
||||
frame (including handles).
|
||||
|
||||
This also checks the files exist and checks the "ticks" (substeps) files.
|
||||
|
||||
"""
|
||||
order = pyblish.api.ValidatorOrder
|
||||
label = 'Instancer Cache Frame Ranges'
|
||||
families = ['instancer']
|
||||
|
||||
@classmethod
|
||||
def get_invalid(cls, instance):
|
||||
|
||||
import pyseq
|
||||
|
||||
start_frame = instance.data.get("frameStart", 0)
|
||||
end_frame = instance.data.get("frameEnd", 0)
|
||||
required = range(int(start_frame), int(end_frame) + 1)
|
||||
|
||||
invalid = list()
|
||||
resources = instance.data.get("resources", [])
|
||||
|
||||
for resource in resources:
|
||||
if not is_cache_resource(resource):
|
||||
continue
|
||||
|
||||
node = resource['node']
|
||||
all_files = resource['files'][:]
|
||||
all_lookup = set(all_files)
|
||||
|
||||
# The first file is usually the .xml description file.
|
||||
xml = all_files.pop(0)
|
||||
assert xml.endswith(".xml")
|
||||
|
||||
# Ensure all files exist (including ticks)
|
||||
# The remainder file paths should be the .mcx or .mcc files
|
||||
valdidate_files(all_files)
|
||||
|
||||
# Maya particle caches support substeps by saving out additional
|
||||
# files that end with a Tick60.mcx, Tick120.mcx, etc. suffix.
|
||||
# To avoid `pyseq` getting confused we filter those out and then
|
||||
# for each file (except the last frame) check that at least all
|
||||
# ticks exist.
|
||||
|
||||
tick_files, ticks = filter_ticks(all_files)
|
||||
if tick_files:
|
||||
files = [f for f in all_files if f not in tick_files]
|
||||
else:
|
||||
files = all_files
|
||||
|
||||
sequences = pyseq.get_sequences(files)
|
||||
if len(sequences) != 1:
|
||||
invalid.append(node)
|
||||
cls.log.warning("More than one sequence found? "
|
||||
"{0} {1}".format(node, files))
|
||||
cls.log.warning("Found caches: {0}".format(sequences))
|
||||
continue
|
||||
|
||||
sequence = sequences[0]
|
||||
cls.log.debug("Found sequence: {0}".format(sequence))
|
||||
|
||||
start = sequence.start()
|
||||
end = sequence.end()
|
||||
|
||||
if start > start_frame or end < end_frame:
|
||||
invalid.append(node)
|
||||
cls.log.warning("Sequence does not have enough "
|
||||
"frames: {0}-{1} (requires: {2}-{3})"
|
||||
"".format(start, end,
|
||||
start_frame,
|
||||
end_frame))
|
||||
continue
|
||||
|
||||
# Ensure all frames are present
|
||||
missing = set(sequence.missing())
|
||||
if missing:
|
||||
required_missing = [x for x in required if x in missing]
|
||||
if required_missing:
|
||||
invalid.append(node)
|
||||
cls.log.warning("Sequence is missing required frames: "
|
||||
"{0}".format(required_missing))
|
||||
continue
|
||||
|
||||
# Ensure all tick files (substep) exist for the files in the folder
|
||||
# for the frames required by the time range.
|
||||
if ticks:
|
||||
ticks = list(sorted(ticks))
|
||||
cls.log.debug("Found ticks: {0} "
|
||||
"(substeps: {1})".format(ticks, len(ticks)))
|
||||
|
||||
# Check all frames except the last since we don't
|
||||
# require subframes after our time range.
|
||||
tick_check_frames = set(required[:-1])
|
||||
|
||||
# Check all frames
|
||||
for item in sequence:
|
||||
frame = item.frame
|
||||
if not frame:
|
||||
invalid.append(node)
|
||||
cls.log.error("Path is not a frame in sequence: "
|
||||
"{0}".format(item))
|
||||
continue
|
||||
|
||||
# Not required for our time range
|
||||
if frame not in tick_check_frames:
|
||||
continue
|
||||
|
||||
path = item.path
|
||||
for num in ticks:
|
||||
base, ext = os.path.splitext(path)
|
||||
tick_file = base + "Tick{0}".format(num) + ext
|
||||
if tick_file not in all_lookup:
|
||||
invalid.append(node)
|
||||
cls.log.warning("Tick file found that is not "
|
||||
"in cache query filenames: "
|
||||
"{0}".format(tick_file))
|
||||
|
||||
return invalid
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
invalid = self.get_invalid(instance)
|
||||
|
||||
if invalid:
|
||||
self.log.error("Invalid nodes: {0}".format(invalid))
|
||||
raise PublishValidationError(
|
||||
("Invalid particle caches in instance. "
|
||||
"See logs for details."))
|
||||
Loading…
Add table
Add a link
Reference in a new issue