diff --git a/lib/mayaHydra/mayaPlugin/renderOverride.cpp b/lib/mayaHydra/mayaPlugin/renderOverride.cpp index 9fe7b96a9..f17ac9e46 100644 --- a/lib/mayaHydra/mayaPlugin/renderOverride.cpp +++ b/lib/mayaHydra/mayaPlugin/renderOverride.cpp @@ -48,6 +48,7 @@ #include #ifdef MAYA_HAS_VIEW_SELECTED_OBJECT_API #include +#include #endif #include #include @@ -332,6 +333,10 @@ MtohRenderOverride::MtohRenderOverride(const MtohRendererDescription& desc) std::lock_guard lock(_allInstancesMutex); _allInstances.push_back(this); } + +#ifdef MAYA_HAS_VIEW_SELECTED_OBJECT_API + Fvp::Instruments::instance().set(kNbViewSelectedChangedCalls, VtValue(_nbViewSelectedChangedCalls)); +#endif } MtohRenderOverride::~MtohRenderOverride() @@ -1761,9 +1766,26 @@ void MtohRenderOverride::_RenderOverrideChangedCallback( void MtohRenderOverride::_ViewSelectedChangedCb( const MString& viewName, bool viewSelectedObjectsChanged, - void* /* data */ + void* data ) { + // For simplicity, we leave the view selected changed callback active even + // when Maya Hydra isn't the renderer, and early out. Another option would + // be to add and remove the callback in _InitHydraResources() and + // ClearHydraResources(). + auto* instance = reinterpret_cast(data); + if (!TF_VERIFY(instance)) { + return; + } + if (!instance->_initializationSucceeded) { + return; + } + + auto& nbCalls = instance->_nbViewSelectedChangedCalls; + ++nbCalls; + Fvp::Instruments::instance().set( + kNbViewSelectedChangedCalls, VtValue(nbCalls)); + M3dView view; if (!TF_VERIFY(M3dView::getM3dViewFromModelPanel(viewName, view) == MS::kSuccess, "No view found for view name %s.", viewName.asChar())) { diff --git a/lib/mayaHydra/mayaPlugin/renderOverride.h b/lib/mayaHydra/mayaPlugin/renderOverride.h index a04d4b6c0..cfcc5215f 100644 --- a/lib/mayaHydra/mayaPlugin/renderOverride.h +++ b/lib/mayaHydra/mayaPlugin/renderOverride.h @@ -100,6 +100,10 @@ class MtohRenderOverride : public MHWRender::MRenderOverride, { public: +#ifdef MAYA_HAS_VIEW_SELECTED_OBJECT_API + static constexpr char kNbViewSelectedChangedCalls[] = "MtohRenderOverride:NbViewSelectedChangedCalls"; +#endif + MtohRenderOverride(const MtohRendererDescription& desc); ~MtohRenderOverride() override; @@ -332,6 +336,9 @@ class MtohRenderOverride : public MHWRender::MRenderOverride, bool _useDefaultMaterial; bool _xRayEnabled; MFrameContext::LightingMode _lightingMode = MFrameContext::LightingMode::kSceneLights; +#ifdef MAYA_HAS_VIEW_SELECTED_OBJECT_API + long int _nbViewSelectedChangedCalls{0}; +#endif }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt b/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt index 34ac5227d..7e00a87e2 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt +++ b/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt @@ -89,6 +89,7 @@ set(INTERACTIVE_TEST_SCRIPT_FILES if (MAYA_HAS_VIEW_SELECTED_OBJECT_API) list(APPEND INTERACTIVE_TEST_SCRIPT_FILES cpp/testIsolateSelect.py + cpp/testIsolateSelectSwitchToVP2.py cpp/testIsolateSelectMayaSelectionHighlighting.py cpp/testUsdNativeInstancingIsolateSelect.py cpp/testUsdPointInstancingIsolateSelect.py diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testIsolateSelectSwitchToVP2.py b/test/lib/mayaUsd/render/mayaToHydra/cpp/testIsolateSelectSwitchToVP2.py new file mode 100644 index 000000000..c3a48c0c8 --- /dev/null +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testIsolateSelectSwitchToVP2.py @@ -0,0 +1,163 @@ +# Copyright 2024 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 fixturesUtils +import mtohUtils +import maya.cmds as cmds +import maya.mel as mel + +def enableIsolateSelect(modelPanel): + # Surprisingly + # + # cmds.isolateSelect('modelPanel1', state=1) + # + # is insufficient to turn on isolate selection in a viewport, and we must + # use the MEL script used by the menu and Ctrl-1 hotkey. This is because + # the viewport uses the selectionConnection command to filter the selection + # it receives and create its isolate selection, and the the + # mainListConnection, lockMainConnection and unlockMainConnection flags of + # the editor command to suspend changes to its selection connection. See + # the documentation for more details. + cmds.setFocus(modelPanel) + mel.eval("enableIsolateSelect %s 1" % modelPanel) + +def disableIsolateSelect(modelPanel): + cmds.setFocus(modelPanel) + mel.eval("enableIsolateSelect %s 0" % modelPanel) + +# This test is very similar to testIsolateSelect.py. See HYDRA-1245. + +class TestIsolateSelectSwitchToVP2(mtohUtils.MayaHydraBaseTestCase): + # MayaHydraBaseTestCase.setUpClass requirement. + _file = __file__ + + # Base class setUp() defines HdStorm as the renderer. + + _pluginsToLoad = ['mayaHydraCppTests'] + _pluginsToUnload = [] + + @classmethod + def setUpClass(cls): + super(TestIsolateSelectSwitchToVP2, cls).setUpClass() + for p in cls._pluginsToLoad: + if not cmds.pluginInfo(p, q=True, loaded=True): + cls._pluginsToUnload.append(p) + cmds.loadPlugin(p, quiet=True) + + @classmethod + def tearDownClass(cls): + super(TestIsolateSelectSwitchToVP2, cls).tearDownClass() + # Clean out the scene to allow all plugins to unload cleanly. + cmds.file(new=True, force=True) + for p in reversed(cls._pluginsToUnload): + cmds.unloadPlugin(p) + + def setupScene(self): + + cmds.polyTorus() + cmds.polySphere() + cmds.polyCube() + + cmds.refresh() + + scene = [ + # Maya objects + '|pTorus1', + '|pTorus1|pTorusShape1', + '|pSphere1', + '|pSphere1|pSphereShape1', + '|pCube1', + '|pCube1|pCubeShape1'] + + return scene + + def assertVisible(self, visible): + for v in visible: + self.trace("Testing %s for visibility\n" % v) + cmds.mayaHydraCppTest(v, f="TestHydraPrim.isVisible") + + def assertNotVisible(self, notVisible): + for nv in notVisible: + self.trace("Testing %s for invisibility\n" % nv) + cmds.mayaHydraCppTest(nv, f="TestHydraPrim.notVisible") + + def assertVisibility(self, visible, notVisible): + self.assertVisible(visible) + self.assertNotVisible(notVisible) + + def test_isolateSelectSwitchToVP2(self): + + scene = self.setupScene() + modelPanel = 'modelPanel4' + enableIsolateSelect(modelPanel) + + # Isolate select Maya object. + cmds.select('|pTorus1') + cmds.editor(modelPanel, edit=True, updateMainConnection=True) + cmds.isolateSelect(modelPanel, loadSelected=True) + + visible = ['|pTorus1', '|pTorus1|pTorusShape1'] + + notVisible = scene.copy() + for p in visible: + notVisible.remove(p) + + cmds.refresh() + + self.assertVisibility(visible, notVisible) + + # Record the number of view selected changed calls so far. + viewSelectedChangedCallsPre = cmds.mayaHydraInstruments("MtohRenderOverride:NbViewSelectedChangedCalls", q=True) + + self.assertGreater(viewSelectedChangedCallsPre, 0) + + # Switch to VP2, and make a different isolate selection. The number of + # Hydra view selected changed calls should remain the same. + self.setViewport2Renderer() + + cmds.select('|pSphere1') + cmds.editor(modelPanel, edit=True, updateMainConnection=True) + cmds.isolateSelect(modelPanel, loadSelected=True) + + cmds.refresh() + + viewSelectedChangedCallsVP2 = cmds.mayaHydraInstruments("MtohRenderOverride:NbViewSelectedChangedCalls", q=True) + + self.assertEqual(viewSelectedChangedCallsPre, viewSelectedChangedCallsVP2) + + # Switch back to Hydra Storm, and make a different isolate selection. + # The number of Hydra view selected changed calls should increase. + self.setHdStormRenderer() + + cmds.select('|pCube1') + cmds.editor(modelPanel, edit=True, updateMainConnection=True) + cmds.isolateSelect(modelPanel, loadSelected=True) + + visible = ['|pCube1', '|pCube1|pCubeShape1'] + + notVisible = scene.copy() + for p in visible: + notVisible.remove(p) + + cmds.refresh() + + self.assertVisibility(visible, notVisible) + + viewSelectedChangedCallsPost = cmds.mayaHydraInstruments("MtohRenderOverride:NbViewSelectedChangedCalls", q=True) + + self.assertGreater(viewSelectedChangedCallsPost, viewSelectedChangedCallsPre) + +if __name__ == '__main__': + fixturesUtils.runTests(globals())