@equinor/videx-3d 1.1.1 → 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.
- package/README.md +120 -120
- package/dist/chunk-61X6qE5N.js +981 -0
- package/dist/chunk-ChG5d4HC.js +675 -0
- package/dist/{chunk-BlPg4RjP.js → chunk-M-Pcc_Yg.js} +19 -19
- package/dist/generators.js +271 -260
- package/dist/main.js +4919 -3344
- package/dist/sdk.js +92 -90
- package/dist/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/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/generators/surface-generator.d.ts +1 -1
- package/dist/types/layers/layers.d.ts +4 -0
- package/dist/types/rendering/OitMaterial.d.ts +59 -0
- package/dist/types/rendering/Pass.d.ts +7 -0
- package/dist/types/rendering/RenderingPipeline.d.ts +37 -0
- package/dist/types/rendering/fullscreen-renderer.d.ts +1 -0
- package/dist/types/rendering/gpu-timer.d.ts +46 -0
- package/dist/types/rendering/index.d.ts +7 -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} +13 -4
- package/dist/types/rendering/passes/FXAAPass.d.ts +12 -0
- package/dist/types/rendering/passes/OITRenderPass.d.ts +282 -0
- package/dist/types/rendering/passes/OutputPass.d.ts +10 -0
- package/dist/types/rendering/passes/RenderPass.d.ts +8 -0
- package/dist/types/rendering/passes/SMAAPass.d.ts +40 -0
- package/dist/types/rendering/passes/TAAPass.d.ts +94 -0
- package/dist/types/rendering/passes/index.d.ts +6 -0
- package/dist/types/rendering/rendering-state.d.ts +59 -0
- package/dist/types/sdk/utils/elevation-map.d.ts +23 -0
- package/dist/types/sdk/utils/trigonometry.d.ts +4 -1
- package/package.json +1 -1
- package/dist/chunk-CnY6Tmof.js +0 -358
- package/dist/chunk-iY0wQ9Z6.js +0 -887
- package/dist/types/rendering/render-passes.d.ts +0 -16
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { WebGLRenderer } from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* Tiny GPU timer for WebGL2 built on `EXT_disjoint_timer_query_webgl2`.
|
|
4
|
+
*
|
|
5
|
+
* DEBUG-ONLY instrumentation: it brackets named, non-overlapping segments with
|
|
6
|
+
* `TIME_ELAPSED` queries and reads the results back asynchronously (a few frames
|
|
7
|
+
* later), reporting a smoothed millisecond figure per segment. Because the GPU runs
|
|
8
|
+
* behind the CPU, results are never available the same frame they are issued, so a
|
|
9
|
+
* small ring of queries per segment is kept in flight.
|
|
10
|
+
*
|
|
11
|
+
* Only one timer query can be active at a time per spec, so {@link begin}/{@link end}
|
|
12
|
+
* calls must be strictly sequential (never nested). All methods are no-ops when the
|
|
13
|
+
* extension is unavailable (older browsers, or the WebGPU renderer), so call sites
|
|
14
|
+
* can leave instrumentation in place unconditionally.
|
|
15
|
+
*
|
|
16
|
+
* This is measurement only — it issues no draws and mutates no render state — so it
|
|
17
|
+
* does not affect the rendered result and is safe to leave compiled in behind a flag.
|
|
18
|
+
*
|
|
19
|
+
* @group Rendering
|
|
20
|
+
*/
|
|
21
|
+
export declare class GpuTimer {
|
|
22
|
+
private gl;
|
|
23
|
+
private ext;
|
|
24
|
+
private segments;
|
|
25
|
+
private pool;
|
|
26
|
+
private active;
|
|
27
|
+
private activeSeg;
|
|
28
|
+
/** Whether GPU timing is available in this context. */
|
|
29
|
+
get supported(): boolean;
|
|
30
|
+
constructor(renderer: WebGLRenderer);
|
|
31
|
+
/** Begin timing a segment. No-op if unsupported or another segment is active. */
|
|
32
|
+
begin(label: string): void;
|
|
33
|
+
/** End timing the current segment. */
|
|
34
|
+
end(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Harvest finished queries and update the smoothed timings. Call once per frame
|
|
37
|
+
* (e.g. at the top of the host pass's render). Disjoint frames (GPU context
|
|
38
|
+
* disruption) are discarded.
|
|
39
|
+
*/
|
|
40
|
+
poll(): void;
|
|
41
|
+
/** Smoothed elapsed milliseconds for a segment, or -1 if no result yet. */
|
|
42
|
+
get(label: string): number;
|
|
43
|
+
/** Snapshot of every segment's smoothed timing in milliseconds. */
|
|
44
|
+
snapshot(): Record<string, number>;
|
|
45
|
+
dispose(): void;
|
|
46
|
+
}
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
export * from './fullscreen-renderer';
|
|
2
|
-
export * from './
|
|
2
|
+
export * from './gpu-timer';
|
|
3
|
+
export * from './oit-material';
|
|
4
|
+
export * from './OitMaterial';
|
|
5
|
+
export * from './Pass';
|
|
6
|
+
export * from './passes';
|
|
7
|
+
export * from './rendering-state';
|
|
8
|
+
export * from './RenderingPipeline';
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { IUniform, Material, ShaderMaterial, Side, Texture, Vector2 } from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* The OIT render passes a material provides a variant for.
|
|
4
|
+
* - `depthMin`: min view-space linear depth pre-pass (front-layer detection)
|
|
5
|
+
* - `accum`: single-buffer weighted-blended OIT tail (b-weighted, carries coverage)
|
|
6
|
+
* - `front`: exact depth-peeled front layer (alpha-over)
|
|
7
|
+
* - `occlusion`: optional depth-only stamp that writes depth where the surface's own
|
|
8
|
+
* alpha clears `oitOcclusionThreshold` (used to occlude annotation labels). Off by
|
|
9
|
+
* default; its program is only compiled by Three when the pass actually renders it.
|
|
10
|
+
*/
|
|
11
|
+
export type OitPass = 'depthMin' | 'accum' | 'front' | 'occlusion';
|
|
12
|
+
/** The set of per-pass variant materials used by the OITRenderPass. */
|
|
13
|
+
export type OitVariants = Record<OitPass, Material>;
|
|
14
|
+
/** The OIT uniforms shared across a material's variants and set by the pass. */
|
|
15
|
+
export type OitUniforms = {
|
|
16
|
+
oitDepthFar: IUniform<number>;
|
|
17
|
+
oitScreenSize: IUniform<Vector2>;
|
|
18
|
+
oitMinDepthTexture: IUniform<Texture | null>;
|
|
19
|
+
oitSkipFront: IUniform<number>;
|
|
20
|
+
oitOcclusionThreshold: IUniform<number>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* A material that can participate in the {@link OITRenderPass} hybrid pipeline.
|
|
24
|
+
* Implemented by library materials (via {@link attachOitVariants}) and by patched
|
|
25
|
+
* stock / user materials (via {@link makeOitCompatible}).
|
|
26
|
+
*/
|
|
27
|
+
export interface OitCapableMaterial {
|
|
28
|
+
/** Returns the lazily-built per-pass variant materials (shared uniforms). */
|
|
29
|
+
getOitVariants(): OitVariants;
|
|
30
|
+
/** Returns the OIT uniforms object the pass updates each frame. */
|
|
31
|
+
getOitUniforms(): OitUniforms;
|
|
32
|
+
}
|
|
33
|
+
/** Options for making a material OIT-compatible. */
|
|
34
|
+
export type OitMaterialOptions = {
|
|
35
|
+
/**
|
|
36
|
+
* Force a specific `side` on all variants (e.g. `DoubleSide` for surfaces so back
|
|
37
|
+
* faces contribute to the tail). Defaults to the base material's side.
|
|
38
|
+
*/
|
|
39
|
+
side?: Side;
|
|
40
|
+
/**
|
|
41
|
+
* Names of properties on the material that hold uniform containers (objects of
|
|
42
|
+
* `IUniform`) which should be shared *by reference* with each per-pass variant.
|
|
43
|
+
* `ShaderMaterial` variants already share `uniforms`, but non-`ShaderMaterial`
|
|
44
|
+
* materials are cloned, so any custom uniform object they read in
|
|
45
|
+
* `onBeforeCompile` (e.g. a `uniforms` field used for slicing) must be listed
|
|
46
|
+
* here for live per-frame updates to reach the variants.
|
|
47
|
+
*/
|
|
48
|
+
shareUniforms?: string[];
|
|
49
|
+
/**
|
|
50
|
+
* Names of **value** properties to keep in sync from the base material onto the
|
|
51
|
+
* per-pass variants every frame. Only relevant for stock/built-in materials, whose
|
|
52
|
+
* variants are *cloned* and would otherwise snapshot their appearance at build time
|
|
53
|
+
* (`ShaderMaterial` variants share `uniforms` and are always live, so this is
|
|
54
|
+
* ignored for them).
|
|
55
|
+
*
|
|
56
|
+
* Restricted to value properties that do **not** affect the compiled program:
|
|
57
|
+
* - primitives (e.g. `metalness`, `roughness`, `emissiveIntensity`), and
|
|
58
|
+
* - copyable value objects with a `.copy()` method (e.g. `color`, `emissive` —
|
|
59
|
+
* `Color`; or `Vector2/3/4`), which are copied in place (no allocation, no
|
|
60
|
+
* recompile).
|
|
61
|
+
*
|
|
62
|
+
* Do **not** list program-affecting properties here (textures such as `map`,
|
|
63
|
+
* `vertexColors`, anything that toggles a shader `#define`) — changing those needs
|
|
64
|
+
* a recompile and is intentionally unsupported through this fast path. `opacity` is
|
|
65
|
+
* always kept live and need not be listed. Use {@link COMMON_OIT_SYNC_PROPS} for a
|
|
66
|
+
* sensible default set.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* makeOitCompatible(material, { syncProperties: ['color', 'metalness'] });
|
|
71
|
+
* // or spread the common set:
|
|
72
|
+
* makeOitCompatible(material, { syncProperties: [...COMMON_OIT_SYNC_PROPS] });
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
syncProperties?: string[];
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* A convenient default set of common appearance properties to pass as
|
|
79
|
+
* {@link OitMaterialOptions.syncProperties} so runtime changes (e.g. recoloring) are
|
|
80
|
+
* reflected through the OIT passes for cloned built-in materials. Properties not
|
|
81
|
+
* present on a given material are ignored.
|
|
82
|
+
*
|
|
83
|
+
* @group Rendering
|
|
84
|
+
*/
|
|
85
|
+
export declare const COMMON_OIT_SYNC_PROPS: readonly ["color", "emissive", "emissiveIntensity", "metalness", "roughness"];
|
|
86
|
+
/** Type guard for {@link OitCapableMaterial}. */
|
|
87
|
+
export declare function isOitCapable(material: Material | null | undefined): material is Material & OitCapableMaterial;
|
|
88
|
+
/**
|
|
89
|
+
* Make a library `ShaderMaterial` OIT-capable. The material's fragment shader is
|
|
90
|
+
* expected to already `#include` `oit.glsl` and call `oitProcess(gl_FragColor)`
|
|
91
|
+
* guarded by `#ifdef USE_OIT` (a no-op in the default pipeline). This adds the OIT
|
|
92
|
+
* uniforms to the material and attaches the per-pass variant machinery.
|
|
93
|
+
*
|
|
94
|
+
* @param material - the library ShaderMaterial to extend
|
|
95
|
+
* @param options - optional overrides (e.g. `side`)
|
|
96
|
+
* @returns the same material, typed as {@link OitCapableMaterial}
|
|
97
|
+
*
|
|
98
|
+
* @group Rendering
|
|
99
|
+
* @see {@link makeOitCompatible}
|
|
100
|
+
*/
|
|
101
|
+
export declare function attachOitVariants<T extends ShaderMaterial>(material: T, options?: OitMaterialOptions): T & OitCapableMaterial;
|
|
102
|
+
/**
|
|
103
|
+
* Make any stock Three.js material or user-authored material OIT-compatible by
|
|
104
|
+
* patching its shaders at compile time (via `onBeforeCompile`) to include the OIT
|
|
105
|
+
* logic, and attaching the per-pass variant machinery.
|
|
106
|
+
*
|
|
107
|
+
* Works with lit built-in materials (which provide `vViewPosition`) and with
|
|
108
|
+
* materials lacking it (e.g. `LineBasicMaterial`), in which case `vViewPosition` is
|
|
109
|
+
* injected automatically. All injected code is guarded by `#ifdef USE_OIT`, so the
|
|
110
|
+
* base program is unchanged outside the OIT pipeline.
|
|
111
|
+
*
|
|
112
|
+
* Note: targets materials compiled by Three.js (built-ins, `ShaderMaterial`). Raw
|
|
113
|
+
* `RawShaderMaterial` (no Three.js shader prelude) is not auto-patched.
|
|
114
|
+
*
|
|
115
|
+
* @param material - the material to patch
|
|
116
|
+
* @param options - optional overrides (e.g. `side`)
|
|
117
|
+
* @returns the same material, typed as {@link OitCapableMaterial}
|
|
118
|
+
*
|
|
119
|
+
* @group Rendering
|
|
120
|
+
* @see {@link attachOitVariants}
|
|
121
|
+
*/
|
|
122
|
+
export declare function makeOitCompatible<T extends Material>(material: T, options?: OitMaterialOptions): T & OitCapableMaterial;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Camera, CanvasTexture, Clock, PerspectiveCamera, ShaderMaterial, Vector2, WebGLRenderer, WebGLRenderTarget } from 'three';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
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
|
+
}
|