Merge remote-tracking branch 'upstream/develop' into maya_new_publisher

# Conflicts:
#	openpype/hosts/maya/plugins/create/create_look.py
#	openpype/hosts/maya/plugins/create/create_review.py
#	openpype/hosts/maya/plugins/publish/collect_instances.py
#	openpype/hosts/maya/plugins/publish/validate_attributes.py
#	openpype/hosts/maya/plugins/publish/validate_frame_range.py
#	openpype/hosts/maya/plugins/publish/validate_maya_units.py
#	openpype/hosts/maya/plugins/publish/validate_mesh_overlapping_uvs.py
#	openpype/modules/deadline/plugins/publish/collect_pools.py
This commit is contained in:
Roy Nieterau 2023-04-04 17:05:42 +02:00
commit fd6285399e
8 changed files with 110 additions and 135 deletions

View file

@ -17,6 +17,7 @@ class CreateLook(plugin.MayaCreator):
icon = "paint-brush"
make_tx = True
rs_tex = False
def get_instance_attr_defs(self):
@ -32,6 +33,11 @@ class CreateLook(plugin.MayaCreator):
label="MakeTX",
tooltip="Whether to generate .tx files for your textures",
default=self.make_tx),
BoolDef("rstex",
label="Convert textures to .rstex",
tooltip="Whether to generate Redshift .rstex files for "
"your textures",
default=self.make_tx),
BoolDef("forceCopy",
label="Force Copy",
tooltip="Enable users to force a copy instead of hardlink."

View file

@ -26,14 +26,15 @@ class CreateReview(plugin.MayaCreator):
family = "review"
icon = "video-camera"
use_maya_timeline = True
useMayaTimeline = True
panZoom = False
def get_instance_attr_defs(self):
defs = lib.collect_animation_defs()
# Option for using Maya or asset frame range in settings.
if not self.use_maya_timeline:
if not self.useMayaTimeline:
# Update the defaults to be the asset frame range
frame_range = lib.get_frame_range()
defs_by_key = {attr_def.key: attr_def for attr_def in defs}
@ -72,7 +73,10 @@ class CreateReview(plugin.MayaCreator):
default=True),
EnumDef("transparency",
label="Transparency",
items=TRANSPARENCIES)
items=TRANSPARENCIES),
BoolDef("panZoom",
label="Enable camera pan/zoom",
default=True),
])
return defs

View file

@ -1,47 +1,7 @@
from maya import cmds
import maya.api.OpenMaya as om
import pyblish.api
def get_all_children(nodes):
"""Return all children of `nodes` including each instanced child.
Using maya.cmds.listRelatives(allDescendents=True) includes only the first
instance. As such, this function acts as an optimal replacement with a
focus on a fast query.
"""
sel = om.MSelectionList()
traversed = set()
iterator = om.MItDag(om.MItDag.kDepthFirst)
for node in nodes:
if node in traversed:
# Ignore if already processed as a child
# before
continue
sel.clear()
sel.add(node)
dag = sel.getDagPath(0)
iterator.reset(dag)
# ignore self
iterator.next() # noqa: B305
while not iterator.isDone():
path = iterator.fullPathName()
if path in traversed:
iterator.prune()
iterator.next() # noqa: B305
continue
traversed.add(path)
iterator.next() # noqa: B305
return list(traversed)
from openpype.hosts.maya.api.lib import get_all_children
class CollectNewInstances(pyblish.api.InstancePlugin):

View file

@ -1,6 +1,10 @@
import pymel.core as pm
from collections import defaultdict
from maya import cmds
import pyblish.api
from openpype.hosts.maya.api.lib import set_attribute
from openpype.pipeline.publish import (
RepairContextAction,
ValidateContentsOrder,
@ -8,7 +12,7 @@ from openpype.pipeline.publish import (
)
class ValidateAttributes(pyblish.api.ContextPlugin,
class ValidateAttributes(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
"""Ensure attributes are consistent.
@ -29,88 +33,83 @@ class ValidateAttributes(pyblish.api.ContextPlugin,
attributes = None
def process(self, context):
# Check for preset existence.
if not self.is_active(context.data):
def process(self, instance):
if not self.is_active(instance.data):
return
# Check for preset existence.
if not self.attributes:
return
invalid = self.get_invalid(context, compute=True)
invalid = self.get_invalid(instance, compute=True)
if invalid:
raise RuntimeError(
"Found attributes with invalid values: {}".format(invalid)
)
@classmethod
def get_invalid(cls, context, compute=False):
invalid = context.data.get("invalid_attributes", [])
def get_invalid(cls, instance, compute=False):
if compute:
invalid = cls.get_invalid_attributes(context)
return invalid
return cls.get_invalid_attributes(instance)
else:
return instance.data.get("invalid_attributes", [])
@classmethod
def get_invalid_attributes(cls, context):
def get_invalid_attributes(cls, instance):
invalid_attributes = []
for instance in context:
# Filter publisable instances.
if not instance.data["publish"]:
# Filter families.
families = [instance.data["family"]]
families += instance.data.get("families", [])
families = set(families) & set(cls.attributes.keys())
if not families:
return []
# Get all attributes to validate.
attributes = defaultdict(dict)
for family in families:
if family not in cls.attributes:
# No attributes to validate for family
continue
# Filter families.
families = [instance.data["family"]]
families += instance.data.get("families", [])
families = list(set(families) & set(cls.attributes.keys()))
if not families:
for preset_attr, preset_value in cls.attributes[family].items():
node_name, attribute_name = preset_attr.split(".", 1)
attributes[node_name][attribute_name] = preset_value
if not attributes:
return []
# Get invalid attributes.
nodes = cmds.ls(long=True)
for node in nodes:
node_name = node.rsplit("|", 1)[-1].rsplit(":", 1)[-1]
if node_name not in attributes:
continue
# Get all attributes to validate.
attributes = {}
for family in families:
for preset in cls.attributes[family]:
[node_name, attribute_name] = preset.split(".")
try:
attributes[node_name].update(
{attribute_name: cls.attributes[family][preset]}
)
except KeyError:
attributes.update({
node_name: {
attribute_name: cls.attributes[family][preset]
}
})
for attr_name, expected in attributes.items():
# Get invalid attributes.
nodes = pm.ls()
for node in nodes:
name = node.name(stripNamespace=True)
if name not in attributes.keys():
# Skip if attribute does not exist
if not cmds.attributeQuery(attr_name, node=node, exists=True):
continue
presets_to_validate = attributes[name]
for attribute in node.listAttr():
names = [attribute.shortName(), attribute.longName()]
attribute_name = list(
set(names) & set(presets_to_validate.keys())
plug = "{}.{}".format(node, attr_name)
value = cmds.getAttr(plug)
if value != expected:
invalid_attributes.append(
{
"attribute": plug,
"expected": expected,
"current": value
}
)
if attribute_name:
expected = presets_to_validate[attribute_name[0]]
if attribute.get() != expected:
invalid_attributes.append(
{
"attribute": attribute,
"expected": expected,
"current": attribute.get()
}
)
context.data["invalid_attributes"] = invalid_attributes
instance.data["invalid_attributes"] = invalid_attributes
return invalid_attributes
@classmethod
def repair(cls, instance):
invalid = cls.get_invalid(instance)
for data in invalid:
data["attribute"].set(data["expected"])
node, attr = data["attribute"].split(".", 1)
value = data["expected"]
set_attribute(node=node, attribute=attr, value=value)

View file

@ -54,7 +54,6 @@ class ValidateFrameRange(pyblish.api.InstancePlugin,
frame_start_handle = int(context.data.get("frameStartHandle"))
frame_end_handle = int(context.data.get("frameEndHandle"))
handles = int(context.data.get("handles"))
handle_start = int(context.data.get("handleStart"))
handle_end = int(context.data.get("handleEnd"))
frame_start = int(context.data.get("frameStart"))
@ -71,8 +70,6 @@ class ValidateFrameRange(pyblish.api.InstancePlugin,
assert frame_start_handle <= frame_end_handle, (
"start frame is lower then end frame")
assert handles >= 0, ("handles cannot have negative values")
# compare with data on instance
errors = []
if [ef for ef in self.exclude_families

View file

@ -127,7 +127,7 @@ class ValidateMayaUnits(pyblish.api.ContextPlugin):
cls.log.debug(current_linear)
cls.log.info("Setting time unit to match project")
# TODO repace query with using 'context.data["assetEntity"]'
# TODO replace query with using 'context.data["assetEntity"]'
asset_doc = get_current_project_asset()
asset_fps = asset_doc["data"]["fps"]
mayalib.set_scene_fps(asset_fps)

View file

@ -1,10 +1,11 @@
import pyblish.api
import openpype.hosts.maya.api.action
import math
import maya.api.OpenMaya as om
import pymel.core as pm
from six.moves import xrange
from maya import cmds
import maya.api.OpenMaya as om
import pyblish.api
import openpype.hosts.maya.api.action
from openpype.pipeline.publish import (
ValidateMeshOrder,
OptionalPyblishPluginMixin
@ -188,8 +189,7 @@ class GetOverlappingUVs(object):
center, radius = self._createBoundingCircle(meshfn)
for i in xrange(meshfn.numPolygons): # noqa: F821
rayb1, face1Orig, face1Vec = self._createRayGivenFace(
meshfn, i)
rayb1, face1Orig, face1Vec = self._createRayGivenFace(meshfn, i)
if not rayb1:
continue
cui = center[2*i]
@ -209,8 +209,8 @@ class GetOverlappingUVs(object):
if (dsqr >= (ri + rj) * (ri + rj)):
continue
rayb2, face2Orig, face2Vec = self._createRayGivenFace(
meshfn, j)
rayb2, face2Orig, face2Vec = self._createRayGivenFace(meshfn,
j)
if not rayb2:
continue
# Exclude the degenerate face
@ -244,37 +244,45 @@ class ValidateMeshHasOverlappingUVs(pyblish.api.InstancePlugin,
optional = True
@classmethod
def _get_overlapping_uvs(cls, node):
""" Check if mesh has overlapping UVs.
def _get_overlapping_uvs(cls, mesh):
"""Return overlapping UVs of mesh.
Args:
mesh (str): Mesh node name
Returns:
list: Overlapping uvs for the input mesh in all uv sets.
:param node: node to check
:type node: str
:returns: True is has overlapping UVs, False otherwise
:rtype: bool
"""
ovl = GetOverlappingUVs()
# Store original uv set
original_current_uv_set = cmds.polyUVSet(mesh,
query=True,
currentUVSet=True)
overlapping_faces = []
for i, uv in enumerate(pm.polyUVSet(node, q=1, auv=1)):
pm.polyUVSet(node, cuv=1, uvSet=uv)
overlapping_faces.extend(ovl._getOverlapUVFaces(str(node)))
for uv_set in cmds.polyUVSet(mesh, query=True, allUVSets=True):
cmds.polyUVSet(mesh, currentUVSet=True, uvSet=uv_set)
overlapping_faces.extend(ovl._getOverlapUVFaces(mesh))
# Restore original uv set
cmds.polyUVSet(mesh, currentUVSet=True, uvSet=original_current_uv_set)
return overlapping_faces
@classmethod
def get_invalid(cls, instance, compute=False):
invalid = []
if compute:
instance.data["overlapping_faces"] = []
for node in pm.ls(instance, type="mesh"):
invalid = []
for node in cmds.ls(instance, type="mesh"):
faces = cls._get_overlapping_uvs(node)
invalid.extend(faces)
# Store values for later.
instance.data["overlapping_faces"].extend(faces)
else:
invalid.extend(instance.data["overlapping_faces"])
return invalid
instance.data["overlapping_faces"] = invalid
return instance.data.get("overlapping_faces", [])
def process(self, instance):
if not self.is_active(instance.data):

View file

@ -3,7 +3,6 @@
"""
import pyblish.api
from openpype.lib import TextDef
from openpype.pipeline.publish import OpenPypePyblishPluginMixin
@ -14,7 +13,11 @@ class CollectDeadlinePools(pyblish.api.InstancePlugin,
order = pyblish.api.CollectorOrder + 0.420
label = "Collect Deadline Pools"
families = ["rendering", "render.farm", "renderFarm", "renderlayer"]
families = ["rendering",
"render.farm",
"renderFarm",
"renderlayer",
"maxrender"]
primary_pool = None
secondary_pool = None
@ -29,7 +32,6 @@ class CollectDeadlinePools(pyblish.api.InstancePlugin,
def process(self, instance):
attr_values = self.get_attr_values_from_data(instance.data)
if not instance.data.get("primaryPool"):
instance.data["primaryPool"] = (
attr_values.get("primaryPool") or self.primary_pool or "none"
@ -42,7 +44,6 @@ class CollectDeadlinePools(pyblish.api.InstancePlugin,
@classmethod
def get_attribute_defs(cls):
# TODO: Preferably this would be an enum for the user
# but the Deadline server URL can be dynamic and
# can be set per render instance. Since get_attribute_defs