Skip to content

Commit

Permalink
HYDRA-747 : Filtering scene index example can have prims get unfilter…
Browse files Browse the repository at this point in the history
…ed at the wrong location (#42)

* HYDRA-747 : Working fix

* HYDRA-747 : Cleanup, add comments and handle GetChildPrimPaths

* HYDRA-747 : Implement ctor and use cached filtering state instead of doing full check

* HYDRA-747 : Filter out child prim paths

* HYDRA-747 : Simplify code as _GetInputSceneIndex is always valid

* HYDRA-787 : Add unit test for renderer switching

* HYDRA-747 : Add comment on child paths
  • Loading branch information
debloip-adsk authored Feb 2, 2024
1 parent cdb2c23 commit 1cd9715
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 30 deletions.
120 changes: 111 additions & 9 deletions lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
#include <pxr/imaging/hd/meshSchema.h>
#include <pxr/imaging/hd/tokens.h>

#include <stack>

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;
Expand Down Expand Up @@ -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<SdfPath> 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
Expand Down
33 changes: 12 additions & 21 deletions lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions test/lib/mayaUsd/render/mayaToHydra/testFlowViewportAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down

0 comments on commit 1cd9715

Please sign in to comment.