@equinor/videx-3d 1.1.0 → 2.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 (47) hide show
  1. package/README.md +120 -120
  2. package/dist/chunk-61X6qE5N.js +981 -0
  3. package/dist/chunk-ChG5d4HC.js +675 -0
  4. package/dist/{chunk-BolRQZt9.js → chunk-M-Pcc_Yg.js} +22 -20
  5. package/dist/generators.js +271 -260
  6. package/dist/main.js +5185 -3434
  7. package/dist/sdk.js +492 -316
  8. package/dist/shaderLib/oit.glsl +106 -0
  9. package/dist/types/components/Annotations/AutoUpdate.d.ts +1 -1
  10. package/dist/types/components/Annotations/index.d.ts +2 -2
  11. package/dist/types/components/Annotations/types.d.ts +3 -1
  12. package/dist/types/components/Annotations/update-annotations.d.ts +10 -0
  13. package/dist/types/components/EventEmitter/EventEmitterContext.d.ts +2 -1
  14. package/dist/types/components/EventEmitter/index.d.ts +1 -0
  15. package/dist/types/components/EventEmitter/picking-helper.d.ts +25 -0
  16. package/dist/types/components/EventEmitter/picking-material.d.ts +8 -5
  17. package/dist/types/components/Surfaces/Surface.d.ts +8 -1
  18. package/dist/types/components/Surfaces/SurfaceMaterial.d.ts +3 -0
  19. package/dist/types/components/Surfaces/surface-defs.d.ts +1 -0
  20. package/dist/types/components/Wellbores/Casings/CasingEmitterMaterial.d.ts +16 -0
  21. package/dist/types/components/Wellbores/Casings/CasingSection.d.ts +3 -2
  22. package/dist/types/components/Wellbores/Casings/Casings.d.ts +3 -2
  23. package/dist/types/generators/surface-generator.d.ts +1 -1
  24. package/dist/types/layers/layers.d.ts +4 -0
  25. package/dist/types/rendering/OitMaterial.d.ts +59 -0
  26. package/dist/types/rendering/Pass.d.ts +7 -0
  27. package/dist/types/rendering/RenderingPipeline.d.ts +37 -0
  28. package/dist/types/rendering/fullscreen-renderer.d.ts +1 -0
  29. package/dist/types/rendering/gpu-timer.d.ts +46 -0
  30. package/dist/types/rendering/index.d.ts +7 -1
  31. package/dist/types/rendering/oit-material.d.ts +122 -0
  32. package/dist/types/{components/Annotations/annotations-renderer.d.ts → rendering/passes/AnnotationsPass.d.ts} +13 -4
  33. package/dist/types/rendering/passes/FXAAPass.d.ts +12 -0
  34. package/dist/types/rendering/passes/OITRenderPass.d.ts +282 -0
  35. package/dist/types/rendering/passes/OutputPass.d.ts +10 -0
  36. package/dist/types/rendering/passes/RenderPass.d.ts +8 -0
  37. package/dist/types/rendering/passes/SMAAPass.d.ts +40 -0
  38. package/dist/types/rendering/passes/TAAPass.d.ts +94 -0
  39. package/dist/types/rendering/passes/index.d.ts +6 -0
  40. package/dist/types/rendering/rendering-state.d.ts +59 -0
  41. package/dist/types/sdk/index.d.ts +2 -0
  42. package/dist/types/sdk/utils/elevation-map.d.ts +23 -0
  43. package/dist/types/sdk/utils/trigonometry.d.ts +4 -1
  44. package/package.json +1 -1
  45. package/dist/chunk-CnY6Tmof.js +0 -358
  46. package/dist/chunk-iY0wQ9Z6.js +0 -887
  47. package/dist/types/rendering/render-passes.d.ts +0 -16
@@ -1,7 +1,8 @@
1
1
  import { Camera, CanvasTexture, Clock, PerspectiveCamera, ShaderMaterial, Vector2, WebGLRenderer, WebGLRenderTarget } from 'three';
2
- import { FullscreenRenderer } from '../../rendering/fullscreen-renderer';
3
- import { AnnotationInstance } from './types';
4
- export declare class AnnotationsRenderer {
2
+ import { AnnotationInstance } from '../../components/Annotations/types';
3
+ import { FullscreenRenderer } from '../fullscreen-renderer';
4
+ import { Pass } from '../Pass';
5
+ export declare class AnnotationsPass extends Pass {
5
6
  maxVisible: number;
6
7
  camera: PerspectiveCamera;
7
8
  clock: Clock;
@@ -12,11 +13,19 @@ export declare class AnnotationsRenderer {
12
13
  annotationsRenderTarget: WebGLRenderTarget;
13
14
  annotationsBuffer: Uint8Array;
14
15
  annotationsMaterial: ShaderMaterial;
15
- fullscreenRenderer: FullscreenRenderer;
16
16
  annotationsData: AnnotationInstance[];
17
17
  isBusy: boolean;
18
18
  dataTextureNeedsUpdate: boolean;
19
+ fullscreenRenderer: FullscreenRenderer;
19
20
  unsubscribeListeners: () => void;
21
+ private prevCameraMatrix;
22
+ private prevPointerX;
23
+ private prevPointerY;
24
+ private prevSizeX;
25
+ private prevSizeY;
26
+ private occlusionChanged;
27
+ connectorTargetFrameTime: number;
28
+ connectorStretchSlack: number;
20
29
  constructor(camera: Camera, clock: Clock, pointer: Vector2, maxVisible?: number);
21
30
  updateAnnotationsData(buffer: Uint8Array): void;
22
31
  updateOverlayTexture(inViewSpace: AnnotationInstance[]): void;
@@ -0,0 +1,12 @@
1
+ import { WebGLRenderer, WebGLRenderTarget } from 'three';
2
+ import { Pass } from '../Pass';
3
+ export declare class FxaaPass extends Pass {
4
+ private scratch;
5
+ private fxaaMaterial;
6
+ private blitMaterial;
7
+ private fullscreenRenderer;
8
+ constructor();
9
+ setSize(width: number, height: number): void;
10
+ dispose(): void;
11
+ render(renderer: WebGLRenderer, buffer: WebGLRenderTarget): void;
12
+ }
@@ -0,0 +1,282 @@
1
+ import { Camera, Scene, WebGLRenderer, WebGLRenderTarget } from 'three';
2
+ import { Pass } from '../Pass';
3
+ /** Per-frame object counts for each classification, exposed for debugging. */
4
+ export type OITRenderPassStats = {
5
+ /** Plain opaque renderables (not OIT-capable, not overlay). */
6
+ opaque: number;
7
+ /** OIT-capable renderables currently transparent (routed through OIT). */
8
+ oit: number;
9
+ /**
10
+ * OIT-capable renderables that are currently fully opaque and therefore drawn in
11
+ * the opaque pass as real occluders (depth-writing), bypassing the OIT passes.
12
+ */
13
+ oitOpaque: number;
14
+ /** Additive/glow renderables (tagged `LAYERS.EMISSIVE`), drawn before the transparent layers. */
15
+ emissive: number;
16
+ /** Always-on-top renderables (tagged `LAYERS.OVERLAY`), drawn after the transparent layers. */
17
+ overlay: number;
18
+ /** Subset of `oit` whose whole material is OIT-capable (hidden in opaque pass). */
19
+ oitHidden: number;
20
+ /** Subset of `oit` that are mixed multi-material meshes (some opaque groups). */
21
+ oitMixed: number;
22
+ };
23
+ /**
24
+ * Resource/accumulation counters for leak monitoring. Unlike {@link OITRenderPassStats}
25
+ * (per-frame object classification, which naturally varies with the camera), these
26
+ * track internal structures and global GPU resources that should stay *bounded* over
27
+ * time. Watch them while toggling the pipeline on/off (which recreates the passes): a
28
+ * steady climb indicates passes or GPU resources are not being disposed.
29
+ */
30
+ export type OITRenderPassResources = {
31
+ /**
32
+ * Active OIT pipeline registrations on this canvas (the ref-counted
33
+ * {@link RenderingState} `_oitCount`). Should read 1 while a single OIT pipeline is
34
+ * mounted; a value that climbs each time the pipeline is recreated means a pass was
35
+ * acquired but never released in {@link OITRenderPass.dispose} (a real leak).
36
+ */
37
+ oitPipelines: number;
38
+ /**
39
+ * Total classification entries created since this pass instance was constructed
40
+ * (monotonic). Resets only when the pass itself is recreated, so it grows quickly
41
+ * during warm-up and should then plateau.
42
+ */
43
+ entriesTotal: number;
44
+ /**
45
+ * Classification entries created this frame (cache misses). ~0 in steady state; a
46
+ * persistently non-zero value means object material identities churn every frame,
47
+ * which also churns the cached per-pass OIT variants.
48
+ */
49
+ entriesThisFrame: number;
50
+ /** GPU textures currently tracked by the renderer (global; watch for unbounded growth). */
51
+ textures: number;
52
+ /** GPU geometries currently tracked by the renderer (global). */
53
+ geometries: number;
54
+ /** Compiled shader programs currently held by the renderer (global). `-1` if unavailable. */
55
+ programs: number;
56
+ };
57
+ /**
58
+ * Per-segment GPU timings in milliseconds, populated when {@link OITRenderPass.profile}
59
+ * is enabled and the platform supports timer queries. `-1` means "no result yet"
60
+ * (or unsupported). `tail` is the single weighted-blended OIT pass cost.
61
+ */
62
+ export type OITRenderPassTimings = {
63
+ /** Opaque pass (step 1), including any forced-opaque OIT occluders. */
64
+ opaque: number;
65
+ /** Additive/glow emissive pass (step 1b). */
66
+ emissive: number;
67
+ /** Min-depth pre-pass (step 2). */
68
+ minDepth: number;
69
+ /** Weighted-blended OIT tail pass (step 3). */
70
+ tail: number;
71
+ /** Fullscreen tail composite (step 4). */
72
+ composite: number;
73
+ /** Exact front-layer pass (step 5). */
74
+ front: number;
75
+ /** Optional occlusion depth-stamp pass (step 5b). */
76
+ occlusion: number;
77
+ /** Optional emitter depth-stamp pass (step 1c). */
78
+ emitterStamp: number;
79
+ /** Always-on-top overlay pass (step 6). */
80
+ overlay: number;
81
+ /** Sum of the measured OIT segments above. */
82
+ total: number;
83
+ };
84
+ /**
85
+ * Hybrid order-independent-transparency (OIT) render pass for use with the
86
+ * {@link RenderingPipeline} (or any custom composer). Renders the nearest transparent
87
+ * layer exactly (depth-peeled, alpha-over) and the remaining layers using
88
+ * weighted-blended OIT (WBOIT), partitioned per-pixel in view-space linear depth.
89
+ *
90
+ * Transparency is opt-in: this pass only affects materials that are OIT-capable
91
+ * (library materials, or stock/user materials patched with `makeOitCompatible`).
92
+ * Two per-object escape-hatch layers override the default routing: `LAYERS.FORCE_OPAQUE`
93
+ * draws the object as a depth-writing opaque occluder (its material is temporarily
94
+ * forced to `depthWrite=true, transparent=false`); `LAYERS.OIT_EXCLUDED` also draws it
95
+ * in the opaque pass but leaves the material's own properties untouched.
96
+ * Additive/glow objects tagged with the `LAYERS.EMISSIVE` layer are drawn between the
97
+ * opaque and transparent layers (so transparent surfaces in front attenuate them);
98
+ * always-on-top objects tagged with the `LAYERS.OVERLAY` layer are drawn last, on top
99
+ * of the resolved transparency. While this pass is active it sets the per-canvas
100
+ * rendering state to `'oit'` so components can disable conflicting self-transparency
101
+ * workarounds.
102
+ *
103
+ * @example
104
+ * ```tsx
105
+ * const passes = useMemo(
106
+ * () => [new OITRenderPass(scene, camera), new OutputPass()],
107
+ * [scene, camera],
108
+ * );
109
+ * return <RenderingPipeline passes={passes} />;
110
+ * ```
111
+ *
112
+ * @group Rendering
113
+ * @see {@link RenderingPipeline}
114
+ * @see {@link makeOitCompatible}
115
+ */
116
+ export declare class OITRenderPass extends Pass {
117
+ private scene;
118
+ private camera;
119
+ /**
120
+ * Debug: when true, the exact depth-peeled front layer is disabled and every
121
+ * transparent fragment is resolved through the weighted-blended (WBOIT) tail.
122
+ * Useful for isolating tail behaviour and comparing against the hybrid result.
123
+ */
124
+ skipFront: boolean;
125
+ /**
126
+ * Optional feature (default off): after the transparent OIT passes, stamp depth
127
+ * for transparent surfaces wherever their own alpha is at least
128
+ * {@link occlusionDepthThreshold}. Transparent surfaces normally write no depth, so
129
+ * annotation labels behind a high-but-not-full opacity surface are never occluded;
130
+ * enabling this makes a surface occlude labels once its alpha clears the threshold.
131
+ *
132
+ * The test is per-fragment and per-surface (each surface judged on its own alpha,
133
+ * not accumulated coverage), and the stamped depth uses the same encoding the
134
+ * {@link AnnotationsPass} already samples. Costs one extra transparent-geometry
135
+ * pass per frame when enabled; nothing (not even a shader compile) when off.
136
+ */
137
+ occlusionDepthStamp: boolean;
138
+ /** Alpha threshold (0..1) for {@link occlusionDepthStamp}. Default 0.5. */
139
+ occlusionDepthThreshold: number;
140
+ /**
141
+ * Optional feature (default off): stamp depth for emissive/glow emitters (objects
142
+ * on `LAYERS.EMISSIVE`) wherever their fragment strength is at least
143
+ * {@link emitterDepthThreshold}, drawn before the transparent OIT passes. This lets
144
+ * the dense core of an additive emitter (e.g. perforation jets) occlude transparent
145
+ * surfaces behind it, preventing the wash-out where a far transparent surface would
146
+ * otherwise dim the emitter. Surfaces in front still attenuate it.
147
+ *
148
+ * An emitter opts in by exposing a depth-only stamp material on its material's
149
+ * `userData.occlusionDepthMaterial` (with a `uOcclusionThreshold` uniform the pass
150
+ * drives). Emitters without one are simply skipped. Costs one extra emissive pass
151
+ * per frame when enabled; nothing when off.
152
+ */
153
+ emitterDepthStamp: boolean;
154
+ /** Strength threshold (0..1) for {@link emitterDepthStamp}. Default 0.5. */
155
+ emitterDepthThreshold: number;
156
+ /**
157
+ * When true, draws small thumbnails of the internal render targets (min-depth,
158
+ * accumulation) into the bottom-left of the output, for debugging.
159
+ * GPU-only; no pixel readback.
160
+ */
161
+ debugTargets: boolean;
162
+ /**
163
+ * When true, measures per-segment GPU time (opaque/emissive/min-depth/tail/
164
+ * composite/front/overlay) via timer queries and exposes it on {@link timings}. Adds a
165
+ * little CPU/driver overhead and lags a few frames, so it is off by default. No-op
166
+ * on platforms without `EXT_disjoint_timer_query_webgl2`.
167
+ *
168
+ * The most relevant figure for the transparent-geometry cost is
169
+ * {@link OITRenderPassTimings.tail}.
170
+ */
171
+ profile: boolean;
172
+ /**
173
+ * Per-segment GPU timings (ms) from the last completed measurement. Only updated
174
+ * while {@link profile} is enabled. `-1` means "no result yet" or unsupported.
175
+ */
176
+ readonly timings: OITRenderPassTimings;
177
+ /**
178
+ * Per-frame object counts for each pass, updated every {@link render}. Useful for
179
+ * verifying which objects are routed through OIT vs. drawn opaque/overlay.
180
+ */
181
+ readonly stats: OITRenderPassStats;
182
+ /**
183
+ * Resource/accumulation counters for leak monitoring, updated every {@link render}.
184
+ * See {@link OITRenderPassResources}.
185
+ */
186
+ readonly resources: OITRenderPassResources;
187
+ private fullscreenRenderer;
188
+ private minDepthTarget;
189
+ private accumTarget;
190
+ private compositeMaterial;
191
+ /** Lazily-created material for the debug-target thumbnails. */
192
+ private debugMaterial;
193
+ /** Lazily-created GPU timer, only when {@link profile} is first enabled. */
194
+ private gpuTimer;
195
+ /**
196
+ * OIT pipeline registration release handle. Acquired lazily on the first
197
+ * {@link render} rather than in the constructor: the host (e.g. a `useMemo`) may
198
+ * construct passes that React then discards without ever committing/rendering them,
199
+ * and a constructor-time acquire on such an orphan would never be released. Only
200
+ * committed passes are rendered, so acquiring here keeps the registration count
201
+ * symmetric with {@link dispose}.
202
+ */
203
+ private releaseOit?;
204
+ private entryCache;
205
+ /** Monotonic count of classification entries created (cache misses). */
206
+ private entriesCreated;
207
+ /** Saved material state for OIT objects temporarily forced opaque this frame. */
208
+ private forcedOpaque;
209
+ private width;
210
+ private height;
211
+ private depthFar;
212
+ constructor(scene: Scene, camera: Camera);
213
+ setSize(width: number, height: number): void;
214
+ dispose(): void;
215
+ private getEntry;
216
+ /**
217
+ * Traverse the scene once, classifying renderables into transparent-OIT,
218
+ * plain-opaque, emissive (additive/glow) and always-on-top overlay sets.
219
+ * OIT-capable objects that are currently fully opaque, or explicitly tagged with
220
+ * the `LAYERS.FORCE_OPAQUE` layer, are added to both `opaqueList` (for the
221
+ * visibility lifecycle) and `oitOpaqueList` (so their materials can be forced
222
+ * depth-writing), making them real occluders. Objects tagged `LAYERS.OIT_EXCLUDED`
223
+ * are added to `opaqueList` only, so they render with their material untouched.
224
+ * Emissive objects are detected by the EMISSIVE layer, overlay objects by the
225
+ * OVERLAY layer.
226
+ */
227
+ private collect;
228
+ /**
229
+ * Prepare the OIT renderables for the opaque pass. Objects whose whole material
230
+ * is OIT-capable are simply hidden (and collected into `hidden` for restore), so
231
+ * their geometry isn't rasterised at all. Mixed multi-material meshes are swapped
232
+ * to their opaque variant (opaque groups kept, OIT groups drawn as no-op).
233
+ */
234
+ private applyOpaqueSwap;
235
+ private applyPassSwap;
236
+ private restoreMaterials;
237
+ private setOitUniforms;
238
+ private setVisible;
239
+ /**
240
+ * Resolve the opt-in depth-stamp material for an emissive emitter, if any. The
241
+ * emitter exposes it on `material.userData.occlusionDepthMaterial`; this also drives
242
+ * its `uOcclusionThreshold` uniform from {@link emitterDepthThreshold}. Returns null
243
+ * when the emitter provides no stamp material (it is then skipped).
244
+ */
245
+ private getEmitterStamp;
246
+ /**
247
+ * Current effective opacity of a material. `ShaderMaterial`s drive opacity through
248
+ * a `uniforms.opacity` value (the material's own `opacity` field is often left at
249
+ * 1), so prefer that; otherwise use `Material.opacity`.
250
+ */
251
+ private static effectiveOpacity;
252
+ /** Whether a material currently renders as fully opaque. */
253
+ private static isMaterialOpaque;
254
+ /**
255
+ * Whether an OIT entry is currently fully opaque (every OIT-capable material is
256
+ * opaque). Such objects are drawn in the opaque pass as real occluders instead of
257
+ * being routed through the (more expensive, depth-non-writing) OIT passes.
258
+ */
259
+ private isEntryOpaque;
260
+ /**
261
+ * Temporarily force the OIT-capable materials of the given entries to write depth
262
+ * and render opaque, so they act as genuine occluders during the opaque pass. The
263
+ * previous state is saved and restored by {@link restoreForcedOpaque}. These
264
+ * objects are hidden during the OIT sub-passes, so the forced state only takes
265
+ * effect where intended.
266
+ */
267
+ private applyForcedOpaque;
268
+ private restoreForcedOpaque;
269
+ /**
270
+ * Copy the latest smoothed GPU timings out of the timer into {@link timings} and
271
+ * recompute the `total`. Segments without a result yet (or skipped this frame)
272
+ * report `-1` and are excluded from the total.
273
+ */
274
+ private updateTimings;
275
+ render(renderer: WebGLRenderer, buffer: WebGLRenderTarget): void;
276
+ /**
277
+ * Draw small thumbnails of the auxiliary render targets along the bottom-left of
278
+ * the output buffer (min-depth, accumulation). Uses the buffer's viewport
279
+ * to scope each draw; GPU-only.
280
+ */
281
+ private renderDebugTargets;
282
+ }
@@ -0,0 +1,10 @@
1
+ import { MeshBasicMaterial, WebGLRenderer, WebGLRenderTarget } from 'three';
2
+ import { FullscreenRenderer } from '../fullscreen-renderer';
3
+ import { Pass } from '../Pass';
4
+ export declare class OutputPass extends Pass {
5
+ fullscreenRenderer: FullscreenRenderer;
6
+ material: MeshBasicMaterial;
7
+ constructor();
8
+ render(renderer: WebGLRenderer, buffer: WebGLRenderTarget): void;
9
+ dispose(): void;
10
+ }
@@ -0,0 +1,8 @@
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
+ constructor(scene: Scene, camera: Camera);
7
+ render(renderer: WebGLRenderer, buffer: WebGLRenderTarget): void;
8
+ }
@@ -0,0 +1,40 @@
1
+ import { Vector2, WebGLRenderer, WebGLRenderTarget } from 'three';
2
+ import { Pass } from '../Pass';
3
+ /**
4
+ * Subpixel Morphological Anti-Aliasing (SMAA) post-process pass for use with the
5
+ * {@link RenderingPipeline}. A drop-in alternative to {@link FxaaPass}: it detects
6
+ * edges by colour discontinuity and reconstructs anti-aliased silhouettes using
7
+ * precomputed area/search lookup tables, giving noticeably cleaner long edges on
8
+ * opaque geometry than FXAA, with less detail blurring.
9
+ *
10
+ * SMAA operates in linear space and must run before the {@link OutputPass} (i.e.
11
+ * before tone-mapping / output-encoding), exactly like {@link FxaaPass}.
12
+ *
13
+ * Like all morphological techniques it cannot recover sub-pixel features (e.g.
14
+ * 1px WebGL lines that fall between samples) — use {@link TAAPass} for those.
15
+ *
16
+ * This wraps the well-tested SMAA shaders and lookup textures from `three-stdlib`
17
+ * and drives the three sub-passes (edge detection, blend-weight calculation,
18
+ * neighbourhood blending) through the pipeline's {@link FullscreenRenderer},
19
+ * compositing the result back into the shared buffer in place.
20
+ *
21
+ * @group Rendering
22
+ * @see {@link RenderingPipeline}
23
+ * @see {@link FxaaPass}
24
+ * @see {@link TAAPass}
25
+ */
26
+ export declare class SMAAPass extends Pass {
27
+ private inner;
28
+ private scratch;
29
+ private blitMaterial;
30
+ private fullscreenRenderer;
31
+ private materialEdges;
32
+ private materialWeights;
33
+ private materialBlend;
34
+ constructor();
35
+ setSize(width: number, height: number): void;
36
+ dispose(): void;
37
+ render(renderer: WebGLRenderer, buffer: WebGLRenderTarget): void;
38
+ /** Resolution uniform helper kept for parity with other passes. */
39
+ get resolution(): Vector2;
40
+ }
@@ -0,0 +1,94 @@
1
+ import { Camera, WebGLRenderer, WebGLRenderTarget } from 'three';
2
+ import { Pass } from '../Pass';
3
+ /**
4
+ * Temporal Anti-Aliasing pass (jittered accumulation) for use with the
5
+ * {@link RenderingPipeline}.
6
+ *
7
+ * Each frame the camera's projection is offset by a sub-pixel jitter from a
8
+ * Halton(2,3) sequence and the freshly rendered buffer is accumulated into a
9
+ * history target as a running average. Because the 1px-line problem with
10
+ * supersampling is that the line stays one device-pixel wide as the buffer
11
+ * grows, jittered accumulation is the technique that *does* anti-alias thin
12
+ * features: the same 1px line lands on slightly different sub-pixel positions
13
+ * each frame, so the average is coverage-weighted without thinning.
14
+ *
15
+ * The accumulation resets whenever the (un-jittered) camera view changes, so an
16
+ * orbit-and-inspect workflow converges to near-supersampled quality within a
17
+ * handful of static frames. Once the full jitter sequence has accumulated the
18
+ * pass freezes (no further jitter or blending) and presents the converged image
19
+ * until the next camera move, so a still camera settles to a stable result.
20
+ * Place it where you would place {@link FxaaPass} — before the {@link OutputPass}.
21
+ *
22
+ * Limitations (no history reprojection / neighbourhood clamping): animated
23
+ * content that moves while the camera is static (e.g. additive jet streams) does
24
+ * not update once the image has converged and frozen, and ghosts before then.
25
+ * Camera motion itself never ghosts because it triggers a reset.
26
+ *
27
+ * @todo Improve TAA. Current trade-offs to address: (1) AA is only present once
28
+ * the camera settles — during motion the image is un-anti-aliased and it takes
29
+ * roughly a second of stillness to converge; (2) because the pass freezes on
30
+ * convergence, content that changes while the camera is static (a highlight
31
+ * toggled on, async geometry finishing loading) does not appear until the next
32
+ * camera move. A proper fix needs motion vectors + history reprojection +
33
+ * neighbourhood colour clamping so the history can be reused under motion and
34
+ * invalidated per-pixel on content change, rather than the all-or-nothing
35
+ * reset-on-camera-move + freeze-on-convergence heuristic used here. Likely
36
+ * revisited as part of the WebGPU/TSL renderer migration.
37
+ *
38
+ * @group Rendering
39
+ * @see {@link RenderingPipeline}
40
+ * @see {@link FxaaPass}
41
+ * @see {@link SMAAPass}
42
+ */
43
+ export declare class TAAPass extends Pass {
44
+ private camera;
45
+ /**
46
+ * Number of unique jitter samples to cycle through before the average is
47
+ * considered fully converged. Higher = smoother but slower to settle.
48
+ */
49
+ sampleCount: number;
50
+ private historyRead;
51
+ private historyWrite;
52
+ private resolveMaterial;
53
+ private blitMaterial;
54
+ private fullscreenRenderer;
55
+ private width;
56
+ private height;
57
+ /** Index into the jitter sequence for the current frame. */
58
+ private sampleIndex;
59
+ /** How many frames have been accumulated since the last reset. */
60
+ private accumulated;
61
+ /** Jitter (in clip-space units) currently baked into the camera projection. */
62
+ private appliedJitterX;
63
+ private appliedJitterY;
64
+ /** Snapshot of the previous frame's camera state used to detect motion. The
65
+ * view matrix and the projection are stored separately so the two projection
66
+ * elements we jitter can be excluded from the comparison (see `detectMotion`). */
67
+ private prevView;
68
+ private prevProjection;
69
+ private hasPrev;
70
+ constructor(camera: Camera, sampleCount?: number);
71
+ setSize(width: number, height: number): void;
72
+ dispose(): void;
73
+ /** Force the accumulation to restart on the next frame. */
74
+ reset(): void;
75
+ /** Indices into the projection matrix offset elements for the active camera. */
76
+ private jitterElements;
77
+ private clearJitter;
78
+ private applyJitter;
79
+ /**
80
+ * Compare the current camera against the previous frame and reset the
81
+ * accumulation on any real view change (orbit, pan, zoom, fov).
82
+ *
83
+ * Motion is measured from the camera's view matrix (`matrixWorldInverse`,
84
+ * which we never touch) and its projection matrix *excluding* the two elements
85
+ * we jitter (`ex`/`ey`). This is critical: deriving motion from a quantity that
86
+ * includes our own sub-pixel jitter — or trying to subtract the jitter back out
87
+ * of the projection — couples the test to the jitter and makes every frame look
88
+ * like motion (the jitter delta dwarfs the tolerance), so the accumulation
89
+ * resets forever and the image never settles. By ignoring the jittered slots
90
+ * outright, only genuine camera changes trigger a reset.
91
+ */
92
+ private detectMotion;
93
+ render(renderer: WebGLRenderer, buffer: WebGLRenderTarget): void;
94
+ }
@@ -0,0 +1,6 @@
1
+ export * from './FXAAPass';
2
+ export * from './OITRenderPass';
3
+ export * from './OutputPass';
4
+ export * from './RenderPass';
5
+ export * from './SMAAPass';
6
+ export * from './TAAPass';
@@ -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;
@@ -11,7 +11,9 @@ export * from './geometries/curve/curve-3d';
11
11
  export * from './geometries/curve/tube-geometry';
12
12
  export * from './geometries/delatin';
13
13
  export * from './geometries/fence';
14
+ export * from './geometries/geometry';
14
15
  export * from './geometries/packing';
16
+ export * from './geometries/planar-geometry';
15
17
  export * from './geometries/triangulate-grid';
16
18
  export * from './geometries/triangulate-grid-delaunay';
17
19
  export * from './managers/CameraManager';
@@ -13,3 +13,26 @@ export declare function createNormalTexture(buffer: Uint8Array, width: number, h
13
13
  * Create a data texture from RGBA encoded depth values
14
14
  */
15
15
  export declare function createElevationTexture(buffer: Float32Array, width: number, height: number): DataTexture;
16
+ /**
17
+ * Compute geometric surface normals from an elevation grid, encoded as a compact
18
+ * RG8 buffer (2 bytes/texel) using a hemisphere encoding: only the grid-local
19
+ * `x` and `z` components are stored (mapped to [0, 1]); the consumer reconstructs
20
+ * `y = sqrt(1 - x^2 - z^2)`.
21
+ *
22
+ * This replicates the per-fragment normal that `SurfaceMaterial`'s shader derives
23
+ * from the elevation texture (same four diagonal neighbours, cross products and
24
+ * hole handling), but pays the cost once on the CPU instead of in every OIT pass.
25
+ * The result is laid out to match the elevation buffer (row-major, intended for a
26
+ * `flipY = true` texture), so it samples 1:1 with the same grid UVs.
27
+ *
28
+ * @param data elevation values (row-major, holes < 0)
29
+ * @param columns number of columns (nx)
30
+ * @param rows number of rows (ny)
31
+ * @param xScale column spacing (xinc)
32
+ * @param yScale row spacing (yinc)
33
+ */
34
+ export declare function computeSurfaceNormalsRG(data: Float32Array, columns: number, rows: number, xScale: number, yScale: number): Uint8Array<ArrayBuffer>;
35
+ /**
36
+ * Create an RG8 data texture from a buffer produced by {@link computeSurfaceNormalsRG}.
37
+ */
38
+ export declare function createPackedNormalTexture(buffer: Uint8Array, width: number, height: number): DataTexture;
@@ -8,5 +8,8 @@ export declare const PI8: number;
8
8
  * Given a 2D rectangle and an angle off the center, find the point
9
9
  * of the closest corner. Used for anchoring connector lines
10
10
  * to annotation labels.
11
+ *
12
+ * Pass an optional `target` array to write the result into, avoiding
13
+ * an allocation in hot paths.
11
14
  */
12
- export declare function edgeOfRectangle(rect: Vec2, theta: number): Vec2;
15
+ export declare function edgeOfRectangle(rect: Vec2, theta: number, target?: Vec2): Vec2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/videx-3d",
3
- "version": "1.1.0",
3
+ "version": "2.0.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",