@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.
- package/README.md +120 -120
- package/dist/chunk-DKAquGKk.js +2820 -0
- package/dist/chunk-DsUZyEG_.js +16 -0
- package/dist/generators.js +512 -716
- package/dist/main.js +6909 -8947
- package/dist/sdk.js +2 -785
- package/dist/src/sdk/materials/shaderLib/oit.glsl +106 -0
- package/dist/types/components/Annotations/AutoUpdate.d.ts +1 -1
- package/dist/types/components/Annotations/index.d.ts +2 -2
- package/dist/types/components/Annotations/types.d.ts +3 -1
- package/dist/types/components/Annotations/update-annotations.d.ts +10 -0
- package/dist/types/components/EventEmitter/picking-helper.d.ts +23 -1
- package/dist/types/components/Ocean/Ocean.d.ts +333 -0
- package/dist/types/components/Ocean/index.d.ts +6 -0
- package/dist/types/components/Ocean/ocean-bed-material.d.ts +60 -0
- package/dist/types/components/Ocean/ocean-contact.d.ts +39 -0
- package/dist/types/components/Ocean/ocean-material.d.ts +145 -0
- package/dist/types/components/Ocean/ocean-sampler.d.ts +93 -0
- package/dist/types/components/Ocean/ocean-volume-material.d.ts +54 -0
- package/dist/types/components/Surfaces/Surface.d.ts +8 -1
- package/dist/types/components/Surfaces/SurfaceMaterial.d.ts +3 -0
- package/dist/types/components/Surfaces/surface-defs.d.ts +1 -0
- package/dist/types/components/Tanker/Tanker.d.ts +47 -0
- package/dist/types/components/Tanker/TankerSuperstructure.d.ts +23 -0
- package/dist/types/components/Tanker/tanker-geometry-builder.d.ts +21 -0
- package/dist/types/generators/surface-generator.d.ts +1 -1
- package/dist/types/layers/layers.d.ts +4 -0
- package/dist/types/main.d.ts +1 -0
- package/dist/types/rendering/OitMaterial.d.ts +59 -0
- package/dist/types/rendering/Pass.d.ts +16 -0
- package/dist/types/rendering/RenderingPipeline.d.ts +46 -0
- package/dist/types/rendering/debug/DebugBoxOutputPass.d.ts +22 -0
- package/dist/types/rendering/debug/DebugPatternPass.d.ts +30 -0
- package/dist/types/rendering/fullscreen-renderer.d.ts +1 -0
- package/dist/types/rendering/fxaa-resolver.d.ts +25 -0
- package/dist/types/rendering/gpu-timer.d.ts +46 -0
- package/dist/types/rendering/index.d.ts +8 -1
- package/dist/types/rendering/oit-material.d.ts +122 -0
- package/dist/types/{components/Annotations/annotations-renderer.d.ts → rendering/passes/AnnotationsPass.d.ts} +14 -4
- package/dist/types/rendering/passes/FXAAPass.d.ts +17 -0
- package/dist/types/rendering/passes/OITRenderPass.d.ts +429 -0
- package/dist/types/rendering/passes/OutputPass.d.ts +19 -0
- package/dist/types/rendering/passes/RenderPass.d.ts +10 -0
- package/dist/types/rendering/passes/index.d.ts +4 -0
- package/dist/types/rendering/rendering-state.d.ts +59 -0
- package/dist/types/rendering/smaa-resolver.d.ts +58 -0
- package/dist/types/rendering/taa-resolver.d.ts +161 -0
- package/dist/types/rendering/temporal-resolver.d.ts +152 -0
- package/dist/types/sdk/geometries/boundary-loops.d.ts +38 -0
- package/dist/types/sdk/geometries/geometry-attributes.d.ts +37 -0
- package/dist/types/sdk/geometries/grid-sampling.d.ts +50 -0
- package/dist/types/sdk/geometries/ocean-geometry.d.ts +288 -0
- package/dist/types/sdk/geometries/packing.d.ts +1 -1
- package/dist/types/sdk/geometries/tessellation.d.ts +25 -0
- package/dist/types/sdk/index.d.ts +5 -0
- package/dist/types/sdk/utils/elevation-map.d.ts +23 -0
- package/dist/types/sdk/utils/trigonometry.d.ts +4 -1
- package/dist/types/sdk/utils/vector-operations.d.ts +7 -0
- package/package.json +9 -10
- package/dist/chunk-BlPg4RjP.js +0 -689
- package/dist/chunk-CnY6Tmof.js +0 -358
- package/dist/chunk-DuRASjkF.js +0 -17
- package/dist/chunk-iY0wQ9Z6.js +0 -887
- package/dist/types/rendering/render-passes.d.ts +0 -16
- /package/dist/{shaderLib → src/sdk/materials/shaderLib}/color-conversion.glsl +0 -0
- /package/dist/{shaderLib → src/sdk/materials/shaderLib}/colors.glsl +0 -0
- /package/dist/{shaderLib → src/sdk/materials/shaderLib}/glyphs.glsl +0 -0
- /package/dist/{shaderLib → src/sdk/materials/shaderLib}/random.glsl +0 -0
- /package/dist/{shaderLib → src/sdk/materials/shaderLib}/remap.glsl +0 -0
- /package/dist/{shaderLib → src/sdk/materials/shaderLib}/render-number.glsl +0 -0
- /package/dist/{shaderLib → src/sdk/materials/shaderLib}/render-text.glsl +0 -0
- /package/dist/{shaderLib → src/sdk/materials/shaderLib}/rotation.glsl +0 -0
- /package/dist/{shaderLib → src/sdk/materials/shaderLib}/sdf-functions.glsl +0 -0
- /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,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
|
+
}
|