Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HYDRA-1098 : Viewport filters for Hydra data #189

Open
wants to merge 43 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e123772
HYDRA-1098 : Add new pruning scene index
debloip-adsk Oct 10, 2024
3f36ca7
HYDRA-1098 : Implement enable/disable filter
debloip-adsk Oct 10, 2024
dc636e5
HYDRA-1098 : Add pruning tokens
debloip-adsk Oct 10, 2024
3258809
HYDRA-1098 : Implement notifications handlers
debloip-adsk Oct 10, 2024
8fd711d
HYDRA-1098 : Workaround for PathInterface + basic integration
debloip-adsk Oct 10, 2024
580eda8
HYDRA-1098 : Implement GetPrim and GetChildPrimPaths
debloip-adsk Oct 10, 2024
c68aa74
HYDRA-1098 : Update filter map on enable/disable
debloip-adsk Oct 10, 2024
30387f1
HYDRA-108 : Exclude scene roots
debloip-adsk Oct 11, 2024
ae0e6ae
HYDRA-1098 : Add ancestor check
debloip-adsk Oct 11, 2024
b157dae
HYDRA-1098 : Handle all the different cases (hopefully)
debloip-adsk Oct 11, 2024
0a29f77
HYDRA-1098 : Refactor common code
debloip-adsk Oct 11, 2024
e05f9df
HYDRA-1098 : Refactor common code
debloip-adsk Oct 11, 2024
4b543d2
HYDRA-1098 : Provide accessor for active filters
debloip-adsk Oct 11, 2024
34e68cd
HYDRA-1098 : Adjust comment
debloip-adsk Oct 11, 2024
aa23f84
HYDRA-1098 : Legibility improvements
debloip-adsk Oct 11, 2024
d313b1b
HYDRA-1098 : Minor touchups for consistency
debloip-adsk Oct 11, 2024
88c4bbc
HYDRA-1098 : Add filtering tokens
debloip-adsk Oct 11, 2024
cb21f9a
HYDRA-1098 : Remove unimplementable tokens for now
debloip-adsk Oct 11, 2024
239e0fe
HYDRA-1098 : Implement various filter handlers
debloip-adsk Oct 11, 2024
d9b3a65
HYDRA-1098 : Plug Maya filters to Fvp pruning scene index
debloip-adsk Oct 11, 2024
36a1013
HYDRA-1098 : Restructure Maya plugging code
debloip-adsk Oct 11, 2024
f8a0f70
HYDRA-1098 : Add comment
debloip-adsk Oct 11, 2024
1fd1afb
HYDRA-1098 : Add filter tests with USD data for polygon and nurbs cur…
debloip-adsk Oct 15, 2024
751dece
HYDRA-1098 : Add filter test with USD data for nurbs patches filter
debloip-adsk Oct 15, 2024
e6743e0
HYDRA-1098 : Add filter test with USD data for lights filter
debloip-adsk Oct 15, 2024
aed47d4
HYDRA-1098 : Add USD camera filter test
debloip-adsk Oct 16, 2024
97c6f51
HYDRA-1098 : Add 3rd party data producer polygon filter test
debloip-adsk Oct 16, 2024
e439c69
HYDRA-1098 : Cleanup
debloip-adsk Oct 21, 2024
e7ddbb8
HYDRA-1098 : Add comments
debloip-adsk Oct 21, 2024
bbb43b6
HYDRA-1098 : Re-order member variables
debloip-adsk Oct 21, 2024
4a3dcbd
HYDRA-1098 : Make constants const
debloip-adsk Oct 21, 2024
27fa447
HYDRA-1098 : Remove commented debug code
debloip-adsk Oct 21, 2024
44d95e7
HYDRA-1098 : Use excluded scene root
debloip-adsk Oct 21, 2024
bd60069
HYDRA-1098 : Add comments
debloip-adsk Oct 21, 2024
acbaefc
HYDRA-1098 : Update tests
debloip-adsk Oct 21, 2024
b06bc6d
HYDRA-1098 : Minor refactor from code review
debloip-adsk Oct 21, 2024
e678d7f
HYDRA-1098 : Remove superflous selection clears
debloip-adsk Oct 21, 2024
0d34fd8
HYDRA-1098 : Update camera reference image
debloip-adsk Nov 12, 2024
274ac73
HYDRA-1098 : Add camera picking test
debloip-adsk Nov 12, 2024
7f0b85a
Merge branch 'dev' into debloip/HYDRA-1098/viewport-filters-hydra-data
debloip-adsk Nov 20, 2024
a37d7c8
HYDRA-1098 : Update reference image
debloip-adsk Nov 20, 2024
5a24bca
Merge branch 'dev' into debloip/HYDRA-1098/viewport-filters-hydra-data
debloip-adsk Dec 16, 2024
3fac4d4
Merge branch 'dev' into debloip/HYDRA-1098/viewport-filters-hydra-data
debloip-adsk Dec 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/flowViewport/sceneIndex/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ target_sources(${TARGET_NAME}
fvpWireframeSelectionHighlightSceneIndex.cpp
fvpDisplayStyleOverrideSceneIndex.cpp
fvpPruneTexturesSceneIndex.cpp
fvpPruningSceneIndex.cpp
ppt-adsk marked this conversation as resolved.
Show resolved Hide resolved
fvpBBoxSceneIndex.cpp
fvpReprSelectorSceneIndex.cpp
fvpBlockPrimRemovalPropagationSceneIndex.cpp
Expand All @@ -32,6 +33,7 @@ set(HEADERS
fvpWireframeSelectionHighlightSceneIndex.h
fvpDisplayStyleOverrideSceneIndex.h
fvpPruneTexturesSceneIndex.h
fvpPruningSceneIndex.h
fvpBBoxSceneIndex.h
fvpReprSelectorSceneIndex.h
fvpBlockPrimRemovalPropagationSceneIndex.h
Expand Down
344 changes: 344 additions & 0 deletions lib/flowViewport/sceneIndex/fvpPruningSceneIndex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,344 @@
// Copyright 2024 Autodesk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include "fvpPruningSceneIndex.h"

#include <pxr/base/tf/staticTokens.h>
#include <pxr/imaging/hd/filteringSceneIndex.h>
#include <pxr/imaging/hd/sceneIndexPrimView.h>
#include <pxr/imaging/hd/tokens.h>

PXR_NAMESPACE_OPEN_SCOPE

TF_DEFINE_PUBLIC_TOKENS(FvpPruningTokens, FVP_PRUNING_TOKENS);

PXR_NAMESPACE_CLOSE_SCOPE

PXR_NAMESPACE_USING_DIRECTIVE

namespace {

template<typename Container>
bool _HasAncestorInclusiveInContainer(const SdfPath& path, const Container& pathsContainer) {
SdfPath currPath = path;
while (!currPath.IsEmpty() && !currPath.IsAbsoluteRootPath()) {
if (pathsContainer.find(currPath) != pathsContainer.end()) {
return true;
} else {
currPath = currPath.GetParentPath();
}
}
return false;
}

bool _MeshesFilterHandler(const HdSceneIndexBaseRefPtr& sceneIndex, const SdfPath& primPath, const HdSceneIndexPrim& prim)
{
// Currently we just flat out remove any prim with a mesh type. If we were to add extra checks to make sure this is not
// a mesh prim that serves another purpose, we would add them here.
return prim.primType == HdPrimTypeTokens->mesh;
}

bool _CapsulesFilterHandler(const HdSceneIndexBaseRefPtr& sceneIndex, const SdfPath& primPath, const HdSceneIndexPrim& prim)
ppt-adsk marked this conversation as resolved.
Show resolved Hide resolved
{
return prim.primType == HdPrimTypeTokens->capsule;
}

bool _ConesFilterHandler(const HdSceneIndexBaseRefPtr& sceneIndex, const SdfPath& primPath, const HdSceneIndexPrim& prim)
{
return prim.primType == HdPrimTypeTokens->cone;
}

bool _CubesFilterHandler(const HdSceneIndexBaseRefPtr& sceneIndex, const SdfPath& primPath, const HdSceneIndexPrim& prim)
{
return prim.primType == HdPrimTypeTokens->cube;
}

bool _CylindersFilterHandler(const HdSceneIndexBaseRefPtr& sceneIndex, const SdfPath& primPath, const HdSceneIndexPrim& prim)
{
return prim.primType == HdPrimTypeTokens->cylinder;
}

bool _SpheresFilterHandler(const HdSceneIndexBaseRefPtr& sceneIndex, const SdfPath& primPath, const HdSceneIndexPrim& prim)
{
return prim.primType == HdPrimTypeTokens->sphere;
}

bool _NurbsCurvesFilterHandler(const HdSceneIndexBaseRefPtr& sceneIndex, const SdfPath& primPath, const HdSceneIndexPrim& prim)
{
return prim.primType == HdPrimTypeTokens->nurbsCurves;
}

bool _NurbsPatchesFilterHandler(const HdSceneIndexBaseRefPtr& sceneIndex, const SdfPath& primPath, const HdSceneIndexPrim& prim)
{
return prim.primType == HdPrimTypeTokens->nurbsPatch;
}

} // namespace

namespace FVP_NS_DEF {

PruningSceneIndexRefPtr PruningSceneIndex::New(const HdSceneIndexBaseRefPtr &inputSceneIndex)
{
return TfCreateRefPtr(new PruningSceneIndex(inputSceneIndex));
}

PruningSceneIndex::PruningSceneIndex(HdSceneIndexBaseRefPtr const &inputSceneIndex) :
HdSingleInputFilteringSceneIndexBase(inputSceneIndex),
InputSceneIndexUtils(inputSceneIndex)
{
}

void PruningSceneIndex::AddExcludedSceneRoot(const PXR_NS::SdfPath& sceneRoot)
{
_excludedSceneRoots.emplace(sceneRoot);
}

bool PruningSceneIndex::_IsExcluded(const PXR_NS::SdfPath& primPath) const
{
return _HasAncestorInclusiveInContainer(primPath, _excludedSceneRoots);
}

bool PruningSceneIndex::_PrunePrim(const SdfPath& primPath, const HdSceneIndexPrim& prim, const TfToken& pruningToken) const
{
if (_IsExcluded(primPath)) {
return false;
}
using FilterHandler = std::function<bool(const HdSceneIndexBaseRefPtr&, const SdfPath&, const HdSceneIndexPrim&)>;
static std::map<TfToken, FilterHandler> filterHandlers = {
{ FvpPruningTokens->meshes, _MeshesFilterHandler },
{ FvpPruningTokens->capsules, _CapsulesFilterHandler },
{ FvpPruningTokens->cones, _ConesFilterHandler },
{ FvpPruningTokens->cubes, _CubesFilterHandler },
{ FvpPruningTokens->cylinders, _CylindersFilterHandler },
{ FvpPruningTokens->spheres, _SpheresFilterHandler },
{ FvpPruningTokens->nurbsCurves, _NurbsCurvesFilterHandler },
{ FvpPruningTokens->nurbsPatches, _NurbsPatchesFilterHandler }
};
return filterHandlers[pruningToken](GetInputSceneIndex(), primPath, prim);
ppt-adsk marked this conversation as resolved.
Show resolved Hide resolved
}

bool PruningSceneIndex::_IsAncestorPrunedInclusive(const SdfPath& primPath) const
{
return _HasAncestorInclusiveInContainer(primPath, _filtersByPrunedPath);
}

HdSceneIndexPrim PruningSceneIndex::GetPrim(const SdfPath& primPath) const
{
if (_filtersByPrunedPath.find(primPath) != _filtersByPrunedPath.end()) {
// Path is pruned out; return nothing. Note that we could also use
// _IsAncestorPrunedInclusive, but child paths of a pruned out prim
// should not be reachable in the first place due to GetChildPrimPaths
// pruning them out as well.
return {};
}
return GetInputSceneIndex()->GetPrim(primPath);
}

SdfPathVector PruningSceneIndex::GetChildPrimPaths(const SdfPath& primPath) const
{
SdfPathVector baseChildPaths = GetInputSceneIndex()->GetChildPrimPaths(primPath);
SdfPathVector editedChildPaths;
for (const auto& baseChildPath : baseChildPaths) {
// Only keep child paths which are not pruned out.
if (_filtersByPrunedPath.find(baseChildPath) == _filtersByPrunedPath.end()) {
editedChildPaths.emplace_back(baseChildPath);
}
}
return editedChildPaths;
}

bool PruningSceneIndex::EnableFilter(const TfToken& pruningToken)
{
if (_prunedPathsByFilter.find(pruningToken) != _prunedPathsByFilter.end()) {
// Filter already enabled, no change needed.
return false;
}

// Enable the filter
_prunedPathsByFilter[pruningToken] = SdfPathSet();

HdSceneIndexObserver::RemovedPrimEntries prunedPrims;

for (const SdfPath& primPath : HdSceneIndexPrimView(GetInputSceneIndex())) {
if (_PrunePrim(primPath, GetInputSceneIndex()->GetPrim(primPath), pruningToken)) {
// Only send notification if it was not already pruned out, either directly or indirectly
if (!_IsAncestorPrunedInclusive(primPath)) {
prunedPrims.emplace_back(primPath);
}

_InsertEntry(primPath, pruningToken);
}
}

if (!prunedPrims.empty()) {
_SendPrimsRemoved(prunedPrims);
}

return true;
}

bool PruningSceneIndex::DisableFilter(const TfToken& pruningToken)
{
if (_prunedPathsByFilter.find(pruningToken) == _prunedPathsByFilter.end()) {
// Filter already disabled, no change needed.
return false;
}

HdSceneIndexObserver::AddedPrimEntries unprunedPrims;

SdfPathSet prunedPaths = _prunedPathsByFilter[pruningToken];
for (const auto& primPath : prunedPaths) {
_RemoveEntry(primPath, pruningToken);

// Only send notification if it was pruned and no longer is
if (!_IsAncestorPrunedInclusive(primPath)) {
unprunedPrims.emplace_back(primPath, GetInputSceneIndex()->GetPrim(primPath).primType);
}
}

// Disable the filter
_prunedPathsByFilter.erase(pruningToken);

if (!unprunedPrims.empty()) {
_SendPrimsAdded(unprunedPrims);
}

return true;
}

std::set<TfToken> PruningSceneIndex::GetActiveFilters()
{
std::set<TfToken> pruningTokens;
for (const auto& filterEntry : _prunedPathsByFilter) {
pruningTokens.emplace(filterEntry.first);
}
return pruningTokens;
}

void PruningSceneIndex::_InsertEntry(const PXR_NS::SdfPath& primPath, const PXR_NS::TfToken& pruningToken)
{
_prunedPathsByFilter[pruningToken].emplace(primPath);
_filtersByPrunedPath[primPath].emplace(pruningToken);
}

void PruningSceneIndex::_RemoveEntry(const PXR_NS::SdfPath& primPath, const PXR_NS::TfToken& pruningToken)
{
if (_prunedPathsByFilter.find(pruningToken) != _prunedPathsByFilter.end()) {
_prunedPathsByFilter[pruningToken].erase(primPath);
}

if (_filtersByPrunedPath.find(primPath) != _filtersByPrunedPath.end()) {
_filtersByPrunedPath[primPath].erase(pruningToken);
if (_filtersByPrunedPath[primPath].empty()) {
_filtersByPrunedPath.erase(primPath);
}
}
}

void PruningSceneIndex::_PrimsAdded(
const PXR_NS::HdSceneIndexBase &sender,
const PXR_NS::HdSceneIndexObserver::AddedPrimEntries &entries)
{
HdSceneIndexObserver::AddedPrimEntries editedEntries;

for (const auto& addedEntry : entries) {
for (const auto& pruningToken : GetActiveFilters()) {
if (_PrunePrim(addedEntry.primPath, GetInputSceneIndex()->GetPrim(addedEntry.primPath), pruningToken)) {
_InsertEntry(addedEntry.primPath, pruningToken);
}
}

// Only send notification if not pruned
if (!_IsAncestorPrunedInclusive(addedEntry.primPath)) {
editedEntries.emplace_back(addedEntry);
}
}

if (!editedEntries.empty()) {
_SendPrimsAdded(editedEntries);
}
}

void PruningSceneIndex::_PrimsRemoved(
const PXR_NS::HdSceneIndexBase &sender,
const PXR_NS::HdSceneIndexObserver::RemovedPrimEntries &entries)
{
HdSceneIndexObserver::RemovedPrimEntries editedEntries;

for (const auto& removedEntry : entries) {
if (!_IsAncestorPrunedInclusive(removedEntry.primPath)) {
// Prim was not pruned; forward the notification
editedEntries.emplace_back(removedEntry);
} else {
// Prim was pruned; we have either already sent a PrimsRemoved
// notification from EnableFilter() or have prevented the original
// PrimsAdded notification from being forwarded in the first place.
// No need to send a PrimsRemoved notification for a prim that
// doesn't exist, just remove the pruning entry.
for (const auto& pruningToken : GetActiveFilters()) {
_RemoveEntry(removedEntry.primPath, pruningToken);
}
}
}

if (!editedEntries.empty()) {
_SendPrimsRemoved(editedEntries);
}
}

void PruningSceneIndex::_PrimsDirtied(
const PXR_NS::HdSceneIndexBase &sender,
const PXR_NS::HdSceneIndexObserver::DirtiedPrimEntries &entries)
{
HdSceneIndexObserver::RemovedPrimEntries removedEntries;
HdSceneIndexObserver::AddedPrimEntries addedEntries;
HdSceneIndexObserver::DirtiedPrimEntries editedEntries;

for (const auto& dirtiedEntry : entries) {
bool wasInitiallyPruned = _IsAncestorPrunedInclusive(dirtiedEntry.primPath);

HdSceneIndexPrim dirtiedPrim = GetInputSceneIndex()->GetPrim(dirtiedEntry.primPath);

for (const auto& pruningToken : GetActiveFilters()) {
if (_PrunePrim(dirtiedEntry.primPath, dirtiedPrim, pruningToken)) {
_InsertEntry(dirtiedEntry.primPath, pruningToken);
} else {
_RemoveEntry(dirtiedEntry.primPath, pruningToken);
}
}

bool isNowPruned = _IsAncestorPrunedInclusive(dirtiedEntry.primPath);

if (!wasInitiallyPruned && isNowPruned) {
removedEntries.emplace_back(dirtiedEntry.primPath);
} else if (wasInitiallyPruned && !isNowPruned) {
addedEntries.emplace_back(dirtiedEntry.primPath, dirtiedPrim.primType);
} else {
editedEntries.emplace_back(dirtiedEntry);
}
}

if (!removedEntries.empty()) {
_SendPrimsRemoved(removedEntries);
}
if (!addedEntries.empty()) {
_SendPrimsAdded(addedEntries);
}
if (!editedEntries.empty()) {
_SendPrimsDirtied(editedEntries);
}
}

} // namespace FVP_NS_DEF
Loading