3D feature grids
Lightplane Renderer or Splatter represent 3D scenes as a grid-list grid
of M
feature grids g_i
:
grid: List[torch.Tensor] = [g_1, ..., g_M]
Each g_i
is a 5D tensor of shape (B, D, H, W, C)
, with batch size B
, number of feature channels C
(equal for all grids), and the grid depth, height, and width D
, H
, and W
respectively.
Representing Voxel grid: If all g_i
’s dimensions are non-singular (H>1 or D>1 or W>1
), g_i
represents a batch of voxel grids with C
-dimensional features.
Representing 2D plane: In case one of the g_i
’s dimensions is singular (H == 1 or D==1 or W==1
), g_i
is treated as a planar 2D grid whose cells represent all points along a 3D line passing through the cell’s center orthogonal to the plane (akin to a triplane).
The grid-list is a mandatory argument for both LightplaneRenderer
and LigthplaneMLPSplatter
, and is output by LigthplaneSplatter
and LigthplaneMLPSplatter
.
Note
Below are examples of representing the latest grid-based representations:
Triplane:
grid = [
torch.randn(B, 1, H, W, C), # xy plane
torch.randn(B, D, 1, W, C), # xz plane
torch.randn(B, D, H, 1, C), # yz plane
]
Voxel grid:
grid = [torch.randn(B, D, H, W, C)]
Voxel grid and triplane:
grid = [
torch.randn(B, D_voxels, H_voxels, W_voxels, C), # voxel grid
torch.randn(B, 1, H, W, C), # xy plane
torch.randn(B, D, 1, W, C), # xz plane
torch.randn(B, D, H, 1, C), # yz plane
]
Note
All grids in a grid-list have to share the same number of channels C
and batch size B
, however, the spatial dimensions D
, H
, W
of each grid can be arbitrarily different across grids.
Grid coordinate frame
We follow the PyTorch grid_sample coordinate convention.
Each grid g
represents a 3D cube of side [-1, 1]
centered at [0, 0, 0]
. All rendering rays thus have to be correctly emitted to render points inside the latter cube.
A continuous 3D point pt_3d=[x,y,z]
with coordinates [-1.0, -1.0, -1.0]
indexes the outer corner of g
’s voxel at integer cell [0, 0, 0]
in the 3D grid, while a 3D point [1.0, 1.0, 1.0]
corresponds to the opposite cell at [D-1, H-1, W-1]
.
A 3D point pt_3d=[x,y,z]
indexes the g
tensor in reverse order of p
’s dimensions, i.e.:
x=pt_3d[0]
indexes the width (i.e. 3rdW
-dimension) ofg
y=pt_3d[1]
indexes the height (i.e. 2ndH
-dimension) ofg
z=pt_3d[2]
indexes the depth (i.e. 1stD
-dimension) ofg
For example, in a 3D grid g
of size [2, 4, 8]
, a continuous 3D point pt_3d=[-0.25, 0.25, 0.0]
corresponds to g
’s element at integer coordinates [0, 1, 3]
.
Feature grid sampling
Lightplane Renderer and Splatter rely on a function sample_grid(pt_3d, grid)
that sums the C
-dimensional vectors sample(pt_3d, g)
sampled at a continuous 3D location pt_3d=[x,y,z]
from each grid g
of the grid-list grid
:
sample_grid(pt_3d, grid) = sum(sample(pt_3d, g) for g in grid)
Here, sample
interpolates the grid g
using a linearly-weighted scheme depending on the number of g
’s non-singular dimensions:
3 non-singular dimensions: If all spatial dimensions of the grid
g
are non-singular (i.e.D>1 and H>1 and W>1
), the feature is trilinearly interpolated from the grid at locationpt_3d
.# define a random voxel grid B, D, H, W, C = 4, 3, 7, 5, 6 g = torch.randn(B, D, H, W, C) # sample with trilinear interpolation sampled_feature = trilinear_interpolation(g, pt_3d)
2 non-singular dimensions: If one of the spatial dimensions of the grid is singular (i.e.
D==1 or H==1 or W==1
), the feature is bilinearly interpolated from the 2D gridg_2d
(obtained by squeezing the singular dimension ofg
) at the 2D coordinatept_2d
comprising the 2 coordinates of the 3D pointpt_3d
corresponding to non-singular dimensions. The following example demonstrates Lightplane’s bilinear interpolation of a(B, D, 1, W, C)
grid.# define a random grid with a singular height B, D, H, W, C = 4, 3, 1, 5, 6 g = torch.randn(B, D, H, W, C) # squeeze the singular height-dimension to obtain the corresponding 2d grid g_2d = g.squeeze(2) # the height-dimension is singular so we only sample the x- and z-coordinates # using bilinear interpolation x, y, z = pt_3d sampled_feature = bilinear_interpolation(g, [x, z])
Feature grid splatting
Lightplane Splatter pushes 3d-point-specific C
-dimensional vectors f(pt_3d)
to each grid g
of the grid-list grid
by means of splatting:
grid_splatted = [splat_to_grid(f(pt_3d), g_i) for g_i in grid]
Similar to the renderer, splatting is either bilinear or trilinear depending on the number of singular dimensions of g_i
.
3 non-singular dimensions: If all spatial dimensions of the grid
g
are non-singular (i.e.D>1 and H>1 and W>1
), the feature is trilinearly splatted to the grid at locationpt_3d
.# define a random voxel grid B, D, H, W, C = 4, 3, 7, 5, 6 g = torch.randn(B, D, H, W, C) # splat feature f(pt_3d) to the grid g to create a new grid g_splatted = trilinear_splatting(g, pt_3d, f(pt_3d))
2 non-singular dimensions: If one of the spatial dimensions of the grid is singular (i.e.
D==1 or H==1 or W==1
), the feature is bilinearly splatted to the 2D gridg_2d
(obtained by squeezing the singular dimension ofg
) at the 2D coordinatept_2d
comprising the 2 coordinates of the 3D pointpt_3d
corresponding to non-singular dimensions. The following example demonstrates Lightplane’s bilinear splatting of a(B, D, 1, W, C)
grid.# define a random grid with a singular height B, D, H, W, C = 4, 3, 1, 5, 6 g = torch.randn(B, D, H, W, C) # squeeze the singular height-dimension to obtain the corresponding 2d grid g_2d = g.squeeze(2) # the height-dimension is singular so we only sample the x- and z-coordinates # using bilinear interpolation x, y, z = pt_3d g_splatted = bilinear_splatting(g, [x, z], f(pt_3d))