Skip to content

Feat: HdV2 render Gaussian splats as points - #4786

Open
adsk-gagnonf wants to merge 8 commits into
devfrom
gagnonf/splat-display-points
Open

adsk-gagnonf wants to merge 8 commits into
devfrom
gagnonf/splat-display-points

Conversation

@adsk-gagnonf

Copy link
Copy Markdown
Collaborator

Add HdVP2GaussianSplat to handle the particleField rprim (USD 26.05+). Splats are drawn as small 5x5 quads for now. Most of the gaussianSplat.cpp logic is copied from or based on points.cpp.

Add HdVP2GaussianSplat to handle the particleField rprim (USD 26.05+). Splats are drawn as small 5x5 quads for now. Most of the gaussianSplat.cpp logic is copied from or based on points.cpp.
Comment on lines +40 to +42
PXR_NAMESPACE_OPEN_SCOPE

namespace {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is there a reason for placing this code in the pixar namespace instead of using just:
namespace MAYAUSD_NS_DEF

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I followed the principles used in points.cpp as a source of inspiration. for vt* types should I do "using PXR_NS" while inside MAYAUSD_NS_DEF or place PXR_NS:: in front of every types

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The problem is we have many old files in the repo which were inherited from Pixar (thus their namespace). New files should use the MayaUsd namespace and use PXR_NS:: in front of Usd types.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I used PXR_NS:: in the header and using namespace PXR_NS; in the .cpp, is that OK?

@seando-adsk seando-adsk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please try to remove the pixar namespace and put this stuff into MayaUsd namespace. This will require using PXR_NS:: on all the USD classes/functions.

Comment thread lib/mayaUsd/render/vp2RenderDelegate/gaussianSplat.cpp Outdated
result = value.UncheckedGet<VtFloatArray>();
return true;
}
if (value.IsHolding<VtHalfArray>()) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

similar comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

replaced implementation with the Vt...Cast approach

Comment thread lib/mayaUsd/render/vp2RenderDelegate/gaussianSplat.cpp Outdated

/*! \brief Fill the color buffer from the first spherical harmonics coefficient of each splat.

Splats are drawn opaque, so alpha is always 1.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why did we deal with opacities above if splats are draw opaque always?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The idea is that this implementation will be built upon aiming towards full salts display, implementation of alpha blended points is planned, we want to have most of the splat logic exist in the class and ready to be expended when depth sorting is figured out

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

OK, but from other code i saw its actually used yeah? to filter out indices?

Otherwise, if it is not currently used, i would remove from the PR. maybe with a comment explaining high level how to load opacities. At Autodesk nothing is more permanent than something temporary...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, we do filter out small alpha points, but in practice it's mostly redondant as low opacity splats are already mostly culled in the offline training phase.

I'll remove it for now. I am convinced it will be added back very soon, but it is low impact so It's fine

"color.",
id.GetText(),
shCoeffs.size(),
numSplats);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

using default where?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

"using default color", formatter split on two lines, default color is at line 203: const GfVec3f defaultColor = param->GetDrawScene().GetDefaultColor(HdPrimTypeTokens->points);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe bring it closer then, there are early returns between here and usage a defualt color, which would render the message misleading

unsigned int offset = 0;
for (size_t i = 0; i < numSplats; ++i) {
const GfVec3f color
= hasSH ? GfVec3f(0.5f) + kSH_C0 * shCoeffs[i * shStride] : defaultColor;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can you comment on the 0.5 here / math

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

it's the 3dgs spherical harmonics sRGB mapping to RGB for band 0 (constant color) of the SH . I'll had a comment in the code

const GfVec3f color
= hasSH ? GfVec3f(0.5f) + kSH_C0 * shCoeffs[i * shStride] : defaultColor;
bufferData[offset++] = GfClamp(color[0], 0.0f, 1.0f);
bufferData[offset++] = GfClamp(color[1], 0.0f, 1.0f);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What does it mean for colors to be out of range here and clamped?

@adsk-gagnonf adsk-gagnonf Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

the SHs can learn values that causes the resulting color to be negative we clamp to 0 in that case, it's a regular operation in 3dgs spherical harmonics handling, I'll add a comment in the code

| HdChangeTracker::DirtyDisplayStyle | HdChangeTracker::DirtyRepr
| HdChangeTracker::DirtyMaterialId | HdChangeTracker::DirtyTransform
| HdChangeTracker::DirtyVisibility | HdChangeTracker::DirtyRenderTag
| DirtySelectionHighlight;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Instancing of splat works? And what happens with display styles and selection highlight?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Instancing of splats is not handled yet. Only the prototype is drawn, without the per-instance transforms, so I removed the instancer dirty bit for now. Supporting it can be a separate story, after the full splat rendering.

Display styles and selection highlight behave like MayaUSD points. Splats are drawn in the shaded modes only, they are not displayed in wireframe or bounding box mode, and a selected splat is drawn in the highlight color. A bounding box display style could be added in a future story.

Comment thread lib/mayaUsd/render/vp2RenderDelegate/gaussianSplat.cpp
Comment thread lib/mayaUsd/render/vp2RenderDelegate/gaussianSplat.cpp
Comment thread lib/mayaUsd/render/vp2RenderDelegate/gaussianSplat.cpp
TRACE_FUNCTION();

const unsigned int numVisibleSplats = _splatSharedData._numVisibleSplats;
if (numVisibleSplats == 0 || !drawItemData._indexBuffer) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What is the !indexBuffer case?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Over-cautious, since the index buffer is always created with the render item. I removed the check.

unsigned int numIndices = 0;
for (size_t i = 0; i < opacities.size(); ++i) {
if (opacities[i] >= kMinVisibleOpacity) {
indexData[numIndices++] = static_cast<int>(i);

@deboisj deboisj Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I see so inivisible splats are just removed completely, i think its worth commenting on this around where i asked above

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

added comment

Comment thread lib/mayaUsd/render/vp2RenderDelegate/gaussianSplat.cpp
if (_selectionStatus != kUnselected || inTemplateMode) {
const MColor color = _GetHighlightColor(HdPrimTypeTokens->points);
shader = _delegate->Get3dFatPointShader(color);
isTransparent = (color.a < 0.999f);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(minor) maybe define an epsilon or use one that exist already

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

fixed by defining a constant

// Determine if the render item should be enabled or not.
if (itemDirtyBits
& (HdChangeTracker::DirtyVisibility | HdChangeTracker::DirtyRenderTag
| HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyPrimvar

@deboisj deboisj Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why are dirty points/selection/extent relevent?
Oh i guess you dont know if point counts changed with just that bit...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

But yeah there's also DirtyTopology

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The splat count comes from the positions primvar, so DirtyPrimvar covers it. A particle field has no topology, so I removed DirtyTopology.

deboisj
deboisj previously approved these changes Oct 20, 2026

@deboisj deboisj left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

thanks for the changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants