File size: 3,733 Bytes
c69c125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
from dataclasses import dataclass
from typing import Literal

import torch
from einops import rearrange, repeat
from jaxtyping import Float, Int
from torch import Tensor

from ...scene_trainer.gaussian_module import GaussiansModule
from ..types import Gaussians
from .cuda_splatting_fastgs import (
    render_cuda_fastgs,
    render_depth_cuda_fastgs,
    render_metric_counts_fastgs,
)
from .splatting_cuda_decoder import SplattingCUDADecoder


@dataclass
class FastGSDecoderSplattingCUDACfg:
    name: Literal["fastgs"]
    scale_invariant: bool
    # False: pass scales+rotations and let the CUDA kernel compute the covariance.
    # True: precompute Python-side and pass cov3D_precomp.
    use_covariances: bool = False
    # FastGS compact-box multiplier (controls the tile count per splat); matches the
    # FastGS training default.
    mult: float = 0.5


class FastGSDecoderSplattingCUDA(SplattingCUDADecoder[FastGSDecoderSplattingCUDACfg]):
    """FastGS diff_gaussian_rasterization_fastgs backend. Only the rasterizer calls differ from
    the shared base; see splatting_cuda_decoder.SplattingCUDADecoder for the orchestration."""

    def _produces_abs_grad(self) -> bool:
        # FastGS's [N,4] screen tensor carries the Abs-GS split signal in cols [2:]; expose it.
        return True

    def _raster(self, ext, intr, near, far, image_shape, bg, means, covars, shs, opacities,
                scales, rotations_wxyz, means2d_out, means2d_abs_out=None):
        return render_cuda_fastgs(
            ext, intr, near, far, image_shape, bg, means, covars, shs, opacities,
            scale_invariant=self.cfg.scale_invariant,
            gaussian_scales=scales,
            gaussian_rotations=rotations_wxyz,
            mult=self.cfg.mult,
            means2d_out=means2d_out,
            means2d_abs_out=means2d_abs_out,
        )

    def _raster_depth(self, ext, intr, near, far, image_shape, means, covars, opacities, mode):
        return render_depth_cuda_fastgs(
            ext, intr, near, far, image_shape, means, covars, opacities,
            mode=mode, scale_invariant=self.cfg.scale_invariant, mult=self.cfg.mult,
        )

    @torch.no_grad()
    def render_metric_counts(
        self,
        gaussians: Gaussians | GaussiansModule,
        extrinsics: Float[Tensor, "batch view 4 4"],
        intrinsics: Float[Tensor, "batch view 3 3"],
        near: Float[Tensor, "batch view"],
        far: Float[Tensor, "batch view"],
        image_shape: tuple[int, int],
        metric_maps: Int[Tensor, "view height_width"],  # per-view binary high-error pixel maps
    ) -> Int[Tensor, "view gaussian"]:
        """FastGS multi-view importance signal: per-view per-Gaussian counts of flagged (high-error)
        pixels each Gaussian contributed to. Assumes batch size 1; ``metric_maps`` has one flattened
        [H*W] map per view. Reduce with ``adc.fastgs.compute_fastgs_scores``."""
        b, v, _, _ = extrinsics.shape
        assert b == 1, "render_metric_counts assumes scene batch size 1"
        means, shs, opacities, scales, rotations_wxyz, covars = self._prepare_flat_gaussians(gaussians, b, v)
        bg = repeat(self.background_color, "c -> (b v) c", b=b, v=v)
        return render_metric_counts_fastgs(
            rearrange(extrinsics, "b v i j -> (b v) i j"),
            rearrange(intrinsics, "b v i j -> (b v) i j"),
            rearrange(near, "b v -> (b v)"),
            rearrange(far, "b v -> (b v)"),
            image_shape, bg, means,
            covars,
            shs, opacities, metric_maps,
            scale_invariant=self.cfg.scale_invariant,
            gaussian_scales=scales,
            gaussian_rotations=rotations_wxyz,
            mult=self.cfg.mult,
        )