@equinor/videx-3d 1.1.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +120 -120
  2. package/dist/chunk-DKAquGKk.js +2820 -0
  3. package/dist/chunk-DsUZyEG_.js +16 -0
  4. package/dist/generators.js +512 -716
  5. package/dist/main.js +6909 -8947
  6. package/dist/sdk.js +2 -785
  7. package/dist/src/sdk/materials/shaderLib/oit.glsl +106 -0
  8. package/dist/types/components/Annotations/AutoUpdate.d.ts +1 -1
  9. package/dist/types/components/Annotations/index.d.ts +2 -2
  10. package/dist/types/components/Annotations/types.d.ts +3 -1
  11. package/dist/types/components/Annotations/update-annotations.d.ts +10 -0
  12. package/dist/types/components/EventEmitter/picking-helper.d.ts +23 -1
  13. package/dist/types/components/Ocean/Ocean.d.ts +333 -0
  14. package/dist/types/components/Ocean/index.d.ts +6 -0
  15. package/dist/types/components/Ocean/ocean-bed-material.d.ts +60 -0
  16. package/dist/types/components/Ocean/ocean-contact.d.ts +39 -0
  17. package/dist/types/components/Ocean/ocean-material.d.ts +145 -0
  18. package/dist/types/components/Ocean/ocean-sampler.d.ts +93 -0
  19. package/dist/types/components/Ocean/ocean-volume-material.d.ts +54 -0
  20. package/dist/types/components/Surfaces/Surface.d.ts +8 -1
  21. package/dist/types/components/Surfaces/SurfaceMaterial.d.ts +3 -0
  22. package/dist/types/components/Surfaces/surface-defs.d.ts +1 -0
  23. package/dist/types/components/Tanker/Tanker.d.ts +47 -0
  24. package/dist/types/components/Tanker/TankerSuperstructure.d.ts +23 -0
  25. package/dist/types/components/Tanker/tanker-geometry-builder.d.ts +21 -0
  26. package/dist/types/generators/surface-generator.d.ts +1 -1
  27. package/dist/types/layers/layers.d.ts +4 -0
  28. package/dist/types/main.d.ts +1 -0
  29. package/dist/types/rendering/OitMaterial.d.ts +59 -0
  30. package/dist/types/rendering/Pass.d.ts +16 -0
  31. package/dist/types/rendering/RenderingPipeline.d.ts +46 -0
  32. package/dist/types/rendering/debug/DebugBoxOutputPass.d.ts +22 -0
  33. package/dist/types/rendering/debug/DebugPatternPass.d.ts +30 -0
  34. package/dist/types/rendering/fullscreen-renderer.d.ts +1 -0
  35. package/dist/types/rendering/fxaa-resolver.d.ts +25 -0
  36. package/dist/types/rendering/gpu-timer.d.ts +46 -0
  37. package/dist/types/rendering/index.d.ts +8 -1
  38. package/dist/types/rendering/oit-material.d.ts +122 -0
  39. package/dist/types/{components/Annotations/annotations-renderer.d.ts → rendering/passes/AnnotationsPass.d.ts} +14 -4
  40. package/dist/types/rendering/passes/FXAAPass.d.ts +17 -0
  41. package/dist/types/rendering/passes/OITRenderPass.d.ts +429 -0
  42. package/dist/types/rendering/passes/OutputPass.d.ts +19 -0
  43. package/dist/types/rendering/passes/RenderPass.d.ts +10 -0
  44. package/dist/types/rendering/passes/index.d.ts +4 -0
  45. package/dist/types/rendering/rendering-state.d.ts +59 -0
  46. package/dist/types/rendering/smaa-resolver.d.ts +58 -0
  47. package/dist/types/rendering/taa-resolver.d.ts +161 -0
  48. package/dist/types/rendering/temporal-resolver.d.ts +152 -0
  49. package/dist/types/sdk/geometries/boundary-loops.d.ts +38 -0
  50. package/dist/types/sdk/geometries/geometry-attributes.d.ts +37 -0
  51. package/dist/types/sdk/geometries/grid-sampling.d.ts +50 -0
  52. package/dist/types/sdk/geometries/ocean-geometry.d.ts +288 -0
  53. package/dist/types/sdk/geometries/packing.d.ts +1 -1
  54. package/dist/types/sdk/geometries/tessellation.d.ts +25 -0
  55. package/dist/types/sdk/index.d.ts +5 -0
  56. package/dist/types/sdk/utils/elevation-map.d.ts +23 -0
  57. package/dist/types/sdk/utils/trigonometry.d.ts +4 -1
  58. package/dist/types/sdk/utils/vector-operations.d.ts +7 -0
  59. package/package.json +9 -10
  60. package/dist/chunk-BlPg4RjP.js +0 -689
  61. package/dist/chunk-CnY6Tmof.js +0 -358
  62. package/dist/chunk-DuRASjkF.js +0 -17
  63. package/dist/chunk-iY0wQ9Z6.js +0 -887
  64. package/dist/types/rendering/render-passes.d.ts +0 -16
  65. /package/dist/{shaderLib → src/sdk/materials/shaderLib}/color-conversion.glsl +0 -0
  66. /package/dist/{shaderLib → src/sdk/materials/shaderLib}/colors.glsl +0 -0
  67. /package/dist/{shaderLib → src/sdk/materials/shaderLib}/glyphs.glsl +0 -0
  68. /package/dist/{shaderLib → src/sdk/materials/shaderLib}/random.glsl +0 -0
  69. /package/dist/{shaderLib → src/sdk/materials/shaderLib}/remap.glsl +0 -0
  70. /package/dist/{shaderLib → src/sdk/materials/shaderLib}/render-number.glsl +0 -0
  71. /package/dist/{shaderLib → src/sdk/materials/shaderLib}/render-text.glsl +0 -0
  72. /package/dist/{shaderLib → src/sdk/materials/shaderLib}/rotation.glsl +0 -0
  73. /package/dist/{shaderLib → src/sdk/materials/shaderLib}/sdf-functions.glsl +0 -0
  74. /package/dist/textures/{normal_map.jpg → public/normal_map.jpg} +0 -0
@@ -0,0 +1,429 @@
1
+ import { Camera, Scene, WebGLRenderer, WebGLRenderTarget } from 'three';
2
+ import { Pass } from '../Pass';
3
+ import { SMAAQuality } from '../smaa-resolver';
4
+ import { TaaResolver } from '../taa-resolver';
5
+ import { TemporalResolver } from '../temporal-resolver';
6
+ /** Per-frame object counts for each classification, exposed for debugging. */
7
+ export type OITRenderPassStats = {
8
+ /** Plain opaque renderables (not OIT-capable, not overlay). */
9
+ opaque: number;
10
+ /** OIT-capable renderables currently transparent (routed through OIT). */
11
+ oit: number;
12
+ /**
13
+ * OIT-capable renderables that are currently fully opaque and therefore drawn in
14
+ * the opaque pass as real occluders (depth-writing), bypassing the OIT passes.
15
+ */
16
+ oitOpaque: number;
17
+ /** Additive/glow renderables (tagged `LAYERS.EMISSIVE`), drawn before the transparent layers. */
18
+ emissive: number;
19
+ /** Always-on-top renderables (tagged `LAYERS.OVERLAY`), drawn after the transparent layers. */
20
+ overlay: number;
21
+ /** Subset of `oit` whose whole material is OIT-capable (hidden in opaque pass). */
22
+ oitHidden: number;
23
+ /** Subset of `oit` that are mixed multi-material meshes (some opaque groups). */
24
+ oitMixed: number;
25
+ };
26
+ /**
27
+ * Resource/accumulation counters for leak monitoring. Unlike {@link OITRenderPassStats}
28
+ * (per-frame object classification, which naturally varies with the camera), these
29
+ * track internal structures and global GPU resources that should stay *bounded* over
30
+ * time. Watch them while toggling the pipeline on/off (which recreates the passes): a
31
+ * steady climb indicates passes or GPU resources are not being disposed.
32
+ */
33
+ export type OITRenderPassResources = {
34
+ /**
35
+ * Active OIT pipeline registrations on this canvas (the ref-counted
36
+ * {@link RenderingState} `_oitCount`). Should read 1 while a single OIT pipeline is
37
+ * mounted; a value that climbs each time the pipeline is recreated means a pass was
38
+ * acquired but never released in {@link OITRenderPass.dispose} (a real leak).
39
+ */
40
+ oitPipelines: number;
41
+ /**
42
+ * Total classification entries created since this pass instance was constructed
43
+ * (monotonic). Resets only when the pass itself is recreated, so it grows quickly
44
+ * during warm-up and should then plateau.
45
+ */
46
+ entriesTotal: number;
47
+ /**
48
+ * Classification entries created this frame (cache misses). ~0 in steady state; a
49
+ * persistently non-zero value means object material identities churn every frame,
50
+ * which also churns the cached per-pass OIT variants.
51
+ */
52
+ entriesThisFrame: number;
53
+ /** GPU textures currently tracked by the renderer (global; watch for unbounded growth). */
54
+ textures: number;
55
+ /** GPU geometries currently tracked by the renderer (global). */
56
+ geometries: number;
57
+ /** Compiled shader programs currently held by the renderer (global). `-1` if unavailable. */
58
+ programs: number;
59
+ };
60
+ /**
61
+ * Per-segment GPU timings in milliseconds, populated when {@link OITRenderPass.profile}
62
+ * is enabled and the platform supports timer queries. `-1` means "no result yet"
63
+ * (or unsupported). `tail` is the single weighted-blended OIT pass cost.
64
+ */
65
+ export type OITRenderPassTimings = {
66
+ /** Opaque pass (step 1), including any forced-opaque OIT occluders. */
67
+ opaque: number;
68
+ /** Additive/glow emissive pass (step 1b). */
69
+ emissive: number;
70
+ /** Min-depth pre-pass (step 2). */
71
+ minDepth: number;
72
+ /** Weighted-blended OIT tail pass (step 3). */
73
+ tail: number;
74
+ /** Fullscreen tail composite (step 4). */
75
+ composite: number;
76
+ /** Exact front-layer pass (step 5). */
77
+ front: number;
78
+ /** Optional occlusion depth-stamp pass (step 5b). */
79
+ occlusion: number;
80
+ /** Optional emitter depth-stamp pass (step 1c). */
81
+ emitterStamp: number;
82
+ /** Always-on-top overlay pass (step 6). */
83
+ overlay: number;
84
+ /** Sum of the measured OIT segments above. */
85
+ total: number;
86
+ };
87
+ /**
88
+ * Built-in anti-aliasing mode for {@link OITRenderPass.antialias}. See that field for
89
+ * the per-mode description. Exported as the single source of truth so consumers
90
+ * (and Storybook arg types) can reference it instead of re-declaring the union.
91
+ *
92
+ * @group Rendering
93
+ */
94
+ export type OITAntialiasMode = 'none' | 'temporal' | 'smaa' | 'temporal-smaa' | 'taa' | 'fxaa';
95
+ /**
96
+ * Hybrid order-independent-transparency (OIT) render pass for use with the
97
+ * {@link RenderingPipeline} (or any custom composer). Renders the nearest transparent
98
+ * layer exactly (depth-peeled, alpha-over) and the remaining layers using
99
+ * weighted-blended OIT (WBOIT), partitioned per-pixel in view-space linear depth.
100
+ *
101
+ * Transparency is opt-in: this pass only affects materials that are OIT-capable
102
+ * (library materials, or stock/user materials patched with `makeOitCompatible`).
103
+ * Two per-object escape-hatch layers override the default routing: `LAYERS.FORCE_OPAQUE`
104
+ * draws the object as a depth-writing opaque occluder (its material is temporarily
105
+ * forced to `depthWrite=true, transparent=false`); `LAYERS.OIT_EXCLUDED` also draws it
106
+ * in the opaque pass but leaves the material's own properties untouched.
107
+ * Additive/glow objects tagged with the `LAYERS.EMISSIVE` layer are drawn between the
108
+ * opaque and transparent layers (so transparent surfaces in front attenuate them);
109
+ * always-on-top objects tagged with the `LAYERS.OVERLAY` layer are drawn last, on top
110
+ * of the resolved transparency. While this pass is active it sets the per-canvas
111
+ * rendering state to `'oit'` so components can disable conflicting self-transparency
112
+ * workarounds.
113
+ *
114
+ * @example
115
+ * ```tsx
116
+ * const passes = useMemo(
117
+ * () => [new OITRenderPass(scene, camera), new OutputPass()],
118
+ * [scene, camera],
119
+ * );
120
+ * return <RenderingPipeline passes={passes} />;
121
+ * ```
122
+ *
123
+ * @group Rendering
124
+ * @see {@link RenderingPipeline}
125
+ * @see {@link makeOitCompatible}
126
+ */
127
+ export declare class OITRenderPass extends Pass {
128
+ private scene;
129
+ private camera;
130
+ /**
131
+ * Debug: when true, the exact depth-peeled front layer is disabled and every
132
+ * transparent fragment is resolved through the weighted-blended (WBOIT) tail.
133
+ * Useful for isolating tail behaviour and comparing against the hybrid result.
134
+ */
135
+ skipFront: boolean;
136
+ /**
137
+ * Number of MSAA samples (0 = off) for the hybrid multisample path. When > 0 the
138
+ * opaque geometry (including fully-opaque OIT occluders such as casings/completion
139
+ * tools), the emissive layer, the weighted-blended (WBOIT) tail composite, the exact
140
+ * front layer and the overlay are all rendered into ONE dedicated multisample target
141
+ * sharing the pipeline depth. The single-sample min-depth/accum aux targets read the
142
+ * opaque depth resolved on the first switch away from the multisample target; the
143
+ * final colour is resolved ONCE more and blitted into the single-sample pipeline
144
+ * buffer (~2 resolves total). This costs more than multisampling the opaque pass
145
+ * alone but far less than multisampling the whole half-float pipeline buffer
146
+ * (~4 resolves). Clamped to `renderer.capabilities.maxSamples`.
147
+ *
148
+ * **MSAA is not recommended with OIT.** The min-depth/accum aux buffers must be
149
+ * single-sample (WebGL2 cannot sample a multisample texture), so the transparent
150
+ * tail is composited single-sample over the multisample opaque edges. Opaque edges
151
+ * are matted against the cleared background before the transparent surfaces exist,
152
+ * and the single-sample composite cannot reconstruct per-sample coverage — so a
153
+ * background-coloured fringe survives along opaque and thin-line edges *over
154
+ * transparent surfaces*. This is structural and cannot be made clean here; only
155
+ * supersampling the whole composite (an {@link antialias} temporal mode, or the
156
+ * {@link RenderingPipeline} `supersample` prop) removes it.
157
+ *
158
+ * `opaqueSamples` is therefore intended only for the narrow **opaque-only** close-up
159
+ * (no transparent surfaces composited in front — e.g. a casing detail view), where
160
+ * the fringe cannot occur. For anything with transparent surfaces leave this at `0`
161
+ * and use {@link antialias} (temporal / SMAA / TAA / FXAA) or the
162
+ * {@link RenderingPipeline} `supersample` prop instead. (Pipeline-level `samples`
163
+ * does not anti-alias the OIT result either, and is only for a plain opaque
164
+ * `RenderPass` pipeline with no OIT.)
165
+ *
166
+ * Do not combine `opaqueSamples > 0` with an {@link antialias} temporal mode
167
+ * (`'temporal'`/`'temporal-smaa'`/`'taa'`): it is wasteful — the multisample colour
168
+ * is resolved first and the temporal resolver then runs on the already-resolved
169
+ * buffer, so you pay for MSAA rasterisation on top of temporal supersampling that
170
+ * already anti-aliases the same edges.
171
+ */
172
+ opaqueSamples: number;
173
+ /**
174
+ * Built-in anti-aliasing mode for the composited result.
175
+ *
176
+ * - `'none'`: no built-in AA. Pair with {@link opaqueSamples} (MSAA) for
177
+ * opaque-edge AA in an opaque-only close-up; transparent/additive edges stay
178
+ * un-anti-aliased, and MSAA leaves a background-coloured fringe over transparent
179
+ * surfaces (see {@link opaqueSamples}).
180
+ * - `'temporal'`: temporal supersampling (see {@link TemporalResolver}). The camera
181
+ * is sub-pixel jittered each frame and the composited frame is accumulated into a
182
+ * running average **while the camera is still**, converging to a genuinely
183
+ * supersampled image (thin trajectory lines, transparent-surface edges, contour
184
+ * lines and the additive highlight all anti-alias). There is no reprojection, so
185
+ * nothing ghosts; while the camera moves the current frame is shown un-jittered
186
+ * (the moving frame is not anti-aliased unless combined with SMAA or MSAA).
187
+ * - `'smaa'`: subpixel morphological AA (see {@link smaaQuality}) applied as a
188
+ * spatial post pass every frame. Anti-aliases moving frames too, but (like all
189
+ * morphological techniques) cannot recover sub-pixel features such as 1px lines
190
+ * that fall between samples.
191
+ * - `'temporal-smaa'`: both, mutually exclusive per frame — temporal accumulation
192
+ * while the camera is still (crisp, recovers sub-pixel detail) and SMAA while it
193
+ * moves. SMAA never softens the converged still image and only costs GPU time
194
+ * during motion.
195
+ * - `'taa'` (default): reprojected temporal anti-aliasing (see {@link TaaResolver}).
196
+ * Like `'temporal'` the camera is sub-pixel jittered, but the history is
197
+ * reprojected every frame using the nearest visible surface's depth (opaque
198
+ * hardware depth refined by the OIT front-layer depth), so anti-aliasing is
199
+ * retained *during* camera motion. Ghosting from additive/animated/disoccluded
200
+ * content is bounded by neighbourhood colour clamping. This is the recommended
201
+ * default for the OIT pipeline — it anti-aliases both still and moving frames.
202
+ * Use `'temporal'` instead if you need guaranteed ghost-free stills and don't
203
+ * mind losing motion AA.
204
+ * - `'fxaa'`: fast approximate AA (see {@link FxaaResolver}) applied as a single
205
+ * cheap spatial post pass every frame. Cheaper and softer than `'smaa'`, with no
206
+ * OIT or temporal coupling. Like all spatial techniques it cannot recover
207
+ * sub-pixel features. Also available as the standalone {@link FXAAPass} for
208
+ * non-OIT (plain `RenderPass`) setups.
209
+ *
210
+ * The jitter is applied to the shared camera only between this pass's own scene
211
+ * render and resolve, so it never leaks to later passes (annotations, picking).
212
+ * This is the OIT pipeline's high-quality AA. Non-OIT setups (plain `RenderPass`)
213
+ * should use MSAA instead.
214
+ */
215
+ antialias: OITAntialiasMode;
216
+ /**
217
+ * SMAA quality preset used by the `'smaa'` and `'temporal-smaa'` {@link antialias}
218
+ * modes (default `'high'`). Ignored by the other modes.
219
+ */
220
+ smaaQuality: SMAAQuality;
221
+ /**
222
+ * The temporal-supersampling resolver, exposed for debug/tuning (e.g. its
223
+ * `clampStrength` anti-ghost knob). Non-null only while {@link antialias} is
224
+ * `'temporal'` / `'temporal-smaa'` and after at least one frame has rendered (it is
225
+ * created lazily and recreated on a mode switch, resetting to defaults).
226
+ */
227
+ get temporalResolver(): TemporalResolver | null;
228
+ /**
229
+ * The reprojected-TAA resolver, exposed for debug/tuning (e.g. its
230
+ * `restClampStrength` / `restBoxGamma` / `restNeighbourhoodRadius` anti-ghost knobs).
231
+ * Non-null only while {@link antialias} is `'taa'` and after at least one frame has
232
+ * rendered (it is created lazily and recreated on a mode switch, resetting to
233
+ * defaults).
234
+ */
235
+ get taaResolver(): TaaResolver | null;
236
+ /**
237
+ * Optional feature (default off): after the transparent OIT passes, stamp depth
238
+ * for transparent surfaces wherever their own alpha is at least
239
+ * {@link occlusionDepthThreshold}. Transparent surfaces normally write no depth, so
240
+ * annotation labels behind a high-but-not-full opacity surface are never occluded;
241
+ * enabling this makes a surface occlude labels once its alpha clears the threshold.
242
+ *
243
+ * The test is per-fragment and per-surface (each surface judged on its own alpha,
244
+ * not accumulated coverage), and the stamped depth uses the same encoding the
245
+ * {@link AnnotationsPass} already samples. Costs one extra transparent-geometry
246
+ * pass per frame when enabled; nothing (not even a shader compile) when off.
247
+ */
248
+ occlusionDepthStamp: boolean;
249
+ /** Alpha threshold (0..1) for {@link occlusionDepthStamp}. Default 0.5. */
250
+ occlusionDepthThreshold: number;
251
+ /**
252
+ * Optional feature (default off): stamp depth for emissive/glow emitters (objects
253
+ * on `LAYERS.EMISSIVE`) wherever their fragment strength is at least
254
+ * {@link emitterDepthThreshold}, drawn before the transparent OIT passes. This lets
255
+ * the dense core of an additive emitter (e.g. perforation jets) occlude transparent
256
+ * surfaces behind it, preventing the wash-out where a far transparent surface would
257
+ * otherwise dim the emitter. Surfaces in front still attenuate it.
258
+ *
259
+ * An emitter opts in by exposing a depth-only stamp material on its material's
260
+ * `userData.occlusionDepthMaterial` (with a `uOcclusionThreshold` uniform the pass
261
+ * drives). Emitters without one are simply skipped. Costs one extra emissive pass
262
+ * per frame when enabled; nothing when off.
263
+ */
264
+ emitterDepthStamp: boolean;
265
+ /** Strength threshold (0..1) for {@link emitterDepthStamp}. Default 0.5. */
266
+ emitterDepthThreshold: number;
267
+ /**
268
+ * When true, draws small thumbnails of the internal render targets (min-depth,
269
+ * accumulation) into the bottom-left of the output, for debugging.
270
+ * GPU-only; no pixel readback.
271
+ */
272
+ debugTargets: boolean;
273
+ /**
274
+ * When true, measures per-segment GPU time (opaque/emissive/min-depth/tail/
275
+ * composite/front/overlay) via timer queries and exposes it on {@link timings}. Adds a
276
+ * little CPU/driver overhead and lags a few frames, so it is off by default. No-op
277
+ * on platforms without `EXT_disjoint_timer_query_webgl2`.
278
+ *
279
+ * The most relevant figure for the transparent-geometry cost is
280
+ * {@link OITRenderPassTimings.tail}.
281
+ */
282
+ profile: boolean;
283
+ /**
284
+ * Per-segment GPU timings (ms) from the last completed measurement. Only updated
285
+ * while {@link profile} is enabled. `-1` means "no result yet" or unsupported.
286
+ */
287
+ readonly timings: OITRenderPassTimings;
288
+ /**
289
+ * Per-frame object counts for each pass, updated every {@link render}. Useful for
290
+ * verifying which objects are routed through OIT vs. drawn opaque/overlay.
291
+ */
292
+ readonly stats: OITRenderPassStats;
293
+ /**
294
+ * Resource/accumulation counters for leak monitoring, updated every {@link render}.
295
+ * See {@link OITRenderPassResources}.
296
+ */
297
+ readonly resources: OITRenderPassResources;
298
+ private fullscreenRenderer;
299
+ /** Lazily-created temporal-supersampling resolver, used when {@link antialias} is `'temporal'`. */
300
+ private temporal;
301
+ /**
302
+ * Lazily-created reprojected-TAA resolver, used when {@link antialias} is `'taa'`.
303
+ */
304
+ private taa;
305
+ /**
306
+ * Lazily-created SMAA spatial resolver, used when {@link antialias} is `'smaa'` or
307
+ * `'temporal-smaa'`.
308
+ */
309
+ private smaa;
310
+ /** Lazily-created FXAA spatial resolver, used when {@link antialias} is `'fxaa'`. */
311
+ private fxaa;
312
+ private minDepthTarget;
313
+ private accumTarget;
314
+ private compositeMaterial;
315
+ /** Shared multisample target for the hybrid MSAA path (see {@link opaqueSamples}). */
316
+ private opaqueTarget;
317
+ /** Sample count the current opaqueTarget was built with (-1 = none yet). */
318
+ private opaqueTargetSamples;
319
+ /** Blit material: copy the resolved multisample colour into the buffer (no blending). */
320
+ private opaqueBlitMaterial;
321
+ /** Lazily-created material for the debug-target thumbnails. */
322
+ private debugMaterial;
323
+ /** Lazily-created GPU timer, only when {@link profile} is first enabled. */
324
+ private gpuTimer;
325
+ /**
326
+ * OIT pipeline registration release handle. Acquired lazily on the first
327
+ * {@link render} rather than in the constructor: the host (e.g. a `useMemo`) may
328
+ * construct passes that React then discards without ever committing/rendering them,
329
+ * and a constructor-time acquire on such an orphan would never be released. Only
330
+ * committed passes are rendered, so acquiring here keeps the registration count
331
+ * symmetric with {@link dispose}.
332
+ */
333
+ private releaseOit?;
334
+ private entryCache;
335
+ /** Monotonic count of classification entries created (cache misses). */
336
+ private entriesCreated;
337
+ /** Saved material state for OIT objects temporarily forced opaque this frame. */
338
+ private forcedOpaque;
339
+ private width;
340
+ private height;
341
+ private depthFar;
342
+ constructor(scene: Scene, camera: Camera);
343
+ /**
344
+ * Create or resize the shared multisample target, sharing the pipeline's depth
345
+ * texture so resolving writes the AA colour AND the resolved opaque depth the
346
+ * auxiliary OIT passes read. Recreated when sample count, size or shared depth
347
+ * texture changes.
348
+ */
349
+ private ensureOpaqueTarget;
350
+ private disposeOpaqueTarget;
351
+ setSize(width: number, height: number): void;
352
+ dispose(): void;
353
+ private getEntry;
354
+ /**
355
+ * Whether an OIT entry is currently fully invisible (every OIT-capable material
356
+ * has opacity ≤ 0). Such objects are hidden from all passes — they contribute
357
+ * nothing to any render target, so rasterising them (even through the cheap aux
358
+ * passes) is pure waste.
359
+ */
360
+ private isEntryInvisible;
361
+ /**
362
+ * Traverse the scene once, classifying renderables into transparent-OIT,
363
+ * plain-opaque, emissive (additive/glow) and always-on-top overlay sets.
364
+ * OIT-capable objects that are currently fully opaque, or explicitly tagged with
365
+ * the `LAYERS.FORCE_OPAQUE` layer, are added to both `opaqueList` (for the
366
+ * visibility lifecycle) and `oitOpaqueList` (so their materials can be forced
367
+ * depth-writing), making them real occluders. Objects tagged `LAYERS.OIT_EXCLUDED`
368
+ * are added to `opaqueList` only, so they render with their material untouched.
369
+ * Emissive objects are detected by the EMISSIVE layer, overlay objects by the
370
+ * OVERLAY layer.
371
+ */
372
+ private collect;
373
+ /**
374
+ * Prepare the OIT renderables for the opaque pass. Objects whose whole material
375
+ * is OIT-capable are simply hidden (and collected into `hidden` for restore), so
376
+ * their geometry isn't rasterised at all. Mixed multi-material meshes are swapped
377
+ * to their opaque variant (opaque groups kept, OIT groups drawn as no-op).
378
+ */
379
+ private applyOpaqueSwap;
380
+ private applyPassSwap;
381
+ private restoreMaterials;
382
+ private setOitUniforms;
383
+ private setVisible;
384
+ /**
385
+ * Resolve the opt-in depth-stamp material for an emissive emitter, if any. The
386
+ * emitter exposes it on `material.userData.occlusionDepthMaterial`; this also drives
387
+ * its `uOcclusionThreshold` uniform from {@link emitterDepthThreshold}. Returns null
388
+ * when the emitter provides no stamp material (it is then skipped).
389
+ */
390
+ private getEmitterStamp;
391
+ /**
392
+ * Current effective opacity of a material. `ShaderMaterial`s drive opacity through
393
+ * a `uniforms.opacity` value (the material's own `opacity` field is often left at
394
+ * 1), so prefer that; otherwise use `Material.opacity`.
395
+ */
396
+ private static effectiveOpacity;
397
+ /** Whether a material currently renders as fully opaque. */
398
+ private static isMaterialOpaque;
399
+ /** Whether a material currently renders as fully invisible (opacity ≤ 0). */
400
+ private static isMaterialInvisible;
401
+ /**
402
+ * Whether an OIT entry is currently fully opaque (every OIT-capable material is
403
+ * opaque). Such objects are drawn in the opaque pass as real occluders instead of
404
+ * being routed through the (more expensive, depth-non-writing) OIT passes.
405
+ */
406
+ private isEntryOpaque;
407
+ /**
408
+ * Temporarily force the OIT-capable materials of the given entries to write depth
409
+ * and render opaque, so they act as genuine occluders during the opaque pass. The
410
+ * previous state is saved and restored by {@link restoreForcedOpaque}. These
411
+ * objects are hidden during the OIT sub-passes, so the forced state only takes
412
+ * effect where intended.
413
+ */
414
+ private applyForcedOpaque;
415
+ private restoreForcedOpaque;
416
+ /**
417
+ * Copy the latest smoothed GPU timings out of the timer into {@link timings} and
418
+ * recompute the `total`. Segments without a result yet (or skipped this frame)
419
+ * report `-1` and are excluded from the total.
420
+ */
421
+ private updateTimings;
422
+ render(renderer: WebGLRenderer, buffer: WebGLRenderTarget): void;
423
+ /**
424
+ * Draw small thumbnails of the auxiliary render targets along the bottom-left of
425
+ * the output buffer (min-depth, accumulation). Uses the buffer's viewport
426
+ * to scope each draw; GPU-only.
427
+ */
428
+ private renderDebugTargets;
429
+ }
@@ -0,0 +1,19 @@
1
+ import { MeshBasicMaterial, WebGLRenderer, WebGLRenderTarget } from 'three';
2
+ import { FullscreenRenderer } from '../fullscreen-renderer';
3
+ import { Pass } from '../Pass';
4
+ /**
5
+ * Terminal pass: composites the pipeline's linear HDR buffer to the screen and
6
+ * applies tone mapping + sRGB output encoding once, for the whole buffer, via
7
+ * `renderer.toneMapping` / `toneMappingExposure` (`toneMapped: true` below).
8
+ *
9
+ * Because tone mapping is deferred to this single pass, scene materials must render
10
+ * linear (`toneMapped: false`) or they double-tone-map, and the per-material
11
+ * `toneMapped = false` opt-out is not honored. See documents/oit-guide.md §7.
12
+ */
13
+ export declare class OutputPass extends Pass {
14
+ fullscreenRenderer: FullscreenRenderer;
15
+ material: MeshBasicMaterial;
16
+ constructor();
17
+ render(renderer: WebGLRenderer, buffer: WebGLRenderTarget): void;
18
+ dispose(): void;
19
+ }
@@ -0,0 +1,10 @@
1
+ import { Camera, Scene, WebGLRenderer, WebGLRenderTarget } from 'three';
2
+ import { Pass } from '../Pass';
3
+ export declare class RenderPass extends Pass {
4
+ private scene;
5
+ private camera;
6
+ /** Reused scratch for saving the renderer clear colour (no per-frame alloc). */
7
+ private prevClearColor;
8
+ constructor(scene: Scene, camera: Camera);
9
+ render(renderer: WebGLRenderer, buffer: WebGLRenderTarget): void;
10
+ }
@@ -0,0 +1,4 @@
1
+ export * from './FXAAPass';
2
+ export * from './OITRenderPass';
3
+ export * from './OutputPass';
4
+ export * from './RenderPass';
@@ -0,0 +1,59 @@
1
+ import { Object3D } from 'three';
2
+ import { StoreApi } from 'zustand/vanilla';
3
+ /**
4
+ * Transparency rendering mode currently active for a given scene/canvas.
5
+ *
6
+ * - `'standard'`: default rendering, as if no custom rendering pipeline is used.
7
+ * Components apply their default self-transparency workarounds.
8
+ * - `'oit'`: an order-independent-transparency pipeline (e.g. {@link OITRenderPass})
9
+ * is active. Components should disable workarounds that conflict with OIT (such as
10
+ * depth-only mask passes) and let the pipeline resolve transparency.
11
+ */
12
+ export type TransparencyMode = 'standard' | 'oit';
13
+ /**
14
+ * Per-canvas rendering pipeline state.
15
+ *
16
+ * Lets components react to which rendering pipeline (if any) is active without the
17
+ * user having to manually configure each component. The defaults match the behavior
18
+ * of default rendering with no custom pipeline.
19
+ *
20
+ * @group Rendering
21
+ */
22
+ export type RenderingState = {
23
+ /** The active transparency mode. Defaults to `'standard'`. */
24
+ transparencyMode: TransparencyMode;
25
+ /** @internal reference count of active OIT pipelines. */
26
+ _oitCount: number;
27
+ /**
28
+ * Register an active OIT pipeline. Sets {@link RenderingState.transparencyMode}
29
+ * to `'oit'`. Returns a release function that must be called when the pipeline is
30
+ * disposed; the mode reverts to `'standard'` once all registrations are released.
31
+ * Reference counted so multiple/short-lived passes behave correctly.
32
+ */
33
+ acquireOit: () => () => void;
34
+ };
35
+ /**
36
+ * Get (or lazily create) the {@link RenderingState} store for a given scene.
37
+ *
38
+ * Both the rendering passes (which hold a reference to the scene) and the hooks used
39
+ * by components (which resolve the scene via R3F) call this with the same scene, so
40
+ * they share a single store instance per canvas. No provider is required — the store
41
+ * is created on first access, so components used without any pipeline still work and
42
+ * simply observe the `'standard'` default.
43
+ *
44
+ * @group Rendering
45
+ */
46
+ export declare function getRenderingState(scene: Object3D): StoreApi<RenderingState>;
47
+ /**
48
+ * Hook to read the per-canvas {@link RenderingState}. Resolves the store from the
49
+ * current R3F scene, so it must be used inside a `Canvas`.
50
+ *
51
+ * @example
52
+ * ```tsx
53
+ * const isOit = useRenderingState(state => state.transparencyMode === 'oit');
54
+ * ```
55
+ *
56
+ * @group Hooks
57
+ * @category Rendering
58
+ */
59
+ export declare function useRenderingState<T>(selector: (state: RenderingState) => T): T;
@@ -0,0 +1,58 @@
1
+ import { WebGLRenderer, WebGLRenderTarget } from 'three';
2
+ /**
3
+ * Quality preset for SMAA. Higher presets lower the edge-detection threshold (so
4
+ * fainter edges are anti-aliased) and increase the orthogonal search distance (so
5
+ * longer near-horizontal/vertical edges are reconstructed). The underlying
6
+ * three-stdlib SMAA shaders do not implement the reference SMAA's diagonal search
7
+ * and corner rounding, so those are unaffected by the preset.
8
+ *
9
+ * @group Rendering
10
+ */
11
+ export type SMAAQuality = 'low' | 'medium' | 'high' | 'ultra';
12
+ /**
13
+ * Subpixel Morphological Anti-Aliasing (SMAA) resolver, used internally by
14
+ * {@link OITRenderPass} when its `antialias` mode is `'smaa'` or `'temporal-smaa'`.
15
+ * It detects edges by colour discontinuity and reconstructs anti-aliased
16
+ * silhouettes using precomputed area/search lookup tables, giving clean long edges
17
+ * with little detail blurring.
18
+ *
19
+ * It operates in linear space (the OIT buffer is linear FP16) but detects edges on
20
+ * an sRGB-encoded copy so the perceptual thresholds behave as intended; the blend
21
+ * and output stay linear, so brightness is untouched.
22
+ *
23
+ * This wraps the well-tested SMAA shaders and lookup textures from `three-stdlib`
24
+ * and drives the three sub-passes (edge detection, blend-weight calculation,
25
+ * neighbourhood blending) through a {@link FullscreenRenderer}, compositing the
26
+ * result back into the shared buffer in place.
27
+ *
28
+ * Like all morphological techniques it cannot recover sub-pixel features (e.g. 1px
29
+ * WebGL lines that fall between samples) — those are handled by the temporal
30
+ * supersampling mode while the camera is still.
31
+ */
32
+ export declare class SmaaResolver {
33
+ private inner;
34
+ private scratch;
35
+ private encoded;
36
+ private encodeMaterial;
37
+ private blitMaterial;
38
+ private fullscreenRenderer;
39
+ private materialEdges;
40
+ private materialWeights;
41
+ private materialBlend;
42
+ private _quality;
43
+ /** Reused scratch for saving the renderer clear colour each frame (no per-frame alloc). */
44
+ private prevClearColor;
45
+ constructor(quality?: SMAAQuality);
46
+ /**
47
+ * Quality preset (default `'high'`). Assigning it rewrites the edge-detection
48
+ * threshold and orthogonal search-distance shader defines and recompiles the two
49
+ * affected sub-pass programs. The recompile only happens when the value actually
50
+ * changes, so reading/writing the same value every frame is free.
51
+ */
52
+ get quality(): SMAAQuality;
53
+ set quality(value: SMAAQuality);
54
+ private applyQuality;
55
+ setSize(width: number, height: number): void;
56
+ dispose(): void;
57
+ render(renderer: WebGLRenderer, buffer: WebGLRenderTarget): void;
58
+ }