Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion pipeline/pipe/h/hipfile/shot.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ def _post_open_file(self, entity: SGEntity):
hou.playbar.setPlaybackRange(shot.cut_in - 5, shot.cut_out + 5)
if env_stub := (shot.set or self._conn.get_sequence_by_stub(shot.sequence).set): # type: ignore[arg-type]
layout = self._conn.get_env_by_stub(env_stub)
hou.putenv("SET_PATH", layout.path)
if layout and layout.path:
hou.putenv("SET_PATH", layout.path)

def _setup_file(self, path: Path, entity: SGEntity) -> None:
super(HShotFileManager, HShotFileManager)._setup_file(self, path, entity)
Expand Down
3 changes: 3 additions & 0 deletions pipeline/pipe/m/layout/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .file_manager import MLayoutFileManager as MLayoutFileManager
from .publish import MLayoutPublisher as MLayoutPublisher
from .maker import LayoutMaker as LayoutMaker
190 changes: 190 additions & 0 deletions pipeline/pipe/m/layout/file_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
from __future__ import annotations

import logging
import mayaUsd # type: ignore[import-not-found]
import maya.cmds as mc
import mayaUsd.lib as mayaUsdLib # type: ignore[import-not-found]

from pathlib import Path
from pxr import Usd, UsdGeom, Gf
from mayaUsd.lib import proxyAccessor as pa

from pipe.db import DB
from pipe.m.local import get_main_qt_window
from pipe.struct.db import SGEntity, Environment
from pipe.util import FileManager, log_errors
from shared.util import get_production_path

from .publish import MLayoutPublisher

from env_sg import DB_Config

log = logging.getLogger(__name__)

HOUDINI_TO_MAYA_SCALE = Gf.Vec3d(100.0, 100.0, 100.0)


class MLayoutFileManager(FileManager):
set: Environment

def __init__(self, **kwargs) -> None:
conn = DB.Get(DB_Config)
window = get_main_qt_window()
super().__init__(conn, Environment, window, versioning=True, **kwargs)

# Script to select reference when selecting the geo in the viewport, so transformations export correctly
@staticmethod
def change_usd_selection():
# Get current selection
stagePath, sdfPath = pa.getSelectedDagAndPrim()
if sdfPath is None or stagePath is None:
return

if str(sdfPath)[-3:] != "geo":
return

# Get USD stage from DAG path
stage = mayaUsdLib.GetPrim(stagePath).GetStage()
if not stage:
return

prim = stage.GetPrimAtPath(sdfPath)
if not prim or not prim.IsValid():
return

# Go two parents up
parent1 = prim.GetParent()
parent2 = parent1.GetParent() if parent1 else None
parent3 = parent2.GetParent() if parent2 else None

if parent3 and parent3.IsValid():
# Set new selection to the grandparent prim
newPath = f"{stagePath},{parent3.GetPath()}"
mc.select(newPath, replace=True)

@classmethod
def get_stage_shape(cls) -> str:
if ss := mc.ls(type="mayaUsdProxyShape", long=True)[0]:
return ss
raise RuntimeError("No USD stage found in scene")

@classmethod
def get_stage(cls) -> Usd.Stage:
return mayaUsd.ufe.getStage(cls.get_stage_shape())

@classmethod
@log_errors
def run_on_open(cls) -> None:
"""Function to run on file open via script node"""

# change default render resolution
mc.setAttr("defaultResolution.width", 1920) # type: ignore[arg-type]
mc.setAttr("defaultResolution.height", 1080) # type: ignore[arg-type]
mc.setAttr("defaultResolution.pixelAspect", 1.0) # type: ignore[arg-type]
mc.setAttr("defaultResolution.deviceAspectRatio", 1920 / 1080) # type: ignore[arg-type]

mc.scriptJob(event=["SelectionChanged", MLayoutFileManager.change_usd_selection],protected=True,) # type: ignore[arg-type]

def _check_unsaved_changes(self) -> bool:
if mc.file(query=True, modified=True):
warning_response = mc.confirmDialog(
title="Do you want to save?",
message="The current file has not been saved. Continue anyways?",
button=["Continue", "Cancel"],
defaultButton="Cancel",
cancelButton="Cancel",
dismissString="Cancel",
)
if warning_response == "Cancel":
return False
return True

def _generate_filename_ext(self, entity) -> tuple[str, str]:
return "maya_layout", "mb"

def _open_file(self, path: Path) -> None:
mc.file(str(path), open=True, force=True)

def _post_open_file(self, entity: SGEntity) -> None:
"""create `boboOnOpen` script node"""
ON_OPEN_SCRIPT = "boboOnOpen"

# set save path
if not entity.path:
mc.error("entity has no file path")
return

entity_path = get_production_path() / entity.path
filename, ext = self._generate_filename_ext(entity)
file_path = entity_path / f"{filename}.{ext}"
mc.file(rename=str(file_path))
mc.file(save=True, type="mayaBinary")

if mc.objExists(ON_OPEN_SCRIPT):
return

classname = self.__class__.__name__
mc.scriptNode(
beforeScript=(
f"from pipe.m.layout import {classname};"
f"{classname}.{self.__class__.run_on_open.__name__}()"
),
name=ON_OPEN_SCRIPT,
scriptType=1,
sourceType="python",
)
# script node is created, will not run this session, so run manually
self.run_on_open()

def _setup_file(self, path: Path, entity) -> None:
mc.file(newFile=True, force=True)
# set save path
entity_path = get_production_path() / entity.path
filename, ext = self._generate_filename_ext(entity)
file_path = entity_path / f"{filename}.{ext}"
mc.file(rename=str(file_path))
mc.file(save=True, type="mayaBinary")

# Ensure mayaUsdPlugin is loaded
if not mc.pluginInfo("mayaUsdPlugin", loaded=True):
mc.loadPlugin("mayaUsdPlugin")

# Create transform and proxyShape nodes
proxy_transform = mc.createNode("transform", name="main")
proxy_shape = mc.createNode(
"mayaUsdProxyShape", name="mainShape", parent=proxy_transform
)

stage = self.get_stage()
if not stage:
mc.error("Could not get USD stage from proxy shape.")
return

# Define new Xforms
new_xform_path = "/environment"
environment_xform = UsdGeom.Xform.Define(stage, new_xform_path)

scale_op = environment_xform.AddScaleOp()
scale_op.Set(HOUDINI_TO_MAYA_SCALE)

new_xform_path = f"/environment/{entity.name}"
UsdGeom.Xform.Define(stage, new_xform_path)

# Initial publish and pull back in so relative paths work
MLayoutPublisher().publish(needs_confirmation=False)

mc.file(newFile=True, force=True)
mc.file(rename=str(file_path))
mc.file(save=True, type="mayaBinary")

proxy_transform = mc.createNode("transform", name="main")
proxy_shape = mc.createNode(
"mayaUsdProxyShape", name="mainShape", parent=proxy_transform
)

# Set the file path attribute of the proxyShape node
mc.setAttr(
proxy_shape + ".filePath", f"{entity_path}/maya_layout.usd", type="string"
)

mc.scriptJob(event=["SelectionChanged", MLayoutFileManager.change_usd_selection],protected=True,) # type: ignore[arg-type]
Loading