Skip to content

Commit e30207a

Browse files
authored
Maya export postprocessing (#271)
* pass any additional flags from launch into the executable * changes to environment variable handling to allow running hython from within Maya. Added a post export function to the Maya USD exporter for running Houdini HDAs after export
1 parent 29df110 commit e30207a

File tree

10 files changed

+156
-30
lines changed

10 files changed

+156
-30
lines changed

pipeline/__main__.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ def getLevelNamesMapping():
3131
return logging._nameToLevel.keys()
3232

3333

34-
def launch(software_name: str, is_python_shell: bool = False) -> None:
34+
def launch(
35+
software_name: str,
36+
is_python_shell: bool = False,
37+
extra_args: list[str] | None = None,
38+
) -> None:
3539
software = find_implementation(DCCInterface, f"software.{software_name}")
36-
software(is_python_shell).launch()
40+
software(is_python_shell, extra_args).launch()
3741

3842

3943
if __name__ == "__main__":
@@ -58,13 +62,13 @@ def launch(software_name: str, is_python_shell: bool = False) -> None:
5862
action="store_true",
5963
)
6064

61-
args = parser.parse_args()
65+
args, extras = parser.parse_known_args()
6266

6367
logging.basicConfig(
6468
level=args.log_level,
6569
format="%(asctime)s %(processName)s(%(process)s) %(threadName)s [%(name)s(%(lineno)s)] [%(levelname)s] %(message)s",
6670
)
6771

68-
launch(args.software, args.python)
72+
launch(args.software, args.python, extras)
6973

7074
log.info("Exiting")

pipeline/pipe/h/animpostprocess.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from __future__ import annotations
2+
3+
import hou
4+
5+
from typing import TYPE_CHECKING
6+
7+
from pipe.db import DB
8+
from env_sg import DB_Config
9+
10+
if TYPE_CHECKING:
11+
pass
12+
13+
14+
class AnimPostProcessor:
15+
_conn: DB
16+
17+
def __init__(self):
18+
self._conn = DB(DB_Config)
19+
20+
def run(self, shot_code: str) -> None:
21+
# Set up
22+
shot = self._conn.get_shot_by_code(shot_code)
23+
hou.playbar.setFrameRange(shot.cut_in - 5, shot.cut_out + 5)
24+
hou.playbar.setPlaybackRange(shot.cut_in - 5, shot.cut_out + 5)
25+
26+
stage_ctx: hou.Node = hou.node("/stage") # type: ignore[assignment]
27+
28+
load_layer = stage_ctx.createNode("sdm223::main::LnD_Load_Layers::1.0")
29+
load_layer.parm("shot").set(f"$JOB/{shot.path}") # type: ignore[union-attr]
30+
31+
for dep in ["cfx", "fx", "flo", "lighting"]:
32+
load_layer.parm(f"{dep}_enable").set(0) # type: ignore[union-attr]
33+
34+
if env_stub := (shot.set or self._conn.get_sequence_by_stub(shot.sequence).set): # type: ignore[arg-type]
35+
layout = self._conn.get_env_by_stub(env_stub)
36+
load_layer.parm("layout_path").set(f"$JOB/{layout.path}/main.usd") # type: ignore[union-attr]
37+
38+
layer_break = stage_ctx.createNode("layerbreak")
39+
40+
postprocess = stage_ctx.createNode("sdm222::lnd_anim_postprocess::1.0")
41+
42+
publish = stage_ctx.createNode("usd_rop")
43+
44+
publish.parm("trange").set("normal") # type: ignore[union-attr]
45+
publish.parm("lopoutput").set(f"$JOB/{shot.path}/anim/usd/post-process.usd") # type: ignore[union-attr]
46+
publish.parm("savestyle").set("flattenalllayers") # type: ignore[union-attr]
47+
48+
layer_break.setInput(0, load_layer)
49+
postprocess.setInput(0, layer_break)
50+
publish.setInput(0, postprocess)
51+
52+
publish.parm("execute").pressButton() # type: ignore[union-attr]

pipeline/pipe/m/publish/anim.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import logging
55

66
from pathlib import Path
7+
from pxr import Sdf
78
from typing import TYPE_CHECKING
89

910
if TYPE_CHECKING:
@@ -15,6 +16,7 @@
1516
from pipe.glui.dialogs import MessageDialog
1617
from pipe.m.util import maintain_selection
1718
from pipe.struct.timeline import Timeline
19+
from software.houdini import HoudiniDCC
1820
from shared.util import get_production_path
1921

2022
from .publisher import Publisher
@@ -96,3 +98,19 @@ def _get_mayausd_kwargs(self) -> dict[str, Any]:
9698

9799
def _get_confirm_message(self):
98100
return f"Animation has been exported to {self._publish_path}"
101+
102+
def _postpublish(self) -> None:
103+
"""Launch a Houdini process to compute the anim post-process HDA"""
104+
post_script = ";".join(
105+
[
106+
"from pipe.h.animpostprocess import AnimPostProcessor",
107+
f"AnimPostProcessor().run('{self._shot.code}')",
108+
"exit()",
109+
]
110+
)
111+
112+
HoudiniDCC(is_python_shell=True, extra_args=["-c", post_script]).launch()
113+
114+
root_layer = Sdf.Layer.FindOrOpen(str(self._publish_path))
115+
root_layer.subLayerPaths.append("post-process.usd")
116+
root_layer.Save()

pipeline/pipe/m/publish/publisher.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,14 @@ def publish(self):
191191
if self._IS_WINDOWS:
192192
shutil.move(temp_publish_path, self._publish_path)
193193

194+
self._postpublish()
195+
194196
confirm = MessageDialog(
195197
self._window,
196198
self._get_confirm_message(),
197199
"Export Complete",
198200
)
199201
confirm.exec_()
202+
203+
def _postpublish(self) -> None:
204+
pass

pipeline/software/baseclass.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import json
34
import logging
45
import os
56
import subprocess
@@ -46,35 +47,45 @@ def __init__(
4647
self.env_vars = env_vars or {}
4748
self.pre_launch_tasks = pre_launch_tasks or (lambda: None)
4849

49-
def _set_env_vars(
50+
def _get_env_vars(
5051
self, env_vars: typing.Mapping[str, int | str | None] | None = None
51-
) -> None:
52+
) -> dict[str, str]:
5253
"""(Un)Set environment variables to their associated values.
5354
5455
All values will be converted to strings. If a value is None,
5556
that environment variable will be unset.
5657
"""
58+
BASE_ENVIRON = "BASE_ENVIRON"
59+
60+
if BASE_ENVIRON not in os.environ:
61+
venv = os.environ.copy()
62+
venv[BASE_ENVIRON] = json.dumps(venv)
63+
else:
64+
venv = json.loads(os.environ[BASE_ENVIRON])
65+
5766
if env_vars is None:
5867
env_vars = self.env_vars
5968

6069
log.info("(Un)setting environment vars")
6170

6271
for key, val in env_vars.items():
6372
if val is None:
64-
if key in os.environ:
65-
del os.environ[key]
73+
if key in venv:
74+
del venv[key]
6675
else:
67-
os.environ[key] = str(val)
76+
venv[key] = str(val)
6877

69-
if not os.environ["PYTHONPATH"]:
70-
os.environ["PYTHONPATH"] = ""
71-
os.environ["PYTHONPATH"] = os.pathsep.join(
78+
PYTHONPATH = "PYTHONPATH"
79+
if PYTHONPATH not in venv:
80+
venv[PYTHONPATH] = ""
81+
venv[PYTHONPATH] = os.pathsep.join(
7282
[
73-
os.environ["PYTHONPATH"],
83+
venv[PYTHONPATH],
7484
str(get_production_path() / "../pipeline/pipeline/lib/python/any"),
7585
]
7686
)
77-
print(os.environ["PYTHONPATH"])
87+
print(venv[PYTHONPATH])
88+
return venv
7889

7990
def launch(
8091
self,
@@ -97,11 +108,11 @@ def launch(
97108

98109
fix_launcher_metadata()
99110
pre_launch_tasks()
100-
self._set_env_vars()
111+
venv = self._get_env_vars()
101112

102113
log.info("Launching the software")
103114
log.debug(f"Command: {command}, Args: {args}")
104-
subprocess.call([command] + list(args or []))
115+
subprocess.call([command] + list(args or []), env=venv)
105116

106117

107118
class DCCLocalizer(DCCLocalizerInterface):

pipeline/software/houdini/dcc.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ class HoudiniDCC(DCC):
2121
"""Houdini DCC class"""
2222

2323
def __init__(
24-
self,
25-
is_python_shell: bool = False,
24+
self, is_python_shell: bool = False, extra_args: list[str] | None = None
2625
) -> None:
2726
this_path = Path(__file__).resolve()
2827
pipe_path = this_path.parents[2]
@@ -69,6 +68,8 @@ def __init__(
6968
"HSITE": str(resolve_mapped_path(this_path.parent / "hsite")),
7069
# Job directory
7170
"JOB": str(resolve_mapped_path(get_production_path())),
71+
# Ensure LD_LIBRARY_PATH is unset to allow nesting pipe instances
72+
"LD_LIBRARY_PATH": None,
7273
# Manually set LD_LIBRARY_PATH to integrated Houdini libraries (for Axiom)
7374
# "LD_LIBRARY_PATH": str(Executables.hfs / "dsolib")
7475
# if platform.system() == "Linux"
@@ -111,6 +112,9 @@ def __init__(
111112
else:
112113
launch_command = str(Executables.houdini)
113114

114-
launch_args: list[str] = [] if is_python_shell else ["-foreground"]
115+
if is_python_shell:
116+
launch_args = extra_args or []
117+
else:
118+
launch_args = ["-foreground", *(extra_args or [])]
115119

116120
super().__init__(launch_command, launch_args, env_vars)

pipeline/software/maya/dcc.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ class MayaDCC(DCC):
2323

2424
shelf_path: str
2525

26-
def __init__(self, is_python_shell: bool = False) -> None:
26+
def __init__(
27+
self, is_python_shell: bool = False, extra_args: list[str] | None = None
28+
) -> None:
2729
this_path = Path(__file__).resolve()
2830
pipe_path = this_path.parents[2]
2931

@@ -82,19 +84,51 @@ def __init__(self, is_python_shell: bool = False) -> None:
8284
launch_args: list[str] = []
8385
if is_python_shell:
8486
launch_command = str(Executables.mayapy)
85-
launch_args = [
87+
cmd_str = ""
88+
extra_args_preamble = []
89+
90+
print(extra_args)
91+
92+
if extra_args:
93+
# extract the cmd arg so we can append it to everything else
94+
try:
95+
cmd_flag_index = next(
96+
(
97+
i
98+
for i, f in enumerate(extra_args)
99+
if (f[0] == "-") and (f[-1] == "c")
100+
)
101+
)
102+
cmd_str = extra_args[cmd_flag_index + 1]
103+
if len(extra_args[cmd_flag_index]) > 2:
104+
cmd_str_other_flags = ["-" + extra_args[cmd_flag_index][1:-1]]
105+
else:
106+
cmd_str_other_flags = []
107+
108+
extra_args_preamble = (
109+
extra_args[:cmd_flag_index]
110+
+ extra_args[cmd_flag_index + 2 :]
111+
+ cmd_str_other_flags
112+
)
113+
except StopIteration:
114+
pass
115+
116+
launch_args = extra_args_preamble + [
86117
"-ic",
87118
";".join(
88119
[
89120
"import atexit",
90121
"import maya.standalone",
91122
"maya.standalone.initialize()",
92123
"atexit.register(maya.standalone.uninitialize)",
124+
cmd_str,
93125
]
94126
),
95127
]
96128
else:
97129
launch_command = str(Executables.maya)
130+
if extra_args:
131+
launch_args = extra_args
98132

99133
super().__init__(
100134
launch_command, launch_args, env_vars, lambda: self.set_up_shelf_path()

pipeline/software/nuke/dcc.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ class NukeDCC(DCC):
1919
"""Nuke DCC class"""
2020

2121
def __init__(
22-
self,
23-
is_python_shell: bool = False,
22+
self, is_python_shell: bool = False, extra_args: list[str] | None = None
2423
) -> None:
2524
this_path = Path(__file__).resolve()
2625
pipe_path = this_path.parents[2]
@@ -51,8 +50,8 @@ def __init__(
5150
launch_command = str(Executables.nuke)
5251

5352
if is_python_shell:
54-
launch_args = []
53+
launch_args = extra_args or []
5554
else:
56-
launch_args = ["--nukex"]
55+
launch_args = ["--nukex", *(extra_args or [])]
5756

5857
super().__init__(launch_command, launch_args, env_vars)

pipeline/software/substance_designer/dcc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ class SubstanceDesignerDCC(DCC):
1616
"""Substance Designer DCC class"""
1717

1818
def __init__(
19-
self,
20-
is_python_shell: bool = False,
19+
self, is_python_shell: bool = False, extra_args: list[str] | None = None
2120
) -> None:
2221
this_path = Path(__file__).resolve()
2322
pipe_path = this_path.parents[2]
@@ -47,6 +46,7 @@ def __init__(
4746
launch_args = [
4847
"--config-file",
4948
str(this_path.parent / "lnd_configuration.sbscfg"),
49+
*(extra_args or []),
5050
]
5151

5252
super().__init__(launch_command, launch_args, env_vars)

pipeline/software/substance_painter/dcc.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ class SubstancePainterDCC(DCC):
2121
"""Substance Painter DCC class"""
2222

2323
def __init__(
24-
self,
25-
is_python_shell: bool = False,
24+
self, is_python_shell: bool = False, extra_args: list[str] | None = None
2625
) -> None:
2726
this_path = Path(__file__).resolve()
2827
pipe_path = this_path.parents[2]
@@ -55,6 +54,6 @@ def __init__(
5554
f"The operating system {system} is not a supported OS for this DCC software"
5655
)
5756

58-
launch_args: list[str] = []
57+
launch_args: list[str] = extra_args or []
5958

6059
super().__init__(launch_command, launch_args, env_vars)

0 commit comments

Comments
 (0)