diff --git a/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp index ef8cced189..68b384cd96 100644 --- a/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp +++ b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp @@ -22,12 +22,14 @@ #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) + bool ShouldBeFiltered(const HdSceneIndexPrim& sceneIndexPrim) { static bool _hideCameras = false; static bool _hideSimpleLights = false; @@ -64,20 +66,120 @@ namespace } namespace FVP_NS_DEF { +bool FilteringSceneIndexExample::IsFiltered(const SdfPath& primPath) const +{ + return _filteredPrims.find(primPath) != _filteredPrims.end(); +} + +void FilteringSceneIndexExample::UpdateFilteringStatus(const SdfPath& primPath) +{ + if (ShouldBeFiltered(_GetInputSceneIndex()->GetPrim(primPath))) { + _filteredPrims.insert(primPath); + } else { + _filteredPrims.erase(primPath); + } +} + +FilteringSceneIndexExample::FilteringSceneIndexExample(const HdSceneIndexBaseRefPtr& inputSceneIndex) + : ParentClass(inputSceneIndex) +{ + std::stack primPathsToTraverse({ SdfPath::AbsoluteRootPath() }); + while (!primPathsToTraverse.empty()) { + SdfPath currPrimPath = primPathsToTraverse.top(); + primPathsToTraverse.pop(); + UpdateFilteringStatus(currPrimPath); + for (const auto& childPath : inputSceneIndex->GetChildPrimPaths(currPrimPath)) { + primPathsToTraverse.push(childPath); + } + } +} -//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 IsFiltered(primPath) ? HdSceneIndexPrim() : _GetInputSceneIndex()->GetPrim(primPath); +} + +SdfPathVector FilteringSceneIndexExample::GetChildPrimPaths(const SdfPath& primPath) const { + // A filtered prim should not exist from the point of view of downstream scene indices, + // so return an empty vector if the current prim is filtered. This case should normally + // not be reached during scene index hierarchy traversal, as its parent should not even + // return it when GetChildPrimPaths is called on it (see other comment in this method.) + if (IsFiltered(primPath)) { + return SdfPathVector(); + } + + // If the current prim is not filtered, we still do not want to return a path + // to a filtered child prim, as a filtered prim should not exist at all (and + // we might have sent a PrimsRemoved notification prior). Thus, remove all + // child paths to filtered prims before returning. + SdfPathVector childPaths = _GetInputSceneIndex()->GetChildPrimPaths(primPath); + childPaths.erase( + std::remove_if( + childPaths.begin(), + childPaths.end(), + [this](const SdfPath& childPath) -> bool { return IsFiltered(childPath); }), + childPaths.end()); + return childPaths; +} + +void FilteringSceneIndexExample::_PrimsAdded( + const HdSceneIndexBase& sender, + const HdSceneIndexObserver::AddedPrimEntries& entries) +{ + HdSceneIndexObserver::AddedPrimEntries unfilteredEntries; + for (const auto& entry : entries) { + // We only want to forward the notifications for prims that don't get filtered out + UpdateFilteringStatus(entry.primPath); + if (!IsFiltered(entry.primPath)) { + unfilteredEntries.push_back(entry); } } + _SendPrimsAdded(unfilteredEntries); +} - return HdSceneIndexPrim(); +void FilteringSceneIndexExample::_PrimsRemoved( + const HdSceneIndexBase& sender, + const HdSceneIndexObserver::RemovedPrimEntries& entries) +{ + for (const auto& entry : entries) { + // We don't need to update or check the filtering status, since the prim is getting removed either way + _filteredPrims.erase(entry.primPath); + } + _SendPrimsRemoved(entries); +} + +void FilteringSceneIndexExample::_PrimsDirtied( + const HdSceneIndexBase& sender, + const HdSceneIndexObserver::DirtiedPrimEntries& entries) +{ + // There are three potential scenarios here for a given prim : + // 1. Its filtering status did NOT change -> forward the PrimsDirtied notification as-is + // 2. Its filtering status DID change : + // 2a. If the prim was previously filtered -> it is now unfiltered, so send a PrimsAdded notification + // 2b. If the prim was previously unfiltered -> it is now filtered, so send a PrimsRemoved notification + HdSceneIndexObserver::AddedPrimEntries newlyUnfilteredEntries; + HdSceneIndexObserver::RemovedPrimEntries newlyFilteredEntries; + HdSceneIndexObserver::DirtiedPrimEntries dirtiedEntries; + for (const auto& entry : entries) { + bool wasPreviouslyFiltered = IsFiltered(entry.primPath); + UpdateFilteringStatus(entry.primPath); + if (wasPreviouslyFiltered == IsFiltered(entry.primPath)) { + // Filtering status did not change, forward notification as-is + dirtiedEntries.push_back(entry); + } + else { + // Filtering status changed, send a different notification instead + if (wasPreviouslyFiltered) { + newlyUnfilteredEntries.emplace_back( + entry.primPath, _GetInputSceneIndex()->GetPrim(entry.primPath).primType); + } else { + newlyFilteredEntries.emplace_back(entry.primPath); + } + } + } + _SendPrimsAdded(newlyUnfilteredEntries); + _SendPrimsRemoved(newlyFilteredEntries); + _SendPrimsDirtied(dirtiedEntries); } }//end of namespace FVP_NS_DEF diff --git a/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h index e5c34292c7..32b3e2df46 100644 --- a/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h +++ b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h @@ -46,41 +46,32 @@ class FilteringSceneIndexExample : public HdSingleInputFilteringSceneIndexBase } // From HdSceneIndexBase - HdSceneIndexPrim GetPrim(const SdfPath& primPath) const override;//Is the useful function where we do filtering + HdSceneIndexPrim GetPrim(const SdfPath& primPath) const override; - SdfPathVector GetChildPrimPaths(const SdfPath& primPath) const override{//We leave this function with no filtering for simplicity - if (_GetInputSceneIndex()){ - return _GetInputSceneIndex()->GetChildPrimPaths(primPath); - } - - return {}; - } + SdfPathVector GetChildPrimPaths(const SdfPath& primPath) const override; ~FilteringSceneIndexExample() override = default; protected: - FilteringSceneIndexExample(const HdSceneIndexBaseRefPtr& inputSceneIndex) : ParentClass(inputSceneIndex) {} + FilteringSceneIndexExample(const HdSceneIndexBaseRefPtr& inputSceneIndex); void _PrimsAdded( const HdSceneIndexBase& sender, - const HdSceneIndexObserver::AddedPrimEntries& entries) override final - { - _SendPrimsAdded(entries); - } + const HdSceneIndexObserver::AddedPrimEntries& entries) override; void _PrimsRemoved( const HdSceneIndexBase& sender, - const HdSceneIndexObserver::RemovedPrimEntries& entries) override - { - _SendPrimsRemoved(entries); - } + const HdSceneIndexObserver::RemovedPrimEntries& entries) override; void _PrimsDirtied( const HdSceneIndexBase& sender, - const HdSceneIndexObserver::DirtiedPrimEntries& entries) override - { - _SendPrimsDirtied(entries); - } + const HdSceneIndexObserver::DirtiedPrimEntries& entries) override; + + bool IsFiltered(const SdfPath& primPath) const; + + void UpdateFilteringStatus(const SdfPath& primPath); + + SdfPathSet _filteredPrims; }; }//end of namespace FVP_NS_DEF diff --git a/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_VP2AndThenBackToStorm_MovedSphereUnFiltered.png b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_VP2AndThenBackToStorm_MovedSphereUnFiltered.png new file mode 100644 index 0000000000..e6d9f5b34b Binary files /dev/null and b/test/lib/mayaUsd/render/mayaToHydra/FlowViewportAPITest/filter_VP2AndThenBackToStorm_MovedSphereUnFiltered.png differ diff --git a/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py b/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py index 83994b7450..f0a38ac2b9 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py +++ b/test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py @@ -186,6 +186,14 @@ def test_FilteringPrimitives(self): self.setHdStormRenderer() self.assertSnapshotClose("filter_VP2AndThenBackToStorm.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) + #Test unfiltering the sphere after switching renderers (HYDRA-747) + self.setViewport2Renderer() + cmds.xform(sphereNode, translation=[0,5,0], scale=[4,4,4]) + self.setHdStormRenderer() + cmds.setAttr(sphereShape + '.subdivisionsAxis', 30) #Unfilter the prim + cmds.refresh() + self.assertSnapshotClose("filter_VP2AndThenBackToStorm_MovedSphereUnFiltered.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT) + #Finish by a File New command cmds.file(new=True, force=True)