Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maya: Fix Maya Alembic Extractors #478

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9be28b8
Fix `publish_attributes` access
BigRoy May 1, 2024
b05cac0
Fix repair logic
BigRoy May 1, 2024
8567e54
Fix label
BigRoy May 1, 2024
665a4e2
Fix `writeCreases` support
BigRoy May 1, 2024
141767e
Cosmetics
BigRoy May 1, 2024
0352c17
Add support for extracting the user attributes
BigRoy May 1, 2024
367eba0
Remove `autoSubd` in favor of legacy `writeCreases` usage across the …
BigRoy May 1, 2024
26eb917
Add `uvsOnly` argument
BigRoy May 1, 2024
e43a4ba
Fix usage of `root` argument
BigRoy May 1, 2024
828f7bb
Fix `writeNormals` usage
BigRoy May 1, 2024
5193d26
Fix passing of callbacks
BigRoy May 1, 2024
ba50a64
Remove debugging error
BigRoy May 1, 2024
02cccea
Bump Maya addon version
BigRoy May 1, 2024
2bf6ed7
Do not modify `roots` in-place so that `roots` remains the roots and …
BigRoy May 1, 2024
1513660
Pass `preRollStartFrame` as separate argument
BigRoy May 1, 2024
0e23615
Enable uvWrite in settings by default
BigRoy May 1, 2024
3824b0f
Merge branch 'develop' into bugfix/maya_validate_alembic_options_default
antirotor May 2, 2024
e7093f6
Merge branch 'develop' into bugfix/maya_validate_alembic_options_default
BigRoy May 2, 2024
8dfa1b3
Merge branch 'develop' into bugfix/maya_validate_alembic_options_default
BigRoy May 2, 2024
99e5cf9
Tweak the validation report
BigRoy May 3, 2024
9ac69eb
Merge branch 'bugfix/maya_validate_alembic_options_default' of https:…
BigRoy May 3, 2024
4ac8123
Simplify messaging
BigRoy May 3, 2024
b4b1e2a
Ignore attributes not found in settings with a warning
BigRoy May 3, 2024
9f184a2
Merge branch 'develop' into bugfix/maya_validate_alembic_options_default
BigRoy May 6, 2024
bd1f7dc
Fix repair for instances with older publish attributes that mismatch …
BigRoy May 6, 2024
0973b71
Merge branch 'develop' into bugfix/maya_validate_alembic_options_default
tokejepsen May 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 49 additions & 4 deletions client/ayon_core/hosts/maya/api/alembic.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
"melPostJobCallback": str,
"noNormals": bool,
"preRoll": bool,
"preRollStartFrame": int,
"pythonPerFrameCallback": str,
"pythonPostJobCallback": str,
"renderableOnly": bool,
Expand Down Expand Up @@ -54,15 +53,22 @@ def extract_alembic(
endFrame=None,
eulerFilter=True,
frameRange="",
melPerFrameCallback=None,
melPostJobCallback=None,
noNormals=False,
preRoll=False,
preRollStartFrame=0,
pythonPerFrameCallback=None,
pythonPostJobCallback=None,
renderableOnly=False,
root=None,
selection=True,
startFrame=None,
step=1.0,
stripNamespaces=True,
userAttr=None,
userAttrPrefix=None,
uvsOnly=False,
uvWrite=True,
verbose=False,
wholeFrameGeo=False,
Expand Down Expand Up @@ -102,6 +108,11 @@ def extract_alembic(
string formatted as: "startFrame endFrame". This argument
overrides `startFrame` and `endFrame` arguments.

melPerFrameCallback (Optional[str]): MEL callback run per frame.

melPostJobCallback (Optional[str]): MEL callback after last frame is
written.

noNormals (bool): When on, normal data from the original polygon
objects is not included in the exported Alembic cache file.

Expand All @@ -113,6 +124,11 @@ def extract_alembic(
dependent translations and can be used to evaluate run-up that
isn't actually translated. Defaults to 0.

pythonPerFrameCallback (Optional[str]): Python callback run per frame.

pythonPostJobCallback (Optional[str]): Python callback after last frame
is written.

renderableOnly (bool): When on, any non-renderable nodes or hierarchy,
such as hidden objects, are not included in the Alembic file.
Defaults to False.
Expand All @@ -137,6 +153,15 @@ def extract_alembic(
object with the namespace taco:foo:bar appears as bar in the
Alembic file.

userAttr (list of str, optional): A specific user defined attribute to
write out. Defaults to [].

userAttrPrefix (list of str, optional): Prefix filter for determining
which user defined attributes to write out. Defaults to [].

uvsOnly (bool): When on, only uv data for PolyMesh and SubD shapes
will be written to the Alembic file.

uvWrite (bool): When on, UV data from polygon meshes and subdivision
objects are written to the Alembic file. Only the current UV map is
included.
Expand Down Expand Up @@ -183,6 +208,8 @@ def extract_alembic(
# Ensure list arguments are valid.
attr = attr or []
attrPrefix = attrPrefix or []
userAttr = userAttr or []
userAttrPrefix = userAttrPrefix or []
root = root or []

# Pass the start and end frame on as `frameRange` so that it
Expand Down Expand Up @@ -213,8 +240,10 @@ def extract_alembic(
"eulerFilter": eulerFilter,
"noNormals": noNormals,
"preRoll": preRoll,
"root": root,
"renderableOnly": renderableOnly,
"uvWrite": uvWrite,
"uvsOnly": uvsOnly,
"writeColorSets": writeColorSets,
"writeFaceSets": writeFaceSets,
"wholeFrameGeo": wholeFrameGeo,
Expand All @@ -226,9 +255,10 @@ def extract_alembic(
"step": step,
"attr": attr,
"attrPrefix": attrPrefix,
"userAttr": userAttr,
"userAttrPrefix": userAttrPrefix,
"stripNamespaces": stripNamespaces,
"verbose": verbose,
"preRollStartFrame": preRollStartFrame
"verbose": verbose
}

# Validate options
Expand Down Expand Up @@ -264,6 +294,17 @@ def extract_alembic(
if maya_version >= 2018:
options['autoSubd'] = options.pop('writeCreases', False)

# Only add callbacks if they are set so that we're not passing `None`
callbacks = {
"melPerFrameCallback": melPerFrameCallback,
"melPostJobCallback": melPostJobCallback,
"pythonPerFrameCallback": pythonPerFrameCallback,
"pythonPostJobCallback": pythonPostJobCallback,
}
for key, callback in callbacks.items():
if callback:
options[key] = str(callback)

# Format the job string from options
job_args = list()
for key, value in options.items():
Expand Down Expand Up @@ -297,7 +338,11 @@ def extract_alembic(
# exports are made. (PLN-31)
# TODO: Make sure this actually fixes the issues
with evaluation("off"):
cmds.AbcExport(j=job_str, verbose=verbose)
cmds.AbcExport(
j=job_str,
verbose=verbose,
preRollStartFrame=preRollStartFrame
)

if verbose:
log.debug("Extracted Alembic to: %s", file)
Expand Down
44 changes: 17 additions & 27 deletions client/ayon_core/hosts/maya/plugins/publish/extract_pointcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from ayon_core.pipeline import publish
from ayon_core.hosts.maya.api.alembic import extract_alembic
from ayon_core.hosts.maya.api.lib import (
get_all_children,
suspended_refresh,
maintained_selection,
iter_visible_nodes_in_range
Expand Down Expand Up @@ -40,7 +41,6 @@ class ExtractAlembic(publish.Extractor, AYONPyblishPluginMixin):
# From settings
attr = []
attrPrefix = []
autoSubd = False
bake_attributes = []
bake_attribute_prefixes = []
dataFormat = "ogawa"
Expand All @@ -63,6 +63,7 @@ class ExtractAlembic(publish.Extractor, AYONPyblishPluginMixin):
wholeFrameGeo = False
worldSpace = True
writeColorSets = False
writeCreases = False
writeFaceSets = False
writeNormals = True
writeUVSets = False
Expand Down Expand Up @@ -173,15 +174,9 @@ def process(self, instance):
"writeVisibility": attribute_values.get(
"writeVisibility", self.writeVisibility
),
"autoSubd": attribute_values.get(
"autoSubd", self.autoSubd
),
"uvsOnly": attribute_values.get(
"uvsOnly", self.uvsOnly
),
"writeNormals": attribute_values.get(
"writeNormals", self.writeNormals
),
"melPerFrameCallback": attribute_values.get(
"melPerFrameCallback", self.melPerFrameCallback
),
Expand All @@ -193,7 +188,12 @@ def process(self, instance):
),
"pythonPostJobCallback": attribute_values.get(
"pythonPostJobCallback", self.pythonPostJobCallback
)
),
# Note that this converts `writeNormals` to `noNormals` for the
# `AbcExport` equivalent in `extract_alembic`
"noNormals": not attribute_values.get(
"writeNormals", self.writeNormals
),
}

if instance.data.get("visibleOnly", False):
Expand Down Expand Up @@ -249,7 +249,6 @@ def process(self, instance):
with maintained_selection():
cmds.select(instance.data["proxy"])
extract_alembic(**kwargs)

representation = {
"name": "proxy",
"ext": "abc",
Expand All @@ -268,20 +267,6 @@ def get_attribute_defs(cls):
return []

override_defs = OrderedDict({
"autoSubd": BoolDef(
"autoSubd",
label="Auto Subd",
default=cls.autoSubd,
tooltip=(
"If this flag is present and the mesh has crease edges, "
"crease vertices or holes, the mesh (OPolyMesh) would now "
"be written out as an OSubD and crease info will be stored"
" in the Alembic file. Otherwise, creases info won't be "
"preserved in Alembic file unless a custom Boolean "
"attribute SubDivisionMesh has been added to mesh node and"
" its value is true."
)
),
"eulerFilter": BoolDef(
"eulerFilter",
label="Euler Filter",
Expand Down Expand Up @@ -354,6 +339,13 @@ def get_attribute_defs(cls):
default=cls.writeColorSets,
tooltip="Write vertex colors with the geometry."
),
"writeCreases": BoolDef(
"writeCreases",
label="Write Creases",
default=cls.writeCreases,
tooltip="Write the geometry's edge and vertex crease "
"information."
),
"writeFaceSets": BoolDef(
"writeFaceSets",
label="Write Face Sets",
Expand Down Expand Up @@ -527,9 +519,7 @@ def get_members_and_roots(self, instance):
roots = cmds.sets(out_set, query=True) or []

# Include all descendants
nodes = roots
nodes += cmds.listRelatives(
roots, allDescendents=True, fullPath=True
) or []
nodes = roots.copy()
nodes.extend(get_all_children(roots, ignore_intermediate_objects=True))

return nodes, roots
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import inspect
import pyblish.api

from ayon_core.pipeline import OptionalPyblishPluginMixin
Expand Down Expand Up @@ -29,29 +30,28 @@ def _get_settings(cls, context):

@classmethod
def _get_publish_attributes(cls, instance):
attributes = instance.data["publish_attributes"][
cls.plugin_name(
instance.data["publish_attributes"]
)
]

return attributes
return instance.data["publish_attributes"][cls.plugin_name]

def process(self, instance):
if not self.is_active(instance.data):
return

settings = self._get_settings(instance.context)

attributes = self._get_publish_attributes(instance)

msg = (
"Alembic Extract setting \"{}\" is not the default value:"
"\nCurrent: {}"
"\nDefault Value: {}\n"
)
errors = []
invalid = {}
for key, value in attributes.items():
if key not in settings:
# This may occur if attributes have changed over time and an
# existing instance has older legacy attributes that do not
# match the current settings definition.
self.log.warning(
"Publish attribute %s not found in Alembic Export "
"default settings. Ignoring validation for attribute.",
key
)
continue

default_value = settings[key]

# Lists are best to compared sorted since we cant rely on the order
Expand All @@ -61,10 +61,35 @@ def process(self, instance):
default_value = sorted(default_value)

if value != default_value:
errors.append(msg.format(key, value, default_value))
invalid[key] = value, default_value

if errors:
raise PublishValidationError("\n".join(errors))
if invalid:
non_defaults = "\n".join(
f"- {key}: {value} \t(default: {default_value})"
for key, (value, default_value) in invalid.items()
)

raise PublishValidationError(
"Alembic extract options differ from default values:\n"
f"{non_defaults}",
description=self.get_description()
)

@staticmethod
def get_description():
return inspect.cleandoc(
"""### Alembic Extract settings differ from defaults

The alembic export options differ from the project default values.

If this is intentional you can disable this validation by
disabling **Validate Alembic Options Default**.

If not you may use the "Repair" action to revert all the options to
their default values.

"""
)

@classmethod
def repair(cls, instance):
Expand All @@ -75,13 +100,20 @@ def repair(cls, instance):
)

# Set the settings values on the create context then save to workfile.
publish_attributes = instance.data["publish_attributes"]
plugin_name = cls.plugin_name(publish_attributes)
attributes = cls._get_publish_attributes(instance)
settings = cls._get_settings(instance.context)
create_publish_attributes = create_instance.data["publish_attributes"]
attributes = cls._get_publish_attributes(create_instance)
for key in attributes:
create_publish_attributes[plugin_name][key] = settings[key]
if key not in settings:
# This may occur if attributes have changed over time and an
# existing instance has older legacy attributes that do not
# match the current settings definition.
cls.log.warning(
"Publish attribute %s not found in Alembic Export "
"default settings. Ignoring repair for attribute.",
key
)
continue
attributes[key] = settings[key]

create_context.save_changes()

Expand All @@ -93,6 +125,6 @@ class ValidateAlembicDefaultsAnimation(

The defaults are defined in the project settings.
"""
label = "Validate Alembic Options Defaults"
label = "Validate Alembic Options Defaults"
families = ["animation"]
plugin_name = "ExtractAnimation"
2 changes: 1 addition & 1 deletion server_addon/maya/package.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
name = "maya"
title = "Maya"
version = "0.1.17"
version = "0.1.18"
Loading
Loading