10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 | class ExtractCameraAlembic(plugin.MayaExtractorPlugin,
publish.OptionalPyblishPluginMixin):
"""Extract a Camera as Alembic.
The camera gets baked to world space by default. Only when the instance's
`bakeToWorldSpace` is set to False it will include its full hierarchy.
'camera' product type expects only single camera, if multiple cameras
are needed, 'matchmove' is better choice.
"""
label = "Extract Camera (Alembic)"
hosts = ["maya"]
families = ["camera", "matchmove"]
bake_attributes = "[]"
def process(self, instance):
# Collect the start and end including handles
start = instance.data["frameStartHandle"]
end = instance.data["frameEndHandle"]
step = instance.data.get("step", 1.0)
bake_to_worldspace = instance.data("bakeToWorldSpace", True)
# get cameras
members = instance.data['setMembers']
cameras = cmds.ls(members, leaf=True, long=True,
dag=True, type="camera")
# validate required settings
assert isinstance(step, float), "Step must be a float value"
# Define extract output file path
dir_path = self.staging_dir(instance)
if not os.path.exists(dir_path):
os.makedirs(dir_path)
filename = "{0}.abc".format(instance.name)
path = os.path.join(dir_path, filename)
# Perform alembic extraction
member_shapes = cmds.ls(
members, leaf=True, shapes=True, long=True, dag=True)
with lib.maintained_selection():
cmds.select(
member_shapes,
replace=True, noExpand=True)
# Enforce forward slashes for AbcExport because we're
# embedding it into a job string
path = path.replace("\\", "/")
job_str = ' -selection -dataFormat "ogawa" '
job_str += ' -attrPrefix cb'
job_str += ' -frameRange {0} {1} '.format(start, end)
job_str += ' -step {0} '.format(step)
if bake_to_worldspace:
job_str += ' -worldSpace'
# if baked, drop the camera hierarchy to maintain
# clean output and backwards compatibility
camera_roots = cmds.listRelatives(
cameras, parent=True, fullPath=True)
for camera_root in camera_roots:
job_str += ' -root {0}'.format(camera_root)
for member in members:
descendants = cmds.listRelatives(member,
allDescendents=True,
fullPath=True) or []
shapes = cmds.ls(descendants, shapes=True,
noIntermediate=True, long=True)
cameras = cmds.ls(shapes, type="camera", long=True)
if cameras:
if not set(shapes) - set(cameras):
continue
self.log.warning((
"Camera hierarchy contains additional geometry. "
"Extraction will fail.")
)
transform = cmds.listRelatives(
member, parent=True, fullPath=True)
transform = transform[0] if transform else member
job_str += ' -root {0}'.format(transform)
job_str += ' -file "{0}"'.format(path)
bake_attributes = json.loads(self.bake_attributes)
# bake specified attributes in preset
assert isinstance(bake_attributes, list), (
"Attributes to bake must be specified as a list"
)
for attr in bake_attributes:
self.log.debug("Adding {} attribute".format(attr))
job_str += " -attr {0}".format(attr)
with lib.evaluation("off"):
with lib.suspended_refresh():
cmds.AbcExport(j=job_str, verbose=False)
if "representations" not in instance.data:
instance.data["representations"] = []
representation = {
'name': 'abc',
'ext': 'abc',
'files': filename,
"stagingDir": dir_path,
}
instance.data["representations"].append(representation)
self.log.debug("Extracted instance '{0}' to: {1}".format(
instance.name, path))
|