splatParams.ts

src/render/splatParams.ts · raw · all examples · site home

Exports: SplatViewParamsSplatObjectParamsSplatParamNodesSplatParams

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
import { GpuSh } from "../gpu/sh.tsl";
import { TSL } from "../gpu/tsl";

const { uniform } = TSL;

// What every splat drawn together shares (a SplatRenderer's params, a
// view's over them): the draw reads these too
export interface SplatViewParams {
  // Gaussian extent drawn, in standard deviations
  maxStdDev: number;
  // Fragments and splats below this alpha are dropped
  minAlpha: number;
  // 1: Gaussian falloff; 0: flat discs
  falloff: number;
}

// What each object is projected with (a SplatRenderer's objectParams, a
// view's over them, a splat object's over both)
export interface SplatObjectParams {
  // LoD opacities above 1 grow the splat instead of its opacity
  lodInflate: boolean;
  // Anti-aliasing blur in pixel area units, with opacity compensation
  blurAmount: number;
  preBlurAmount: number;
  // Centers farther than this outside the frustum (in NDC) are culled
  clipXY: number;
  minPixelRadius: number;
  maxPixelRadius: number;
  // ewa: splats whose drawn weight (opacity x 2D Gaussian area in pixels,
  // 2 pi sqrt(det)) is below this are culled; 0 keeps them all
  minContribution: number;
  // Depth of field: distance to the focal plane and tan of half the aperture angle
  focalDistance: number;
  apertureTan: number;
  // For the CPU sort: splats outside the head's view widened by this much
  // (NDC beyond the edges, plus their reach) get the invalid key, so the
  // sort orders and the draw draws fewer; 0 keeps them all. Its order lags
  // the camera, so re-sort when the view turns, not only moves
  sortGuard: number;
  // Highest spherical-harmonics band drawn (0 to 4): caps an object's SH
  // below its generator's degree without compiling anything
  maxShDegree: number;
}

// The params as the uniforms the projection and the draw read: one set,
// shared by every program, set before each dispatch and draw (three gives
// each program and draw its own copy of the values)
const nodes = {
  minAlpha: uniform(0.5 / 255),
  maxStdDev: uniform(Math.sqrt(8)),
  falloff: uniform(1),
  lodInflate: uniform(true),
  blurAmount: uniform(0.3),
  preBlurAmount: uniform(0),
  clipXY: uniform(1.4),
  minPixelRadius: uniform(0),
  maxPixelRadius: uniform(512),
  minContribution: uniform(0),
  focalDistance: uniform(0),
  apertureTan: uniform(0),
  sortGuard: uniform(0),
  maxShDegree: GpuSh.maxDegree,
};

export type SplatParamNodes = typeof nodes;

export class SplatParams {
  static readonly VIEW: Readonly<SplatViewParams> = { maxStdDev: Math.sqrt(8), minAlpha: 0.5 / 255, falloff: 1 };
  static readonly OBJECT: Readonly<SplatObjectParams> = {
    lodInflate: true, blurAmount: 0.3, preBlurAmount: 0, clipXY: 1.4, minPixelRadius: 0, maxPixelRadius: 512, minContribution: 0, focalDistance: 0, apertureTan: 0, sortGuard: 0,
    maxShDegree: 4,
  };

  static readonly nodes = nodes;

  static setView(params: SplatViewParams) {
    nodes.maxStdDev.value = params.maxStdDev;
    nodes.minAlpha.value = params.minAlpha;
    nodes.falloff.value = params.falloff;
  }

  // `params`, with `overrides` on top
  static setObject(params: SplatObjectParams, overrides?: Partial<SplatObjectParams>) {
    for (const key of Object.keys(SplatParams.OBJECT) as (keyof SplatObjectParams)[]) {
      (nodes[key] as { value: unknown }).value = overrides?.[key] ?? params[key];
    }
  }
}