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-1286 : Support displacement on GeomSubset wireframe highlights #242

Open
wants to merge 21 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e952874
HYDRA-1286 : Initial displacement (no updates)
debloip-adsk Jan 27, 2025
5f503d4
HYDRA-1286 : Update GeomSubset highlight on displacement update
debloip-adsk Jan 27, 2025
9c3f4e8
HYDRA-1286 : Add utility method to create data source dependencies
debloip-adsk Jan 27, 2025
7b62cc9
HYDRA-1286 : Extract method to make geomSubset highlights
debloip-adsk Jan 27, 2025
5e3302d
HYDRA-1286 : Support displacement in point instancing
debloip-adsk Jan 27, 2025
80c825d
HYDRA-1286 : Cleanup
debloip-adsk Jan 27, 2025
bb01e29
HYDRA-1286 : Handle scaling
debloip-adsk Jan 28, 2025
9fe659f
HYDRA-1286 : Cleanup
debloip-adsk Jan 28, 2025
4e65cdc
HYDRA-1286 : Re-order methods
debloip-adsk Jan 28, 2025
c7a5663
HYDRA-1286 : Move TrimMeshForGeomSubset to FVP namespace
debloip-adsk Jan 28, 2025
9be90b2
HYDRA-1286 : Update variable names
debloip-adsk Jan 28, 2025
32e8a29
HYDRA-1286 : Update tokens
debloip-adsk Jan 28, 2025
d2bf391
HYDRA-1286 : Add GeomSubset displacement test scene
debloip-adsk Jan 28, 2025
2149576
HYDRA-1286 : Add GeomSubset displacement test
debloip-adsk Jan 28, 2025
a9d252c
HYDRA-1286 : Go back to using only copy-pasted data sources from rero…
debloip-adsk Jan 28, 2025
1045c15
HYDRA-1286 : Handle conditional compilation
debloip-adsk Jan 28, 2025
8fe7bd0
HYDRA-1286 : Additional conditional compilation
debloip-adsk Jan 28, 2025
49b45bf
HYDRA-1286 : Additional conditional compilation
debloip-adsk Jan 28, 2025
5478876
HYDRA-1286 : Rename ComputeSmoothNormals
debloip-adsk Jan 29, 2025
40f7d9d
HYDRA-1286 : Move transpose of inverse matrix out of loop
debloip-adsk Jan 29, 2025
aefa92a
HYDRA-1286 : Extract out utility functions
debloip-adsk Jan 29, 2025
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
554 changes: 452 additions & 102 deletions lib/flowViewport/sceneIndex/wireframeHighlights/fvpBaseWhSi.cpp

Large diffs are not rendered by default.

71 changes: 43 additions & 28 deletions lib/flowViewport/sceneIndex/wireframeHighlights/fvpBaseWhSi.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <flowViewport/fvpWireframeColorInterface.h>
#include <flowViewport/sceneIndex/fvpSceneIndexUtils.h>

#include <pxr/base/vt/value.h>
#include <pxr/imaging/hd/filteringSceneIndex.h>
#include <pxr/imaging/hd/selectionSchema.h>

Expand All @@ -29,32 +30,6 @@

namespace FVP_NS_DEF {

// Essentially a port of USD's _RerootingSceneIndexContainerDataSource in rerootingSceneIndex.cpp
class RepathingContainerDataSource : public PXR_NS::HdContainerDataSource
{
public:
HD_DECLARE_DATASOURCE(RepathingContainerDataSource)

RepathingContainerDataSource(
const PXR_NS::SdfPath &srcPrefix,
const PXR_NS::SdfPath &dstPrefix,
PXR_NS::HdContainerDataSourceHandle const &inputDataSource)
: _srcPrefix(srcPrefix)
, _dstPrefix(dstPrefix)
, _inputDataSource(inputDataSource)
{
}

PXR_NS::TfTokenVector GetNames() override;

PXR_NS::HdDataSourceBaseHandle Get(const PXR_NS::TfToken& name) override;

private:
const PXR_NS::SdfPath _srcPrefix;
const PXR_NS::SdfPath _dstPrefix;
PXR_NS::HdContainerDataSourceHandle const _inputDataSource;
};

using SelectionKey = std::pair<PXR_NS::SdfPath, std::string>;

enum InstancingPathsCollectionDirection {
Expand Down Expand Up @@ -217,6 +192,18 @@ class BaseWhSi
FVP_API
void CollectInstancingPaths(const PXR_NS::SdfPath& primPath, InstancingPathsCollectionDirection direction, PXR_NS::SdfPathSet& outInstancerPaths, PXR_NS::SdfPathSet& outPrototypePaths) const;

// Return the displacement value from the given prim data source's assigned material
FVP_API
PXR_NS::VtValue GetMaterialDisplacementValue(const PXR_NS::HdContainerDataSourceHandle& primDataSource) const;

#if PXR_VERSION >= 2403
// Given a mesh and geomSubset data sources, edits and returns the mesh data source to fit the given geomSubset
FVP_API
PXR_NS::HdContainerDataSourceHandle MakeGeomSubsetHighlight(
const PXR_NS::HdContainerDataSourceHandle& meshPrimDataSource,
const PXR_NS::HdContainerDataSourceHandle& geomSubsetPrimDataSource) const;
#endif

const PXR_NS::SdfPath _highlightHierarchyPrefix;
const std::shared_ptr<WireframeColorInterface> _wireframeColorInterface;

Expand All @@ -231,13 +218,41 @@ class BaseWhSi
// Make the given prim be drawn as a wireframe of the given color.
PXR_NS::HdContainerDataSourceHandle SetWireframeRepr(const PXR_NS::HdContainerDataSourceHandle& dataSource, const PXR_NS::GfVec4f& color);

// Return a Fvp::PrimSelection equivalent to the given Hydra selection
Fvp::PrimSelection ConvertHydraToFvpSelection(const PXR_NS::SdfPath& primPath, const PXR_NS::HdSelectionSchema& selectionSchema);

// Repath instancing-related data sources by replacing srcPrefix with dstPrefix.
// Mainly used to setup selection highlight instancers and instances.
PXR_NS::HdContainerDataSourceHandle RepathInstancingDataSources(
const PXR_NS::HdContainerDataSourceHandle& primDataSource,
const PXR_NS::SdfPath& srcPrefix,
const PXR_NS::SdfPath& dstPrefix);

// Get the path to the prim's bound material.
PXR_NS::SdfPath GetMaterialPath(const PXR_NS::HdContainerDataSourceHandle& primDataSource);

#if PXR_VERSION >= 2403
// Edit the given mesh data source such that its topology matches the given geomSubset.
PXR_NS::HdContainerDataSourceHandle
TrimMeshForGeomSubset(const PXR_NS::HdContainerDataSourceHandle& meshRootDataSource, const PXR_NS::HdContainerDataSourceHandle& geomSubsetRootDataSource);
TrimMeshForGeomSubset(const PXR_NS::HdContainerDataSourceHandle& meshPrimDataSource, const PXR_NS::HdContainerDataSourceHandle& geomSubsetPrimDataSource);
#endif

Fvp::PrimSelection ConvertHydraToFvpSelection(const PXR_NS::SdfPath& primPath, const PXR_NS::HdSelectionSchema& selectionSchema);
// Computes and adds the normals primvar with smooth normals. If normals are already present, does nothing.
PXR_NS::HdContainerDataSourceHandle ComputeSmoothNormals(const PXR_NS::HdContainerDataSourceHandle& meshPrimDataSource);

// Manually apply scaling on the prim.
PXR_NS::HdContainerDataSourceHandle ForceScale(const PXR_NS::HdContainerDataSourceHandle& meshPrimDataSource);

// Manually apply displacement on the prim.
PXR_NS::HdContainerDataSourceHandle ForceDisplacement(const PXR_NS::HdContainerDataSourceHandle& meshPrimDataSource, float displacement);

// Add an entry to the __dependencies data source
PXR_NS::HdContainerDataSourceHandle AddDependency(
const PXR_NS::HdContainerDataSourceHandle& primDataSource,
const PXR_NS::TfToken& dependencyToken,
const PXR_NS::SdfPath& dependedOnPrimPath,
const PXR_NS::HdDataSourceLocator& dependedOnDataSourceLocator,
const PXR_NS::HdDataSourceLocator& affectedDataSourceLocator);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,14 @@ HdSceneIndexPrim GeomSubsetWhSi::GetHighlightPrim(const SdfPath &selectionPath,

auto originalPath = fullPrimPath.ReplacePrefix(selectionPath, originalMeshPath.GetParentPath());
HdSceneIndexPrim prim = GetInputSceneIndex()->GetPrim(originalPath);
prim.dataSource = RepathingContainerDataSource::New(originalMeshPath.GetParentPath(), selectionPath, prim.dataSource);
if (prim.primType == HdPrimTypeTokens->mesh) {
prim.dataSource = SetWireframeRepr(prim.dataSource, _wireframeColorInterface->getWireframeColor(selectionKey.first));
if (originalPath == selectionKey.first.GetParentPath()) {
prim.dataSource = TrimMeshForGeomSubset(prim.dataSource, GetInputSceneIndex()->GetPrim(selectionKey.first).dataSource);
if (originalPath == originalMeshPath) {
HdSceneIndexPrim geomSubsetPrim = GetInputSceneIndex()->GetPrim(selectionKey.first);
prim.dataSource = MakeGeomSubsetHighlight(prim.dataSource, geomSubsetPrim.dataSource);
}
}
prim.dataSource = RepathInstancingDataSources(prim.dataSource, originalMeshPath.GetParentPath(), selectionPath);
return prim;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ HdSceneIndexPrim MeshWhSi::GetHighlightPrim(const SdfPath &selectionPath, const

auto originalPath = fullPrimPath.ReplacePrefix(selectionPath, SdfPath::AbsoluteRootPath());
HdSceneIndexPrim prim = GetInputSceneIndex()->GetPrim(originalPath);
prim.dataSource = RepathingContainerDataSource::New(SdfPath::AbsoluteRootPath(), selectionPath, prim.dataSource);
if (prim.primType == HdPrimTypeTokens->mesh) {
prim.dataSource = SetWireframeRepr(prim.dataSource, _wireframeColorInterface->getWireframeColor(selectionKey.first));
}
prim.dataSource = RepathInstancingDataSources(prim.dataSource, SdfPath::AbsoluteRootPath(), selectionPath);
return prim;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@ NiInstanceWhSiRefPtr NiInstanceWhSi::New(
HdSceneIndexPrim NiInstanceWhSi::GetHighlightPrim(const SdfPath &selectionPath, const SdfPath &fullPrimPath) const
{
SelectionKey selectionKey = SelectionKeyFromPath(selectionPath);

auto originalPath = fullPrimPath.ReplacePrefix(selectionPath, _selectionPathsToPrototypePrefixes.at(selectionPath));
HdSceneIndexPrim prim = GetInputSceneIndex()->GetPrim(originalPath);
prim.dataSource = RepathingContainerDataSource::New(_selectionPathsToPrototypePrefixes.at(selectionPath), selectionPath, prim.dataSource);
HdContainerDataSourceEditor dsEditor(prim.dataSource);

dsEditor.Set(HdInstancedBySchema::GetDefaultLocator(), HdBlockDataSource::New());

HdSceneIndexPrim instancePrim = GetInputSceneIndex()->GetPrim(selectionKey.first);
Expand All @@ -67,6 +68,7 @@ HdSceneIndexPrim NiInstanceWhSi::GetHighlightPrim(const SdfPath &selectionPath,
if (prim.primType == HdPrimTypeTokens->mesh) {
prim.dataSource = SetWireframeRepr(prim.dataSource, _wireframeColorInterface->getWireframeColor(selectionKey.first));
}
prim.dataSource = RepathInstancingDataSources(prim.dataSource, _selectionPathsToPrototypePrefixes.at(selectionPath), selectionPath);
return prim;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ HdSceneIndexPrim NiPrototypeWhSi::GetHighlightPrim(const SdfPath &selectionPath,

auto originalPath = fullPrimPath.ReplacePrefix(selectionPath, _selectionPathsToPrototypePrefixes.at(selectionPath));
HdSceneIndexPrim prim = GetInputSceneIndex()->GetPrim(originalPath);

prim.dataSource = RepathingContainerDataSource::New(_selectionPathsToPrototypePrefixes.at(selectionPath), selectionPath, prim.dataSource);
HdContainerDataSourceEditor dsEditor(prim.dataSource);

HdSelectionsSchema activeSelectionsSchema = HdSelectionsSchema::GetFromParent(GetInputSceneIndex()->GetPrim(selectionKey.first).dataSource);
Expand All @@ -88,6 +86,7 @@ HdSceneIndexPrim NiPrototypeWhSi::GetHighlightPrim(const SdfPath &selectionPath,
if (prim.primType == HdPrimTypeTokens->mesh) {
prim.dataSource = SetWireframeRepr(prim.dataSource, _wireframeColorInterface->getWireframeColor(ConvertHydraToFvpSelection(selectionKey.first, activeSelection)));
}
prim.dataSource = RepathInstancingDataSources(prim.dataSource, _selectionPathsToPrototypePrefixes.at(selectionPath), selectionPath);
return prim;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,16 @@ HdSceneIndexPrim PiInstancerWhSi::GetHighlightPrim(const SdfPath &selectionPath,

auto originalPath = fullPrimPath.ReplacePrefix(selectionPath, SdfPath::AbsoluteRootPath());
HdSceneIndexPrim prim = GetInputSceneIndex()->GetPrim(originalPath);
prim.dataSource = RepathingContainerDataSource::New(SdfPath::AbsoluteRootPath(), selectionPath, prim.dataSource);
if (prim.primType == HdPrimTypeTokens->mesh) {
prim.dataSource = SetWireframeRepr(prim.dataSource, primSelection.nestedInstanceIndices.empty() ? _wireframeColorInterface->getWireframeColor(selectionKey.first) : _wireframeColorInterface->getWireframeColor(primSelection));
}
if (_IsPointInstancer(prim) && originalPath == selectionKey.first && selectionKey.second != kFullHighlight) {
else if (_IsPointInstancer(prim) && originalPath == selectionKey.first && selectionKey.second != kFullHighlight) {
// Adjust the instancer mask to only show selected instances
HdSelectionsSchema selectionsSchema = HdSelectionsSchema::GetFromParent(prim.dataSource);
HdSelectionSchema activeSelection = selectionsSchema.GetElement(std::stoul(selectionKey.second));
prim.dataSource = _GetSelectionHighlightInstancerDataSource(prim.dataSource, activeSelection);
}
prim.dataSource = RepathInstancingDataSources(prim.dataSource, SdfPath::AbsoluteRootPath(), selectionPath);
return prim;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ HdSceneIndexPrim PiPrototypeWhSi::GetHighlightPrim(const SdfPath &selectionPath,
prim.dataSource = SetWireframeRepr(prim.dataSource, _wireframeColorInterface->getWireframeColor(selectionKey.first));
#if PXR_VERSION >= 2403
if (originalPrototypePrim.primType == HdPrimTypeTokens->geomSubset && originalPath == selectionKey.first.GetParentPath()) {
prim.dataSource = TrimMeshForGeomSubset(prim.dataSource, originalPrototypePrim.dataSource);
prim.dataSource = MakeGeomSubsetHighlight(prim.dataSource, originalPrototypePrim.dataSource);
}
#endif
}
prim.dataSource = RepathingContainerDataSource::New(SdfPath::AbsoluteRootPath(), selectionPath, prim.dataSource);
prim.dataSource = RepathInstancingDataSources(prim.dataSource, SdfPath::AbsoluteRootPath(), selectionPath);
return prim;
};

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Existing tests did not change, just refactored things to allow the displacement test to use a different scene.

Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,25 @@ class TestGeomSubsetsWireframeHighlight(mtohUtils.MayaHydraBaseTestCase):
# MayaHydraBaseTestCase.setUpClass requirement.
_file = __file__

_stageUfePathSegment = "|GeomSubsetsWireframeHighlightTestScene|GeomSubsetsWireframeHighlightTestSceneShape"
_baseStageFilename = "GeomSubsetsWireframeHighlightTestScene.usda"
_baseStageUfePathSegment = "|GeomSubsetsWireframeHighlightTestScene|GeomSubsetsWireframeHighlightTestSceneShape"

_cubeMeshUfePathSegment = "/Root/CubeMeshXform/CubeMesh"
_sphereMeshUfePathSegment = "/Root/SphereMeshXform/SphereMesh"

_cubeUpperHalfName = "CubeUpperHalf"
_sphereUpperHalfName = "SphereUpperHalf"

_displacementStageFilename = "GeomSubsetWireframeHighlightDisplacementTestScene.usda"
_displacementStageUfePathSegment = "|GeomSubsetWireframeHighlightDisplacementTestScene|GeomSubsetWireframeHighlightDisplacementTestSceneShape"
_displacementGeomSubsetUfePathSegment = "/Torus/GeomSubset"

IMAGE_DIFF_FAIL_THRESHOLD = 0.05
IMAGE_DIFF_FAIL_PERCENT = 1

def loadUsdScene(self):
usdScenePath = testUtils.getTestScene('testGeomSubsetsWireframeHighlight', 'GeomSubsetsWireframeHighlightTestScene.usda')
def loadUsdScene(self, stageFilename):
usdScenePath = testUtils.getTestScene('testGeomSubsetsWireframeHighlight', stageFilename)
usdUtils.createStageFromFile(usdScenePath)

def setUp(self):
super(TestGeomSubsetsWireframeHighlight, self).setUp()
self.loadUsdScene()
cmds.select(clear=True)
cmds.optionVar(
sv=('mayaHydra_GeomSubsetsPickMode', 'Faces'))
Expand All @@ -54,10 +55,12 @@ def test_SimpleGeomSubset(self):
if self._usdVersion < (0, 24, 3):
self.skipTest("Skipping test, USD version used does not support Hydra GeomSubset prims")

self.loadUsdScene(self._baseStageFilename)

sn = ufe.GlobalSelection.get()
sn.clear()

cubeGeomSubsetPath = self._stageUfePathSegment + "," + self._cubeMeshUfePathSegment + "/" + self._cubeUpperHalfName
cubeGeomSubsetPath = self._baseStageUfePathSegment + "," + self._cubeMeshUfePathSegment + "/" + self._cubeUpperHalfName
cubeGeomSubsetItem = ufe.Hierarchy.createItem(ufe.PathString.path(cubeGeomSubsetPath))

sn.clear()
Expand All @@ -68,10 +71,12 @@ def test_InstancedGeomSubset(self):
if self._usdVersion < (0, 24, 3):
self.skipTest("Skipping test, USD version used does not support Hydra GeomSubset prims")

self.loadUsdScene(self._baseStageFilename)

sn = ufe.GlobalSelection.get()
sn.clear()

sphereGeomSubsetPath = self._stageUfePathSegment + "," + self._sphereMeshUfePathSegment + "/" + self._sphereUpperHalfName
sphereGeomSubsetPath = self._baseStageUfePathSegment + "," + self._sphereMeshUfePathSegment + "/" + self._sphereUpperHalfName
sphereGeomSubsetItem = ufe.Hierarchy.createItem(ufe.PathString.path(sphereGeomSubsetPath))

sn.clear()
Expand All @@ -81,14 +86,16 @@ def test_InstancedGeomSubset(self):
def test_WireframeColorChange(self):
if self._usdVersion < (0, 24, 3):
self.skipTest("Skipping test, USD version used does not support Hydra GeomSubset prims")

self.loadUsdScene(self._baseStageFilename)

sn = ufe.GlobalSelection.get()
sn.clear()

cubeGeomSubsetPath = self._stageUfePathSegment + "," + self._cubeMeshUfePathSegment + "/" + self._cubeUpperHalfName
cubeGeomSubsetPath = self._baseStageUfePathSegment + "," + self._cubeMeshUfePathSegment + "/" + self._cubeUpperHalfName
cubeGeomSubsetItem = ufe.Hierarchy.createItem(ufe.PathString.path(cubeGeomSubsetPath))

sphereGeomSubsetPath = self._stageUfePathSegment + "," + self._sphereMeshUfePathSegment + "/" + self._sphereUpperHalfName
sphereGeomSubsetPath = self._baseStageUfePathSegment + "," + self._sphereMeshUfePathSegment + "/" + self._sphereUpperHalfName
sphereGeomSubsetItem = ufe.Hierarchy.createItem(ufe.PathString.path(sphereGeomSubsetPath))

sn.clear()
Expand All @@ -102,13 +109,15 @@ def test_MeshAndGeomSubsetSelection(self):
if self._usdVersion < (0, 24, 3):
self.skipTest("Skipping test, USD version used does not support Hydra GeomSubset prims")

self.loadUsdScene(self._baseStageFilename)

sn = ufe.GlobalSelection.get()
sn.clear()

cubeMeshPath = self._stageUfePathSegment + "," + self._cubeMeshUfePathSegment
cubeMeshPath = self._baseStageUfePathSegment + "," + self._cubeMeshUfePathSegment
cubeMeshItem = ufe.Hierarchy.createItem(ufe.PathString.path(cubeMeshPath))

cubeGeomSubsetPath = self._stageUfePathSegment + "," + self._cubeMeshUfePathSegment + "/" + self._cubeUpperHalfName
cubeGeomSubsetPath = self._baseStageUfePathSegment + "," + self._cubeMeshUfePathSegment + "/" + self._cubeUpperHalfName
cubeGeomSubsetItem = ufe.Hierarchy.createItem(ufe.PathString.path(cubeGeomSubsetPath))

sn.clear()
Expand All @@ -121,6 +130,21 @@ def test_MeshAndGeomSubsetSelection(self):
#sn.append(cubeMeshItem)
#sn.append(cubeGeomSubsetItem)
#self.assertSnapshotClose("meshThenGeomSubsetSelection.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT)

def test_Displacement(self):
if self._usdVersion < (0, 24, 3):
self.skipTest("Skipping test, USD version used does not support Hydra GeomSubset prims")

self.loadUsdScene(self._displacementStageFilename)
self.setBasicCam(8)

sn = ufe.GlobalSelection.get()
sn.clear()

geomSubsetPath = self._displacementStageUfePathSegment + "," + self._displacementGeomSubsetUfePathSegment
geomSubsetItem = ufe.Hierarchy.createItem(ufe.PathString.path(geomSubsetPath))
sn.append(geomSubsetItem)
self.assertSnapshotClose("displacement.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT)

if __name__ == '__main__':
fixturesUtils.runTests(globals())
Loading