File size: 2,524 Bytes
31c7d49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
export type ModelKind = 'sharp' | 'triposplat'

export type GenerationStage =
  | 'loading-model'
  | 'preprocessing'
  | 'inference'
  | 'encoding-dinov3'
  | 'encoding-vae'
  | 'sampling'
  | 'decoding-octree'
  | 'decoding-gaussians'
  | 'filtering'
  | 'building-ply'

export interface GenerationProgress {
  stage: GenerationStage
  message: string
  /** Normalized progress for the current stage, when it can be measured. */
  progress?: number
  /** One-based iterative step, used by TripoSplat's flow sampler. */
  step?: number
  totalSteps?: number
}

export interface GenerationOptions {
  signal?: AbortSignal
  onProgress?: (progress: GenerationProgress) => void

  /** SHARP camera input. The UI supplies EXIF-derived pixels when available. */
  focalPx?: number
  /** SHARP output filtering. */
  opacityThreshold?: number
  maxGaussians?: number

  /** TripoSplat flow-matching controls. */
  steps?: 4 | 20 | number
  seed?: number
  guidanceScale?: number
  shift?: number
  numGaussians?: number
  erodeRadius?: number
  /** Skip BiRefNet/crop only for an official 1024x1024 RGB-on-black prepared image. */
  inputIsPrepared?: boolean
  /** Optional recorded tensors for cross-runtime parity; otherwise browser noise is seeded. */
  vaeNoise?: Float32Array
  latentNoise?: Float32Array
  cameraNoise?: Float32Array
}

export interface GaussianAttributes {
  /** Object-space center, xyz-interleaved. */
  positions: Float32Array
  /** Positive linear scale, xyz-interleaved. */
  scales: Float32Array
  /** Unit or pre-normalized quaternion in wxyz order. */
  rotations: Float32Array
  /** Degree-zero spherical-harmonic coefficients, rgb-interleaved. */
  sh0: Float32Array
  /** Activated opacity in [0, 1]. */
  opacities: Float32Array
}

export interface GaussianScene {
  model: ModelKind
  count: number
  totalCount: number
  /** Canonical 3DGS binary PLY, ready for the existing viewers/export path. */
  ply: Uint8Array
  gaussians?: GaussianAttributes
  coordinateSystem: 'opencv-camera' | 'triposplat-object'
  colorSpace: 'linear-rgb' | 'sh0'
  metadata?: Readonly<Record<string, string | number | boolean>>
}

export interface ImageToGaussianModel {
  load(): Promise<void>
  generate(image: ImageBitmap, options?: GenerationOptions): Promise<GaussianScene>
  dispose(): Promise<void>
}

export function throwIfAborted(signal?: AbortSignal): void {
  if (signal?.aborted) {
    throw signal.reason instanceof Error ? signal.reason : new DOMException('Operation aborted', 'AbortError')
  }
}