Skip to content

Added median depth rasterization for 3dgs [fwd only]#930

Open
sangeethagramas wants to merge 1 commit intonerfstudio-project:mainfrom
sangeethagramas:3dgs_median_depth
Open

Added median depth rasterization for 3dgs [fwd only]#930
sangeethagramas wants to merge 1 commit intonerfstudio-project:mainfrom
sangeethagramas:3dgs_median_depth

Conversation

@sangeethagramas
Copy link
Copy Markdown

Change : Add median depth rasterization for 3dgs for the forward pass only

Description : This commit currently supports median depth calculation for 3D gaussians only on the forward pass. We currently do not anticipate the need for median depth support in the backward pass. We can add it in the future if the need arises.
The changes in this PR follows the style similar to 2D gaussian median depth rasterization.

Test cases :

  1. Group 1: sanity check tests for output shape checks on sample scene
  2. Group 2: check workflow for depth_mode=="median"
  3. Group 3: sanity check for API validation (rejects undefined/ill-specified inputs)
  4. Group 4: median depth kernel tests for dummy scenes

@sangeethagramas sangeethagramas marked this pull request as draft April 22, 2026 22:20
@sangeethagramas sangeethagramas marked this pull request as ready for review April 22, 2026 22:20
Comment on lines +114 to +115
render_median, \
median_ids \
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 think we should make them optional tensors -- to make sure we dont introduce any perf regression when median depth is not needed.

Comment on lines +63 to +68
scalar_t
*__restrict__ render_median, // [I, image_height, image_width, 1]
// depth of the Gaussian that causes
// transmittance to cross 0.5, or the
// last-hit depth as a fallback.
int32_t *__restrict__ median_ids // [I, image_height, image_width]
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.

related to optional: we want to allow them to be null ptr when not needed. and in the function we skip compute median depth and write out so we dont waste compute if they are not needed


// Track last hit depth (depth is stored as the last channel of
// colors, consistent with the existing D/ED plumbing and 2DGS).
const float dep = c_ptr[CDIM - 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.

This silently assume render mode is in ED or D. Should assert this to protect in the rendering.py

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.

Also for the best performance, I think you can push this link and next into the if (!median_found && T > 0.5f && next_T <= 0.5f) { condition?

Comment on lines +240 to +246
// Median depth: if transmittance never crossed 0.5 fall back to the
// last contributing Gaussian's depth (0.0 if there were no hits).
if (!median_found) {
median_depth = last_hit_depth;
}
render_median[pix_id] = median_depth;
median_ids[pix_id] = static_cast<int32_t>(median_idx);
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.

Skip write if median is not required (render_median is a null ptr)

at::Tensor renders, // [..., image_height, image_width, channels]
at::Tensor alphas, // [..., image_height, image_width]
at::Tensor last_ids, // [..., image_height, image_width]
at::Tensor render_median, // [..., image_height, image_width, 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.

to be consistent on the naming convension in gsplat, suggested naming is median_depths

Comment on lines -289 to +328
last_ids.data_ptr<int32_t>()
last_ids.data_ptr<int32_t>(),
render_median.data_ptr<float>(),
median_ids.data_ptr<int32_t>()
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.

update for optional

Comment thread gsplat/cuda/_wrapper.py
packed: If True, the input tensors are expected to be packed with shape [nnz, ...]. Default: False.
absgrad: If True, the backward pass will compute a `.absgrad` attribute for `means2d`. Default: False.
return_median: If True, additionally returns per-pixel median depth, defined
as the value of the last channel of ``colors`` for the Gaussian whose
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 value of the last channel of colors " is weird to read. Maybe just say something like "expect the last channel to be depth"

Comment thread gsplat/cuda/_wrapper.py
), f"Assert Failed: {tile_width} * {tile_size} >= {image_width}"

render_colors, render_alphas = _RasterizeToPixels.apply(
render_colors, render_alphas, render_median, _median_ids = _RasterizeToPixels.apply(
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.

if we are not returning median ids we might just remove it entirely?

Comment thread gsplat/rendering.py
extra_signals_sh_degree: Optional[
int
] = None, # Currently only None or 3 is accepted.
depth_mode: Literal["expected", "median"] = "expected",
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.

"depth_mode" is a bit weird here because we already say render mode has ED or D. this "depth mode" between expected and median could be very confusing on the relationship between the ED and D in render mode.

My suggested interface change:

use argument return_median_depth: bool = False here. Then additionally return median depth (and id if you need it) if this is True. If not only return the original returns, and do not waste any compute in the kernel for median depth. This way we are backward compatible and cause minimal confusion.

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.

2 participants