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
43 changes: 37 additions & 6 deletions lib/mayaUsd/utils/utilComponentCreator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ bool isAdskUsdComponent(const std::string& proxyShapePath)
" import mayaUsd.ufe\n"
" try:\n"
" from AdskUsdComponentCreator import ComponentDescription\n"
" except ImportError:\n"
" except:\n"
" return -1\n"
" proxyStage = mayaUsd.ufe.getStage('^1s')\n"
" component_description = ComponentDescription.CreateFromStageMetadata(proxyStage)\n"
Expand All @@ -115,6 +115,37 @@ bool isAdskUsdComponent(const std::string& proxyShapePath)
return isStageAComponent == 1;
}

bool isAdskUsdComponentCreatorAvailable()
Comment thread
pierrebai-adsk marked this conversation as resolved.
{
// Availability of the python packages cannot change during a session, so cache it.
static int cached = -1;
if (cached >= 0) {
return cached == 1;
}

MString defineCmd = "def mayausd_is_component_creator_available():\n"
" try:\n"
" import AdskUsdComponentCreator\n"
" import usd_component_creator_plugin\n"
" except:\n"
" return 0\n"
" return 1\n";

int available = 0;
MStatus success;
if (MS::kSuccess == (success = MGlobal::executePythonCommand(defineCmd, false, false))) {
success
= MGlobal::executePythonCommand("mayausd_is_component_creator_available()", available);
}
if (success != MS::kSuccess) {
// Don't cache a transient failure.
return false;
}

cached = (available == 1) ? 1 : 0;
return cached == 1;
}

void saveAdskUsdComponent(const std::string& proxyPath)
{
if (proxyPath.empty()) {
Expand Down Expand Up @@ -201,7 +232,7 @@ std::string previewSaveAdskUsdComponent(
" try:\n"
" from AdskUsdComponentCreator import ComponentDescription, "
"PreviewMoveComponentHierarchy\n"
" except ImportError:\n"
" except:\n"
" return None\n"
" proxyStage = mayaUsd.ufe.getStage('^1s')\n"
" component_description = "
Expand Down Expand Up @@ -244,7 +275,7 @@ std::string moveAdskUsdComponent(
" try:\n"
" from AdskUsdComponentCreator import ComponentDescription, MoveComponent\n"
" from usd_component_creator_plugin import MayaComponentManager\n"
" except ImportError:\n"
" except:\n"
" return ''\n"
" proxyStage = mayaUsd.ufe.getStage('^1s')\n"
" MayaComponentManager.GetInstance().SaveComponent(proxyStage)\n"
Expand Down Expand Up @@ -320,7 +351,7 @@ std::string getComponentOptionString(const std::string& proxyPath, const char* o
" import mayaUsd.ufe\n"
" try:\n"
" from AdskUsdComponentCreator import ComponentDescription\n"
" except ImportError:\n"
" except:\n"
" return ''\n"
" proxyStage = mayaUsd.ufe.getStage('^1s')\n"
" component_description = ComponentDescription.CreateFromStageMetadata(proxyStage)\n"
Expand Down Expand Up @@ -377,7 +408,7 @@ bool addMayaNodesToComponent(
" add_to_component_from_nodes\n"
" import mayaUsd.ufe, mayaUsd.lib\n"
" import maya.OpenMaya as om\n"
" except ImportError as e:\n"
" except:\n"
" return 0\n"
" export_options = mayaUsd.lib.Util.getDictionaryFromEncodedOptions('^3s')\n"
" stage = mayaUsd.ufe.getStage('^1s')\n"
Expand Down Expand Up @@ -428,7 +459,7 @@ bool setComponentVariantSelection(
" try:\n"
" import mayaUsd.ufe\n"
" from AdskUsdComponentCreator import ComponentAPI, ComponentDescription\n"
" except ImportError:\n"
" except:\n"
" return 0\n"
" stage = mayaUsd.ufe.getStage('^1s')\n"
" if stage is None:\n"
Expand Down
5 changes: 5 additions & 0 deletions lib/mayaUsd/utils/utilComponentCreator.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ namespace ComponentUtils {
MAYAUSD_CORE_PUBLIC
bool isAdskUsdComponent(const std::string& proxyPath);

/*! \brief Returns whether the Autodesk USD Component Creator python packages are available.
*/
MAYAUSD_CORE_PUBLIC
bool isAdskUsdComponentCreatorAvailable();

/*! \brief Returns the ids of the USD layers that should be saved for the Autodesk USD Component.
*
* \note Expects \p proxyPath to be a valid component path.
Expand Down
8 changes: 8 additions & 0 deletions lib/usd/ui/layerEditor/mayaSessionState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <mayaUsd/nodes/proxyShapeBase.h>
#include <mayaUsd/nodes/usdPrimProvider.h>
#include <mayaUsd/utils/util.h>
#include <mayaUsd/utils/utilComponentCreator.h>

#ifdef WANT_ADSK_USD_EDIT_FORWARD_BUILD
#include <mayaUsd/editForward/MayaUsdEditForwardHost.h>
Expand Down Expand Up @@ -426,6 +427,13 @@ void MayaSessionState::setupCreateMenu(QMenu* in_menu)
script += "menuItem -runTimeCommand mayaUsdCreateStageWithNewLayer;";
script += "menuItem -runTimeCommand mayaUsdCreateStageFromFile;";
script += "menuItem -runTimeCommand mayaUsdCreateStageFromFileOptions -optionBox true;";

if (MayaUsd::ComponentUtils::isAdskUsdComponentCreatorAvailable()) {
script += "menuItem -divider true;";
script += "menuItem -runTimeCommand mayaUsdCreateComponent;";
script += "menuItem -runTimeCommand mayaUsdCreateComponentOptions -optionBox true;";
}

MGlobal::executeCommand(
script,
/*display*/ false,
Expand Down
1 change: 1 addition & 0 deletions plugin/adsk/scripts/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ list(APPEND scripts_src
mayaUsdMenu.py
mayaUsd_createStageFromFile.mel
mayaUsd_createStageWithNewLayer.py
mayaUsd_createComponent.py
mayaUsd_createStageFromAsset.mel
mayaUsd_imageFileDialogs.mel
mayaUsd_initializeComponentCreator.py
Expand Down
3 changes: 3 additions & 0 deletions plugin/adsk/scripts/mayaUSDRegisterStrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@
"kMenuStageFromFile": "Stage From File...",
"kMenuStageFromFileAnn": "Create a USD Stage from an existing USD file",
"kMenuStageFromFileOptionsAnn": "Create a USD Stage from an existing USD file options",
"kMenuComponent": "Component",
"kMenuComponentAnn": "Create a new, empty USD Component",
"kMenuComponentOptionsAnn": "Open the USD Component Creator options",
"kMenuStageSubMenu": "Universal Scene Description (USD)",
"kMenuStageSubMenuAnn": "Create a USD stage",
"kMenuSaveAs": "Save As...",
Expand Down
34 changes: 33 additions & 1 deletion plugin/adsk/scripts/mayaUsdMenu.mel
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ global string $gMayaUsdSelectMenuDivider = "";
global string $gMayaUsdSelectModeSubMenu = "";
global string $gMayaUsdOpenUsdCompositionEditorMenuItem = "";
global string $gMayaUsdOpenUsdRenderSetupMenuItem = "";
global int $gHasComponentCreator = -1;

///////////////////////////////////////////////////////////////////////////////
// findDividerByLabel
Expand Down Expand Up @@ -144,6 +145,17 @@ proc int mayaUSD_isSelectionKindValid() {
return true;
}

///////////////////////////////////////////////////////////////////////////////
// hasComponentCreator
// return 1 if the Autodesk USD Component Creator python packages are importable
global proc int hasComponentCreator() {
global int $gHasComponentCreator;
if ($gHasComponentCreator < 0) {
$gHasComponentCreator = `python("res = -1; exec('try:\\n import AdskUsdComponentCreator\\n import usd_component_creator_plugin\\n res = 1;\\nexcept:\\n res = 0;\\n'); res")`;
}
return $gHasComponentCreator;
}

///////////////////////////////////////////////////////////////////////////////
// initRuntimeCommands
// create all the runtime commands we'll use and the user can map to hotkeys
Expand Down Expand Up @@ -174,7 +186,27 @@ proc initRuntimeCommands() {
-category "Menu items.Maya USD"
-command "mayaUsd_createStageFromFileOptions"
mayaUsdCreateStageFromFileOptions;
}
}

if (hasComponentCreator()) {
if (!`runTimeCommand -exists mayaUsdCreateComponent`) {
runTimeCommand -default true -plugin "mayaUsdPlugin"
-label `getMayaUsdString("kMenuComponent")`
-annotation `getMayaUsdString("kMenuComponentAnn")`
-category "Menu items.Maya USD"
-command "python(\"import mayaUsd_createComponent; mayaUsd_createComponent.createComponent()\")"
-image "USD_stage.png"
mayaUsdCreateComponent;
}

if (!`runTimeCommand -exists mayaUsdCreateComponentOptions`) {
runTimeCommand -default true -plugin "mayaUsdPlugin"
-annotation `getMayaUsdString("kMenuComponentOptionsAnn")`
-category "Menu items.Maya USD"
-command "python(\"import mayaUsd_createComponent; mayaUsd_createComponent.createComponentOptions()\")"
mayaUsdCreateComponentOptions;
}
}

if (`exists mayaUsdLayerEditorWindow`) {
if (!`runTimeCommand -exists mayaUsdOpenUsdLayerEditor`) {
Expand Down
93 changes: 93 additions & 0 deletions plugin/adsk/scripts/mayaUsd_createComponent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Copyright 2026 Autodesk
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import maya.cmds as cmds

from pxr import Sdf, Usd

from AdskUsdComponentCreator import (
Options,
GenerateUniqueComponentName,
GenerateVariantSetNameFromObjectName,
GenerateVariantNameFromObjectName,
TheHost,
CreateFromStageCommand,
)
from usd_component_creator_plugin import (
print_exceptions,
MayaUndoChunk,
execute_ufe_command,
CreateProxyShapeForComponentCommand,
AddComponentToManagerCommand,
OpenComponentCommand,
show_create_component_options,
)


def _build_options():
Comment thread
pierrebai-adsk marked this conversation as resolved.
"""
Create fresh, validated Options with a unique component name/folder
and an initial variant set/variant.
"""
options = Options()
options.Validate()
options.component_folder = cmds.workspace(expandName=cmds.internalVar(userTmpDir=True))
options = GenerateUniqueComponentName(options)

component_name = options.component_name
options.component_variants = [
(
GenerateVariantSetNameFromObjectName(options, '', []),
GenerateVariantNameFromObjectName(options, '', [], []),
),
]
options.Validate()
return options


@print_exceptions('Failed to create the USD component')
def createComponent():
"""
Create a new, empty Autodesk USD Component from a temporary anonymous
in-memory stage, add it to the component manager, and open it.
"""
options = _build_options()

# Include the whole (empty) stage root.
options.included_paths = [Sdf.Path.absoluteRootPath]
options.replace_variant_content = True

stage = Usd.Stage.CreateInMemory()

with MayaUndoChunk('Create USD Component'):
# Single creation pass: no UnlockComponentContext needed.
create_cmd = CreateFromStageCommand(None, stage, options)
if not TheHost.GetHost().ExecuteWithUndo(create_cmd):
print('Failed to create the empty USD component.')
return

proxy_cmd = CreateProxyShapeForComponentCommand(create_cmd, target_default_variant=True)
execute_ufe_command(proxy_cmd)

add_cmd = AddComponentToManagerCommand(create_cmd)
execute_ufe_command(add_cmd)

open_cmd = OpenComponentCommand(create_cmd)
execute_ufe_command(open_cmd)


def createComponentOptions():
"""Open the existing Component Creator options dialog wired to createComponent."""
show_create_component_options('Create USD Component', createComponent, show_export_options=False)
Loading