From 5d7752237d0f931b960878f1c5351e5bf55138eb Mon Sep 17 00:00:00 2001 From: David Lanier <122012029+lanierd-adsk@users.noreply.github.com> Date: Fri, 1 Dec 2023 17:34:53 +0100 Subject: [PATCH] =?UTF-8?q?HYDRA-600=20:=20Add=20filtering=20scene=20index?= =?UTF-8?q?=20interface=20to=20flow=20viewport=20tool=E2=80=A6=20(#21)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * HYDRA-600 : Add filtering scene index interface to flow viewport toolkit. * HYDRA-600 : Fix OSX compilation. * HYDRA-600 : Fixes from the code review. * HYDRA-600 : more modifications from code review. * HYDRA-600 :; found a potential issue with declaring ref ptr * HYDRA-600 : switch to using vector instead set for ViewportInformationAndSceneIndicesPerViewportData and add const where it was possible. --- lib/flowViewport/API/CMakeLists.txt | 4 + .../API/fvpDataProducerSceneIndexInterface.h | 13 +- .../API/fvpFilteringSceneIndexClient.h | 157 +++++++++++++ .../API/fvpFilteringSceneIndexClientFwd.h | 35 +++ .../API/fvpFilteringSceneIndexInterface.h | 65 ++++++ .../API/fvpInformationInterface.h | 11 +- lib/flowViewport/API/fvpViewportAPITokens.h | 42 ++++ .../API/interfacesImp/CMakeLists.txt | 2 + .../fvpDataProducerSceneIndexInterfaceImp.cpp | 18 +- .../fvpDataProducerSceneIndexInterfaceImp.h | 9 +- .../fvpFilteringSceneIndexInterfaceImp.cpp | 208 ++++++++++++++++++ .../fvpFilteringSceneIndexInterfaceImp.h | 64 ++++++ .../fvpInformationInterfaceImp.cpp | 2 +- .../fvpSelectionInterfaceImp.cpp | 2 +- .../CMakeLists.txt | 6 + ...ataProducerSceneIndexDataAbstractFactory.h | 6 +- .../fvpDataProducerSceneIndexDataBase.h | 2 +- ...vpFilteringSceneIndexDataAbstractFactory.h | 37 ++++ .../fvpFilteringSceneIndexDataBase.cpp | 41 ++++ .../fvpFilteringSceneIndexDataBase.h | 64 ++++++ .../fvpFilteringSceneIndicesChainManager.cpp | 169 ++++++++++++++ .../fvpFilteringSceneIndicesChainManager.h | 99 +++++++++ .../fvpViewportAPITokens.cpp | 24 ++ ...ormationAndSceneIndicesPerViewportData.cpp | 5 +- ...nformationAndSceneIndicesPerViewportData.h | 19 +- ...nAndSceneIndicesPerViewportDataManager.cpp | 45 ++-- ...ionAndSceneIndicesPerViewportDataManager.h | 13 +- lib/flowViewport/API/samples/CMakeLists.txt | 4 + .../fvpDataProducerSceneIndexExample.cpp | 4 +- .../fvpFilteringSceneIndexClientExample.cpp | 43 ++++ .../fvpFilteringSceneIndexClientExample.h | 86 ++++++++ .../samples/fvpFilteringSceneIndexExample.cpp | 85 +++++++ .../samples/fvpFilteringSceneIndexExample.h | 91 ++++++++ .../samples/fvpInformationClientExample.cpp | 4 +- .../sceneIndex/fvpRenderIndexProxyFwd.h | 2 +- .../flowViewportAPIMayaLocator.cpp | 30 ++- .../hydraExtensions/sceneIndex/CMakeLists.txt | 4 + ...ayaHydraMayaDataProducerSceneIndexData.cpp | 4 +- .../mayaHydraMayaDataProducerSceneIndexData.h | 21 +- .../mayaHydraMayaFilteringSceneIndexData.cpp | 127 +++++++++++ .../mayaHydraMayaFilteringSceneIndexData.h | 66 ++++++ ...FilteringSceneIndexDataConcreteFactory.cpp | 31 +++ ...yaFilteringSceneIndexDataConcreteFactory.h | 41 ++++ .../mayaHydraSceneIndexDataFactoriesSetup.cpp | 5 + lib/mayaHydra/mayaPlugin/renderOverride.cpp | 14 +- lib/mayaHydra/mayaPlugin/renderOverride.h | 1 + .../mayaUsd/render/mayaToHydra/CMakeLists.txt | 1 + .../filter_NodeCreated.png | Bin 0 -> 9129 bytes .../filter_NodeDeleted.png | Bin 0 -> 2140 bytes .../filter_NodeDeletedRedo.png | Bin 0 -> 2140 bytes .../filter_NodeDeletedUndo.png | Bin 0 -> 6063 bytes .../FlowViewportAPITest/filter_NodeHidden.png | Bin 0 -> 2140 bytes .../FlowViewportAPITest/filter_NodeMoved.png | Bin 0 -> 6643 bytes .../filter_NodeUnhidden.png | Bin 0 -> 6063 bytes .../filter_SphereFiltered.png | Bin 0 -> 6063 bytes .../filter_SphereFilteredAgain.png | Bin 0 -> 6063 bytes .../filter_SphereUnFiltered.png | Bin 0 -> 6662 bytes .../filter_VP2AndThenBackToStorm.png | Bin 0 -> 6063 bytes ...iewports_VP2AndThenBackToStorm_modPan2.png | Bin 3265 -> 3230 bytes ...iewports_VP2AndThenBackToStorm_modPan4.png | Bin 5821 -> 5876 bytes .../multipleViewports_VP2_modPan2.png | Bin 2225 -> 2174 bytes .../multipleViewports_VP2_modPan4.png | Bin 2155 -> 2135 bytes .../render/mayaToHydra/cpp/CMakeLists.txt | 1 + .../cpp/testFlowViewportAPIAddPrims.cpp | 24 +- .../cpp/testFlowViewportAPIFilterPrims.cpp | 119 ++++++++++ .../cpp/testFlowViewportAPIFilterPrims.py | 41 ++++ .../cpp/testMayaSceneFlattening.cpp | 4 +- .../mayaToHydra/cpp/testMayaUsdUfeItems.cpp | 4 +- .../mayaToHydra/cpp/testMergingSceneIndex.cpp | 2 +- .../cpp/testMeshAdapterTransform.cpp | 2 +- .../cpp/testSelectionSceneIndex.cpp | 2 +- .../render/mayaToHydra/cpp/testUtils.h | 38 ++++ ...tWireframeSelectionHighlightSceneIndex.cpp | 2 +- .../render/mayaToHydra/testFlowViewportAPI.py | 108 ++++++++- 74 files changed, 2054 insertions(+), 119 deletions(-) create mode 100644 lib/flowViewport/API/fvpFilteringSceneIndexClient.h create mode 100644 lib/flowViewport/API/fvpFilteringSceneIndexClientFwd.h create mode 100644 lib/flowViewport/API/fvpFilteringSceneIndexInterface.h create mode 100644 lib/flowViewport/API/fvpViewportAPITokens.h create mode 100644 lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.cpp create mode 100644 lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.h create mode 100644 lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataAbstractFactory.h create mode 100644 lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataBase.cpp create mode 100644 lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataBase.h create mode 100644 lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.cpp create mode 100644 lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.h create mode 100644 lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportAPITokens.cpp create mode 100644 lib/flowViewport/API/samples/fvpFilteringSceneIndexClientExample.cpp create mode 100644 lib/flowViewport/API/samples/fvpFilteringSceneIndexClientExample.h create mode 100644 lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp create mode 100644 lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h create mode 100644 lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexData.cpp create mode 100644 lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexData.h create mode 100644 lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexDataConcreteFactory.cpp create mode 100644 lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexDataConcreteFactory.h create mode 100644 test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeCreated.png create mode 100644 test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeDeleted.png create mode 100644 test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeDeletedRedo.png create mode 100644 test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeDeletedUndo.png create mode 100644 test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeHidden.png create mode 100644 test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeMoved.png create mode 100644 test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeUnhidden.png create mode 100644 test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_SphereFiltered.png create mode 100644 test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_SphereFilteredAgain.png create mode 100644 test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_SphereUnFiltered.png create mode 100644 test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_VP2AndThenBackToStorm.png create mode 100644 test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIFilterPrims.cpp create mode 100644 test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIFilterPrims.py diff --git a/lib/flowViewport/API/CMakeLists.txt b/lib/flowViewport/API/CMakeLists.txt index 2229b0c326..5c42732fd5 100644 --- a/lib/flowViewport/API/CMakeLists.txt +++ b/lib/flowViewport/API/CMakeLists.txt @@ -5,6 +5,10 @@ set(HEADERS fvpInformationInterface.h fvpInformationClient.h fvpDataProducerSceneIndexInterface.h + fvpFilteringSceneIndexClient.h + fvpFilteringSceneIndexClientFwd.h + fvpFilteringSceneIndexInterface.h + fvpViewportAPITokens.h ) # ----------------------------------------------------------------------------- diff --git a/lib/flowViewport/API/fvpDataProducerSceneIndexInterface.h b/lib/flowViewport/API/fvpDataProducerSceneIndexInterface.h index 6f42666dc5..420a924847 100644 --- a/lib/flowViewport/API/fvpDataProducerSceneIndexInterface.h +++ b/lib/flowViewport/API/fvpDataProducerSceneIndexInterface.h @@ -19,6 +19,7 @@ //Local headers #include "flowViewport/api.h" +#include "flowViewport/API/fvpViewportAPITokens.h" //Hydra headers #include @@ -38,12 +39,6 @@ namespace FVP_NS_DEF /// Interface accessor static FVP_API DataProducerSceneIndexInterface& get(); - /// Use this string in the viewport identifier parameters, named "hydraViewportId" in this class, to apply the data producer scene index to all viewports. - static FVP_API const std::string allViewports; - - /// Use this string in the AddDataProducerSceneIndex method for the "rendererNames" parameter to apply to all renderers. - static FVP_API const std::string allRenderers; - /** * @brief Adds a custom data producer scene index. * @@ -77,8 +72,8 @@ namespace FVP_NS_DEF */ virtual bool addDataProducerSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& customDataProducerSceneIndex, void* dccNode = nullptr, - const std::string& hydraViewportId = allViewports, - const std::string& rendererNames = allRenderers, + const std::string& hydraViewportId = PXR_NS::FvpViewportAPITokens->allViewports, + const std::string& rendererNames = PXR_NS::FvpViewportAPITokens->allRenderers, const PXR_NS::SdfPath& customDataProducerSceneIndexRootPathForInsertion = PXR_NS::SdfPath::AbsoluteRootPath() ) = 0; @@ -94,7 +89,7 @@ namespace FVP_NS_DEF */ virtual void removeViewportDataProducerSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& customDataProducerSceneIndex, - const std::string& hydraViewportId = allViewports + const std::string& hydraViewportId = PXR_NS::FvpViewportAPITokens->allViewports ) = 0; }; diff --git a/lib/flowViewport/API/fvpFilteringSceneIndexClient.h b/lib/flowViewport/API/fvpFilteringSceneIndexClient.h new file mode 100644 index 0000000000..222059036b --- /dev/null +++ b/lib/flowViewport/API/fvpFilteringSceneIndexClient.h @@ -0,0 +1,157 @@ +// +// Copyright 2023 Autodesk, Inc. All rights reserved. +// +// 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. +// + + +/// Is the definition of a customer Hydra client to register a set of callbacks for a Hydra viewport. +#ifndef FLOW_VIEWPORT_API_FILTERING_SCENE_INDEX_CLIENT_H +#define FLOW_VIEWPORT_API_FILTERING_SCENE_INDEX_CLIENT_H + +#include "flowViewport/api.h" +#include "flowViewport/API/fvpViewportAPITokens.h" + +#include + +namespace FVP_NS_DEF +{ + ///Subclass this to create a callbacks FilteringSceneIndexClient and register it through the FilteringSceneIndexInterface class + class FilteringSceneIndexClient + { + public: + /** + * A Category is a container in which you want your filtering scene index or scene index chain to go to. + * The filtering scene indices inside a Category don't have any specific priority when they are called. + */ + enum class Category + { + /// kSelectionHighlighting is to register a filtering scene index to do custom selection highlighting (still a WIP) + kSelectionHighlighting, + /** kSceneFiltering is to register a filtering scene index applied to the primitives from the scene, + * including usd stages, DCC native objects and custom data producer scene indices primitives. + */ + kSceneFiltering, + }; + + /** + * @brief Callback function to append a scene index. + * + * This callback function gets called for you to append a scene index to a Hydra viewport scene index, like a filtering scene index. + * A typical case is when a new Hydra viewport is created, after some internal managment of this scene index, we call this function so you can append one scene index + * or a chain of scene indices and return the last element of the chain. + * The returned value of this function is the last custom scene index of a a chain that you want to append to this scene index, + * or just return the input scene index passed if you don't want to append any scene index. + * + * @param[in] displayName is a display name to be associated with your plugin. + * @param[in] category is the container in which you want your filtering scene index (or filtering scene index chain) to go into. + * @param[in] rendererNames is the names of the renderers you want this client to be associated to. + * If there are several, separate them with for example a coma, like "GL, Arnold", we actually look for the renderer name in this string. + * If you want your client to work on any renderer please use FvpViewportAPITokens->allRenderers. + * @param[in] dccNode is a MObject* for Maya, if you provide the pointer value, then we automatically track some events such as visibility changed, + * node deleted/undeleted and we remove/add automatically your filtering scene indices from the viewport. Meaning if the maya node is visible your filtering + * scene indices are applied to the scene, if the node is not visible (or deleted) your filtering scene indices are removed from the scene. + * If it is a nullptr, your filtering scene indices will stay applied to the viewport(s) until you remove them. + * + * @param[in] inputArgs is a container data source handle to deal with the possibility to send custom data from our Hydra viewport plugin for the creation of your scene index. + * This parameter is currently not used by the Hydra viewport plugin but is left for possible future use. + */ + FilteringSceneIndexClient(const std::string& displayName, const Category category, const std::string& rendererNames, void* dccNode): + _displayName{displayName}, _category{category}, _rendererNames{rendererNames}, _dccNode{dccNode} + {} + + /** + * @brief Callback function to append a scene index. + * + * This callback function gets called for you to append a scene index to a Hydra viewport scene index, like a filtering scene index. + * A typical case is when a new Hydra viewport is created, after some internal managment of this scene index, we call this function so you can append one scene index + * or a chain of scene indices and return the last element of the chain. + * The returned value of this function is the last custom scene index of a a chain that you want to append to this scene index, + * or just return the input scene index passed if you don't want to append any scene index. + * + * @param[in] inputSceneIndex is a HdSceneIndexBaseRefPtr which was created by our Hydra viewport plugin. This could be the Hydra viewport scene index or it could be some appended + * scene index, as a chain of scene indices is appended to the Hydra viewport scene index if several filtering scene index clients are registered. + * So don't assume it's the Hydra viewport scene index. + * @param[in] inputArgs is a container data source handle to deal with the possibility to send custom data from our Hydra viewport plugin for the creation of your scene index. + * This parameter is currently not used by the Hydra viewport plugin but is left for possible future use. + * + * @return If you don't want to append a scene index, just return _inputSceneIndex. + * If you want to append a scene index or a scene indices chain, you should return the last scene index of the scene indices chain to append. + */ + virtual PXR_NS::HdSceneIndexBaseRefPtr appendSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& inputSceneIndex, const PXR_NS::HdContainerDataSourceHandle& inputArgs) = 0; + + /// Destructor + virtual ~FilteringSceneIndexClient() = default; + + /** + * @brief Get the display name. + * @return the display name. + */ + const std::string& getDisplayName() const {return _displayName;} + + /** + * @brief Get the Category. + * @return the Category. + */ + const Category getCategory() const {return _category;} + + /** + * @brief Get the renderer names. + * @return the renderer names. + */ + const std::string& getRendererNames() const {return _rendererNames;} + + /** + * @brief Set the dcc node. + */ + void setDccNode(void* dccNode) {_dccNode = dccNode;} + + /** + * @brief Get the dcc node. + * @return the dcc node. + */ + void* getDccNode() const {return _dccNode;} + + bool operator == (const FilteringSceneIndexClient& other)const + { + return _displayName == other._displayName && + _category == other._category && + _rendererNames == other._rendererNames && + _dccNode == other._dccNode; + } + + protected: + /**_displayName is a display name to be associated with your plugin. + */ + const std::string _displayName {"Unnamed"}; + + /**_category is the container in which you want your filtering scene index (or filtering scene index chain) to go into. + */ + const Category _category {Category::kSceneFiltering}; + + /**_rendererNames is the names of the renderers you want this client to be associated to. + * If there are several, separate them with comas, like "GL, Arnold" + * If you want your client to work on any renderer please use FvpViewportAPITokens->allRenderers. + */ + const std::string _rendererNames = PXR_NS::FvpViewportAPITokens->allRenderers; + + /**_dccNode is a MObject* for Maya, if you provide the pointer value, then we automatically track some events such as visibility changed, + * node deleted/undeleted and we remove/add automatically your filtering scene indices from the viewport. Meaning if the maya node is visible your filtering + * scene indices are applied to the scene, if the node is not visible (or deleted) your filtering scene indices are removed from the scene. + * If it is a nullptr, your filtering scene indices will stay applied to the viewport(s) until you remove them. + */ + void* _dccNode = nullptr; + }; +}//end of namespace + +#endif //FLOW_VIEWPORT_API_FILTERING_SCENE_INDEX_CLIENT_H diff --git a/lib/flowViewport/API/fvpFilteringSceneIndexClientFwd.h b/lib/flowViewport/API/fvpFilteringSceneIndexClientFwd.h new file mode 100644 index 0000000000..3fb5c2dfa1 --- /dev/null +++ b/lib/flowViewport/API/fvpFilteringSceneIndexClientFwd.h @@ -0,0 +1,35 @@ +// +// Copyright 2023 Autodesk, Inc. All rights reserved. +// +// 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. +// + + +/// Is the forward declaration of a FilteringSceneIndexClient + +#ifndef FLOW_VIEWPORT_API_FILTERING_SCENE_INDEX_CLIENT_FWD_H +#define FLOW_VIEWPORT_API_FILTERING_SCENE_INDEX_CLIENT_FWD_H + +#include "flowViewport/api.h" + +#include + +//Is the forward declaration of the FilteringSceneIndexClient class and FilteringSceneIndexClientPtr +namespace FVP_NS_DEF +{ + class FilteringSceneIndexClient; + using FilteringSceneIndexClientPtr = std::shared_ptr; + +}//end of namespace + +#endif //FLOW_VIEWPORT_API_FILTERING_SCENE_INDEX_CLIENT_FWD_H diff --git a/lib/flowViewport/API/fvpFilteringSceneIndexInterface.h b/lib/flowViewport/API/fvpFilteringSceneIndexInterface.h new file mode 100644 index 0000000000..22f1c28e21 --- /dev/null +++ b/lib/flowViewport/API/fvpFilteringSceneIndexInterface.h @@ -0,0 +1,65 @@ +// +// Copyright 2023 Autodesk, Inc. All rights reserved. +// +// 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. +// + +#ifndef FLOW_VIEWPORT_API_FILTERING_SCENE_INDEX_INTERFACE_H +#define FLOW_VIEWPORT_API_FILTERING_SCENE_INDEX_INTERFACE_H + +//Local headers +#include "flowViewport/api.h" +#include "flowViewport/sceneIndex/fvpRenderIndexProxyFwd.h" +#include "flowViewport/API/fvpFilteringSceneIndexClientFwd.h" + +//Std headers +#include + +namespace FVP_NS_DEF +{ + /** + * Interface to register a callbacks FilteringSceneIndexClient and append custom filtering scene indices to Hydra viewports scene indices. + * To get an instance of the FilteringSceneIndexInterface class, please use : + * Fvp::FilteringSceneIndexInterface& filteringSceneIndexInterface = Fvp::FilteringSceneIndexInterface::get(); + * + * The filtering scene indices added to a hydra viewport will act on all kind of data : DCC native data, USD stages and custom primitives added by data producer scene indices. + */ + class FilteringSceneIndexInterface + { + public: + + ///Interface accessor + static FVP_API FilteringSceneIndexInterface& get(); + + /** + * @brief Register a callbacks SceneIndexClient instance + * + * @param[in] client is a FilteringSceneIndexClient. + * + * @return true if it succeded, false otherwise like the client if already registered. + */ + virtual bool registerFilteringSceneIndexClient(const std::shared_ptr& client) = 0; + + /** + * @brief Unregister an SceneIndexClient instance + * + * Unregister an SceneIndexClient instance, to stop receiving notifications. + * + * @param[in] client is the FilteringSceneIndexClient to remove. + */ + virtual void unregisterFilteringSceneIndexClient(const std::shared_ptr& client)= 0; + }; + +}//end of namespace + +#endif //FLOW_VIEWPORT_API_FILTERING_SCENE_INDEX_INTERFACE_H diff --git a/lib/flowViewport/API/fvpInformationInterface.h b/lib/flowViewport/API/fvpInformationInterface.h index 70b68e74a6..96795af357 100644 --- a/lib/flowViewport/API/fvpInformationInterface.h +++ b/lib/flowViewport/API/fvpInformationInterface.h @@ -47,14 +47,21 @@ namespace FVP_NS_DEF : _viewportId(viewportId), _cameraName(cameraName) {} ///_viewportId is a Hydra viewport string identifier which is unique for all hydra viewports during a session - const std::string _viewportId; + std::string _viewportId; ///_cameraName is the name of the camera/viewport when the viewport was created, it is not updated if the camera's name has changed. - const std::string _cameraName; + std::string _cameraName; ///_rendererName is the Hydra viewport renderer name (example : "GL" for Storm or "Arnold" for the Arnold render delegate) std::string _rendererName; + ViewportInformation& operator = (const ViewportInformation& other){ + _viewportId = other._viewportId; + _cameraName = other._cameraName; + _rendererName = other._rendererName; + return *this; + } + bool operator ==(const ViewportInformation& other)const{ return _viewportId == other._viewportId && _cameraName == other._cameraName && diff --git a/lib/flowViewport/API/fvpViewportAPITokens.h b/lib/flowViewport/API/fvpViewportAPITokens.h new file mode 100644 index 0000000000..ecf76bd95d --- /dev/null +++ b/lib/flowViewport/API/fvpViewportAPITokens.h @@ -0,0 +1,42 @@ +// +// Copyright 2023 Autodesk, Inc. All rights reserved. +// +// 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. +// + + +/// Is the definition of a customer Hydra client to register a set of callbacks for a Hydra viewport. +#ifndef FLOW_VIEWPORT_API_VIEWPORT_API_TOKENS_H +#define FLOW_VIEWPORT_API_VIEWPORT_API_TOKENS_H + +#include "flowViewport/api.h" + +#include + +// *** TODO / FIXME *** Figure out how to put tokens into non-Pixar namespace. + +PXR_NAMESPACE_OPEN_SCOPE + +// clang-format off +#define FVP_VIEWPORT_API_TOKENS\ + /** Use this string in the viewport identifier parameters, named "hydraViewportId" in this class, to apply the data producer scene index to all viewports.*/\ + (allViewports) \ + /** Use this string for the "rendererNames" parameter to apply to all renderers.*/\ + (allRenderers) +// clang-format on + +TF_DECLARE_PUBLIC_TOKENS(FvpViewportAPITokens, FVP_API, FVP_VIEWPORT_API_TOKENS); + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif //FLOW_VIEWPORT_API_VIEWPORT_API_TOKENS_H diff --git a/lib/flowViewport/API/interfacesImp/CMakeLists.txt b/lib/flowViewport/API/interfacesImp/CMakeLists.txt index f0390f6bdd..9a77bfe82e 100644 --- a/lib/flowViewport/API/interfacesImp/CMakeLists.txt +++ b/lib/flowViewport/API/interfacesImp/CMakeLists.txt @@ -7,6 +7,7 @@ target_sources(${TARGET_NAME} fvpVersionInterfaceImp.cpp fvpInformationInterfaceImp.cpp fvpDataProducerSceneIndexInterfaceImp.cpp + fvpFilteringSceneIndexInterfaceImp.cpp ) set(HEADERS @@ -14,6 +15,7 @@ set(HEADERS fvpVersionInterfaceImp.h fvpInformationInterfaceImp.h fvpDataProducerSceneIndexInterfaceImp.h + fvpFilteringSceneIndexInterfaceImp.h ) # ----------------------------------------------------------------------------- diff --git a/lib/flowViewport/API/interfacesImp/fvpDataProducerSceneIndexInterfaceImp.cpp b/lib/flowViewport/API/interfacesImp/fvpDataProducerSceneIndexInterfaceImp.cpp index fcc6428696..f45c6c5d6d 100644 --- a/lib/flowViewport/API/interfacesImp/fvpDataProducerSceneIndexInterfaceImp.cpp +++ b/lib/flowViewport/API/interfacesImp/fvpDataProducerSceneIndexInterfaceImp.cpp @@ -23,7 +23,7 @@ //Hydra headers #include -//STL Headers +//Std Headers #include namespace @@ -41,9 +41,6 @@ PXR_NAMESPACE_USING_DIRECTIVE namespace FVP_NS_DEF { -const std::string DataProducerSceneIndexInterface::allViewports = "allViewports"; -const std::string DataProducerSceneIndexInterface::allRenderers = "allRenderers"; - DataProducerSceneIndexInterface& DataProducerSceneIndexInterface::get() { return DataProducerSceneIndexInterfaceImp::get(); @@ -67,7 +64,7 @@ bool DataProducerSceneIndexInterfaceImp::addDataProducerSceneIndex(const PXR_NS: if (nullptr == dataProducerSceneIndexData){ return false; } - if (DataProducerSceneIndexInterface::allViewports == hydraViewportId){ + if (PXR_NS::FvpViewportAPITokens->allViewports == hydraViewportId){ //Apply this data producer scene index to all viewports return _AddDataProducerSceneIndexToAllViewports(dataProducerSceneIndexData); } @@ -92,7 +89,7 @@ void DataProducerSceneIndexInterfaceImp::removeAllViewportDataProducerSceneIndic auto& dataProducerSceneIndicesDataForthisViewport = viewportInformationAndSceneIndicesPerViewportData.GetDataProducerSceneIndicesData(); - for (auto& dataProducerSceneIndicesData : dataProducerSceneIndicesDataForthisViewport){ + for (const auto& dataProducerSceneIndicesData : dataProducerSceneIndicesDataForthisViewport){ //Remove it from the render index if (dataProducerSceneIndicesData){ const auto& sceneIndex = dataProducerSceneIndicesData->GetDataProducerLastSceneIndexChain(); @@ -110,16 +107,15 @@ void DataProducerSceneIndexInterfaceImp::removeAllViewportDataProducerSceneIndic void DataProducerSceneIndexInterfaceImp::removeViewportDataProducerSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& customDataProducerSceneIndex, const std::string& hydraViewportId /*= allViewports*/) { - if (DataProducerSceneIndexInterface::allViewports == hydraViewportId){ + if (PXR_NS::FvpViewportAPITokens->allViewports == hydraViewportId){ //It was applied to all viewports - ViewportInformationAndSceneIndicesPerViewportDataSet& allViewportsInfoAndSceneIndices = + ViewportInformationAndSceneIndicesPerViewportDataVector& allViewportsInfoAndSceneIndices = ViewportInformationAndSceneIndicesPerViewportDataManager::Get().GetAllViewportInfoAndData(); //We need to remove it from all viewports where it was applied. for (auto& viewportInfoAndData : allViewportsInfoAndSceneIndices){ - ViewportInformationAndSceneIndicesPerViewportData& nonConstViewportInfoAndData = const_cast(viewportInfoAndData); - nonConstViewportInfoAndData.RemoveViewportDataProducerSceneIndex(customDataProducerSceneIndex); + viewportInfoAndData.RemoveViewportDataProducerSceneIndex(customDataProducerSceneIndex); } //Also remove it from the dataProducerSceneIndicesThatApplyToAllViewports array @@ -194,7 +190,7 @@ void DataProducerSceneIndexInterfaceImp::_AddDataProducerSceneIndexToThisViewpor //Check if there is some filtering per Hydra renderer const std::string& viewportRendererName = viewportInformation._rendererName; const std::string& dataProducerSceneIndexApplyToRendererNames = dataProducerSceneIndexData->GetRendererNames(); - if ( (! viewportRendererName.empty() )&& (dataProducerSceneIndexApplyToRendererNames != DataProducerSceneIndexInterface::allRenderers) ){ + if ( (! viewportRendererName.empty() )&& (dataProducerSceneIndexApplyToRendererNames != PXR_NS::FvpViewportAPITokens->allRenderers) ){ //Filtering per renderer is applied if (std::string::npos == dataProducerSceneIndexApplyToRendererNames.find(viewportRendererName)){ return; //Ignore the current hydra viewport renderer name is not part of the supported renderers for this data producer scene index diff --git a/lib/flowViewport/API/interfacesImp/fvpDataProducerSceneIndexInterfaceImp.h b/lib/flowViewport/API/interfacesImp/fvpDataProducerSceneIndexInterfaceImp.h index a567dc45af..ee7b6bd407 100644 --- a/lib/flowViewport/API/interfacesImp/fvpDataProducerSceneIndexInterfaceImp.h +++ b/lib/flowViewport/API/interfacesImp/fvpDataProducerSceneIndexInterfaceImp.h @@ -24,8 +24,9 @@ #include "flowViewport/API/fvpDataProducerSceneIndexInterface.h" #include "flowViewport/API/fvpInformationInterface.h" #include "flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataAbstractFactory.h" +#include "flowViewport/API/fvpViewportAPITokens.h" -//STL Headers +//Std Headers #include namespace FVP_NS_DEF { @@ -45,12 +46,12 @@ class DataProducerSceneIndexInterfaceImp : public DataProducerSceneIndexInterfac ///From FVP_NS_DEF::DataProducerSceneIndexInterface bool addDataProducerSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& customDataProducerSceneIndex, void* dccNode = nullptr, - const std::string& hydraViewportId = allViewports, - const std::string& rendererNames = allRenderers, + const std::string& hydraViewportId = PXR_NS::FvpViewportAPITokens->allViewports, + const std::string& rendererNames = PXR_NS::FvpViewportAPITokens->allRenderers, const PXR_NS::SdfPath& customDataProducerSceneIndexRootPathForInsertion = PXR_NS::SdfPath::AbsoluteRootPath() )override; void removeViewportDataProducerSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& customDataProducerSceneIndex, - const std::string& hydraViewportId = allViewports)override; + const std::string& hydraViewportId = PXR_NS::FvpViewportAPITokens->allViewports)override; //Called by flow viewport ///hydraViewportSceneIndexAdded is called when a new hydra viewport is created by the ViewportInformationAndSceneIndicesPerViewportDataManager, it's not a callback. diff --git a/lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.cpp b/lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.cpp new file mode 100644 index 0000000000..eee2610bc4 --- /dev/null +++ b/lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.cpp @@ -0,0 +1,208 @@ +// +// Copyright 2023 Autodesk, Inc. All rights reserved. +// +// 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. +// + +//Local headers +#include "fvpFilteringSceneIndexInterfaceImp.h" +#include "flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.h" + +//Std headers +#include + +namespace +{ + std::mutex selectionHighlightFilteringClient_mutex; + std::mutex sceneFilteringClient_mutex; + + //Set of scene Filtering scene index data, they belong to the Fpv::FilteringSceneIndexClient::Category::kSceneFiltering + std::set sceneFilteringSceneIndicesData; + + //Set of selection highlighting Filtering scene index data, they belong to the Fpv::FilteringSceneIndexClient::Category::kSelectionHighlighting + std::set selectionHighlightFilteringSceneIndicesData; + + // Abstract factory to create the scene index data, an implementation is provided by the DCC + FVP_NS::FilteringSceneIndexDataAbstractFactory* sceneIndexDataFactory{nullptr}; +} + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FVP_NS_DEF { + +FilteringSceneIndexInterface& FilteringSceneIndexInterface::get() +{ + return FilteringSceneIndexInterfaceImp::get(); +} + +FilteringSceneIndexInterfaceImp& FilteringSceneIndexInterfaceImp::get() +{ + static FilteringSceneIndexInterfaceImp theInterface; + return theInterface; +} + +FilteringSceneIndexInterfaceImp::~FilteringSceneIndexInterfaceImp() +{ +} + +bool FilteringSceneIndexInterfaceImp::registerFilteringSceneIndexClient(const std::shared_ptr& client) +{ + switch(client->getCategory()){ + case Fvp::FilteringSceneIndexClient::Category::kSceneFiltering:{ + return _CreateSceneFilteringSceneIndicesData(client); + } + break; + case Fvp::FilteringSceneIndexClient::Category::kSelectionHighlighting:{ + return _CreateSelectionHighlightFilteringSceneIndicesData(client); + } + break; + default:{ + TF_AXIOM(0);//Should never happen + } + } + return false; +} + +bool FilteringSceneIndexInterfaceImp::_CreateSceneFilteringSceneIndicesData(const std::shared_ptr& client) +{ + TF_AXIOM(sceneIndexDataFactory); + + bool bNeedToUpdateViewportsFilteringSceneIndicesChain = false; + + //Block for the lock lifetime + { + std::lock_guard lock(sceneFilteringClient_mutex); + + auto findResult = std::find_if(sceneFilteringSceneIndicesData.cbegin(), sceneFilteringSceneIndicesData.cend(), + [&client](const PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr& filteringSIData) { return filteringSIData->getClient() == client;}); + if (findResult != sceneFilteringSceneIndicesData.cend()){ + return false; + } + + //Call the abstract scene index data factory to create a subclass of FilteringSceneIndexDataBase + PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr data = sceneIndexDataFactory->createFilteringSceneIndexDataBase(client); + sceneFilteringSceneIndicesData.insert(data); + bNeedToUpdateViewportsFilteringSceneIndicesChain = true; + } + + if (bNeedToUpdateViewportsFilteringSceneIndicesChain){ + FilteringSceneIndicesChainManager::get().updateFilteringSceneIndicesChain(client->getRendererNames()); + } + + return true; +} + +bool FilteringSceneIndexInterfaceImp::_CreateSelectionHighlightFilteringSceneIndicesData(const std::shared_ptr& client) +{ + TF_AXIOM(sceneIndexDataFactory); + + //Block for the lock lifetime + { + std::lock_guard lock(selectionHighlightFilteringClient_mutex); + + auto findResult = std::find_if(selectionHighlightFilteringSceneIndicesData.cbegin(), selectionHighlightFilteringSceneIndicesData.cend(), + [&client](const PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr& filteringSIData) { return filteringSIData->getClient() == client;}); + if (findResult != selectionHighlightFilteringSceneIndicesData.cend()){ + return false; + } + + //Call the abstract scene index data factory to create a subclass of FilteringSceneIndexDataBase + PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr data = sceneIndexDataFactory->createFilteringSceneIndexDataBase(client); + selectionHighlightFilteringSceneIndicesData.insert(data); + } + + //TODO add it somewhere in selection highlight + + return true; +} + +void FilteringSceneIndexInterfaceImp::_DestroySceneFilteringSceneIndicesData(const std::shared_ptr<::FVP_NS_DEF::FilteringSceneIndexClient>& client) +{ + + bool bNeedToUpdateViewportsFilteringSceneIndicesChain = false; + std::string rendererNames; + + //Block for the lock lifetime + { + std::lock_guard lock(sceneFilteringClient_mutex); + + auto findResult = std::find_if(sceneFilteringSceneIndicesData.cbegin(), sceneFilteringSceneIndicesData.cend(), + [&client](const PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr& filteringSIData) { return filteringSIData->getClient() == client;}); + if (findResult != sceneFilteringSceneIndicesData.cend()){ + const auto& filteringSIData = (*findResult); + rendererNames = (filteringSIData) + ? filteringSIData->getClient()->getRendererNames() + : FvpViewportAPITokens->allRenderers; + + sceneFilteringSceneIndicesData.erase(findResult);//This also decreases ref count + + bNeedToUpdateViewportsFilteringSceneIndicesChain = true; + } + } + + if (bNeedToUpdateViewportsFilteringSceneIndicesChain){ + //Update the filtering scene indices chain from the viewports that were using this filtering scene index client + FilteringSceneIndicesChainManager::get().updateFilteringSceneIndicesChain(rendererNames); + } +} + +void FilteringSceneIndexInterfaceImp::_DestroySelectionHighlightFilteringSceneIndicesData(const std::shared_ptr& client) +{ + //Block for the lock lifetime + { + std::lock_guard lock(selectionHighlightFilteringClient_mutex); + + auto findResult = std::find_if(selectionHighlightFilteringSceneIndicesData.cbegin(), selectionHighlightFilteringSceneIndicesData.cend(), + [&client](const PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr& filteringSIData) { return filteringSIData->getClient() == client;}); + if (findResult != selectionHighlightFilteringSceneIndicesData.cend()){ + selectionHighlightFilteringSceneIndicesData.erase(findResult);//Also decreases ref count + } + } +} + +void FilteringSceneIndexInterfaceImp::unregisterFilteringSceneIndexClient(const std::shared_ptr& client) +{ + switch(client->getCategory()){ + case Fvp::FilteringSceneIndexClient::Category::kSceneFiltering:{ + _DestroySceneFilteringSceneIndicesData(client); + } + break; + case Fvp::FilteringSceneIndexClient::Category::kSelectionHighlighting:{ + _DestroySelectionHighlightFilteringSceneIndicesData(client); + } + break; + default:{ + TF_AXIOM(0);//Should never happen + } + } +} + +const std::set& FilteringSceneIndexInterfaceImp::getSceneFilteringSceneIndicesData()const +{ + std::lock_guard lock(sceneFilteringClient_mutex); + return sceneFilteringSceneIndicesData; +} + +const std::set& FilteringSceneIndexInterfaceImp::getSelectionHighlightFilteringSceneIndicesData() const +{ + std::lock_guard lock(selectionHighlightFilteringClient_mutex); + return selectionHighlightFilteringSceneIndicesData; +} + +void FilteringSceneIndexInterfaceImp::setSceneIndexDataFactory(FilteringSceneIndexDataAbstractFactory& factory) +{ + sceneIndexDataFactory = &factory; +} + +}//End of namespace FVP_NS_DEF + diff --git a/lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.h b/lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.h new file mode 100644 index 0000000000..ad3bb3bdfc --- /dev/null +++ b/lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.h @@ -0,0 +1,64 @@ +// +// Copyright 2023 Autodesk, Inc. All rights reserved. +// +// 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. +// + +#ifndef FLOW_VIEWPORT_API_INTERFACESIMP_FILTERING_SCENE_INDEX_INTERFACE_IMP_H +#define FLOW_VIEWPORT_API_INTERFACESIMP_FILTERING_SCENE_INDEX_INTERFACE_IMP_H + +//Local headers +#include "flowViewport/api.h" +#include "flowViewport/API/fvpFilteringSceneIndexInterface.h"//Viewport API headers +#include "flowViewport/API/fvpFilteringSceneIndexClient.h" +#include "flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataAbstractFactory.h" + +//Std headers +#include + +namespace FVP_NS_DEF { + +///Is a singleton, use Fvp::FilteringSceneIndexInterfaceImp& filteringSceneIndexInterfaceImp = Fvp::FilteringSceneIndexInterfaceImp::Get() to get an instance of that interface +class FilteringSceneIndexInterfaceImp : public FilteringSceneIndexInterface +{ +public: + FilteringSceneIndexInterfaceImp() = default; + virtual ~FilteringSceneIndexInterfaceImp(); + + ///Interface accessor + static FVP_API FilteringSceneIndexInterfaceImp& get(); + + //From FVP_NS_DEF::FilteringSceneIndexInterface + bool registerFilteringSceneIndexClient(const std::shared_ptr& client) override; + void unregisterFilteringSceneIndexClient(const std::shared_ptr& client) override; + + //Called by the DCC + FVP_API + void setSceneIndexDataFactory(FilteringSceneIndexDataAbstractFactory& factory); + + //Called by Flow viewport + const std::set& getSceneFilteringSceneIndicesData() const; + const std::set& getSelectionHighlightFilteringSceneIndicesData() const; + +private : + bool _CreateSceneFilteringSceneIndicesData(const std::shared_ptr& client); + bool _CreateSelectionHighlightFilteringSceneIndicesData(const std::shared_ptr& client); + void _DestroySceneFilteringSceneIndicesData(const std::shared_ptr& client); + void _DestroySelectionHighlightFilteringSceneIndicesData(const std::shared_ptr& client); + +}; + +} //end of namespace FVP_NS_DEF + + +#endif // FLOW_VIEWPORT_API_INTERFACESIMP_FILTERING_SCENE_INDEX_INTERFACE_IMP_H \ No newline at end of file diff --git a/lib/flowViewport/API/interfacesImp/fvpInformationInterfaceImp.cpp b/lib/flowViewport/API/interfacesImp/fvpInformationInterfaceImp.cpp index a46623ad8c..26dccc5bc2 100644 --- a/lib/flowViewport/API/interfacesImp/fvpInformationInterfaceImp.cpp +++ b/lib/flowViewport/API/interfacesImp/fvpInformationInterfaceImp.cpp @@ -88,7 +88,7 @@ void InformationInterfaceImp::SceneIndexRemoved(const InformationInterface::View void InformationInterfaceImp::GetViewportsInformation(ViewportInformationSet& outHydraViewportInformationArray)const { outHydraViewportInformationArray.clear(); - const ViewportInformationAndSceneIndicesPerViewportDataSet& allViewportInformationAndSceneIndicesPerViewportData = + const ViewportInformationAndSceneIndicesPerViewportDataVector& allViewportInformationAndSceneIndicesPerViewportData = ViewportInformationAndSceneIndicesPerViewportDataManager::Get().GetAllViewportInfoAndData(); for (const ViewportInformationAndSceneIndicesPerViewportData& viewportInformationAndSceneIndicesPerViewportData : allViewportInformationAndSceneIndicesPerViewportData){ const InformationInterface::ViewportInformation& viewportInfo = viewportInformationAndSceneIndicesPerViewportData.GetViewportInformation(); diff --git a/lib/flowViewport/API/interfacesImp/fvpSelectionInterfaceImp.cpp b/lib/flowViewport/API/interfacesImp/fvpSelectionInterfaceImp.cpp index d525e7dd71..57fee1f414 100644 --- a/lib/flowViewport/API/interfacesImp/fvpSelectionInterfaceImp.cpp +++ b/lib/flowViewport/API/interfacesImp/fvpSelectionInterfaceImp.cpp @@ -17,7 +17,7 @@ //Local headers #include "fvpSelectionInterfaceImp.h" -//STL +//Std Headers #include namespace{ diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/CMakeLists.txt b/lib/flowViewport/API/perViewportSceneIndicesData/CMakeLists.txt index b06b020251..fb33710423 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/CMakeLists.txt +++ b/lib/flowViewport/API/perViewportSceneIndicesData/CMakeLists.txt @@ -6,6 +6,9 @@ target_sources(${TARGET_NAME} fvpViewportInformationAndSceneIndicesPerViewportData.cpp fvpViewportInformationAndSceneIndicesPerViewportDataManager.cpp fvpDataProducerSceneIndexDataBase.cpp + fvpFilteringSceneIndexDataBase.cpp + fvpFilteringSceneIndicesChainManager.cpp + fvpViewportAPITokens.cpp ) set(HEADERS @@ -13,6 +16,9 @@ set(HEADERS fvpViewportInformationAndSceneIndicesPerViewportDataManager.h fvpDataProducerSceneIndexDataAbstractFactory.h fvpDataProducerSceneIndexDataBase.h + fvpFilteringSceneIndexDataAbstractFactory.h + fvpFilteringSceneIndexDataBase.h + fvpFilteringSceneIndicesChainManager.h ) # ----------------------------------------------------------------------------- diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataAbstractFactory.h b/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataAbstractFactory.h index dcd577e4b1..a24275406e 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataAbstractFactory.h +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataAbstractFactory.h @@ -21,13 +21,13 @@ namespace FVP_NS_DEF { -/** Since Flow viewport is DCC agnostic, the DCC will implement a concrete factory subclassing that class to provide specific -* DCC implementation of the classes mentioned. +/** Since Flow viewport is DCC agnostic, the DCC will implement a concrete factory subclassing that class to provide a specific +* DCC implementation of DataProducerSceneIndexDataBaseRefPtr. */ class DataProducerSceneIndexDataAbstractFactory { public: - /// The DCC will create a subclass of DataProducerSceneIndexDataBaseRefPtr with specific DCC variables that flow viewport cannot manage since it's DCC agnostic + /// The DCC will create a subclass of DataProducerSceneIndexDataBaseRefPtr with specific DCC variables that Flow viewport cannot manage since it's DCC agnostic virtual PXR_NS::FVP_NS_DEF::DataProducerSceneIndexDataBaseRefPtr createDataProducerSceneIndexDataBase( const PXR_NS::FVP_NS_DEF::DataProducerSceneIndexDataBase::CreationParameters& params) = 0; }; diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.h b/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.h index b4cd278e8f..d25f35ec21 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.h +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.h @@ -88,7 +88,7 @@ TF_DECLARE_WEAK_AND_REF_PTRS(DataProducerSceneIndexDataBase);//Be able to use Re void* _dccNode; //The following members are optional and only used when a dccNode was passed in the constructor - /** Is a filtering scene index that modifies the parent prim from the retained scene index to update the transfor/visibility when it is updated in the DCC. + /** Is a filtering scene index that modifies the parent prim from the retained scene index to update the transform/visibility when it is updated in the DCC. It is used only when a dccNode was passed.*/ ParentDataModifierSceneIndexRefPtr _parentDataModifierSceneIndex = nullptr; /// ParentPath prim used to be the parent of all prims from _dataProducerSceneIndex, used only when a dccNode was passed diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataAbstractFactory.h b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataAbstractFactory.h new file mode 100644 index 0000000000..271a8d0cf5 --- /dev/null +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataAbstractFactory.h @@ -0,0 +1,37 @@ +// +// Copyright 2023 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. +// +#ifndef FLOW_VIEWPORT_API_PERVIEWPORTSCENEINDICESDATA_FILTERING_SCENE_INDEX_DATA_ABSTRACT_FACTORY_H +#define FLOW_VIEWPORT_API_PERVIEWPORTSCENEINDICESDATA_FILTERING_SCENE_INDEX_DATA_ABSTRACT_FACTORY_H + +//Flow Viewport headers +#include "fvpFilteringSceneIndexDataBase.h" + +namespace FVP_NS_DEF { + +/** Since Flow viewport is DCC agnostic, the DCC will implement a concrete factory subclassing that class to provide a specific +* DCC implementation of FilteringSceneIndexDataBaseRefPtr. +*/ +class FilteringSceneIndexDataAbstractFactory +{ +public: + /// The DCC will create a subclass of FilteringSceneIndexDataBaseRefPtr with specific DCC variables that Flow viewport cannot manage since it's DCC agnostic + virtual PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr createFilteringSceneIndexDataBase(const std::shared_ptr<::Fvp::FilteringSceneIndexClient>& client) = 0; +}; + +}//End of namespace FVP_NS_DEF { + +#endif //FLOW_VIEWPORT_API_PERVIEWPORTSCENEINDICESDATA_FILTERING_SCENE_INDEX_DATA_ABSTRACT_FACTORY_H + diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataBase.cpp b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataBase.cpp new file mode 100644 index 0000000000..6fc96393e0 --- /dev/null +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataBase.cpp @@ -0,0 +1,41 @@ +// +// Copyright 2023 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. +// + + +//Local headers +#include "fvpFilteringSceneIndexDataBase.h" +#include "flowViewport/API/fvpFilteringSceneIndexClient.h" +#include "flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.h" + +PXR_NAMESPACE_OPEN_SCOPE + +namespace FVP_NS_DEF { + +FilteringSceneIndexDataBase::FilteringSceneIndexDataBase(const std::shared_ptr<::Fvp::FilteringSceneIndexClient>& filteringSIClient) + : _client {filteringSIClient} +{ +} + +void FilteringSceneIndexDataBase::updateVisibilityFromDCCNode(bool isVisible) +{ + _isVisible = isVisible; + const std::string& rendererNames = _client->getRendererNames(); + ::Fvp::FilteringSceneIndicesChainManager::get().updateFilteringSceneIndicesChain(rendererNames); +} + +}//End of namespace FVP_NS_DEF + +PXR_NAMESPACE_CLOSE_SCOPE \ No newline at end of file diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataBase.h b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataBase.h new file mode 100644 index 0000000000..b58e8bda6b --- /dev/null +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataBase.h @@ -0,0 +1,64 @@ +// +// Copyright 2023 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. +// +#ifndef FLOW_VIEWPORT_API_PERVIEWPORTSCENEINDICESDATA_FILTERING_SCENE_INDEX_DATA_BASE_H +#define FLOW_VIEWPORT_API_PERVIEWPORTSCENEINDICESDATA_FILTERING_SCENE_INDEX_DATA_BASE_H + +//Flow Viewport headers +#include "flowViewport/api.h" +#include "flowViewport/API/fvpFilteringSceneIndexInterface.h" + +//Hydra headers +#include +#include + +//The Pixar's namespace needs to be at the highest namespace level for TF_DECLARE_WEAK_AND_REF_PTRS to work. +PXR_NAMESPACE_OPEN_SCOPE + +namespace FVP_NS_DEF { + +class FilteringSceneIndexDataBase;//Predeclaration +TF_DECLARE_WEAK_AND_REF_PTRS(FilteringSceneIndexDataBase);//Be able to use Ref counting pointers on FilteringSceneIndexDataBase + +/** In this class, we store a filtering scene index client and all the filtering scene indices that this client has appended to a viewport, the filtering scene indices +* could be applied to different viewports +*/ + class FVP_API FilteringSceneIndexDataBase : public TfRefBase, public TfWeakBase +{ +public: + + ~FilteringSceneIndexDataBase() override = default; + + void updateVisibilityFromDCCNode(bool isVisible); + std::shared_ptr<::Fvp::FilteringSceneIndexClient> getClient() {return _client;} + bool getVisible() const{return _isVisible;} + void setVisible(bool visible) {_isVisible = visible;} + +protected: + FilteringSceneIndexDataBase(const std::shared_ptr<::Fvp::FilteringSceneIndexClient>& filteringSIClient); + + /// Filtering scene index client, not owned by this class + const std::shared_ptr<::Fvp::FilteringSceneIndexClient> _client; + + ///_isVisible is true when the filteringSceneIndices should be visible and false when they are not such as when the hosting node has been hidden/deleted. + bool _isVisible = true; +}; + +}//End of namespace FVP_NS_DEF { + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif //FLOW_VIEWPORT_API_PERVIEWPORTSCENEINDICESDATA_FILTERING_SCENE_INDEX_DATA_BASE_H + diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.cpp b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.cpp new file mode 100644 index 0000000000..b804ac1a60 --- /dev/null +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.cpp @@ -0,0 +1,169 @@ +// +// Copyright 2023 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. +// + +//Local headers +#include "fvpFilteringSceneIndicesChainManager.h" +#include "flowViewport/sceneIndex/fvpRenderIndexProxy.h" +#include "flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.h" +#include "flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.h" + +//Hydra headers +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FVP_NS_DEF { + +//Singleton access +FilteringSceneIndicesChainManager& FilteringSceneIndicesChainManager::get() +{ + static FilteringSceneIndicesChainManager FilteringSceneIndicesChainManager; + return FilteringSceneIndicesChainManager; +} + +FilteringSceneIndicesChainManager::~FilteringSceneIndicesChainManager() +{ +} + +HdSceneIndexBaseRefPtr FilteringSceneIndicesChainManager::createFilteringSceneIndicesChain(ViewportInformationAndSceneIndicesPerViewportData& viewportInformationAndSceneIndicesPerViewportData, + const HdSceneIndexBaseRefPtr& inputFilteringSceneIndex /*= nullptr*/) +{ + HdSceneIndexBaseRefPtr inputSceneIndex = inputFilteringSceneIndex; + if (nullptr == inputSceneIndex){ + inputSceneIndex = viewportInformationAndSceneIndicesPerViewportData.GetInputSceneIndex(); + }else{ + viewportInformationAndSceneIndicesPerViewportData.SetInputSceneIndex(inputSceneIndex); + } + TF_AXIOM(inputSceneIndex); + + if ( ! _enabled){ + return inputSceneIndex; + } + + if (viewportInformationAndSceneIndicesPerViewportData.GetLastFilteringSceneIndex() != nullptr){ + TF_CODING_ERROR("viewportInformationAndSceneIndicesPerViewportData->GetLastFilteringSceneIndex() != nullptr should not happen, \ + you should call DestroyFilteringSceneIndicesChain before calling the current function"); + return nullptr;//Not an empty filtering scene indices chain + } + + //Append the filtering scene indices chain tp the merging scene index from renderIndexProxy + _AppendFilteringSceneIndicesChain(viewportInformationAndSceneIndicesPerViewportData, inputSceneIndex); + + if (viewportInformationAndSceneIndicesPerViewportData.GetLastFilteringSceneIndex() == nullptr){ + TF_CODING_ERROR("viewportInformationAndSceneIndicesPerViewportData->GetLastFilteringSceneIndex() == nullptr is invalid here"); + return nullptr; + } + + //Add the last element of the filtering scene indices chain to the render index + return viewportInformationAndSceneIndicesPerViewportData.GetLastFilteringSceneIndex(); +} + +void FilteringSceneIndicesChainManager::destroyFilteringSceneIndicesChain(ViewportInformationAndSceneIndicesPerViewportData& viewportInformationAndSceneIndicesPerViewportData) +{ + HdSceneIndexBaseRefPtr& lastSceneIndex = viewportInformationAndSceneIndicesPerViewportData.GetLastFilteringSceneIndex(); + if (nullptr == lastSceneIndex){ + return; + } + + auto renderIndexProxy = viewportInformationAndSceneIndicesPerViewportData.GetRenderIndexProxy(); + TF_AXIOM(renderIndexProxy); + auto renderIndex = renderIndexProxy->GetRenderIndex(); + TF_AXIOM(renderIndex); + renderIndex->RemoveSceneIndex(lastSceneIndex);//Remove the whole chain from the render index + + //Remove a ref on it which should cascade the same on its references + lastSceneIndex.Reset(); +} + +void FilteringSceneIndicesChainManager::updateFilteringSceneIndicesChain(const std::string& rendererDisplayNames) +{ + /* rendererDisplayName is a string containing either FvpViewportAPITokens->allRenderers meaning this should apply to all renderers + * or it contains one or more renderers display names such as ("GL, Arnold") and in this case we must update + * only the viewports filtering scene indices chain which are using this renderer. + */ + + ViewportInformationAndSceneIndicesPerViewportDataVector& allViewportInformationAndSceneIndicesPerViewport = + ViewportInformationAndSceneIndicesPerViewportDataManager::Get().GetAllViewportInfoAndData(); + + for (auto& viewportInformationAndSceneIndicesPerViewportData : allViewportInformationAndSceneIndicesPerViewport){ + + //Check the renderer name + const std::string& rendererDisplayName = viewportInformationAndSceneIndicesPerViewportData.GetViewportInformation()._rendererName; + if ( (FvpViewportAPITokens->allRenderers != rendererDisplayNames) && (! rendererDisplayName.empty()) ){ + //Filtering per renderer is applied + if (std::string::npos == rendererDisplayNames.find(rendererDisplayName)){ + continue; //Ignore this filtering scene indices chain since the renderer is different + } + } + + const auto& renderIndexProxy = viewportInformationAndSceneIndicesPerViewportData.GetRenderIndexProxy(); + destroyFilteringSceneIndicesChain(viewportInformationAndSceneIndicesPerViewportData); + createFilteringSceneIndicesChain(viewportInformationAndSceneIndicesPerViewportData); + const auto& lastSceneIndex = viewportInformationAndSceneIndicesPerViewportData.GetLastFilteringSceneIndex(); + TF_AXIOM(lastSceneIndex && renderIndexProxy && renderIndexProxy->GetRenderIndex()); + renderIndexProxy->GetRenderIndex()->InsertSceneIndex(lastSceneIndex, SdfPath::AbsoluteRootPath()); + } +} + +void FilteringSceneIndicesChainManager::_AppendFilteringSceneIndicesChain( ViewportInformationAndSceneIndicesPerViewportData& viewportInformationAndSceneIndicesPerViewportData, + const HdSceneIndexBaseRefPtr& inputScene) +{ + TF_AXIOM(inputScene); + + HdContainerDataSourceHandle _inputArgs = nullptr;//Possibility to send custom data for scene index registration + + const std::string& rendererDisplayName = viewportInformationAndSceneIndicesPerViewportData.GetViewportInformation()._rendererName; + + HdSceneIndexBaseRefPtr& lastSceneIndex = viewportInformationAndSceneIndicesPerViewportData.GetLastFilteringSceneIndex(); + //Set the merging scene index as the last element to use this scene index as the input scene index of filtering scene indices + lastSceneIndex = inputScene; + + //Call our Hydra viewport API mechanism for custom filtering scene index clients + const auto& viewportFilteringSceneIndicesData = FilteringSceneIndexInterfaceImp::get().getSceneFilteringSceneIndicesData(); + for (const auto& filteringSceneIndexData : viewportFilteringSceneIndicesData) { + auto client = filteringSceneIndexData->getClient(); + const std::string& rendererNames = client->getRendererNames(); + //Filter by render delegate name + if ( (FvpViewportAPITokens->allRenderers != rendererNames) && rendererNames.find(rendererDisplayName) == std::string::npos){ + //Ignore that client info, it is not targeted for this renderer + continue; + } + + const bool isVisible = filteringSceneIndexData->getVisible(); + if (! isVisible){ + continue; //We should not append not visible filtering scene indices + } + + auto tempAppendedSceneIndex = client->appendSceneIndex(lastSceneIndex, _inputArgs); + if ((lastSceneIndex != tempAppendedSceneIndex)){ + //A new scene index was appended, it can also be a chain of scene indices but we need only the last element + lastSceneIndex = tempAppendedSceneIndex; + } + } +} + +void FilteringSceneIndicesChainManager::setEnabled(bool enable) +{ + if (_enabled != enable){ + _enabled = enable; + } + + //Update all viewports + updateFilteringSceneIndicesChain(FvpViewportAPITokens->allRenderers); +} + +}//End of namespace FVP_NS_DEF \ No newline at end of file diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.h b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.h new file mode 100644 index 0000000000..67ef165f60 --- /dev/null +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.h @@ -0,0 +1,99 @@ +// +// Copyright 2023 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. +// + +#ifndef FLOW_VIEWPORT_API_PERVIEWPORTSCENEINDICESDATA_FILTERING_SCENE_INDEX_CHAIN_MANAGER +#define FLOW_VIEWPORT_API_PERVIEWPORTSCENEINDICESDATA_FILTERING_SCENE_INDEX_CHAIN_MANAGER + +//Local headers +#include "flowViewport/api.h" +#include "flowViewport/sceneIndex/fvpRenderIndexProxyFwd.h" + +//Hydra headers +#include + +//Std headers +#include + +namespace FVP_NS_DEF { + +class RenderIndexProxy; //Predeclaration +class ViewportInformationAndSceneIndicesPerViewportData;//Predeclaration + +/**Is a singleton to manage the custom filtering scene indices chain which is appended after the merging scene index +* To access this class, use Fvp::FilteringSceneIndicesChainManager& filteringSceneIndicesChainManager = Fvp::FilteringSceneIndicesChainManager::get(); +*/ +class FVP_API FilteringSceneIndicesChainManager +{ +public: + /// Destructor + ~FilteringSceneIndicesChainManager(); + + ///Singleton accessor + static FilteringSceneIndicesChainManager& get(); + + /** + * @brief Create the filtering scene indices chain for this viewport. + * @param[in] viewportInformationAndSceneIndicesPerViewportData is the ViewportInformationAndSceneIndicesPerViewportData from the hydra viewport. + * @param[in] inputFilteringSceneIndex is the input scene index for your filtering scene index. + * @return the latest scene index from the custom filtering scene indices chain + */ + PXR_NS::HdSceneIndexBaseRefPtr createFilteringSceneIndicesChain(ViewportInformationAndSceneIndicesPerViewportData& viewportInformationAndSceneIndicesPerViewportData, + const PXR_NS::HdSceneIndexBaseRefPtr& inputFilteringSceneIndex = nullptr); + + /** + * @brief Removes from the render index the last element of the filtering scene indices chain for this viewport and delete the whole chain + * @param[in] viewportInformationAndSceneIndicesPerViewportData is the ViewportInformationAndSceneIndicesPerViewportData from the hydra viewport. + */ + void destroyFilteringSceneIndicesChain(ViewportInformationAndSceneIndicesPerViewportData& viewportInformationAndSceneIndicesPerViewportData); + + /** + * @brief Update the whole filtering scene indices chains. + * + * Update the whole chain by destroying it then create it again (use case is : a new FilteringSceneIndexClient was registered / unregistered + * so we must re-create the filtering scene indices chain with this change. + * We update only the viewports whose renderer display name is in rendererDisplayName. + * + * @param[in] rendererDisplayNames is a string containing either nothing ("") meaning this should apply to all renderers + * or it contains one or more renderers display names such as ("GL, Arnold") and in this case we must update + * only the viewports filtering scene indices chain which are using this renderer. + */ + void updateFilteringSceneIndicesChain(const std::string& rendererDisplayNames); + + // For debugging purpose : enable/disable the filtering scene indices chain as a global switch. + void setEnabled(bool enabled); + bool getEnabled()const {return _enabled;} + +private: + /** + * @brief Create the filtering scene indices chain for this viewport. + * @param[in] viewportInformationAndSceneIndicesPerViewportData is the ViewportInformationAndSceneIndicesPerViewportData from the hydra viewport. + * @param[in] inputFilteringSceneIndex is the input scene index for your filtering scene index. + */ + void _AppendFilteringSceneIndicesChain( ViewportInformationAndSceneIndicesPerViewportData& viewportInformationAndSceneIndicesPerViewportData, + const PXR_NS::HdSceneIndexBaseRefPtr& inputScene); + + /// Private constructor + FilteringSceneIndicesChainManager() = default; + + ///Enable/Disable the Filtering scene indices chain for debugging purpose + bool _enabled {true}; +}; + + +}//End of namespace FVP_NS_DEF + +#endif //FLOW_VIEWPORT_API_PERVIEWPORTSCENEINDICESDATA_FILTERING_SCENE_INDEX_CHAIN_MANAGER + diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportAPITokens.cpp b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportAPITokens.cpp new file mode 100644 index 0000000000..db6f06668f --- /dev/null +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportAPITokens.cpp @@ -0,0 +1,24 @@ +// Copyright 2023 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. +// + +#include "flowViewport/API/fvpViewportAPITokens.h" + +// *** TODO / FIXME *** Figure out how to put tokens into non-Pixar namespace. + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEFINE_PUBLIC_TOKENS(FvpViewportAPITokens, FVP_VIEWPORT_API_TOKENS); + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportData.cpp b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportData.cpp index 97fc9f261f..f02d04b32d 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportData.cpp +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportData.cpp @@ -19,6 +19,7 @@ #include "flowViewport/API/interfacesImp/fvpInformationInterfaceImp.h" #include "flowViewport/sceneIndex/fvpRenderIndexProxy.h" #include "flowViewport/API/interfacesImp/fvpDataProducerSceneIndexInterfaceImp.h" +#include "flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.h" //Hydra headers #include @@ -39,6 +40,8 @@ ViewportInformationAndSceneIndicesPerViewportData::ViewportInformationAndSceneIn ViewportInformationAndSceneIndicesPerViewportData::~ViewportInformationAndSceneIndicesPerViewportData() { DataProducerSceneIndexInterfaceImp::get().removeAllViewportDataProducerSceneIndices(*this); + //Remove custom filtering scene indices chain + FilteringSceneIndicesChainManager::get().destroyFilteringSceneIndicesChain(*this); } void ViewportInformationAndSceneIndicesPerViewportData::RemoveViewportDataProducerSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& customDataProducerSceneIndex) @@ -71,7 +74,7 @@ void ViewportInformationAndSceneIndicesPerViewportData::_AddAllDataProducerScene } //Add all data producer scene index to the merging scene index through the render index proxy - for (auto& dataProducerSceneIndexData : _dataProducerSceneIndicesData){ + for (const auto& dataProducerSceneIndexData : _dataProducerSceneIndicesData){ // Add the data producer scene index to the merging scene index if (dataProducerSceneIndexData && dataProducerSceneIndexData->GetDataProducerLastSceneIndexChain()) { _renderIndexProxy->InsertSceneIndex(dataProducerSceneIndexData->GetDataProducerLastSceneIndexChain(), diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportData.h b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportData.h index 44bf9a56c0..fd56d79d64 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportData.h +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportData.h @@ -37,8 +37,8 @@ class ViewportInformationAndSceneIndicesPerViewportData ~ViewportInformationAndSceneIndicesPerViewportData(); const InformationInterface::ViewportInformation& GetViewportInformation()const { return _viewportInformation;} - const PXR_NS::HdSceneIndexBaseRefPtr& GetLastFilteringSceneIndexOfTheChain() const {return _lastFilteringSceneIndexOfTheChain;} - void SetRenderIndexProxy(const Fvp::RenderIndexProxyPtr& renderIndexProxy); + PXR_NS::HdSceneIndexBaseRefPtr& GetLastFilteringSceneIndex() {return _lastFilteringSceneIndex;} + const PXR_NS::HdSceneIndexBaseRefPtr& GetLastFilteringSceneIndex() const {return _lastFilteringSceneIndex;} const Fvp::RenderIndexProxyPtr GetRenderIndexProxy() const {return _renderIndexProxy;} void SetInputSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& inputSceneIndex) {_inputSceneIndex = inputSceneIndex;} const PXR_NS::HdSceneIndexBaseRefPtr& GetInputSceneIndex() const {return _inputSceneIndex;} @@ -46,9 +46,14 @@ class ViewportInformationAndSceneIndicesPerViewportData std::set& GetDataProducerSceneIndicesData() {return _dataProducerSceneIndicesData;} void RemoveViewportDataProducerSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& customDataProducerSceneIndex); - //Needed by std::set - bool operator < (const ViewportInformationAndSceneIndicesPerViewportData& other)const{ - return _viewportInformation < other._viewportInformation; //Is for std::set. + //Needed by std::vector + ViewportInformationAndSceneIndicesPerViewportData& operator = (const ViewportInformationAndSceneIndicesPerViewportData& other){ + _viewportInformation = other._viewportInformation; + _dataProducerSceneIndicesData = other._dataProducerSceneIndicesData; + _inputSceneIndex = other._inputSceneIndex; + _lastFilteringSceneIndex = other._lastFilteringSceneIndex; + _renderIndexProxy = other._renderIndexProxy; + return *this; } private: @@ -62,7 +67,7 @@ class ViewportInformationAndSceneIndicesPerViewportData PXR_NS::HdSceneIndexBaseRefPtr _inputSceneIndex {nullptr}; /// The last scene index of the custom filtering scene indices chain for this viewport - PXR_NS::HdSceneIndexBaseRefPtr _lastFilteringSceneIndexOfTheChain {nullptr}; + PXR_NS::HdSceneIndexBaseRefPtr _lastFilteringSceneIndex {nullptr}; ///Is a render index proxy per viewport to avoid accessing directly the render index Fvp::RenderIndexProxyPtr _renderIndexProxy {nullptr}; @@ -71,7 +76,7 @@ class ViewportInformationAndSceneIndicesPerViewportData void _AddAllDataProducerSceneIndexToMergingSCeneIndex(); }; -using ViewportInformationAndSceneIndicesPerViewportDataSet = std::set; +using ViewportInformationAndSceneIndicesPerViewportDataVector = std::vector; } //End of namespace FVP_NS_DEF diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.cpp b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.cpp index 2784f809e2..9393c23fde 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.cpp +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.cpp @@ -19,16 +19,17 @@ #include "flowViewport/API/interfacesImp/fvpDataProducerSceneIndexInterfaceImp.h" #include "flowViewport/API/interfacesImp/fvpInformationInterfaceImp.h" #include "flowViewport/sceneIndex/fvpRenderIndexProxy.h" +#include "flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.h" //Hydra headers #include -//STL Headers +//Std Headers #include namespace { - std::mutex viewportInformationAndSceneIndicesPerViewportDataSet_mutex; + std::mutex viewportInformationAndSceneIndicesPerViewportData_mutex; std::set dummyEmptyArray; } @@ -43,11 +44,16 @@ ViewportInformationAndSceneIndicesPerViewportDataManager& ViewportInformationAnd } //A new Hydra viewport was created -void ViewportInformationAndSceneIndicesPerViewportDataManager::AddViewportInformation(const InformationInterface::ViewportInformation& viewportInfo, const Fvp::RenderIndexProxyPtr& renderIndexProxy) +void ViewportInformationAndSceneIndicesPerViewportDataManager::AddViewportInformation(const InformationInterface::ViewportInformation& viewportInfo, const Fvp::RenderIndexProxyPtr& renderIndexProxy, + const HdSceneIndexBaseRefPtr& inputSceneIndexForCustomFiltering) { + TF_AXIOM(renderIndexProxy && inputSceneIndexForCustomFiltering); + + ViewportInformationAndSceneIndicesPerViewportData* newElement = nullptr; + //Add it in our array if it is not already inside { - std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportDataSet_mutex); + std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportData_mutex); const auto& viewportId = viewportInfo._viewportId; auto findResult = std::find_if(_viewportsInformationAndSceneIndicesPerViewportData.begin(), _viewportsInformationAndSceneIndicesPerViewportData.end(), @@ -56,7 +62,8 @@ void ViewportInformationAndSceneIndicesPerViewportDataManager::AddViewportInform return;//It is already inside our array } - _viewportsInformationAndSceneIndicesPerViewportData.insert(ViewportInformationAndSceneIndicesPerViewportData(viewportInfo, renderIndexProxy)); + ViewportInformationAndSceneIndicesPerViewportData temp(viewportInfo, renderIndexProxy); + newElement = &(_viewportsInformationAndSceneIndicesPerViewportData.emplace_back(temp)); } //Call this to let the data producer scene indices that apply to all viewports to be added to this new viewport as well @@ -64,11 +71,21 @@ void ViewportInformationAndSceneIndicesPerViewportDataManager::AddViewportInform //Let the registered clients know a new viewport has been added InformationInterfaceImp::Get().SceneIndexAdded(viewportInfo); + + //Add the custom filtering scene indices to the merging scene index + TF_AXIOM(newElement); + const HdSceneIndexBaseRefPtr lastFilteringSceneIndex = FilteringSceneIndicesChainManager::get().createFilteringSceneIndicesChain(*newElement, + inputSceneIndexForCustomFiltering); + + //Insert the last filtering scene index into the render index + auto renderIndex = renderIndexProxy->GetRenderIndex(); + TF_AXIOM(renderIndex); + renderIndex->InsertSceneIndex(lastFilteringSceneIndex, SdfPath::AbsoluteRootPath()); } void ViewportInformationAndSceneIndicesPerViewportDataManager::RemoveViewportInformation(const std::string& modelPanel) { - std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportDataSet_mutex); + std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportData_mutex); auto findResult = std::find_if(_viewportsInformationAndSceneIndicesPerViewportData.begin(), _viewportsInformationAndSceneIndicesPerViewportData.end(), [&modelPanel](const ViewportInformationAndSceneIndicesPerViewportData& other) { return other.GetViewportInformation()._viewportId == modelPanel;}); @@ -81,7 +98,7 @@ void ViewportInformationAndSceneIndicesPerViewportDataManager::RemoveViewportInf if(renderIndexProxy){ //Destroy the custom filtering scene indices chain auto renderIndex = renderIndexProxy->GetRenderIndex(); - const auto& filteringSceneIndex = findResult->GetLastFilteringSceneIndexOfTheChain(); + const auto& filteringSceneIndex = findResult->GetLastFilteringSceneIndex(); if (renderIndex && filteringSceneIndex){ renderIndex->RemoveSceneIndex(filteringSceneIndex);//Remove the whole chain from the render index } @@ -93,7 +110,7 @@ void ViewportInformationAndSceneIndicesPerViewportDataManager::RemoveViewportInf const ViewportInformationAndSceneIndicesPerViewportData* ViewportInformationAndSceneIndicesPerViewportDataManager::GetViewportInfoAndDataFromViewportId(const std::string& viewportId)const { - std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportDataSet_mutex); + std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportData_mutex); auto findResult = std::find_if(_viewportsInformationAndSceneIndicesPerViewportData.cbegin(), _viewportsInformationAndSceneIndicesPerViewportData.cend(), [&viewportId](const ViewportInformationAndSceneIndicesPerViewportData& other) { return other.GetViewportInformation()._viewportId == viewportId;}); @@ -107,9 +124,9 @@ const ViewportInformationAndSceneIndicesPerViewportData* ViewportInformationAndS ViewportInformationAndSceneIndicesPerViewportData* ViewportInformationAndSceneIndicesPerViewportDataManager::GetViewportInfoAndDataFromViewportId(const std::string& viewportId) { - std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportDataSet_mutex); + std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportData_mutex); - ViewportInformationAndSceneIndicesPerViewportDataSet::iterator findResult = std::find_if(_viewportsInformationAndSceneIndicesPerViewportData.begin(), _viewportsInformationAndSceneIndicesPerViewportData.end(), + ViewportInformationAndSceneIndicesPerViewportDataVector::iterator findResult = std::find_if(_viewportsInformationAndSceneIndicesPerViewportData.begin(), _viewportsInformationAndSceneIndicesPerViewportData.end(), [&viewportId](const ViewportInformationAndSceneIndicesPerViewportData& other) { return other.GetViewportInformation()._viewportId == viewportId;}); if (findResult != _viewportsInformationAndSceneIndicesPerViewportData.end()){ ViewportInformationAndSceneIndicesPerViewportData& data = const_cast(*findResult); @@ -122,7 +139,7 @@ ViewportInformationAndSceneIndicesPerViewportData* ViewportInformationAndSceneIn const std::set& ViewportInformationAndSceneIndicesPerViewportDataManager::GetDataProducerSceneIndicesDataFromViewportId(const std::string& viewportId)const { - std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportDataSet_mutex); + std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportData_mutex); for (const auto& viewportInformationAndSceneIndicesPerViewportData : _viewportsInformationAndSceneIndicesPerViewportData){ const auto& viewportIdFromContainer = viewportInformationAndSceneIndicesPerViewportData.GetViewportInformation()._viewportId; @@ -136,7 +153,7 @@ ViewportInformationAndSceneIndicesPerViewportDataManager::GetDataProducerSceneIn bool ViewportInformationAndSceneIndicesPerViewportDataManager::ModelPanelIsAlreadyRegistered(const std::string& modelPanel)const { - std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportDataSet_mutex); + std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportData_mutex); auto findResult = std::find_if(_viewportsInformationAndSceneIndicesPerViewportData.cbegin(), _viewportsInformationAndSceneIndicesPerViewportData.cend(), [&modelPanel](const ViewportInformationAndSceneIndicesPerViewportData& other) { return other.GetViewportInformation()._viewportId == modelPanel;}); @@ -147,7 +164,7 @@ bool ViewportInformationAndSceneIndicesPerViewportDataManager::ModelPanelIsAlrea void ViewportInformationAndSceneIndicesPerViewportDataManager::RemoveAllViewportsInformation() { //Block for the lifetime of the lock - std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportDataSet_mutex); + std::lock_guard lock(viewportInformationAndSceneIndicesPerViewportData_mutex); for(auto& viewportInfoAndData :_viewportsInformationAndSceneIndicesPerViewportData){ @@ -158,7 +175,7 @@ void ViewportInformationAndSceneIndicesPerViewportDataManager::RemoveAllViewport if(renderIndexProxy){ //Destroy the custom filtering scene indices chain auto renderIndex = renderIndexProxy->GetRenderIndex(); - const auto& filteringSceneIndex = viewportInfoAndData.GetLastFilteringSceneIndexOfTheChain(); + const auto& filteringSceneIndex = viewportInfoAndData.GetLastFilteringSceneIndex(); if (renderIndex && filteringSceneIndex){ renderIndex->RemoveSceneIndex(filteringSceneIndex);//Remove the whole chain from the render index } diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.h b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.h index 3ba0f6467e..139bb84844 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.h +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.h @@ -39,14 +39,15 @@ class FVP_API ViewportInformationAndSceneIndicesPerViewportDataManager /// Manager accessor static ViewportInformationAndSceneIndicesPerViewportDataManager& Get(); - ///A new Hydra viewport was created - void AddViewportInformation(const InformationInterface::ViewportInformation& viewportInfo, const Fvp::RenderIndexProxyPtr& renderIndexProxy); + //A new Hydra viewport was created, we need inputSceneIndexForCustomFiltering to be used as an input scene index for custom filtering scene indices + void AddViewportInformation(const InformationInterface::ViewportInformation& viewportInfo, const Fvp::RenderIndexProxyPtr& renderIndexProxy, + const PXR_NS::HdSceneIndexBaseRefPtr& inputSceneIndexForCustomFiltering); - ///A Hydra viewport was deleted + //A Hydra viewport was deleted void RemoveViewportInformation(const std::string& modelPanel); - const ViewportInformationAndSceneIndicesPerViewportDataSet& GetAllViewportInfoAndData() const {return _viewportsInformationAndSceneIndicesPerViewportData;} - ViewportInformationAndSceneIndicesPerViewportDataSet& GetAllViewportInfoAndData() {return _viewportsInformationAndSceneIndicesPerViewportData;} + const ViewportInformationAndSceneIndicesPerViewportDataVector& GetAllViewportInfoAndData() const {return _viewportsInformationAndSceneIndicesPerViewportData;} + ViewportInformationAndSceneIndicesPerViewportDataVector& GetAllViewportInfoAndData() {return _viewportsInformationAndSceneIndicesPerViewportData;} const ViewportInformationAndSceneIndicesPerViewportData* GetViewportInfoAndDataFromViewportId(const std::string& viewportId)const; ViewportInformationAndSceneIndicesPerViewportData* GetViewportInfoAndDataFromViewportId(const std::string& viewportId); @@ -58,7 +59,7 @@ class FVP_API ViewportInformationAndSceneIndicesPerViewportDataManager private: ///Hydra viewport information - ViewportInformationAndSceneIndicesPerViewportDataSet _viewportsInformationAndSceneIndicesPerViewportData; + ViewportInformationAndSceneIndicesPerViewportDataVector _viewportsInformationAndSceneIndicesPerViewportData; ViewportInformationAndSceneIndicesPerViewportDataManager() = default; }; diff --git a/lib/flowViewport/API/samples/CMakeLists.txt b/lib/flowViewport/API/samples/CMakeLists.txt index 2be4c6cedd..c57ecac5c1 100644 --- a/lib/flowViewport/API/samples/CMakeLists.txt +++ b/lib/flowViewport/API/samples/CMakeLists.txt @@ -6,12 +6,16 @@ target_sources(${TARGET_NAME} fvpSelectionClientExample.cpp fvpInformationClientExample.cpp fvpDataProducerSceneIndexExample.cpp + fvpFilteringSceneIndexExample.cpp + fvpFilteringSceneIndexClientExample.cpp ) set(HEADERS fvpSelectionClientExample.h fvpInformationClientExample.h fvpDataProducerSceneIndexExample.h + fvpFilteringSceneIndexExample.h + fvpFilteringSceneIndexClientExample.h ) # ----------------------------------------------------------------------------- diff --git a/lib/flowViewport/API/samples/fvpDataProducerSceneIndexExample.cpp b/lib/flowViewport/API/samples/fvpDataProducerSceneIndexExample.cpp index 713187f229..ea9d8c7f05 100644 --- a/lib/flowViewport/API/samples/fvpDataProducerSceneIndexExample.cpp +++ b/lib/flowViewport/API/samples/fvpDataProducerSceneIndexExample.cpp @@ -534,7 +534,7 @@ HdRetainedSceneIndex::AddedPrimEntry DataProducerSceneIndexExample::_CreateCubeP void DataProducerSceneIndexExample::addDataProducerSceneIndex() { if (!_dataProducerSceneIndexAdded && _hydraInterface){ - const bool res = _hydraInterface->addDataProducerSceneIndex(_retainedSceneIndex, _containerNode, DataProducerSceneIndexInterface::allViewports, DataProducerSceneIndexInterface::allRenderers, SdfPath::AbsoluteRootPath()); + const bool res = _hydraInterface->addDataProducerSceneIndex(_retainedSceneIndex, _containerNode, PXR_NS::FvpViewportAPITokens->allViewports, PXR_NS::FvpViewportAPITokens->allRenderers, SdfPath::AbsoluteRootPath()); if (false == res){ TF_CODING_ERROR("_hydraInterface->addDataProducerSceneIndex returned false !"); } @@ -545,7 +545,7 @@ void DataProducerSceneIndexExample::addDataProducerSceneIndex() void DataProducerSceneIndexExample::removeDataProducerSceneIndex() { if (_dataProducerSceneIndexAdded && _hydraInterface){ - _hydraInterface->removeViewportDataProducerSceneIndex(_retainedSceneIndex, DataProducerSceneIndexInterface::allViewports); + _hydraInterface->removeViewportDataProducerSceneIndex(_retainedSceneIndex, PXR_NS::FvpViewportAPITokens->allViewports); _dataProducerSceneIndexAdded = false; } } diff --git a/lib/flowViewport/API/samples/fvpFilteringSceneIndexClientExample.cpp b/lib/flowViewport/API/samples/fvpFilteringSceneIndexClientExample.cpp new file mode 100644 index 0000000000..e1e667e73f --- /dev/null +++ b/lib/flowViewport/API/samples/fvpFilteringSceneIndexClientExample.cpp @@ -0,0 +1,43 @@ +// +// Copyright 2023 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. +// + +//Local headers +#include "fvpFilteringSceneIndexClientExample.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace FVP_NS_DEF { + +FilteringSceneIndexClientExample::FilteringSceneIndexClientExample(const std::string& displayName, const Category category, const std::string& rendererNames, void* dccNode): + FilteringSceneIndexClient(displayName, category, rendererNames, dccNode) +{ +} + +//Callback to be able to append a new scene index or scene index chain to this Hydra viewport scene index +HdSceneIndexBaseRefPtr FilteringSceneIndexClientExample::appendSceneIndex(const HdSceneIndexBaseRefPtr& inputSceneIndex, const HdContainerDataSourceHandle& inputArgs) +{ + if (inputSceneIndex){ + //Add a filtering scene index, this will hide some prims matching some criteria. + auto filteringSceneIndex = PXR_NS::FVP_NS_DEF::FilteringSceneIndexExample::New(inputSceneIndex); + + //return the new appended scene index, if you don't want to append a scene index, just return _hydraViewportInputSceneIndex + return filteringSceneIndex; + } + + return inputSceneIndex; +} + +} //End of namespace FVP_NS_DEF \ No newline at end of file diff --git a/lib/flowViewport/API/samples/fvpFilteringSceneIndexClientExample.h b/lib/flowViewport/API/samples/fvpFilteringSceneIndexClientExample.h new file mode 100644 index 0000000000..5f336658cf --- /dev/null +++ b/lib/flowViewport/API/samples/fvpFilteringSceneIndexClientExample.h @@ -0,0 +1,86 @@ +// +// Copyright 2023 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. +// +#ifndef FLOW_VIEWPORT_EXAMPLES_FILTERING_SCENE_INDEX_CLIENT_EXAMPLE_H +#define FLOW_VIEWPORT_EXAMPLES_FILTERING_SCENE_INDEX_CLIENT_EXAMPLE_H + +//Local headers +#include "flowViewport/api.h" +#include "flowViewport/API/fvpFilteringSceneIndexClient.h" +#include "flowViewport/API/fvpFilteringSceneIndexInterface.h" +#include "flowViewport/API/samples/fvpFilteringSceneIndexExample.h" + +namespace FVP_NS_DEF { + +/** This class is an implementation of FilteringSceneIndexClient which is an example on how to filter Hydra primitives from the scene into a Hydra viewport. +* It will use the scene index filter from the class FilteringSceneIndexExample. +* +* Usage of this class is : +* +* Call FilteringSceneIndexInterface::registerFilteringSceneIndexClient with this instance with for example : +* +* const std::shared_ptr hydraViewportFilteringSceneIndexClient = std::make_shared_ptr("FilteringSceneIndexClientExample", +* Fvp::FilteringSceneIndexClient::Category::kSceneFiltering, +* FvpViewportAPITokens->allRenderers, //We could set only Storm by using "GL" or only Arnold by using "Arnold" or both with "GL, Arnold" +* nullptr);//No node associated, you could still do it later though. +* //Register a filtering scene index client +* Fvp::FilteringSceneIndexInterface& filteringSceneIndexInterface = Fvp::FilteringSceneIndexInterface::get(); +* //Register this filtering scene index client, so it can append custom filtering scene indices to Hydra viewport scene indices +* const bool bResult = filteringSceneIndexInterface.registerFilteringSceneIndexClient(hydraViewportFilteringSceneIndexClient); +* +* The callback FilteringSceneIndexClientExample::appendSceneIndex will be called when a new viewport is created to append your filtering scene index. +* +* If you want to unregister your client, please use : +* Fvp::FilteringSceneIndexInterface& filteringSceneIndexInterface = Fvp::FilteringSceneIndexInterface::get(); +* filteringSceneIndexInterface.unregisterFilteringSceneIndexClient(hydraViewportFilteringSceneIndexClient); +*/ + +class FVP_API FilteringSceneIndexClientExample : public FilteringSceneIndexClient +{ +public: + /// Constructor, please see below for the meaning of the parameters + FilteringSceneIndexClientExample(const std::string& displayName, const Category category, const std::string& rendererNames, void* dccNode); + /// Destructor + ~FilteringSceneIndexClientExample() override = default; + + ///Is called by the DCC's node to set its node pointer, used later in the hydra viewport API + void setDccNode(void* node){_dccNode = node;} + + //From FilteringSceneIndexClient + + /** + * @brief Callback function to append a scene index. + * + * This callback function gets called for you to append a scene index to a Hydra viewport scene index, like a filtering scene index. + * A typical case is when a new Hydra viewport is created, after some internal managment of this scene index, we call this function so you can append one scene index + * or a chain of scene indices and return the last element of the chain. + * The returned value of this function is the last custom scene index of a a chain that you want to append to this scene index, + * or just return the input scene index passed if you don't want to append any scene index. + * + * @param[in] inputSceneIndex is a HdSceneIndexBaseRefPtr which was created by our Hydra viewport plugin. This could be the Hydra viewport scene index or it could be some appended + * scene index, as a chain of scene indices is appended to the Hydra viewport scene index if several filtering scene index clients are registered. + * So don't assume it's the Hydra viewport scene index. + * @param[in] inputArgs is a container data source handle to deal with the possibility to send custom data from our Hydra viewport plugin for the creation of your scene index. + * This parameter is currently not used by the Hydra viewport plugin but is left for possible future use. + * + * @return If you don't want to append a scene index, just return _inputSceneIndex. + * If you want to append a scene index or a scene indices chain, you should return the last scene index of the scene indices chain to append. + */ + PXR_NS::HdSceneIndexBaseRefPtr appendSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& inputSceneIndex, const PXR_NS::HdContainerDataSourceHandle& inputArgs)override; +}; + +}//end of namespace FVP_NS_DEF + +#endif //FLOW_VIEWPORT_EXAMPLES_FILTERING_SCENE_INDEX_CLIENT_EXAMPLE_H diff --git a/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp new file mode 100644 index 0000000000..ef8cced189 --- /dev/null +++ b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp @@ -0,0 +1,85 @@ +// +// Copyright 2023 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. +// + +//Local headers +#include "fvpFilteringSceneIndexExample.h" + +//USD/Hydra headers +#include +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +namespace +{ + //As an example, we use a filtering scene index to filter mesh primitives which have more than 10 000 vertices. + bool IsFiltered(const HdSceneIndexPrim& sceneIndexPrim) + { + static bool _hideCameras = false; + static bool _hideSimpleLights = false; + + if (sceneIndexPrim.dataSource){ + + if ((sceneIndexPrim.primType == HdPrimTypeTokens->mesh) || (sceneIndexPrim.primType == HdPrimTypeTokens->basisCurves) ){ + // Retrieve points from source mesh + if (HdSampledDataSourceHandle pointsDs = HdPrimvarsSchema::GetFromParent(sceneIndexPrim.dataSource).GetPrimvar(HdPrimvarsSchemaTokens->points).GetPrimvarValue()) + { + VtValue v = pointsDs->GetValue(0.0f); + if (v.IsHolding>()) { + const VtArray& points = v.Get>(); + const size_t numPoints = points.size(); + if (numPoints > 10000){ + //Hide the prims that have more than 10 000 vertices + return true; + } + } + } + } + + else + if (sceneIndexPrim.primType == HdPrimTypeTokens->camera){ + return _hideCameras; + }else + if (sceneIndexPrim.primType == HdPrimTypeTokens->simpleLight){ + return _hideSimpleLights; + } + } + + return false; + } +} + +namespace FVP_NS_DEF { + +//This is the function where we filter prims +HdSceneIndexPrim FilteringSceneIndexExample::GetPrim(const SdfPath& primPath) const +{ + if (_GetInputSceneIndex()){ + const HdSceneIndexPrim prim = _GetInputSceneIndex()->GetPrim(primPath); + + const bool isThisPrimFiltered = IsFiltered(prim); + if ( ! isThisPrimFiltered){ + return prim;//return only non filtered prims + } + } + + return HdSceneIndexPrim(); +} + +}//end of namespace FVP_NS_DEF + +PXR_NAMESPACE_CLOSE_SCOPE \ No newline at end of file diff --git a/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h new file mode 100644 index 0000000000..e5c34292c7 --- /dev/null +++ b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h @@ -0,0 +1,91 @@ +// +// Copyright 2023 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. +// +#ifndef FLOW_VIEWPORT_EXAMPLES_FILTERING_SCENE_INDEX_EXAMPLE_H +#define FLOW_VIEWPORT_EXAMPLES_FILTERING_SCENE_INDEX_EXAMPLE_H + +//Local headers +#include "flowViewport/api.h" + +//Hydra headers +#include +#include + + +/** This clas is an implementation of a HdSingleInputFilteringSceneIndexBase which is a filtering scene index. +* In this example of filtering scene index we will hide the mesh primitives which have more than 10 000 vertices. +*/ + +//The Pixar's namespace needs to be at the highest namespace level for TF_DECLARE_WEAK_AND_REF_PTRS to work. +PXR_NAMESPACE_OPEN_SCOPE + +namespace FVP_NS_DEF { + +class FilteringSceneIndexExample; +TF_DECLARE_WEAK_AND_REF_PTRS(FilteringSceneIndexExample); + +class FilteringSceneIndexExample : public HdSingleInputFilteringSceneIndexBase +{ +public: + using ParentClass = HdSingleInputFilteringSceneIndexBase; + + static FilteringSceneIndexExampleRefPtr New(const HdSceneIndexBaseRefPtr& inputSceneIndex){ + return TfCreateRefPtr(new FilteringSceneIndexExample(inputSceneIndex)); + } + + // From HdSceneIndexBase + HdSceneIndexPrim GetPrim(const SdfPath& primPath) const override;//Is the useful function where we do filtering + + SdfPathVector GetChildPrimPaths(const SdfPath& primPath) const override{//We leave this function with no filtering for simplicity + if (_GetInputSceneIndex()){ + return _GetInputSceneIndex()->GetChildPrimPaths(primPath); + } + + return {}; + } + + ~FilteringSceneIndexExample() override = default; + +protected: + FilteringSceneIndexExample(const HdSceneIndexBaseRefPtr& inputSceneIndex) : ParentClass(inputSceneIndex) {} + + void _PrimsAdded( + const HdSceneIndexBase& sender, + const HdSceneIndexObserver::AddedPrimEntries& entries) override final + { + _SendPrimsAdded(entries); + } + + void _PrimsRemoved( + const HdSceneIndexBase& sender, + const HdSceneIndexObserver::RemovedPrimEntries& entries) override + { + _SendPrimsRemoved(entries); + } + + void _PrimsDirtied( + const HdSceneIndexBase& sender, + const HdSceneIndexObserver::DirtiedPrimEntries& entries) override + { + _SendPrimsDirtied(entries); + } +}; + +}//end of namespace FVP_NS_DEF + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif //FLOW_VIEWPORT_EXAMPLES_FILTERING_SCENE_INDEX_EXAMPLE_H + diff --git a/lib/flowViewport/API/samples/fvpInformationClientExample.cpp b/lib/flowViewport/API/samples/fvpInformationClientExample.cpp index 89cbd7dd7f..b2b113143f 100644 --- a/lib/flowViewport/API/samples/fvpInformationClientExample.cpp +++ b/lib/flowViewport/API/samples/fvpInformationClientExample.cpp @@ -25,13 +25,13 @@ InformationClientExample::~InformationClientExample() { } -//Callback to be able to act when a Hydra viewport scene index was added, typical use case is an hydra viewport was created. +//Callback to be able to act when a Hydra viewport scene index was added, typical use case is a hydra viewport was created. void InformationClientExample::SceneIndexAdded(const InformationInterface::ViewportInformation& viewportInformation) { } -//Callback to be able to act when a Hydra viewport scene index was removed, typical use case is an hydra viewport was removed. +//Callback to be able to act when a Hydra viewport scene index was removed, typical use case is a hydra viewport was removed. void InformationClientExample::SceneIndexRemoved(const InformationInterface::ViewportInformation& viewportInformation) { } diff --git a/lib/flowViewport/sceneIndex/fvpRenderIndexProxyFwd.h b/lib/flowViewport/sceneIndex/fvpRenderIndexProxyFwd.h index 14b84f8e57..46b5fe44ff 100644 --- a/lib/flowViewport/sceneIndex/fvpRenderIndexProxyFwd.h +++ b/lib/flowViewport/sceneIndex/fvpRenderIndexProxyFwd.h @@ -16,7 +16,7 @@ #define FVP_RENDER_INDEX_PROXY_FWD_H #include "flowViewport/api.h" - +#include namespace FVP_NS_DEF { diff --git a/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/flowViewportAPIMayaLocator.cpp b/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/flowViewportAPIMayaLocator.cpp index 765b0ff3cc..7fda154274 100644 --- a/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/flowViewportAPIMayaLocator.cpp +++ b/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/flowViewportAPIMayaLocator.cpp @@ -15,11 +15,13 @@ // //Flow viewport headers +#include #include #include #include #include #include +#include //Maya hydra headers #include @@ -89,6 +91,8 @@ class FlowViewportAPIMayaLocator : public MPxLocatorNode Fvp::DataProducerSceneIndexExample _hydraViewportDataProducerSceneIndexExample; protected: + /// _hydraViewportFilteringSceneIndexClientExample is the filtering scene index example for a Hydra viewport scene index. + std::shared_ptr _hydraViewportFilteringSceneIndexClientExample; /// _hydraViewportInformationClient is the viewport information example for a Hydra viewport. std::shared_ptr _hydraViewportInformationClient; ///To be used in hydra viewport API to pass the Maya node's MObject for setting callbacks for filtering and data producer scene indices @@ -341,6 +345,14 @@ FlowViewportAPIMayaLocator::FlowViewportAPIMayaLocator() //Add a callback after a load scene _cbAfterOpenId = MSceneMessage::addCallback(MSceneMessage::kAfterOpen, afterOpenCallback, ((void*)this)) ; + + //Create a Filtering scene index client + _hydraViewportFilteringSceneIndexClientExample = std::make_shared( + "FilteringSceneIndexClientExample", + Fvp::FilteringSceneIndexClient::Category::kSceneFiltering, + FvpViewportAPITokens->allRenderers, //We could set only Storm by using "GL" or only Arnold by using "Arnold" or both with "GL, Arnold" + nullptr);//DCC node will be filled later + } //This is called only when our node is destroyed and the undo queue flushed. @@ -364,6 +376,10 @@ FlowViewportAPIMayaLocator::~FlowViewportAPIMayaLocator() //The DataProducerSceneIndexExample in its destructor removes itself by calling DataProducerSceneIndexExample::RemoveDataProducerSceneIndex() + //Unregister filtering scene index client + Fvp::FilteringSceneIndexInterface& filteringSceneIndexInterface = Fvp::FilteringSceneIndexInterface::get(); + filteringSceneIndexInterface.unregisterFilteringSceneIndexClient(_hydraViewportFilteringSceneIndexClientExample); + //Unregister viewport information client Fvp::InformationInterface& informationInterface = Fvp::InformationInterface::Get(); informationInterface.UnregisterInformationClient(_hydraViewportInformationClient); @@ -418,13 +434,25 @@ void FlowViewportAPIMayaLocator::SetupFlowViewportInterfaces() } } - //Store the MObject* of the maya node in various classes //Set the maya node as a parent for this data producer scene index so that when the node is hidden/deleted/moved it gets applied to the prims produced GfMatrix4d nodeInvTransform; GetNodeInverseTransform(_thisMObject, nodeInvTransform); _hydraViewportDataProducerSceneIndexExample.setContainerNode(&_thisMObject); _hydraViewportDataProducerSceneIndexExample.setContainerNodeInverseTransform(nodeInvTransform); _hydraViewportDataProducerSceneIndexExample.addDataProducerSceneIndex(); + + //Register a filtering scene index client + Fvp::FilteringSceneIndexInterface& filteringSceneIndexInterface = Fvp::FilteringSceneIndexInterface::get(); + + + //Store the MObject* of the maya node in various classes + _hydraViewportFilteringSceneIndexClientExample->setDccNode(&_thisMObject); + + //Register this filtering scene index client, so it can append custom filtering scene indices to Hydra viewport scene indices + const bool bResult = filteringSceneIndexInterface.registerFilteringSceneIndexClient(_hydraViewportFilteringSceneIndexClientExample); + if(! bResult){ + perror("ERROR : filteringSceneIndexInterface.registerFilteringSceneIndexClient returned false"); + } } MStatus FlowViewportAPIMayaLocator::compute( const MPlug& plug, MDataBlock& dataBlock) diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/CMakeLists.txt b/lib/mayaHydra/hydraExtensions/sceneIndex/CMakeLists.txt index 61228f65ca..f9188eb888 100644 --- a/lib/mayaHydra/hydraExtensions/sceneIndex/CMakeLists.txt +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/CMakeLists.txt @@ -14,6 +14,8 @@ target_sources(${TARGET_NAME} mayaHydraMayaDataProducerSceneIndexData.cpp mayaHydraMayaDataProducerSceneIndexDataConcreteFactory.cpp mayaHydraSceneIndexDataFactoriesSetup.cpp + mayaHydraMayaFilteringSceneIndexData.cpp + mayaHydraMayaFilteringSceneIndexDataConcreteFactory.cpp ) set(HEADERS @@ -28,6 +30,8 @@ set(HEADERS mayaHydraMayaDataProducerSceneIndexData.h mayaHydraMayaDataProducerSceneIndexDataConcreteFactory.h mayaHydraSceneIndexDataFactoriesSetup.h + mayaHydraMayaFilteringSceneIndexData.h + mayaHydraMayaFilteringSceneIndexDataConcreteFactory.h ) # ----------------------------------------------------------------------------- diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaDataProducerSceneIndexData.cpp b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaDataProducerSceneIndexData.cpp index 940af1d07b..44d84fadf0 100644 --- a/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaDataProducerSceneIndexData.cpp +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaDataProducerSceneIndexData.cpp @@ -61,7 +61,7 @@ namespace //this is how we identify which object we need to deal with. PXR_NS::MayaDataProducerSceneIndexData* mayaDataProducerSceneIndexData = (PXR_NS::MayaDataProducerSceneIndexData*)data; const MObjectHandle objHandle(obj); - if(mayaDataProducerSceneIndexData && mayaDataProducerSceneIndexData->_mObjHandle.isValid() && objHandle.hashCode() == mayaDataProducerSceneIndexData->_mObjHandle.hashCode()){ + if(mayaDataProducerSceneIndexData && mayaDataProducerSceneIndexData->getObjHandle().isValid() && objHandle.hashCode() == mayaDataProducerSceneIndexData->getObjHandle().hashCode()){ mayaDataProducerSceneIndexData->UpdateVisibilityFromDCCNode(true); } } @@ -73,7 +73,7 @@ namespace //this is how we identify which object we need to deal with. PXR_NS::MayaDataProducerSceneIndexData* mayaDataProducerSceneIndexData = (PXR_NS::MayaDataProducerSceneIndexData*)data; const MObjectHandle objHandle(obj); - if(mayaDataProducerSceneIndexData && mayaDataProducerSceneIndexData->_mObjHandle.isValid() && objHandle.hashCode() == mayaDataProducerSceneIndexData->_mObjHandle.hashCode()){ + if(mayaDataProducerSceneIndexData && mayaDataProducerSceneIndexData->getObjHandle().isValid() && objHandle.hashCode() == mayaDataProducerSceneIndexData->getObjHandle().hashCode()){ mayaDataProducerSceneIndexData->UpdateVisibilityFromDCCNode(false); } } diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaDataProducerSceneIndexData.h b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaDataProducerSceneIndexData.h index 217fca5e5c..801ec927ed 100644 --- a/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaDataProducerSceneIndexData.h +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaDataProducerSceneIndexData.h @@ -45,6 +45,18 @@ TF_DECLARE_WEAK_AND_REF_PTRS(MayaDataProducerSceneIndexData);//Be able to use Re ///Destructor ~MayaDataProducerSceneIndexData() override; + /// Get the MObject handle + const MObjectHandle& getObjHandle()const {return _mObjHandle;} + + /// Provide the node name from maya + std::string GetDCCNodeName() const override; + + ///Update transform from maya node + void UpdateTransformFromMayaNode(); + +private: + MayaDataProducerSceneIndexData(const FVP_NS_DEF::DataProducerSceneIndexDataBase::CreationParameters& params); + //The following members are optional and used only when a dccNode was passed in the constructor of DataProducerSceneIndexDataBase /// Is the MObjectHandle of the maya node shape, it may be invalid if no maya node MObject pointer was passed. @@ -55,15 +67,6 @@ TF_DECLARE_WEAK_AND_REF_PTRS(MayaDataProducerSceneIndexData);//Be able to use Re MCallbackIdArray _nodeMessageCallbackIds; /// Are the callbacks Ids set in maya to handle delete and deletion undo/redo MCallbackIdArray _dGMessageCallbackIds; - - /// Provide the node name from maya - std::string GetDCCNodeName() const override; - - ///Update transform from maya node - void UpdateTransformFromMayaNode(); - -private: - MayaDataProducerSceneIndexData(const FVP_NS_DEF::DataProducerSceneIndexDataBase::CreationParameters& params); }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexData.cpp b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexData.cpp new file mode 100644 index 0000000000..6658494e85 --- /dev/null +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexData.cpp @@ -0,0 +1,127 @@ +// +// Copyright 2023 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. +// + + +//Local headers +#include "mayaHydraMayaFilteringSceneIndexData.h" +#include "mayaHydraLib/mayaUtils.h" + +//flow viewport headers +#include + +//Maya headers +#include +#include +#include +#include +#include +#include + +namespace +{ + //Callback when an attribute of this a Maya node changes + void attributeChangedCallback(MNodeMessage::AttributeMessage msg, MPlug& plug, MPlug& otherPlug, void* data) + { + if( ! data){ + return; + } + + bool isVisible = false; + if (MayaHydra::IsAMayaVisibilityAttribute(plug, isVisible)){ + PXR_NS::MayaFilteringSceneIndexData* mayaFilteringSceneIndexData = (PXR_NS::MayaFilteringSceneIndexData*)data; + mayaFilteringSceneIndexData->updateVisibilityFromDCCNode(isVisible); + } + } + + //Callback when a node is added + void onDagNodeAdded(MObject& obj, void* data) + { + //Since when an object is recreated (such as doing an undo after a delete of the node), the MObject are different but their MObjectHandle::hasCode() are identical so + //this is how we identify which object we need to deal with. + PXR_NS::MayaFilteringSceneIndexData* mayaFilteringSceneIndexData = (PXR_NS::MayaFilteringSceneIndexData*)data; + const MObjectHandle objHandle(obj); + if(mayaFilteringSceneIndexData&& mayaFilteringSceneIndexData->getObjHandle().isValid() && objHandle.hashCode() == mayaFilteringSceneIndexData->getObjHandle().hashCode()){ + mayaFilteringSceneIndexData->updateVisibilityFromDCCNode(true); + } + } + + //Callback when a node is removed + void onDagNodeRemoved(MObject& obj, void* data) + { + //Since when an object is recreated (such as doing an undo after a delete of the node), the MObject are different but their MObjectHandle::hasCode() are identical so + //this is how we identify which object we need to deal with. + PXR_NS::MayaFilteringSceneIndexData* mayaFilteringSceneIndexData = (PXR_NS::MayaFilteringSceneIndexData*)data; + const MObjectHandle objHandle(obj); + if(mayaFilteringSceneIndexData&& mayaFilteringSceneIndexData->getObjHandle().isValid() && objHandle.hashCode() == mayaFilteringSceneIndexData->getObjHandle().hashCode()){ + mayaFilteringSceneIndexData->updateVisibilityFromDCCNode(false); + } + } +} + +PXR_NAMESPACE_USING_DIRECTIVE + +MayaFilteringSceneIndexData::MayaFilteringSceneIndexData(const std::shared_ptr<::FVP_NS_DEF::FilteringSceneIndexClient>& client) +: PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBase(client) +{ + //If a maya node is present in client.getDccNode(), add callbacks to handle node deleted/undo/redo and hide/unhide + void* dccNode = client->getDccNode(); + if (dccNode){ + MObject* mObj = reinterpret_cast(dccNode); + _mObjHandle = MObjectHandle(*mObj); + + MCallbackId cbId = MNodeMessage::addAttributeChangedCallback(*mObj, attributeChangedCallback, this); + if (cbId){ + _nodeMessageCallbackIds.append(cbId); + } + + const MDagPath mayaNodeDagPath = MDagPath::getAPathTo(*mObj); + + //Also monitor parent DAG node to be able to update the scene index if the visibility is modified + MDagPath parentDagPath = mayaNodeDagPath; + parentDagPath.pop(); + MObject parentObj = parentDagPath.node(); + cbId = 0; + cbId = MNodeMessage::addAttributeChangedCallback(parentObj, attributeChangedCallback, this); + if (cbId){ + _nodeMessageCallbackIds.append(cbId); + } + + //Get node type name to filter by node type for callbacks + MFnDependencyNode dep(*mObj); + const MString nodeTypeName = dep.typeName(); + + //Setup node added callback, filter by node type using nodeTypeName + cbId = 0; + cbId = MDGMessage::addNodeAddedCallback(onDagNodeAdded, nodeTypeName, this); + if (cbId) { + _dGMessageCallbackIds.append(cbId); + } + + //Setup node remove callback, filter by node type using nodeTypeName + cbId = 0; + cbId = MDGMessage::addNodeRemovedCallback(onDagNodeRemoved, nodeTypeName, this); + if (cbId) { + _dGMessageCallbackIds.append(cbId); + } + } +} + +MayaFilteringSceneIndexData::~MayaFilteringSceneIndexData() +{ + MNodeMessage::removeCallbacks (_nodeMessageCallbackIds); + MMessage::removeCallbacks (_dGMessageCallbackIds); +} + diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexData.h b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexData.h new file mode 100644 index 0000000000..0ecb3c06b9 --- /dev/null +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexData.h @@ -0,0 +1,66 @@ +// +// Copyright 2023 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. +// +#ifndef MAYAHYDRA_SCENE_INDEX_MAYA_FILTERING_SCENE_INDEX_DATA_H +#define MAYAHYDRA_SCENE_INDEX_MAYA_FILTERING_SCENE_INDEX_DATA_H + +//Flow Viewport headers +#include +#include +#include + +//Maya headers +#include +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class MayaFilteringSceneIndexData; +TF_DECLARE_WEAK_AND_REF_PTRS(MayaFilteringSceneIndexData);//Be able to use Ref counting pointers on MayaFilteringSceneIndexData + +/**This class is a Maya implementation of FilteringSceneIndexDataBase with specific variables and callbacks for Maya since FilteringSceneIndexDataBase is +* part of Flow viewport which is DCC agnostic. +*/ + class MayaFilteringSceneIndexData : public FVP_NS_DEF::FilteringSceneIndexDataBase +{ +public: + static TfRefPtr New(const std::shared_ptr<::FVP_NS_DEF::FilteringSceneIndexClient>& client) { + return TfCreateRefPtr(new MayaFilteringSceneIndexData(client)); + } + + ~MayaFilteringSceneIndexData() override; + + const MObjectHandle& getObjHandle()const {return _mObjHandle;} + +private: + MayaFilteringSceneIndexData(const std::shared_ptr<::FVP_NS_DEF::FilteringSceneIndexClient>& client); + + ///The following members are optional and used only when a dccNode was passed in the FilteringSceneIndexClient + + /// Is the MObjectHandle of the maya node shape, it may be invalid if no maya node MObject pointer was passed in the FilteringSceneIndexClient. + MObjectHandle _mObjHandle; + + /// Are the callbacks Ids set in maya to forward the changes done in maya on the dataProducer scene index. + MCallbackIdArray _nodeMessageCallbackIds; + + /// Are the callbacks Ids set in maya to handle delete and deletion undo/redo + MCallbackIdArray _dGMessageCallbackIds; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif //MAYAHYDRA_SCENE_INDEX_MAYA_FILTERING_SCENE_INDEX_DATA_H + diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexDataConcreteFactory.cpp b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexDataConcreteFactory.cpp new file mode 100644 index 0000000000..226ab72914 --- /dev/null +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexDataConcreteFactory.cpp @@ -0,0 +1,31 @@ +// +// Copyright 2023 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. +// + +//Local headers +#include "mayaHydraMayaFilteringSceneIndexDataConcreteFactory.h" +#include "mayaHydraMayaFilteringSceneIndexData.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace MAYAHYDRA_NS_DEF { + +PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr +MayaFilteringSceneIndexDataConcreteFactory::createFilteringSceneIndexDataBase(const std::shared_ptr<::FVP_NS_DEF::FilteringSceneIndexClient>& client) +{ + return MayaFilteringSceneIndexData::New(client); +} + +}//end of namespace MAYAHYDRA_NS_DEF \ No newline at end of file diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexDataConcreteFactory.h b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexDataConcreteFactory.h new file mode 100644 index 0000000000..bc3f93fad4 --- /dev/null +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraMayaFilteringSceneIndexDataConcreteFactory.h @@ -0,0 +1,41 @@ +// +// Copyright 2023 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. +// +#ifndef MAYA_HYDRA_FILTERING_SCENE_INDEX_DATA_CONCRETE_FACTORY_H +#define MAYA_HYDRA_FILTERING_SCENE_INDEX_DATA_CONCRETE_FACTORY_H + +//MayaHydra headers +#include "mayaHydraLib/api.h" +#include "mayaHydraLib/mayaHydra.h" + +//Flow Viewport headers +#include "flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndexDataAbstractFactory.h" + +namespace MAYAHYDRA_NS_DEF { + +/** Since Flow viewport is DCC agnostic, the DCC will implement a concrete factory subclassing that class to provide specific DCC implementation of FilteringSceneIndexDataBaseRefPtr. +*/ +class MayaFilteringSceneIndexDataConcreteFactory : public Fvp::FilteringSceneIndexDataAbstractFactory +{ +public: + /// The DCC will create a subclass of FilteringSceneIndexDataBaseRefPtr with specific DCC variables that Flow viewport cannot manage since it's DCC agnostic + PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr + createFilteringSceneIndexDataBase(const std::shared_ptr& client) override; +}; + +}//end of MAYAHYDRA_NS_DEF + +#endif //MAYA_HYDRA_FILTERING_SCENE_INDEX_DATA_CONCRETE_FACTORY_H + diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraSceneIndexDataFactoriesSetup.cpp b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraSceneIndexDataFactoriesSetup.cpp index 8c0b5efcf3..427c7f7cc0 100644 --- a/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraSceneIndexDataFactoriesSetup.cpp +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraSceneIndexDataFactoriesSetup.cpp @@ -22,14 +22,19 @@ //Local headers #include "mayaHydraSceneIndexDataFactoriesSetup.h" #include "mayaHydraMayaDataProducerSceneIndexDataConcreteFactory.h" +#include "mayaHydraMayaFilteringSceneIndexDataConcreteFactory.h" //Flow viewport headers #include +#include namespace MAYAHYDRA_NS_DEF{ SceneIndexDataFactoriesSetup::SceneIndexDataFactoriesSetup() { + static MayaFilteringSceneIndexDataConcreteFactory filteringFactory; + Fvp::FilteringSceneIndexInterfaceImp::get().setSceneIndexDataFactory(filteringFactory); + static MayaDataProducerSceneIndexDataConcreteFactory dataProducerFactory; Fvp::DataProducerSceneIndexInterfaceImp::get().setSceneIndexDataFactory(dataProducerFactory); } diff --git a/lib/mayaHydra/mayaPlugin/renderOverride.cpp b/lib/mayaHydra/mayaPlugin/renderOverride.cpp index 3426a55944..de4ec9cd53 100644 --- a/lib/mayaHydra/mayaPlugin/renderOverride.cpp +++ b/lib/mayaHydra/mayaPlugin/renderOverride.cpp @@ -600,7 +600,7 @@ MStatus MtohRenderOverride::Render( //Create a HydraViewportInformation const Fvp::InformationInterface::ViewportInformation hydraViewportInformation(std::string(panelName.asChar()), cameraName); - manager.AddViewportInformation(hydraViewportInformation, _renderIndexProxy); + manager.AddViewportInformation(hydraViewportInformation, _renderIndexProxy, _lastFilteringSceneIndexBeforeCustomFiltering); } } @@ -880,28 +880,26 @@ void MtohRenderOverride::_CreateSceneIndicesChainAfterMergingSceneIndex() //This function is where happens the ordering of filtering scene indices that are after the merging scene index TF_AXIOM(_renderIndexProxy); - HdSceneIndexBaseRefPtr lastSceneIndexOfTheChain = _renderIndexProxy->GetMergingSceneIndex(); + _lastFilteringSceneIndexBeforeCustomFiltering = _renderIndexProxy->GetMergingSceneIndex(); _selection = std::make_shared(); - _selectionSceneIndex = Fvp::SelectionSceneIndex::New(lastSceneIndexOfTheChain, _selection); + _selectionSceneIndex = Fvp::SelectionSceneIndex::New(_lastFilteringSceneIndexBeforeCustomFiltering , _selection); _selectionSceneIndex->SetDisplayName("Flow Viewport Selection Scene Index"); - lastSceneIndexOfTheChain = _selectionSceneIndex; + _lastFilteringSceneIndexBeforeCustomFiltering = _selectionSceneIndex; if (!_sceneIndexRegistry) { _sceneIndexRegistry.reset(new MayaHydraSceneIndexRegistry(_renderIndexProxy)); } - auto wfSi = TfDynamic_cast(Fvp::WireframeSelectionHighlightSceneIndex::New(_selectionSceneIndex, _selection)); + auto wfSi = TfDynamic_cast(Fvp::WireframeSelectionHighlightSceneIndex::New(_lastFilteringSceneIndexBeforeCustomFiltering, _selection)); wfSi->SetDisplayName("Flow Viewport Wireframe Selection Highlight Scene Index"); // At time of writing, wireframe selection highlighting of Maya native data // is done by Maya at render item creation time, so avoid double wireframe // selection highlighting. wfSi->addExcludedSceneRoot(_ID); - lastSceneIndexOfTheChain = wfSi; + _lastFilteringSceneIndexBeforeCustomFiltering = wfSi; - _renderIndex->InsertSceneIndex(lastSceneIndexOfTheChain, SdfPath::AbsoluteRootPath()); - // Set the initial selection onto the selection scene index. _selectionSceneIndex->ReplaceSelection(*Ufe::GlobalSelection::get()); } diff --git a/lib/mayaHydra/mayaPlugin/renderOverride.h b/lib/mayaHydra/mayaPlugin/renderOverride.h index 5d30e7ce24..a4fd9ab119 100644 --- a/lib/mayaHydra/mayaPlugin/renderOverride.h +++ b/lib/mayaHydra/mayaPlugin/renderOverride.h @@ -221,6 +221,7 @@ class MtohRenderOverride : public MHWRender::MRenderOverride HdxTaskController* _taskController = nullptr; HdPluginRenderDelegateUniqueHandle _renderDelegate = nullptr; Fvp::RenderIndexProxyPtr _renderIndexProxy{nullptr}; + HdSceneIndexBaseRefPtr _lastFilteringSceneIndexBeforeCustomFiltering {nullptr}; HdRenderIndex* _renderIndex = nullptr; Fvp::SelectionTrackerSharedPtr _fvpSelectionTracker; Fvp::SelectionSceneIndexRefPtr _selectionSceneIndex; diff --git a/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt b/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt index de30349a08..94f297ff34 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt +++ b/test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt @@ -24,6 +24,7 @@ set(TEST_SCRIPT_FILES cpp/testFlowViewportAPIViewportInformation.py cpp/testFlowViewportAPIAddPrims.py cpp/testUsdStageLayerMuting.py + cpp/testFlowViewportAPIFilterPrims.py ) # Test use of mesh adapter code for mesh support, using environment variable. diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeCreated.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeCreated.png new file mode 100644 index 0000000000000000000000000000000000000000..e0a000f100ae9ac5a66820ea40af74640743b199 GIT binary patch literal 9129 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 literal 0 HcmV?d00001 diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeDeleted.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeDeleted.png new file mode 100644 index 0000000000000000000000000000000000000000..07b6793a3060f1bdd3894ce6abad2a03f41f0362 GIT binary patch literal 2140 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 literal 0 HcmV?d00001 diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeHidden.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeHidden.png new file mode 100644 index 0000000000000000000000000000000000000000..07b6793a3060f1bdd3894ce6abad2a03f41f0362 GIT binary patch literal 2140 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 NXfqqrN)z{l{{dd~-xdG> literal 0 HcmV?d00001 diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeUnhidden.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_NodeUnhidden.png new file mode 100644 index 0000000000000000000000000000000000000000..d5a428242c7d901e7f18b9babfbb262b714f20d7 GIT binary patch literal 6063 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 literal 0 HcmV?d00001 diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_SphereFiltered.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_SphereFiltered.png new file mode 100644 index 0000000000000000000000000000000000000000..d5a428242c7d901e7f18b9babfbb262b714f20d7 GIT binary patch literal 6063 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 literal 0 HcmV?d00001 diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_SphereFilteredAgain.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_SphereFilteredAgain.png new file mode 100644 index 0000000000000000000000000000000000000000..d5a428242c7d901e7f18b9babfbb262b714f20d7 GIT binary patch literal 6063 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 literal 0 HcmV?d00001 diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_SphereUnFiltered.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_SphereUnFiltered.png new file mode 100644 index 0000000000000000000000000000000000000000..5a5e990f77f2e1d75c9cb7d636791baa3d15e8f3 GIT binary patch literal 6662 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 au=V`YTi|b*|NHM77|z(zsQiM*@Bae~{~TZd literal 0 HcmV?d00001 diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_VP2AndThenBackToStorm.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_VP2AndThenBackToStorm.png new file mode 100644 index 0000000000000000000000000000000000000000..d5a428242c7d901e7f18b9babfbb262b714f20d7 GIT binary patch literal 6063 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 literal 0 HcmV?d00001 diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/multipleViewports_VP2AndThenBackToStorm_modPan2.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/multipleViewports_VP2AndThenBackToStorm_modPan2.png index 73e33dae93323dc691d1d48fc05c0e82caab26a2..d3875b5574768972536e186339d0ad787707c5a6 100644 GIT binary patch literal 3230 zcmeGfTToM1@B&s4jDf)dHPlcXL1`Vej95g%V*o`_urjTRf{;R6AVfqFNJt`&7K{|e zRzy(Z3{;915D`+6CZQl;+mKjM0!D~{BrolrfP9HEX61+QGggjD^d?cr|sF}hiw6eMF0TRD(*oH zEu%(7<-8;;f`@)x5&&54866Q8pLa<;E@dClzcZ-u&;BI*%YE6me>z5VuO&7*xi|a} zcOtpDD4h3n*P+91hpVk`&B^bD@5^-Rax39w|HLnnGu>fZmXTaOmHZ&p> zD06TCTx@K-yuE;kH;4b85k@KtfUHM-AXxXc2F;{UrRU5S=Lyf~aTTnUe}q8D)JOtz zSdTA4?C#qL$9eSpA^O)r#Q0l_?rW$&O*p2uS#Y*kbW$R3%v?jQ65GF>zoN0$bRl^K z++zABjkNCe(vKrR-!F8yOs|+yTx0D>>|JF7<^N6Zhxg%oD#jj8)Svvc)l=`m|Bx6{ ziNkV0^_r1C)xXjyAF4|9qpM2o?Ud%IZN&IBUXh1sfm&#e$#%lE6K`-V$q{o%v8p{?PLKqFLaU|^A(!#ki^na(H(KoDS z5jr{r!C>p*z~`HDQ%N&O2+T9g)fQ zpPCpuA}HuI&y>4%_!}qqZMv|?#0qZN2$K^zV@mvpDFpknXGhyxMFW}|aLv7>B!+25 zq8|>LduoM7$sI^7-cRd^IT(!+gzFGk&E*pX7Oiq#!DQwX77D<&gskpVX$FHYBbk3R zPww7G$>q>*igaP`1yp(aaTbhnhFCT@jVID?1mgShbfXz|?@+yw3mq_c-qn}KdBj9B z&zr7zV?k897iy6hIc#@61N0aqYo6QPoJBNSM5zC~P+pkfdU~02Rk~6!nRAya8q@{9 zP}bG4Cl9!tHThtC{Z*F76)yrx=2Dfu ziZsb3DVjJ8UN@xf{$0H0=4=981Tt)UzjN5R1;<%PsGmR2b{F{rWOnQ&g%}}Oq3NNc z5$krml#rAnTniJIUlJWL6c-`pX(mBoe^tz0|H<&vWujg>J7f<@1h*txy6^)QgTMqP zZ5SYPEA96u+cjU+yE6K8Y6B}|V%vax&|ok~Iy0Tdz@lc%hKp)#S9ARCm_iR~}-dQp;;ENq(RWymU0+V)JR z&FNIbO~aZio;J-_CtVq!PLOAq?W{=I?92~#|B%7t;yz>Wt>nH}Pkvu)yl$SW8{&8n zndN@n1H=YVVsQRVa69@-$zRejj;UgNmcizrTXEg8!6}XinqtqDf9w0Xy(Y)+t{)~x zTi5Bj37^b&D!kEP8vC6 zutK#8l-RWQmmQK%nutjZD&*0o z?l+HJ!%`=pD&6tY!gaBX>isE)DWs*7$*RD!)>YKCGU4_uJSCT=KW)!btLp25vkkLa zDZ!@)`^NfRtzm&>CYbW1U#Hq?HlhX3?ww4y1FhX<%~y)K0pB1sSeB)niOkf;N)o$| z-zU#rv(UNYBf;>UH6pd5@RnIQqZq75&>T+`f#Lmq9A8hLe^OfBbVhI5!~dX1HWB4b a;~q;hQ{Ay~;qS)^AUbkyL~HobqCWw9Tk6;V literal 3265 zcmeHKc~Fzr7XJd2t;E1niw_krcGO30Q&eb$n1BsfYJsX5;_?D22m%47E(w8bh>QzT z&{PRap{)q57*fiEP!jUB$YLNYn#aC;NLb4fLP$aqk~GLn=l%0$I@9T2^^bebopbKo zIp=qld+x2zLXN=gUF-n>fCqhyI}QM_oV8_ZZI-Y=Z;6?0xNtHkIyl(FyajC62mm~o z;-4}zyQILt%dZ4$WWb}Q0{|SbK{$VWa^d`NXC_hg&lbggajnxQN590~+dGt*;b`Uj zUTNCc;bXB0+Q_+Q0YX`y1yA zr`vzJT+jX#Lt)U|I%nUw;Ttp=Qbd|G&@ah{1Xt8^{TqP9-fz-f0am`173(GoaCCA6 zkQNqxI6vT~tu5dLgSjK!0o-flUkAbiL<&G&kSr~=GFA_jZ`~R%Hb^wpS1{iN`rV!e zwFX^>uc=D~S?QBLOHCHki9}H%!&eB8(>|%{IseX|Hw>*<*CH5N?G(0dSkFnyk=Sge zI+Wy#nNR0bTe&8KmcM^7Y7pC*GtnJdtMif7a{C3j5awFjH@H5@3ghG5t-XDw3SkV=^$n3 z^CKF$O0}Rz34eG&6bS`N{~g{rNRQ%0%3z{IGx(-+9Vj#zTi<-5Pf)OSqS&teQx+D%kN9O?7(hqxM?)K0`e)9d8Vphc^budFI%tLD&8*_ zO6l<%)0`Z0;&yc|_RkK=7ilqJ1VZ#vPt+E6a1_}$&$&=uuO8@OV(+k6_!Fbop(PsV z!(<#qN1F!Ye6}bXJmtM?9>vJzhnYLft@Sg%(hN+ZK`9O8!&};sKeGGKD)peZV_<;a zE8HqFhu&k$!La{FtZVza!M= z914_+)$Q4iXm!eobHTjiW1yH~dd)+92y&l(FSox;9l|t@*JN+HlflAE7wy0at&yP^ ztATN1)Td7IFN1CDvgHO!;kvSs262RF@p6k4yXQly_?{Ty5Mt^lYi?93&fo4nkkY_= z9}?Ow6F{#|A@whuRVvS1dtUmC*;>vFKko z&YXEyRNhFK>mlmC-vJ_UpSUD-UTm+#De5_}|z%;xZk63llPZSoQxD$mA> zR1jjPyV+638d#RQL&+u|dP-X-RT8ee=4nWk!e+oQ%2?y8%+cUb-wvdHA%8TS&to!k zY$E7a7xdq1cJZsQ37Gmk5?ay7chxKwO}~1gEOxJYC{+c|s;7!(i_qjJ`msz@MFfEt zUSF9f5$LdTto;6ovbwC8Vxqoh@|@*49LYTZkA5k?U(ew|fgK6qxmaWJ#G|9RH6$dv zUG}}KMG)hiu9%*Y#tRO);m4acWuBaOE3CgX@pVgIm{$A6wi!k(H9;rK7VsjB^Z_YE zaw#T-GvikvJH6Q2!mly%uNwhgk5{j;{j-C%5fSY&RPp&;X{Gr`@&A7wKu|ykuHx|7 GYrg@YQ~JdK diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/multipleViewports_VP2AndThenBackToStorm_modPan4.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/multipleViewports_VP2AndThenBackToStorm_modPan4.png index 485e6e19c03593bd4e33aa803599b5341177ea98..c7c5a9c29ef6565109e2789a8eb7c05ce1b9af83 100644 GIT binary patch delta 4793 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 literal 5821 zcmeG=>0gp**OoJ6rfD^n;Xd`$l$u(G8z3!isnxirB2$)`xMXC2qNZt03tE}Em5z;R zYC>jefZ|vqJ3UDUzrlg7V_b=l3soo)7nR-@kL6bDeXY?LOz+K7G5dJ^_L9JD58BU`9q-j?#&O6X`M7*=iPAd!>7#rZE{j{i{RDwD|Yeu@=5MQ_*WXKwQ^)6h_OUDwe68K$AN#atsxOJC#Y4_X=)>wmbe zzivJ3ca3%C$N#teU!|7Gnc=+}sQGVoVZlRlQ%g%HoX4@Vr0H%t-i0ggTinOk#CN~` z*Vo#9jOb$>vdrqnS2+buoQ#w&E(r8&B5)2SKWbNv6`{wm7r&vdd)b$`2a}4PD9;pL z)`rNJr-`RhH`^Bf1l(skPQ}hIf9)yiXj>7Ua#bjcE<#WG{yA;8qN*+e℘u-l0+o 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 diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/multipleViewports_VP2_modPan2.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/multipleViewports_VP2_modPan2.png index 4856fd5babbe55952957f6644790efd53661cfb8..6459f82abaf7d3255d2312afb5f60024669c931d 100644 GIT binary patch delta 801 zcmV++1K#|x5&jU6Qbz~;Nkl^yuorg9lfq)9Gdm*VorKr%#{$ z6pv{}WGwgT)2HhZl4sAJ2?(j3FYdOh8!DjK^)^7>BTq?jMCjL|B!8u$&JcK3wm^ zF(Wb0fBfqHJ|ttCm;PLE-vorEym|BHhj`2|Yy)xE4CJ=u$2P~dFa7!8KDi2urHm8c zMC+lG}02unGN$8Z#d?e{>YaeoHoXf}TWEAcO$WxRd+_WHIN z#`bo9rPVy-b+qifKgW2D`}#a^X=WfSW6nPAvYkzga7^2o$6f21g|HFJGLjqXFP^^J0IJ}U!(hobg7{dw5xu3zK*)tIvuSb>1BjBnq*-R$7Ul~Vhi z{{HHzqnX5houhb+*ML>H=8$E)c=6&icJli%cm79@-}T(l2THlXH2$_O-FwL*@k0`v29q1Ls%^3d_JGP zeEIUj&VPIRJL72CvCXmVOMgDNPXfYnUcP*J6Or-%n$Ow8b|$fp#BI-yF}5+bHMV)_ z&jt5QKv>c^*}ad*cH9<>?U?a!;+$0p2+JC?hH>8FC?wmzkDeRrjCIXCSebyZv{$cQ zon{PXNbV{c+hxbPmwx|nNvHGqeChW9e}vbsU*BA6b@a3E+i#gWSq}da5C9T~u(8om f0+InZ3gjOY1Q---EVST}Asq<-NkvXXu0mjfR~W8? delta 852 zcmV-a1FQW05U~-EQb`CeNklxvW00)WvO@A!K9Lotshh@jx*>AdDpIh6En z;>_M3hl%^tT2OQwJCy_^AC*p<>%-x21pxoly-Pm<0REk`@daH1lMn_ff8@cXp8)(R z-o1NweDvti)xCT7PGjrm&!4C9_3PKG=g*&CU+5{qA4Nb|-uw6OPvLm_^yw)a*Vosl zv2{EiPvgOZ2Unjze?E?oJbU&`NLZSWuvps1j~|auo;Vn`gGiee`9`hb=%m6WXy5t*8!IzAS`LD9&QT9_z3IV{<)A?iLfdG zVL2Z@d^qmIG0%H!gK^t!bBu_LIWPUX;I0V>OL_bD?Qx#Z*aqQTDE2FmeMGj$jQPgg zmwtV4mwXG0r96K8_%8vtX-s2(d;@Fy=egaEF*mHl3WR06dGqGDe_cfk=eBdqmC8OU z=eBds@fdggy5Lf*Kv>2&S8;BYvEOdbZ_L}rMT9?o{P?vR*>1OEJO-@7zjl@}R}(kc zp4%A5PupnRbl>fL;QyU~u#DT{u|IadGWlOW2K?Iz2+P>69`^flbuq{I$ZE!5>~H_> zwz*&x0>V=E5!j#4f0*$Y=62q;kH@*WU?l>=GWKuwzgtzzSj-j3x#Mq}16Cj)EMxwc z?BfLaxi|m$vDN-tT7NenbADKbfUu13-@l)}CAB@rG57bs|FK_z%&jxDuUZ91e%;fB7cAfAc@Ly7(u@%sIzn zT>5pwU9kdTDdU#}=Y@jP_KNf0UHh?Lh0Jhl12X1@l~{qWl(9k>=PAb62VftC-;MpT zb3UsNRwE!R=jF?nzalbXFoUq)-v{H|v2&g==cQj4+%*AVNiSZ!xc>I-+piFui^om3 z%`xT}b6xuNTfij<2+JC)hA&^fTy0k)+f~VaY>ydZ+}Fy3l?ez-d-dwo^*H%G##l|v zIQ(vmW9ISWzL$Rfa7ovP!{O4;0saWDU%x(m)oS~*wZrzCSA&z~@LvJ~K;k1TvB6&g ek?<-C`44)u8#oS|o*t1Q9SHzQMNUMnLSTaLQOzCz diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/multipleViewports_VP2_modPan4.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/multipleViewports_VP2_modPan4.png index ac1d96cef3d31ea6ac60063b070e0f5f9846c70a..68d003692689b6d5236bf7a59e19ff849d07453e 100644 GIT binary patch literal 2135 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKL9Be?5hW%z|fD~V9glC$suNIKWzyTr{7^Xen z9tos4^WEHv!2%%Sme#g&3=Hg7JzX3_D(1Ysdpj#QTB70Nl54{IW@|K=fBP76#5yqE z_d~>7X|*-7lg$1)YzqG-Vc`ybxj-Tj)KUoHnoZ{N9N$Bmrrx6e*i z_cxnwU%&5PvhlU^^X<*g&$GQf@7KHPcq_SXIR@$uQezrSanK7G2Lspz)U@xB{1zrLJ&xz<`p;DJuh$>cek zZi)9#FeBr+Lq+?OcOJ`JJ-aThEw$yzwy*h- zz_qirfnoJF>2BxaXAI6Xy!n@V;@wisCuM$#jOmFx1^2z*SNY%fc%eBH)0$g(GI>#t zS9>3OI>YGLzT*pz7s)U(hUI@hTOV)p%K6xg8itg|DW6o1e}E)W(vSQ`N7~bN1t1&E(488}3xx?>)1p=HH*4`r&&( zPBQ;)KJDX-jS|zg^P97#{E@qSyl~DTrm*}u$E5OqJw98%?y2VLCH@ulfQqVs#MwTyH}s~%iEjj z$L+Zx_qlZ4%mxPa=YM~H->vRH?~io<-v*s?=g*tR@2j~P8yA;1&%RzyrCdefz{!fw z&(6O4`1ttj-{0T=SC=bxc-GP5`Q-Zg`0)O}UtV5*_ww>`r6Trk4h@qH9({aqaq;Sv zNi2zR#U9_T@2IzVez2K+_WAkt@B9ARU2_4d*Nc-dVU{2udHl)QXu)5U%D z9@%wo+WF;u6wM798CGxq|KECD^%do=wH6IP%-#MeGlkoLe;+l`{^)p@g zWEbr^D|KFa|MQ!h)0g!}3kW<=>FMZs|24vCll;V=+bZ=_;vVm`yY%-P3yX#1`uP3# z>i+-xtHpBq)_sflhmG!=Kl=Rk_V(oct)YSf50> u7Dh&ejqFSgN(u}rOrz8=34%}JP3ATqt^MzU8V|VJ2n?RCelF{r5}E+gI*&sD diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/CMakeLists.txt b/test/lib/mayaUsd/render/mayaToHydra/cpp/CMakeLists.txt index a2d1b2eb9d..d2dc3448ef 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/cpp/CMakeLists.txt +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/CMakeLists.txt @@ -25,6 +25,7 @@ target_sources(${TARGET_NAME} testFlowViewportAPIAddPrims.cpp testUsdStageLayerMuting.cpp testMeshAdapterTransform.cpp + testFlowViewportAPIFilterPrims.cpp ) # ----------------------------------------------------------------------------- diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIAddPrims.cpp b/test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIAddPrims.cpp index efeb48ba9d..7dd9536dc7 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIAddPrims.cpp +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIAddPrims.cpp @@ -92,26 +92,14 @@ TEST(FlowViewportAPI, addPrimitives) //Setup inspector for the first viewport scene index const SceneIndicesVector& sceneIndices = GetTerminalSceneIndices(); - ASSERT_GT(sceneIndices.size(), static_cast(0)); + ASSERT_GT(sceneIndices.size(), 0u); SceneIndexInspector inspector(sceneIndices.front()); // Retrieve the first cube primitive from its Sdfpath and check its visibility - FindPrimPredicate findFirstCubePrimPredicate - = [&firstCubePath](const HdSceneIndexBasePtr& sceneIndex, const SdfPath& primPath) -> bool { - const std::string primPathString = primPath.GetAsString(); - HdSceneIndexPrim prim = sceneIndex->GetPrim(primPath); - if (primPathString.find(firstCubePath) != std::string::npos) { - //Check if it is visible or not - auto visibilityHandle = HdVisibilitySchema::GetFromParent(prim.dataSource).GetVisibility(); - if (visibilityHandle){ - return visibilityHandle->GetTypedValue(0.0f); //return true if it is visible, false otherwise - } - } - return false; - }; - + const PrimNameVisibilityPredicate findFirstCubePrimPredicate(firstCubePath); + PrimEntriesVector foundPrims = inspector.FindPrims(findFirstCubePrimPredicate, 1); - ASSERT_EQ(foundPrims.size(), static_cast(1)); //The cube should be found + ASSERT_EQ(foundPrims.size(), 1u); //The cube should be found //Hide the shape node MFnDependencyNode depNode(parentSphereShapeMOject, &stat); @@ -121,13 +109,13 @@ TEST(FlowViewportAPI, addPrimitives) visibilityPlug.setBool(false); foundPrims = inspector.FindPrims(findFirstCubePrimPredicate, 1); - ASSERT_EQ(foundPrims.size(), static_cast(0));//The cube should not be found + ASSERT_EQ(foundPrims.size(), 0u);//The cube should not be found //Unhide the shape node visibilityPlug.setBool(true); foundPrims = inspector.FindPrims(findFirstCubePrimPredicate, 1); - ASSERT_EQ(foundPrims.size(), static_cast(1));//The cube should be found + ASSERT_EQ(foundPrims.size(), 1u);//The cube should be found hydraViewportDataProducerSceneIndexExample.removeDataProducerSceneIndex(); } diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIFilterPrims.cpp b/test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIFilterPrims.cpp new file mode 100644 index 0000000000..cfd69f6d6b --- /dev/null +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIFilterPrims.cpp @@ -0,0 +1,119 @@ +// +// Copyright 2023 Autodesk, Inc. All rights reserved. +// +// 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. +// + +//Local headers +#include "testUtils.h" + +//maya hydra +#include +#include + +//Flow viewport headers +#include +#include + +//maya headers +#include +#include +#include +#include + +//Hydra headers +#include + +//Google tests +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +TEST(FlowViewportAPI, filterPrimitives) +{ + /* The python script testFlowViewportAPIFilterPrims.py associated with that file has created 1 cube and 2 spheres with : + * #Create a maya sphere named parentSphere + cmds.polyCube(name="parentCube", w=2, h=2, d=2) + cmds.polySphere(name="smallSphere") + cmds.polySphere(name="bigSphere", subdivisionsAxis=200, subdivisionsHeight= 200) + */ + static const MString parentName("parentCube"); + static const MString parentShapeName("parentCubeShape"); + static const MString smallSphereShapeName("smallSphereShape"); + static const MString bigSphereShapeName("bigSphereShape"); + + //Get the maya nodes which have been created by the python script matching this cpp file. + const MString names[] = {parentName, parentShapeName, smallSphereShapeName, bigSphereShapeName}; + const MStringArray nameArs (names, 4); + MObjectArray objArray; + objArray.setLength(4); + MStatus stat = MayaHydra::GetObjectsFromNodeNames(nameArs, objArray); + ASSERT_EQ(stat, MS::kSuccess); + + MObject parentMOject = objArray[0]; + ASSERT_FALSE(parentMOject.isNull()); + MObject parentShapeMOject = objArray[1]; + ASSERT_FALSE(parentShapeMOject.isNull()); + MObject smallSphereShapeMOject = objArray[2]; + ASSERT_FALSE(smallSphereShapeMOject.isNull()); + MObject bigSphereShapeMOject = objArray[3]; + ASSERT_FALSE(bigSphereShapeMOject.isNull()); + + //FilteringSceneIndexClientExample is an helper class to apply a filtering scene index into the viewport which hides objects with more than 10 000 vertices + //This is the case for the object named "bigSphere", it has more than 10 000 vertices. + const std::shared_ptr hydraViewportFilteringSceneIndexExample = std::make_shared + ("TestFilteringSceneIndex", + Fvp::FilteringSceneIndexClient::Category::kSceneFiltering, + FvpViewportAPITokens->allRenderers, + &parentShapeMOject //Set the cube as the parent of this filtering scene index + ); + //Filtering scene index interface + Fvp::FilteringSceneIndexInterface& filteringSceneIndexInterface = Fvp::FilteringSceneIndexInterface::get(); + + //Register it + const bool bRes = filteringSceneIndexInterface.registerFilteringSceneIndexClient(hydraViewportFilteringSceneIndexExample); + ASSERT_TRUE(bRes); + + //Check that there are primitives in the viewport terminal scene index + const SceneIndicesVector& sceneIndices = GetTerminalSceneIndices(); + ASSERT_GT(sceneIndices.size(), 0u); + SceneIndexInspector inspector(sceneIndices.front()); + + // Define both predicates for the small sphere prim and bug sphere in the list of primitives and return their visibility + const PrimNameVisibilityPredicate smallSpherePredicate(smallSphereShapeName.asChar()); + const PrimNameVisibilityPredicate bigSpherePredicate(bigSphereShapeName.asChar()); + + PrimEntriesVector foundPrims = inspector.FindPrims(smallSpherePredicate, 1); + ASSERT_EQ(foundPrims.size(), 1u); //The small sphere should be found and visible + + foundPrims = inspector.FindPrims(bigSpherePredicate, 1); + ASSERT_EQ(foundPrims.size(), 0u); //The big sphere should be filtered (not visible) + + //Hide the cube shape node which is the parent node of the filtering scene index, this should disable the filtering and make the big sphere visible. + MFnDependencyNode depNode(parentShapeMOject, &stat); + ASSERT_EQ(stat, MS::kSuccess); + MPlug visibilityPlug = depNode.findPlug("visibility"); + ASSERT_FALSE(visibilityPlug.isNull()); + visibilityPlug.setBool(false); + + foundPrims = inspector.FindPrims(bigSpherePredicate, 1); + ASSERT_EQ(foundPrims.size(), 1u);//The big sphere should be visible, as the filtering is disabled since the cube which is its parent node is hidden. + + //Unhide the cube shape node + visibilityPlug.setBool(true); + + foundPrims = inspector.FindPrims(bigSpherePredicate, 1); + ASSERT_EQ(foundPrims.size(), 0u);//The big sphere should not be visible, as filtering is applied again + + filteringSceneIndexInterface.unregisterFilteringSceneIndexClient(hydraViewportFilteringSceneIndexExample); +} diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIFilterPrims.py b/test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIFilterPrims.py new file mode 100644 index 0000000000..3a4f9ce76c --- /dev/null +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testFlowViewportAPIFilterPrims.py @@ -0,0 +1,41 @@ +# +# Copyright 2023 Autodesk, Inc. All rights reserved. +# +# 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 +import fixturesUtils +import mtohUtils +from testUtils import PluginLoaded + +class TestFlowViewportAPIFilterPrims(mtohUtils.MayaHydraBaseTestCase): + # MayaHydraBaseTestCase.setUpClass requirement. + _file = __file__ + + def setupParentChildScene(self): + self.setHdStormRenderer() + #Create a maya sphere named parentSphere + cmds.polyCube(name="parentCube", w=2, h=2, d=2) + cmds.polySphere(name="smallSphere") + #Create a big sphere which has more than 10 000 vertices + cmds.polySphere(name="bigSphere", subdivisionsAxis=200, subdivisionsHeight= 200) + cmds.refresh() + + def test_FilterPrimitives(self): + self.setupParentChildScene() + with PluginLoaded('mayaHydraCppTests'): + cmds.mayaHydraCppTest(f="FlowViewportAPI.filterPrimitives") + +if __name__ == '__main__': + fixturesUtils.runTests(globals()) diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testMayaSceneFlattening.cpp b/test/lib/mayaUsd/render/mayaToHydra/cpp/testMayaSceneFlattening.cpp index 27a4711c5e..7c66d63d35 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/cpp/testMayaSceneFlattening.cpp +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testMayaSceneFlattening.cpp @@ -32,7 +32,7 @@ TEST(MayaSceneFlattening, childHasFlattenedTransform) { // Setup inspector for the first scene index const SceneIndicesVector& sceneIndices = GetTerminalSceneIndices(); - ASSERT_GT(sceneIndices.size(), static_cast(0)); + ASSERT_GT(sceneIndices.size(), 0u); SceneIndexInspector inspector(sceneIndices.front()); // Retrieve the child cube prim @@ -47,7 +47,7 @@ TEST(MayaSceneFlattening, childHasFlattenedTransform) return parentIsCube; }; PrimEntriesVector foundPrims = inspector.FindPrims(findCubePrimPredicate, 1); - ASSERT_EQ(foundPrims.size(), static_cast(1)); + ASSERT_EQ(foundPrims.size(), 1u); HdSceneIndexPrim cubePrim = foundPrims.front().prim; // Extract the Hydra xform matrix from the cube prim diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testMayaUsdUfeItems.cpp b/test/lib/mayaUsd/render/mayaToHydra/cpp/testMayaUsdUfeItems.cpp index 9cef3808fe..1b6a673ca4 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/cpp/testMayaUsdUfeItems.cpp +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testMayaUsdUfeItems.cpp @@ -38,10 +38,10 @@ TEST(MayaUsdUfeItems, skipUsdUfeLights) { // Setup inspector for the first scene index const SceneIndicesVector& sceneIndices = GetTerminalSceneIndices(); - ASSERT_GT(sceneIndices.size(), static_cast(0)); + ASSERT_GT(sceneIndices.size(), 0u); SceneIndexInspector inspector(sceneIndices.front()); // Find UFE lights PrimEntriesVector ufeLights = inspector.FindPrims(&IsUfeLight, 1); - EXPECT_EQ(ufeLights.size(), static_cast(0)); + EXPECT_EQ(ufeLights.size(), 0u); } diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testMergingSceneIndex.cpp b/test/lib/mayaUsd/render/mayaToHydra/cpp/testMergingSceneIndex.cpp index cea06271bf..1278463104 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/cpp/testMergingSceneIndex.cpp +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testMergingSceneIndex.cpp @@ -33,7 +33,7 @@ TEST(FlowViewport, mergingSceneIndex) { // The Flow Viewport custom merging scene index is in the scene index tree. const auto& sceneIndices = GetTerminalSceneIndices(); - ASSERT_GT(sceneIndices.size(), static_cast(0)); + ASSERT_GT(sceneIndices.size(), 0u); auto isFvpMergingSceneIndex = SceneIndexDisplayNamePred( "Flow Viewport Merging Scene Index"); diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testMeshAdapterTransform.cpp b/test/lib/mayaUsd/render/mayaToHydra/cpp/testMeshAdapterTransform.cpp index 82ce986afe..0e9e1a30ab 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/cpp/testMeshAdapterTransform.cpp +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testMeshAdapterTransform.cpp @@ -32,7 +32,7 @@ TEST(MeshAdapterTransform, testDirtying) { // Setup notifications accumulator for the first terminal scene index const SceneIndicesVector& sceneIndices = GetTerminalSceneIndices(); - ASSERT_GT(sceneIndices.size(), static_cast(0)); + ASSERT_GT(sceneIndices.size(), 0u); SceneIndexNotificationsAccumulator notifsAccumulator(sceneIndices.front()); // The test cube should still be selected from the Python driver diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testSelectionSceneIndex.cpp b/test/lib/mayaUsd/render/mayaToHydra/cpp/testSelectionSceneIndex.cpp index 8c9748cfa9..e3836d232b 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/cpp/testSelectionSceneIndex.cpp +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testSelectionSceneIndex.cpp @@ -37,7 +37,7 @@ TEST(FlowViewport, selectionSceneIndex) { // The Flow Viewport selection scene index is in the scene index tree. const auto& sceneIndices = GetTerminalSceneIndices(); - ASSERT_GT(sceneIndices.size(), static_cast(0)); + ASSERT_GT(sceneIndices.size(), 0u); auto isFvpSelectionSceneIndex = SceneIndexDisplayNamePred( "Flow Viewport Selection Scene Index"); diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testUtils.h b/test/lib/mayaUsd/render/mayaToHydra/cpp/testUtils.h index 915359f806..3c255c02ba 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/cpp/testUtils.h +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testUtils.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -166,6 +167,43 @@ class PrimNamePredicate const std::string _primName; }; +/** +* @brief PrimNameVisibilityPredicate is a Predicate to find a name in a primitive SdfPath and check its visibility attribute. This class is to be used as a FindPrimPredicate. +* It returns True if both conditions : +* 1) The predicate's prim name is found in one of the prims from the scene index (it only needs to be inside a path, not matching it exactly), +* 2) If 1) is filled, we check if the visibility attribute is set to true. +* This Predicate returns true only if both conditions are validated. Or false if one these conditions is not filled. +*/ +class PrimNameVisibilityPredicate +{ +public: + PrimNameVisibilityPredicate(const std::string primName) : _primName(primName) {} + + /** + * @brief Predicate to find a name in a primitive SdfPath and check its visibility attribute. This class is to be used as a FindPrimPredicate. + * + * @param[in] sceneIndex : scene index to use for checking the prims . + * @param[in] primPath : The prim path to test. + * + * @return True if the argument prim path's name has the predicate's prim name inside, and if the visibility attribute is set to true, false otherwise. + */ + bool operator()(const HdSceneIndexBasePtr& sceneIndex, const SdfPath& primPath) { + const std::string primPathString = primPath.GetAsString(); + HdSceneIndexPrim prim = sceneIndex->GetPrim(primPath); + if (primPathString.find(_primName) != std::string::npos) { + //Check if it is visible or not + auto visibilityHandle = HdVisibilitySchema::GetFromParent(prim.dataSource).GetVisibility(); + if (visibilityHandle){ + return visibilityHandle->GetTypedValue(0.0f); //return true if it is visible, false otherwise + } + } + return false; + } + +private: + const std::string _primName; +}; + class SceneIndexDisplayNamePred { const std::string _name; public: diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testWireframeSelectionHighlightSceneIndex.cpp b/test/lib/mayaUsd/render/mayaToHydra/cpp/testWireframeSelectionHighlightSceneIndex.cpp index 3b3b553413..cb418d68ae 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/cpp/testWireframeSelectionHighlightSceneIndex.cpp +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testWireframeSelectionHighlightSceneIndex.cpp @@ -94,7 +94,7 @@ TEST(FlowViewport, wireframeSelectionHighlightSceneIndex) // The Flow Viewport wireframe selection highlight scene index is in the // scene index tree. const auto& si = GetTerminalSceneIndices(); - ASSERT_GT(si.size(), static_cast(0)); + ASSERT_GT(si.size(), 0u); auto isFvpWireframeSelectionHighlightSceneIndex = SceneIndexDisplayNamePred( "Flow Viewport Wireframe Selection Highlight Scene Index"); diff --git a/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py b/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py index f8f24092bc..9cb2c3f1d0 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py +++ b/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py @@ -76,22 +76,19 @@ def test_AddingPrimitives(self): cmds.showHidden(transformNode) self.assertSnapshotClose("add_NodeUnhidden.png", None, None) - #Delete the shape node + #Delete the shape node, this should hide the added prims as well cmds.delete(flowViewportNodeName) - self.assertSnapshotClose("add_NodeDeleted.png", None, None) - #Enable undo again - cmds.undoInfo(stateWithoutFlush=True) - - #Undo the delete, the node should be visible again + + #Undo the delete, the node should be visible again so do the added prims cmds.undo() self.assertSnapshotClose("add_NodeDeletedUndo.png", None, None) - #Redo the delete + #Redo the delete, the added prims should be hidden cmds.redo() self.assertSnapshotClose("add_NodeDeletedRedo.png", None, None) - #Undo the delete again, the node should be visible again + #Undo the delete again, the added prims should be visible cmds.undo() self.assertSnapshotClose("add_NodeDeletedUndoAgain.png", None, None) @@ -111,6 +108,84 @@ def test_AddingPrimitives(self): #Finish by a File New command cmds.file(new=True, force=True) + #Test filtering primitives + def test_FilteringPrimitives(self): + self.setupScene() + with PluginLoaded('flowViewportAPIMayaLocator'): + + #Create a maya sphere + sphereNode, sphereShape = cmds.polySphere() + cmds.refresh() + + #Create a FlowViewportAPIMayaLocator node which adds a dataProducerSceneIndex and a Filtering scene index + flowViewportNodeName = cmds.createNode("FlowViewportAPIMayaLocator") + self.assertFalse(flowViewportNodeName == None) + #When the node above is created, its compute method is not called automatically, so work around to trigger a call to compute + cmds.setAttr(flowViewportNodeName + '.dummyInput', 3)#setting this will set dirty the dummyOutput attribute + cmds.getAttr(flowViewportNodeName + '.dummyOutput')#getting this value will trigger a call to compute + cmds.refresh() + #Original images are located for example in maya-hydra\test\lib\mayaUsd\render\mayaToHydra\FlowViewportAPITest + self.assertSnapshotClose("filter_NodeCreated.png", None, None) + + #Move the transform node, the added prims (cube grid) should move as well + # Get the transform node of the FlowViewportAPIMayaLocator + transformNode = cmds.listRelatives(flowViewportNodeName, parent=True)[0] + self.assertFalse(transformNode == None) + #Select the transform node + cmds.select(transformNode) + # Move the selected node + cmds.move(15, 0, 0) + cmds.refresh() + self.assertSnapshotClose("filter_NodeMoved.png", None, None) + + #Change sphere attributes to add more vertices/polygons, our filtering hides a prim when its number of vertices is greater than 10 000. + cmds.setAttr(sphereShape + '.subdivisionsAxis', 200) + cmds.setAttr(sphereShape + '.subdivisionsHeight', 200) + cmds.refresh() + self.assertSnapshotClose("filter_SphereFiltered.png", None, None) + + #Decreasing the number of vertices of this sphere under 10 000 should make it visible again (not filtered) + cmds.setAttr(sphereShape + '.subdivisionsAxis', 30) + cmds.refresh() + self.assertSnapshotClose("filter_SphereUnFiltered.png", None, None) + + #Increasing again the number of vertices above 10 000 should make it filtered again (invisible) + cmds.setAttr(sphereShape + '.subdivisionsAxis', 200) + cmds.refresh() + self.assertSnapshotClose("filter_SphereFilteredAgain.png", None, None) + + #Hide the transform node, this should hide the FlowViewportAPIMayaLocator shape node and disable the filtering as well. + cmds.hide(transformNode) + self.assertSnapshotClose("filter_NodeHidden.png", None, None) + + #Unhide the transform node, this should unhide the FlowViewportAPIMayaLocator node and enable the filtering as well. + cmds.showHidden(transformNode) + self.assertSnapshotClose("filter_NodeUnhidden.png", None, None) + + #Delete the shape node, this should disable filtering + cmds.delete(flowViewportNodeName) + self.assertSnapshotClose("filter_NodeDeleted.png", None, None) + + #Undo the delete, the node should be visible again and filtering be enabled + cmds.undo() + self.assertSnapshotClose("filter_NodeDeletedUndo.png", None, None) + + #Redo the delete, filtering should be disabled + cmds.redo() + self.assertSnapshotClose("filter_NodeDeletedRedo.png", None, None) + + #Undo the delete so filtering is enabled again + cmds.undo() + + #Switch to VP2 + self.setViewport2Renderer() + #Switch back to Storm + self.setHdStormRenderer() + self.assertSnapshotClose("filter_VP2AndThenBackToStorm.png", None, None) + + #Finish by a File New command + cmds.file(new=True, force=True) + #Test Cube grids parameters def test_CubeGrid(self): self.setupScene() @@ -324,6 +399,23 @@ def test_MultipleViewports(self): cmds.setFocus ('modelPanel2') self.assertSnapshotClose("multipleViewports_viewPanel2.png", None, None) + #Change sphere attributes to add more vertices/polygons, our filtering removes a prim when its number of vertices is greater than 10 000. + cmds.setAttr(sphereShape + '.subdivisionsAxis', 200) + cmds.setAttr(sphereShape + '.subdivisionsHeight', 200) + cmds.refresh() + cmds.setFocus ('modelPanel4') + self.assertSnapshotClose("multipleViewports_sphereFiltered_viewPanel4.png", None, None) + cmds.setFocus ('modelPanel2') + self.assertSnapshotClose("multipleViewports_sphereFiltered_viewPanel2.png", None, None) + + #Remove filtering by decreasing the number of vertices + cmds.setAttr(sphereShape + '.subdivisionsAxis', 30) + cmds.refresh() + cmds.setFocus ('modelPanel4') + self.assertSnapshotClose("multipleViewports_sphereUnfiltered_viewPanel4.png", None, None) + cmds.setFocus ('modelPanel2') + self.assertSnapshotClose("multipleViewports_sphereUnfiltered_viewPanel2.png", None, None) + #Switch to VP2 cmds.setFocus ('modelPanel4') self.setViewport2Renderer()