From dc612543e4eff93f82384cdad1b114bc07ee3c82 Mon Sep 17 00:00:00 2001 From: Irene Weng Date: Mon, 11 Sep 2023 18:38:42 -0400 Subject: [PATCH 1/5] Shifter FBX tool: add reset option and set collapsible widget size policies --- .../shifter/game_tools_fbx/fbx_exporter.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/release/scripts/mgear/shifter/game_tools_fbx/fbx_exporter.py b/release/scripts/mgear/shifter/game_tools_fbx/fbx_exporter.py index ab2d1f55..2a409aca 100644 --- a/release/scripts/mgear/shifter/game_tools_fbx/fbx_exporter.py +++ b/release/scripts/mgear/shifter/game_tools_fbx/fbx_exporter.py @@ -30,7 +30,7 @@ class FBXExporter(MayaQWidgetDockableMixin, QtWidgets.QDialog): - def __init__(self, parent=None): + def __init__(self, parent=None, reset=False): super(FBXExporter, self).__init__(parent) self.setWindowFlags(QtCore.Qt.Tool) self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) @@ -46,7 +46,7 @@ def __init__(self, parent=None): self.refresh_fbx_sdk_ui() self.refresh_ue_connection() - WIDGET_SETTINGS.load_ui_state(self.widget_dict) + WIDGET_SETTINGS.load_ui_state(self.widget_dict, reset=reset) self._update_geo_root_data() self._update_joint_root_data() self.save_data_to_export_node() @@ -259,6 +259,9 @@ def create_settings_widget(self): def create_file_path_widget(self): # main collapsible widget layout file_path_collap_wgt = widgets.CollapsibleWidget("File Path") + file_path_collap_wgt.setSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum + ) self.main_layout.addWidget(file_path_collap_wgt) path_main_layout = QtWidgets.QVBoxLayout() path_main_layout.setSpacing(2) @@ -290,6 +293,9 @@ def create_unreal_import_widget(self): self.ue_import_collap_wgt = widgets.CollapsibleWidget( "Unreal Engine Import" ) + self.ue_import_collap_wgt.setSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum + ) self.main_layout.addWidget(self.ue_import_collap_wgt) ue_path_main_layout = QtWidgets.QVBoxLayout() ue_path_main_layout.addSpacing(2) @@ -356,10 +362,10 @@ def create_skeletal_mesh_tab(self): # partitions outliner self.partitions_outliner = partitions_outliner.PartitionsOutliner() - self.partitions_outliner.setSizePolicy( - QtWidgets.QSizePolicy.MinimumExpanding, - QtWidgets.QSizePolicy.MinimumExpanding, - ) + # self.partitions_outliner.setSizePolicy( + # QtWidgets.QSizePolicy.MinimumExpanding, + # QtWidgets.QSizePolicy.MinimumExpanding, + # ) partitions_layout.addWidget(self.partitions_outliner) # partition buttons From 304e2afa35040871c13fe18b736aef6056196f34 Mon Sep 17 00:00:00 2001 From: Irene Weng Date: Mon, 11 Sep 2023 22:38:46 -0400 Subject: [PATCH 2/5] Shifter FBX partitions outliner: remove MASH and pix dependencies --- .../game_tools_fbx/partition_widgets.py | 91 +++++++++---------- 1 file changed, 43 insertions(+), 48 deletions(-) diff --git a/release/scripts/mgear/shifter/game_tools_fbx/partition_widgets.py b/release/scripts/mgear/shifter/game_tools_fbx/partition_widgets.py index bd1fff9d..a9987738 100644 --- a/release/scripts/mgear/shifter/game_tools_fbx/partition_widgets.py +++ b/release/scripts/mgear/shifter/game_tools_fbx/partition_widgets.py @@ -1,19 +1,17 @@ import copy import weakref +import maya.cmds as cmds + +# TODO: Remove following dependencies +import maya.app.flux.core as fx + from mgear.vendor.Qt import QtWidgets, QtCore, QtGui from mgear.core import pyqt, utils from mgear.shifter.game_tools_fbx import fbx_export_node -import maya.cmds as cmds - -# TODO: Remove following dependencies -import maya.app.flux.core as fx -from maya.app.flux.core import pix -from MASH.itemStyle import * - ROW_HEIGHT = 30 LABEL_COLORS = ["red", "blue", "grey", "orange", "green", "yellow", "purple"] COLORS = { @@ -284,7 +282,7 @@ class OutlinerTreeView(QtWidgets.QTreeWidget): TREE_ITEM_CLASS = TreeItem NODE_CLASS = NodeClass - EXPAND_WIDTH = pix(60) + EXPAND_WIDTH = 60 TRASH_IMAGE = pyqt.get_icon("mgear_trash") COPY_IMAGE = pyqt.get_icon("mgear_copy") @@ -312,12 +310,11 @@ def __init__(self, parent=None): self.populate_items() self.header().setCascadingSectionResizes(False) - self.setColumnWidth(0, pix(250)) - self.header().resizeSection(0, pix(250)) + self.setColumnWidth(0, 250) + self.header().resizeSection(0, 250) self.resizeColumnToContents(0) delegate = TreeViewDelegate(self) self.setItemDelegate(delegate) - # self.setStyle(ItemStyle()) self.setRootIsDecorated(False) self.expandAll() self.setExpandsOnDoubleClick(False) @@ -399,7 +396,7 @@ def mouseMoveEvent(self, event): if not self._action_button_pressed: super(OutlinerTreeView, self).mouseMoveEvent(event) - modifiers = QtGui.QGuiApplication.keyboardModifiers() + modifiers = QtWidgets.QApplication.keyboardModifiers() if modifiers == QtCore.Qt.AltModifier: QtWidgets.QWidget.setCursor( self, (QtGui.QCursor(QtCore.Qt.DragCopyCursor)) @@ -414,7 +411,7 @@ def mouseMoveEvent(self, event): self.setDirtyRegion(region) def mouseReleaseEvent(self, event): - QtGui.QGuiApplication.restoreOverrideCursor() + QtWidgets.QApplication.restoreOverrideCursor() if not self._action_button_pressed: super(OutlinerTreeView, self).mouseReleaseEvent(event) else: @@ -620,14 +617,14 @@ def _on_custom_context_menu_requested(self, pos): return if item.is_root(): if num_indexes > 0: - pixmap = QtGui.QPixmap(pix(100), pix(100)) + pixmap = QtGui.QPixMap(100, 100) pixmap.fill(self._get_label_color()) label_icon = QtGui.QIcon(pixmap) prev_menu = self._context_menu.addMenu( label_icon, "Label Color" ) for color_label in LABEL_COLORS: - pixmap = QtGui.QPixmap(pix(100), pix(100)) + pixmap = QtGui.QPixMap(100, 100) pixmap.fill(self._get_color_from_label(color_label)) label_icon = QtGui.QIcon(pixmap) prev_menu.addAction( @@ -683,7 +680,7 @@ def paint(self, painter, option, index): def sizeHint(self, option, index): hint = super(TreeViewDelegate, self).sizeHint(option, index) - hint.setHeight(pix(ROW_HEIGHT)) + hint.setHeight(ROW_HEIGHT) return hint def createEditor(self, parent, option, index): @@ -707,9 +704,9 @@ def updateEditorGeometry(self, editor, option, index): indent = self.tree_view.get_indent(index) rect = copy.deepcopy(option.rect) - rect.setLeft(indent + pix(46.5)) - rect.setBottom(rect.bottom() - pix(4)) - rect.setRight(rect.right() - pix(50)) + rect.setLeft(indent + 46.5) + rect.setBottom(rect.bottom() - 4) + rect.setRight(rect.right() - 50) editor.setGeometry(rect) def setEditorData(self, editor, index): @@ -736,25 +733,25 @@ class RowPainter(object): DISABLED_BACKGROUND_IMAGE = fx.getPixmap("out_MASH_ChevronBG") DISABLED_HIGHLIGHT_IMAGE = fx.getPixmap("out_MASH_ChevronBGSelected") EXPANDED_ARROW = ( - pix(QtCore.QPointF(9.0, 11.0)), - pix(QtCore.QPointF(19.0, 11.0)), - pix(QtCore.QPointF(14.0, 16.0)), + QtCore.QPointF(9.0, 11.0), + QtCore.QPointF(19.0, 11.0), + QtCore.QPointF(14.0, 16.0), ) COLLAPSED_ARROW = ( - pix(QtCore.QPointF(12.0, 8.0)), - pix(QtCore.QPointF(17.0, 13.0)), - pix(QtCore.QPointF(12.0, 18.0)), + QtCore.QPointF(12.0, 8.0), + QtCore.QPointF(17.0, 13.0), + QtCore.QPointF(12.0, 18.0), ) ARROW_COLOR = QtGui.QColor(189, 189, 189) - ICON_PADDING = pix(10.0) - ICON_WIDTH = pix(20) - ICON_WIDTH_NO_DPI = pix(20) - ICON_TOP_OFFSET = pix(4) - COLOR_BAR_WIDTH = pix(6) + ICON_PADDING = 10 + ICON_WIDTH = 20 + ICON_WIDTH_NO_DPI = 20 + ICON_TOP_OFFSET = 4 + COLOR_BAR_WIDTH = 6 DRAG_HANDLE_IMAGE = fx.getPixmap("out_MASH_OutlinerDrag") LOCK_IMAGE = fx.getPixmap("out_MASH_OutlinerNoDrag") - ACTION_BORDER = pix(0) - ACTION_WIDTH = pix(20) + ACTION_BORDER = 0 + ACTION_WIDTH = 20 ENABLED_IMAGE = fx.getPixmap("out_MASH_Enable") DISABLED_IMAGE = fx.getPixmap("out_MASH_Disable") ENABLED_SELECTED_IMAGE = fx.getPixmap("out_MASH_Enable_Selected") @@ -828,10 +825,10 @@ def _draw_fill(self): rect2 = copy.deepcopy(self._rect) old_pen = self._painter.pen() self._painter.setPen( - QtGui.QPen(self.item.get_window_background_color(), pix(2)) + QtGui.QPen(self.item.get_window_background_color(), 2) ) rect2.setLeft(rect2.left()) - rect2.setRight(rect2.right() - pix(2)) + rect2.setRight(rect2.right() - 2) rect2.setTop(rect2.top()) rect2.setBottom(rect2.bottom()) self._painter.drawRect(rect2) @@ -845,9 +842,9 @@ def _draw_arrow_drag_lock(self): self._painter.save() old_brush = self._painter.brush() if self.item.is_root() and self.item.childCount() > 0: - padding = pix(3) + padding = 3 self._painter.translate( - self._rect.left() + padding, self._rect.top() + pix(2) + self._rect.left() + padding, self._rect.top() + 2 ) arrow = self.COLLAPSED_ARROW if self.item.isExpanded(): @@ -858,11 +855,11 @@ def _draw_arrow_drag_lock(self): self._painter.setBrush(old_brush) else: rect2 = copy.deepcopy(self._rect) - padding = pix(26) + padding = 26 new_rect = QtCore.QRect() new_rect.setRight(rect2.left() + padding) new_rect.setLeft(new_rect.right() - self.ICON_WIDTH_NO_DPI) - new_rect.setBottom(rect2.top() - self.ICON_WIDTH + pix(6)) + new_rect.setBottom(rect2.top() - self.ICON_WIDTH + 6) new_rect.setTop(new_rect.bottom() + self.ICON_WIDTH) icon = self.DRAG_HANDLE_IMAGE self._painter.drawPixmap(new_rect, icon) @@ -880,16 +877,14 @@ def _draw_text(self): draw_enabled = False if self.item.node.enabled and draw_enabled: self._painter.setPen( - QtGui.QPen(self.parent().palette().text().color(), pix(1)) + QtGui.QPen(self.parent().palette().text().color(), 1) ) else: - self._painter.setPen( - QtGui.QPen(self.item.get_inactive_color(), pix(1)) - ) + self._painter.setPen(QtGui.QPen(self.item.get_inactive_color(), 1)) text_rect = copy.deepcopy(self._rect) - text_rect.setBottom(text_rect.bottom() + pix(2)) - text_rect.setLeft(text_rect.left() + pix(40) + self.ICON_PADDING) - text_rect.setRight(text_rect.right() - pix(11)) + text_rect.setBottom(text_rect.bottom() + 2) + text_rect.setLeft(text_rect.left() + 40 + self.ICON_PADDING) + text_rect.setRight(text_rect.right() - 11) self._painter.drawText( text_rect, QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, @@ -909,9 +904,9 @@ def _draw_icon(self, text_rect): icon = self.item.get_icon() if icon: new_rect = QtCore.QRect() - new_rect.setRight(rect2.left() - pix(4)) + new_rect.setRight(rect2.left() - 4) new_rect.setLeft(new_rect.right() - self.ICON_WIDTH_NO_DPI) - new_rect.setBottom(rect2.top() - self.ICON_WIDTH + pix(3)) + new_rect.setBottom(rect2.top() - self.ICON_WIDTH + 3) new_rect.setTop(new_rect.bottom() + self.ICON_WIDTH) draw_enabled = True if not self.item.node.is_root and not self.item.network_enabled(): @@ -993,7 +988,7 @@ def _add_action_icons(self): if not show_enabled_button: start += self.ACTION_WIDTH + extra_padding continue - extra_padding = pix(10) + extra_padding = 10 pixmap = self.ENABLED_IMAGE if not self.item.is_root() and not self.item.network_enabled(): pixmap = self.INACTIVE_ENABLED_IMAGE From 1662fe389ee7036c75f93d0dad6996754b7ac5d6 Mon Sep 17 00:00:00 2001 From: Irene Weng Date: Thu, 14 Sep 2023 18:06:14 -0400 Subject: [PATCH 3/5] Shifter FBX tool: fix saving and loading export node data to widget --- .../shifter/game_tools_fbx/fbx_exporter.py | 58 +++++++++---------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/release/scripts/mgear/shifter/game_tools_fbx/fbx_exporter.py b/release/scripts/mgear/shifter/game_tools_fbx/fbx_exporter.py index 2a409aca..10228eff 100644 --- a/release/scripts/mgear/shifter/game_tools_fbx/fbx_exporter.py +++ b/release/scripts/mgear/shifter/game_tools_fbx/fbx_exporter.py @@ -20,17 +20,13 @@ anim_clip_widgets, fbx_export_node, partitions_outliner, - settings_manager, utils, ) from mgear.uegear import commands as uegear -WIDGET_SETTINGS = settings_manager.ExporterSettingsManager("FbxExporter") - - class FBXExporter(MayaQWidgetDockableMixin, QtWidgets.QDialog): - def __init__(self, parent=None, reset=False): + def __init__(self, parent=None): super(FBXExporter, self).__init__(parent) self.setWindowFlags(QtCore.Qt.Tool) self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) @@ -45,21 +41,15 @@ def __init__(self, parent=None, reset=False): self.create_connections() self.refresh_fbx_sdk_ui() self.refresh_ue_connection() - - WIDGET_SETTINGS.load_ui_state(self.widget_dict, reset=reset) - self._update_geo_root_data() - self._update_joint_root_data() - self.save_data_to_export_node() + self._load_node_data_to_widget() def closeEvent(self, event): - self.save_data_to_export_node() - WIDGET_SETTINGS.save_ui_state(self.widget_dict) + self._save_data_to_export_node() super(FBXExporter, self).closeEvent(event) def dockCloseEventTriggered(self): super(FBXExporter, self).dockCloseEventTriggered() - self.save_data_to_export_node() - WIDGET_SETTINGS.save_ui_state(self.widget_dict) + self._save_data_to_export_node() def create_layout(self): self.main_layout = QtWidgets.QVBoxLayout(self) @@ -73,6 +63,7 @@ def create_layout(self): # self.create_unreal_import_widget() self.create_export_widget() + # TODO: need for settings manager but currently not in use, consider removing self.widget_dict = { "geo_roots": self.geo_root_list, "joint_root": self.joint_root_lineedit, @@ -329,8 +320,6 @@ def create_export_widget(self): self.create_skeletal_mesh_tab() self.create_animation_tab() - self.export_tab.setCurrentIndex(1) # temp for testing anim clips - def create_skeletal_mesh_tab(self): # main collapsible widget layout skeletal_mesh_tab = QtWidgets.QWidget() @@ -499,7 +488,7 @@ def export_fbx_presets(self): file_name, file_ext = os.path.splitext(export_file) if not file_ext or file_ext != ".json": export_file = "{}.json".format(file_name) - export_data = self.save_data_to_export_node() + export_data = self._save_data_to_export_node() with open(export_file, "w") as f: json.dump(export_data, f) return export_data @@ -512,7 +501,7 @@ def import_fbx_presets(self): return False with open(import_file, "r") as f: import_data = json.load(f) - self.save_data_to_export_node(import_data) + self._save_data_to_export_node(import_data) self._set_tool_data(import_data) return import_data @@ -585,7 +574,7 @@ def set_use_partitions(self, flag): self.skmesh_rem_btn.setEnabled(flag) def add_skeletal_mesh_partition(self): - export_node = self.get_or_create_export_node() + export_node = self._get_or_create_export_node() name, ok = QtWidgets.QInputDialog.getText( self, "New Partition", @@ -623,7 +612,7 @@ def remove_skeletal_mesh_partition(self): def export_skeletal_mesh(self): print("----- Exporting Skeletal Meshes -----") - export_node = self.get_or_create_export_node() + export_node = self._get_or_create_export_node() geo_roots = self._get_listwidget_item_names(self.geo_root_list) if not geo_roots: @@ -696,7 +685,7 @@ def export_skeletal_mesh(self): def export_animation_clips(self): print("----- Exporting Animation Clips -----") - export_node = self.get_or_create_export_node() + export_node = self._get_or_create_export_node() joint_root = self.get_root_joint() if not joint_root: @@ -718,25 +707,30 @@ def export_animation_clips(self): for anim_clip_data in export_node.get_animation_clips(joint_root): anim_clip_export_data = export_config.copy() anim_clip_export_data.update(anim_clip_data) - utils.export_animation_clip(joint_root, **anim_clip_export_data) + utils.export_animation_clip(joint_root, anim_clip_export_data) return True # helper methods - def get_or_create_export_node(self): + def _get_or_create_export_node(self): return ( fbx_export_node.FbxExportNode.get() or fbx_export_node.FbxExportNode.create() ) - def save_data_to_export_node(self, data=None): - export_node = self.get_or_create_export_node() + def _save_data_to_export_node(self, data=None): + export_node = self._get_or_create_export_node() export_data = data if data else export_node.parse_export_data() current_data = self._get_current_tool_data() export_data.update(current_data) export_node.save_data(export_data) return export_data + def _load_node_data_to_widget(self): + export_node = self._get_or_create_export_node() + node_data = export_node.parse_export_data() + self._set_tool_data(node_data) + def _get_listwidget_item_names(self, listwidget): return [listwidget.item(i).text() for i in range(listwidget.count())] @@ -763,6 +757,7 @@ def _get_current_tool_data(self): "skinning": self.skinning_checkbox.isChecked(), "blendshapes": self.blendshapes_checkbox.isChecked(), "use_partitions": self.partitions_checkbox.isChecked(), + "export_tab": self.export_tab.currentIndex(), } return current_data @@ -786,18 +781,19 @@ def _set_tool_data(self, data, reset=False): self.skinning_checkbox.setChecked(data.get("skinning", False)) self.blendshapes_checkbox.setChecked(data.get("blendshapes", False)) self.partitions_checkbox.setChecked(data.get("use_partitions", False)) + self.export_tab.setCurrentIndex(data.get("export_tab", 0)) self.partitions_outliner.reset_contents() self.anim_clips_listwidget.refresh() - def _update_geo_root_data(self): + def _update_geo_roots_data(self): + export_node = self._get_or_create_export_node() item_names = self._get_listwidget_item_names(self.geo_root_list) - export_node = self.get_or_create_export_node() export_node.save_root_data("geo_roots", item_names) self.partitions_outliner.set_geo_roots(item_names) def _update_joint_root_data(self): + export_node = self._get_or_create_export_node() joint_name = self.joint_root_lineedit.text() - export_node = self.get_or_create_export_node() export_node.save_root_data("joint_root", joint_name) self.anim_clips_listwidget.refresh() @@ -808,7 +804,7 @@ def _auto_set_geo_roots(self, clear=False): if not self.geo_root_list.count(): geo_roots.append(utils.get_geo_root()) self.geo_root_list.addItems(geo_roots) - self._update_geo_root_data() + self._update_geo_roots_data() def _auto_set_joint_root(self): joint_roots = utils.get_joint_root() @@ -876,7 +872,7 @@ def _add_list_items_from_sel(self, listwidget, type_filter, clear=False): continue listwidget.addItem(node_name) if listwidget == self.geo_root_list: - self._update_geo_root_data() + self._update_geo_roots_data() def _remove_list_items_from_sel(self, listwidget): """Removes list widget items from selected list items @@ -888,7 +884,7 @@ def _remove_list_items_from_sel(self, listwidget): for selected_item in selected_items: listwidget.takeItem(listwidget.row(selected_item)) if listwidget == self.geo_root_list: - self._update_geo_root_data() + self._update_geo_roots_data() def _set_lineedit_text_from_sel(self, lineedit, type_filter): """Set line edit text from selected element filtered by type From 2eb04742d594a979acbf6da683ba49147a410177 Mon Sep 17 00:00:00 2001 From: Irene Weng Date: Thu, 14 Sep 2023 18:09:00 -0400 Subject: [PATCH 4/5] Shifter FBX tool: add export tab to node data --- release/scripts/mgear/shifter/game_tools_fbx/fbx_export_node.py | 1 + 1 file changed, 1 insertion(+) diff --git a/release/scripts/mgear/shifter/game_tools_fbx/fbx_export_node.py b/release/scripts/mgear/shifter/game_tools_fbx/fbx_export_node.py index 8be331c7..d3a08bc7 100644 --- a/release/scripts/mgear/shifter/game_tools_fbx/fbx_export_node.py +++ b/release/scripts/mgear/shifter/game_tools_fbx/fbx_export_node.py @@ -28,6 +28,7 @@ class FbxExportNode(object): "deformations": True, "partitions": {}, "anim_clips": {}, + "export_tab": 0, } ANIM_CLIP_DATA = { "title": "Untitled", From bad161a086cc06053a09a9a09184877dfc537ddd Mon Sep 17 00:00:00 2001 From: Irene Weng Date: Thu, 14 Sep 2023 18:09:52 -0400 Subject: [PATCH 5/5] Shifter FBX tool: bug fixes in partitions outliner --- .../mgear/shifter/game_tools_fbx/partition_widgets.py | 6 +++--- .../mgear/shifter/game_tools_fbx/partitions_outliner.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/release/scripts/mgear/shifter/game_tools_fbx/partition_widgets.py b/release/scripts/mgear/shifter/game_tools_fbx/partition_widgets.py index a9987738..72de452f 100644 --- a/release/scripts/mgear/shifter/game_tools_fbx/partition_widgets.py +++ b/release/scripts/mgear/shifter/game_tools_fbx/partition_widgets.py @@ -3,7 +3,7 @@ import maya.cmds as cmds -# TODO: Remove following dependencies +# TODO: Remove dependency import maya.app.flux.core as fx from mgear.vendor.Qt import QtWidgets, QtCore, QtGui @@ -617,14 +617,14 @@ def _on_custom_context_menu_requested(self, pos): return if item.is_root(): if num_indexes > 0: - pixmap = QtGui.QPixMap(100, 100) + pixmap = QtGui.QPixmap(100, 100) pixmap.fill(self._get_label_color()) label_icon = QtGui.QIcon(pixmap) prev_menu = self._context_menu.addMenu( label_icon, "Label Color" ) for color_label in LABEL_COLORS: - pixmap = QtGui.QPixMap(100, 100) + pixmap = QtGui.QPixmap(100, 100) pixmap.fill(self._get_color_from_label(color_label)) label_icon = QtGui.QIcon(pixmap) prev_menu.addAction( diff --git a/release/scripts/mgear/shifter/game_tools_fbx/partitions_outliner.py b/release/scripts/mgear/shifter/game_tools_fbx/partitions_outliner.py index 0a4b3bc3..eeb7a6f4 100644 --- a/release/scripts/mgear/shifter/game_tools_fbx/partitions_outliner.py +++ b/release/scripts/mgear/shifter/game_tools_fbx/partitions_outliner.py @@ -208,7 +208,7 @@ def _update_master_partition(self): found_meshes = [] for geo_root in self._geo_roots: - if not geo_root: + if not (geo_root and cmds.objExists(geo_root)): return children = ( cmds.listRelatives(