@aethervtt/shard-render 0.0.1
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/LICENSE +21 -0
- package/README.md +3 -0
- package/dist/assets.d.ts +104 -0
- package/dist/assets.js +213 -0
- package/dist/atmosphere-model.d.ts +96 -0
- package/dist/atmosphere-model.js +370 -0
- package/dist/atmosphere-nodes.d.ts +55 -0
- package/dist/atmosphere-nodes.js +780 -0
- package/dist/atmosphere-plugin.d.ts +5 -0
- package/dist/atmosphere-plugin.js +42 -0
- package/dist/atmosphere-shaders.d.ts +7 -0
- package/dist/atmosphere-shaders.js +595 -0
- package/dist/atmosphere-state.d.ts +72 -0
- package/dist/atmosphere-state.js +18 -0
- package/dist/atmosphere.d.ts +191 -0
- package/dist/atmosphere.js +950 -0
- package/dist/camera.d.ts +83 -0
- package/dist/camera.js +163 -0
- package/dist/clusters.d.ts +68 -0
- package/dist/clusters.js +288 -0
- package/dist/culling-shaders.d.ts +2 -0
- package/dist/culling-shaders.js +203 -0
- package/dist/culling.d.ts +84 -0
- package/dist/culling.js +498 -0
- package/dist/debug-shaders.d.ts +3 -0
- package/dist/debug-shaders.js +207 -0
- package/dist/debug-views.d.ts +60 -0
- package/dist/debug-views.js +197 -0
- package/dist/deferred-plugin.d.ts +5 -0
- package/dist/deferred-plugin.js +20 -0
- package/dist/deferred-shaders.d.ts +2 -0
- package/dist/deferred-shaders.js +151 -0
- package/dist/deferred.d.ts +22 -0
- package/dist/deferred.js +296 -0
- package/dist/deform.d.ts +80 -0
- package/dist/deform.js +213 -0
- package/dist/describe-plugin.d.ts +5 -0
- package/dist/describe-plugin.js +19 -0
- package/dist/display-nodes.d.ts +5 -0
- package/dist/display-nodes.js +189 -0
- package/dist/dynamic-resolution.d.ts +47 -0
- package/dist/dynamic-resolution.js +191 -0
- package/dist/environment-plugin.d.ts +6 -0
- package/dist/environment-plugin.js +44 -0
- package/dist/environment-shaders.d.ts +2 -0
- package/dist/environment-shaders.js +260 -0
- package/dist/environment-state.d.ts +71 -0
- package/dist/environment-state.js +144 -0
- package/dist/environment.d.ts +70 -0
- package/dist/environment.js +529 -0
- package/dist/forward.d.ts +123 -0
- package/dist/forward.js +1216 -0
- package/dist/fxaa.d.ts +2 -0
- package/dist/fxaa.js +65 -0
- package/dist/gizmo-font.d.ts +21 -0
- package/dist/gizmo-font.js +132 -0
- package/dist/gizmos-plugin.d.ts +5 -0
- package/dist/gizmos-plugin.js +34 -0
- package/dist/gizmos.d.ts +156 -0
- package/dist/gizmos.js +772 -0
- package/dist/gpu-assets.d.ts +114 -0
- package/dist/gpu-assets.js +494 -0
- package/dist/graph.d.ts +204 -0
- package/dist/graph.js +417 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.js +540 -0
- package/dist/instances.d.ts +349 -0
- package/dist/instances.js +1335 -0
- package/dist/large-world.d.ts +13 -0
- package/dist/large-world.js +20 -0
- package/dist/lights.d.ts +160 -0
- package/dist/lights.js +468 -0
- package/dist/material-noise.d.ts +19 -0
- package/dist/material-noise.js +7 -0
- package/dist/material-pipelines.d.ts +46 -0
- package/dist/material-pipelines.js +166 -0
- package/dist/materials.d.ts +108 -0
- package/dist/materials.js +219 -0
- package/dist/noise.d.ts +76 -0
- package/dist/noise.js +286 -0
- package/dist/overlay-registry.d.ts +18 -0
- package/dist/overlay-registry.js +30 -0
- package/dist/overlays.d.ts +35 -0
- package/dist/overlays.js +344 -0
- package/dist/paths.d.ts +20 -0
- package/dist/paths.js +46 -0
- package/dist/picking-plugin.d.ts +2 -0
- package/dist/picking-plugin.js +20 -0
- package/dist/picking.d.ts +94 -0
- package/dist/picking.js +456 -0
- package/dist/pixel-perfect-plugin.d.ts +9 -0
- package/dist/pixel-perfect-plugin.js +135 -0
- package/dist/pixel-perfect.d.ts +27 -0
- package/dist/pixel-perfect.js +70 -0
- package/dist/plugin.d.ts +111 -0
- package/dist/plugin.js +182 -0
- package/dist/pool.d.ts +19 -0
- package/dist/pool.js +43 -0
- package/dist/post-common.d.ts +51 -0
- package/dist/post-common.js +148 -0
- package/dist/post-nodes.d.ts +39 -0
- package/dist/post-nodes.js +849 -0
- package/dist/post-plugin.d.ts +5 -0
- package/dist/post-plugin.js +26 -0
- package/dist/post-shaders.d.ts +8 -0
- package/dist/post-shaders.js +698 -0
- package/dist/post.d.ts +175 -0
- package/dist/post.js +453 -0
- package/dist/readback.d.ts +4 -0
- package/dist/readback.js +95 -0
- package/dist/render-scale.d.ts +53 -0
- package/dist/render-scale.js +63 -0
- package/dist/shaders.d.ts +122 -0
- package/dist/shaders.js +1168 -0
- package/dist/shadows.d.ts +119 -0
- package/dist/shadows.js +562 -0
- package/dist/skin-asset.d.ts +26 -0
- package/dist/skin-asset.js +25 -0
- package/dist/skinning-plugin.d.ts +5 -0
- package/dist/skinning-plugin.js +16 -0
- package/dist/skinning.d.ts +19 -0
- package/dist/skinning.js +343 -0
- package/dist/standard-fields.d.ts +67 -0
- package/dist/standard-fields.js +73 -0
- package/dist/standard.d.ts +7 -0
- package/dist/standard.js +37 -0
- package/dist/stats.d.ts +25 -0
- package/dist/stats.js +18 -0
- package/dist/target.d.ts +55 -0
- package/dist/target.js +70 -0
- package/dist/testing.d.ts +34 -0
- package/dist/testing.js +126 -0
- package/dist/timer.d.ts +28 -0
- package/dist/timer.js +136 -0
- package/dist/view.d.ts +117 -0
- package/dist/view.js +389 -0
- package/dist/visibility.d.ts +10 -0
- package/dist/visibility.js +84 -0
- package/package.json +49 -0
package/dist/post.d.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { type Table } from '@aethervtt/shard-core';
|
|
2
|
+
import type { RenderView } from './graph.js';
|
|
3
|
+
import { type CameraData } from './view.js';
|
|
4
|
+
export declare const Bloom: import("@aethervtt/shard-core").ComponentDef<{
|
|
5
|
+
readonly intensity: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
6
|
+
readonly threshold: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
7
|
+
readonly knee: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
8
|
+
readonly radius: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
9
|
+
}>;
|
|
10
|
+
export declare const METERING_MODES: readonly ['average', 'center', 'spot'];
|
|
11
|
+
export declare const AutoExposure: import("@aethervtt/shard-core").ComponentDef<{
|
|
12
|
+
readonly minEv: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
13
|
+
readonly maxEv: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
14
|
+
readonly compensation: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
15
|
+
readonly speedUp: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
16
|
+
readonly speedDown: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
17
|
+
readonly metering: import("@aethervtt/shard-core").FieldType<"average" | "center" | "spot", "u8">;
|
|
18
|
+
}>;
|
|
19
|
+
export declare const DepthOfField: import("@aethervtt/shard-core").ComponentDef<{
|
|
20
|
+
readonly mode: import("@aethervtt/shard-core").FieldType<"bokeh" | "gaussian", "u8">;
|
|
21
|
+
readonly focusDistance: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
22
|
+
readonly maxBlur: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
23
|
+
}>;
|
|
24
|
+
export declare const MotionBlur: import("@aethervtt/shard-core").ComponentDef<{
|
|
25
|
+
readonly samples: import("@aethervtt/shard-core").FieldType<number, "u32">;
|
|
26
|
+
readonly maxBlur: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
27
|
+
}>;
|
|
28
|
+
export declare const ANTIALIASING_MODES: readonly ['none', 'fxaa', 'taa', 'msaa'];
|
|
29
|
+
export declare const Antialiasing: import("@aethervtt/shard-core").ComponentDef<{
|
|
30
|
+
readonly mode: import("@aethervtt/shard-core").FieldType<"fxaa" | "msaa" | "none" | "taa", "u8">;
|
|
31
|
+
}>;
|
|
32
|
+
export declare const SSAO_QUALITIES: readonly ['low', 'medium', 'high'];
|
|
33
|
+
export declare const Ssao: import("@aethervtt/shard-core").ComponentDef<{
|
|
34
|
+
readonly radius: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
35
|
+
readonly intensity: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
36
|
+
readonly quality: import("@aethervtt/shard-core").FieldType<"high" | "low" | "medium", "u8">;
|
|
37
|
+
}>;
|
|
38
|
+
export declare const Fog: import("@aethervtt/shard-core").ComponentDef<{
|
|
39
|
+
readonly color: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Color, "f32">;
|
|
40
|
+
readonly density: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
41
|
+
readonly heightFalloff: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
42
|
+
readonly start: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
43
|
+
readonly sunScattering: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
44
|
+
readonly mode: import("@aethervtt/shard-core").FieldType<"add" | "default", "u8">;
|
|
45
|
+
}>;
|
|
46
|
+
export declare const ColorGrading: import("@aethervtt/shard-core").ComponentDef<{
|
|
47
|
+
readonly temperature: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
48
|
+
readonly tint: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
49
|
+
readonly saturation: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
50
|
+
readonly contrast: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
51
|
+
readonly lift: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec3, "f32">;
|
|
52
|
+
readonly gamma: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec3, "f32">;
|
|
53
|
+
readonly gain: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec3, "f32">;
|
|
54
|
+
readonly lut: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").AssetRef<"Texture"> | null, "object">;
|
|
55
|
+
}>;
|
|
56
|
+
export declare const Vignette: import("@aethervtt/shard-core").ComponentDef<{
|
|
57
|
+
readonly intensity: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
58
|
+
readonly smoothness: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
59
|
+
}>;
|
|
60
|
+
/** Effect bits, in chain order. */
|
|
61
|
+
export declare const PostEffect: {
|
|
62
|
+
readonly Fog: 1;
|
|
63
|
+
readonly Taa: 2;
|
|
64
|
+
readonly MotionBlur: 4;
|
|
65
|
+
readonly DepthOfField: 8;
|
|
66
|
+
readonly Bloom: 16;
|
|
67
|
+
readonly AutoExposure: 32;
|
|
68
|
+
readonly Fxaa: 64;
|
|
69
|
+
readonly Ssao: 128;
|
|
70
|
+
readonly Grading: 256;
|
|
71
|
+
readonly Vignette: 512;
|
|
72
|
+
/** Aerial perspective of the camera's atmospheres (spec 0044). */
|
|
73
|
+
readonly Atmosphere: 1024;
|
|
74
|
+
};
|
|
75
|
+
/** Effects that are part of the tonemap pass, so every 3D view has them. */
|
|
76
|
+
export declare const CORE_EFFECTS: number;
|
|
77
|
+
/**
|
|
78
|
+
* The effects whose passes are installed: the tonemap's always, then what postPlugin and fxaaPlugin
|
|
79
|
+
* add. A camera asking for one that isn't installed renders without it (render/feature-missing).
|
|
80
|
+
*/
|
|
81
|
+
export declare const PostFeatures: import("@aethervtt/shard-core").ResourceDef<{
|
|
82
|
+
effects: number;
|
|
83
|
+
}>;
|
|
84
|
+
/** The HDR effects that each read the previous one's output, in the fixed order. */
|
|
85
|
+
export declare const HDR_CHAIN: readonly [readonly ['atmosphere', 1024], readonly ['fog', 1], readonly ['taa', 2], readonly ['motion-blur', 4], readonly ['dof', 8], readonly ['bloom', 16]];
|
|
86
|
+
/** A camera's post settings, read from its components each frame. Allocated once per camera. */
|
|
87
|
+
export interface PostSettings {
|
|
88
|
+
effects: number;
|
|
89
|
+
bloom: {
|
|
90
|
+
intensity: number;
|
|
91
|
+
threshold: number;
|
|
92
|
+
knee: number;
|
|
93
|
+
radius: number;
|
|
94
|
+
};
|
|
95
|
+
exposure: {
|
|
96
|
+
minEv: number;
|
|
97
|
+
maxEv: number;
|
|
98
|
+
compensation: number;
|
|
99
|
+
speedUp: number;
|
|
100
|
+
speedDown: number;
|
|
101
|
+
metering: number;
|
|
102
|
+
};
|
|
103
|
+
dof: {
|
|
104
|
+
mode: number;
|
|
105
|
+
focusDistance: number;
|
|
106
|
+
maxBlur: number;
|
|
107
|
+
/** f-number. */
|
|
108
|
+
aperture: number;
|
|
109
|
+
/** mm. */
|
|
110
|
+
focalLength: number;
|
|
111
|
+
/** Sensor height, mm. */
|
|
112
|
+
sensor: number;
|
|
113
|
+
};
|
|
114
|
+
motionBlur: {
|
|
115
|
+
samples: number;
|
|
116
|
+
maxBlur: number;
|
|
117
|
+
shutter: number;
|
|
118
|
+
};
|
|
119
|
+
ssao: {
|
|
120
|
+
radius: number;
|
|
121
|
+
intensity: number;
|
|
122
|
+
quality: number;
|
|
123
|
+
};
|
|
124
|
+
fog: {
|
|
125
|
+
color: Float32Array;
|
|
126
|
+
density: number;
|
|
127
|
+
heightFalloff: number;
|
|
128
|
+
start: number;
|
|
129
|
+
sunScattering: number;
|
|
130
|
+
/** 0 default, 1 add. */
|
|
131
|
+
mode: number;
|
|
132
|
+
};
|
|
133
|
+
grading: {
|
|
134
|
+
temperature: number;
|
|
135
|
+
tint: number;
|
|
136
|
+
saturation: number;
|
|
137
|
+
contrast: number;
|
|
138
|
+
lift: Float32Array;
|
|
139
|
+
gamma: Float32Array;
|
|
140
|
+
gain: Float32Array;
|
|
141
|
+
lut: unknown;
|
|
142
|
+
};
|
|
143
|
+
vignette: {
|
|
144
|
+
intensity: number;
|
|
145
|
+
smoothness: number;
|
|
146
|
+
};
|
|
147
|
+
/** TAA: this frame's sub-pixel jitter in pixels, and the frame index it came from. */
|
|
148
|
+
jitter: Float32Array;
|
|
149
|
+
}
|
|
150
|
+
export declare function createPostSettings(): PostSettings;
|
|
151
|
+
/** The Antialiasing mode index of a camera's table row, or -1 without the component. */
|
|
152
|
+
export declare function antialiasingOf(table: Table, row: number): number;
|
|
153
|
+
/**
|
|
154
|
+
* Reads a camera's effect components into its post settings. Frame time comes in for motion blur
|
|
155
|
+
* (the shutter covers a fraction of a frame). Only `installed` effects turn on; returns the ones the
|
|
156
|
+
* camera asked for that aren't.
|
|
157
|
+
*/
|
|
158
|
+
export declare function extractPost(table: Table, row: number, cam: CameraData, delta: number, taaAllowed: boolean, installed?: number): number;
|
|
159
|
+
/**
|
|
160
|
+
* Thin-lens circle of confusion radius in pixels, for an object at `distance` meters: the blur
|
|
161
|
+
* disc's diameter on the sensor is A · |d − s| / d · f / (s − f), with A = f / N.
|
|
162
|
+
*/
|
|
163
|
+
export declare function cocRadiusPixels(cam: CameraData, distance: number): number;
|
|
164
|
+
/** Parameters of the thin-lens CoC for the shader: signed radius px = x / depth + y, capped at z. */
|
|
165
|
+
export declare function cocParams(cam: CameraData, out: Float32Array): Float32Array;
|
|
166
|
+
/**
|
|
167
|
+
* The aliases a view's post chain needs: each active HDR effect reads what the one before it
|
|
168
|
+
* wrote, alternating between two textures, and the tonemap reads the last. Cached per
|
|
169
|
+
* configuration, so views don't allocate per frame.
|
|
170
|
+
*/
|
|
171
|
+
export declare function postAliases(cam: CameraData, base: Readonly<Record<string, string>>): Readonly<Record<string, string>>;
|
|
172
|
+
/** Whether a view runs an effect. */
|
|
173
|
+
export declare const hasEffect: (bit: number) => (view: RenderView) => boolean;
|
|
174
|
+
/** Views that need the velocity prepass: TAA and motion blur read it, forward SSAO its normals. */
|
|
175
|
+
export declare function needsPrepass(view: RenderView): boolean;
|
package/dist/post.js
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import { defineComponent, defineResource, t } from "@aethervtt/shard-core";
|
|
2
|
+
import { Camera3d, PhysicalCamera } from "./camera.js";
|
|
3
|
+
import { cameraOf, isScaled } from "./view.js";
|
|
4
|
+
const Bloom = defineComponent(
|
|
5
|
+
"render/Bloom",
|
|
6
|
+
{
|
|
7
|
+
intensity: t.f32({
|
|
8
|
+
default: 0.15,
|
|
9
|
+
min: 0,
|
|
10
|
+
max: 1,
|
|
11
|
+
presets: { subtle: 0.08, strong: 0.3 },
|
|
12
|
+
description: "How much of the blurred image mixes in. With threshold 0 the mix conserves energy. Presets: subtle 0.08, strong 0.3."
|
|
13
|
+
}),
|
|
14
|
+
threshold: t.f32({
|
|
15
|
+
min: 0,
|
|
16
|
+
unit: "cd/m\xB2",
|
|
17
|
+
description: "Only luminance above this blooms (0: everything, the physically based default). Set it for a stylized glow on emissive panels."
|
|
18
|
+
}),
|
|
19
|
+
knee: t.f32({
|
|
20
|
+
default: 0.5,
|
|
21
|
+
min: 0,
|
|
22
|
+
max: 1,
|
|
23
|
+
description: "Softness of the threshold, as a fraction of it."
|
|
24
|
+
}),
|
|
25
|
+
radius: t.f32({
|
|
26
|
+
default: 0.8,
|
|
27
|
+
min: 0,
|
|
28
|
+
max: 1,
|
|
29
|
+
description: "Spread: 0 keeps the glow tight, 1 spreads it over the whole view."
|
|
30
|
+
})
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
description: "Light bleeding around bright areas, from a downsampled blur chain. Add to a camera.",
|
|
34
|
+
requires: [Camera3d]
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
const METERING_MODES = ["average", "center", "spot"];
|
|
38
|
+
const AutoExposure = defineComponent(
|
|
39
|
+
"render/AutoExposure",
|
|
40
|
+
{
|
|
41
|
+
minEv: t.f32({
|
|
42
|
+
default: -2,
|
|
43
|
+
presets: { indoor: 3, outdoor: 9 },
|
|
44
|
+
description: "Darkest exposure it adapts to (EV100). Presets: indoor 3, outdoor 9."
|
|
45
|
+
}),
|
|
46
|
+
maxEv: t.f32({
|
|
47
|
+
default: 16,
|
|
48
|
+
presets: { indoor: 10, outdoor: 16 },
|
|
49
|
+
description: "Brightest exposure it adapts to (EV100). Presets: indoor 10, outdoor 16."
|
|
50
|
+
}),
|
|
51
|
+
compensation: t.f32({
|
|
52
|
+
description: "EV stops added to the metered brightness: +1 is twice as bright."
|
|
53
|
+
}),
|
|
54
|
+
speedUp: t.f32({
|
|
55
|
+
default: 3,
|
|
56
|
+
min: 0.01,
|
|
57
|
+
unit: "EV/s",
|
|
58
|
+
description: "Adaptation speed when the scene gets brighter."
|
|
59
|
+
}),
|
|
60
|
+
speedDown: t.f32({
|
|
61
|
+
default: 1,
|
|
62
|
+
min: 0.01,
|
|
63
|
+
unit: "EV/s",
|
|
64
|
+
description: "Adaptation speed when the scene gets darker."
|
|
65
|
+
}),
|
|
66
|
+
metering: t.enum(METERING_MODES, {
|
|
67
|
+
description: "average: the whole view; center: weighted toward the middle; spot: the middle 10% only."
|
|
68
|
+
})
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
description: "Adapts Exposure.ev100 to the scene's measured brightness each frame, starting from the camera's exposure (PhysicalCamera included).",
|
|
72
|
+
requires: [Camera3d]
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
const DepthOfField = defineComponent(
|
|
76
|
+
"render/DepthOfField",
|
|
77
|
+
{
|
|
78
|
+
mode: t.enum(["gaussian", "bokeh"], {
|
|
79
|
+
description: "gaussian: soft; bokeh: disc-shaped highlights like a real lens."
|
|
80
|
+
}),
|
|
81
|
+
focusDistance: t.f32({
|
|
82
|
+
default: 10,
|
|
83
|
+
min: 0.01,
|
|
84
|
+
unit: "m",
|
|
85
|
+
description: "Distance that is in focus."
|
|
86
|
+
}),
|
|
87
|
+
maxBlur: t.f32({
|
|
88
|
+
default: 0.02,
|
|
89
|
+
min: 0,
|
|
90
|
+
max: 0.1,
|
|
91
|
+
description: "Largest blur radius, as a fraction of the view height."
|
|
92
|
+
})
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
description: "Defocus blur from the thin-lens circle of confusion: PhysicalCamera's aperture and focal length (without one: f/2.8 at the lens matching fovY).",
|
|
96
|
+
requires: [Camera3d]
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
const MotionBlur = defineComponent(
|
|
100
|
+
"render/MotionBlur",
|
|
101
|
+
{
|
|
102
|
+
samples: t.u32({ default: 8, min: 2, max: 32, description: "Samples along the motion." }),
|
|
103
|
+
maxBlur: t.f32({
|
|
104
|
+
default: 0.05,
|
|
105
|
+
min: 0,
|
|
106
|
+
max: 0.25,
|
|
107
|
+
description: "Longest blur, as a fraction of the view height."
|
|
108
|
+
})
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
description: "Blur along screen motion, for the time the shutter is open: PhysicalCamera.shutterSpeed (without one, half a frame).",
|
|
112
|
+
requires: [Camera3d]
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
const ANTIALIASING_MODES = ["none", "fxaa", "taa", "msaa"];
|
|
116
|
+
const Antialiasing = defineComponent(
|
|
117
|
+
"render/Antialiasing",
|
|
118
|
+
{
|
|
119
|
+
mode: t.enum(ANTIALIASING_MODES, {
|
|
120
|
+
default: "msaa",
|
|
121
|
+
description: "msaa: 4 samples, forward views only; fxaa: cheap edge smoothing after tonemapping; taa: jittered frames blended over time (smoothest, also cleans shading); none."
|
|
122
|
+
})
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
description: "Anti-aliasing for a camera. Without it: MSAA in forward views (per forwardPlugin), none in deferred ones.",
|
|
126
|
+
requires: [Camera3d]
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
const SSAO_QUALITIES = ["low", "medium", "high"];
|
|
130
|
+
const Ssao = defineComponent(
|
|
131
|
+
"render/Ssao",
|
|
132
|
+
{
|
|
133
|
+
radius: t.f32({
|
|
134
|
+
default: 0.5,
|
|
135
|
+
min: 0.01,
|
|
136
|
+
unit: "m",
|
|
137
|
+
description: "How far occluders count."
|
|
138
|
+
}),
|
|
139
|
+
intensity: t.f32({ default: 1, min: 0, max: 4, description: "Strength of the darkening." }),
|
|
140
|
+
quality: t.enum(SSAO_QUALITIES, {
|
|
141
|
+
default: "medium",
|
|
142
|
+
description: "Slice directions \xD7 steps searched: low 1\xD74, medium 2\xD74, high 3\xD76."
|
|
143
|
+
})
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
description: "Screen-space ambient occlusion: darkens ambient and environment light in creases and contact areas.",
|
|
147
|
+
requires: [Camera3d]
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
const Fog = defineComponent(
|
|
151
|
+
"render/Fog",
|
|
152
|
+
{
|
|
153
|
+
color: t.color({
|
|
154
|
+
default: [0.6, 0.7, 0.85, 1],
|
|
155
|
+
description: "Fog albedo: tints the sky's and sun's light it scatters (linear)."
|
|
156
|
+
}),
|
|
157
|
+
density: t.f32({
|
|
158
|
+
default: 0.02,
|
|
159
|
+
min: 0,
|
|
160
|
+
unit: "1/m",
|
|
161
|
+
description: "Extinction at height 0: 0.02 hides things ~150 m away."
|
|
162
|
+
}),
|
|
163
|
+
heightFalloff: t.f32({
|
|
164
|
+
default: 0.1,
|
|
165
|
+
min: 0,
|
|
166
|
+
unit: "1/m",
|
|
167
|
+
description: "How fast fog thins with height (0: uniform)."
|
|
168
|
+
}),
|
|
169
|
+
start: t.f32({ min: 0, unit: "m", description: "Clear distance from the camera." }),
|
|
170
|
+
sunScattering: t.f32({
|
|
171
|
+
default: 0.5,
|
|
172
|
+
min: 0,
|
|
173
|
+
max: 1,
|
|
174
|
+
description: "Glow toward the sun (forward scattering)."
|
|
175
|
+
}),
|
|
176
|
+
mode: t.enum(["default", "add"], {
|
|
177
|
+
description: "default: fog for flat scenes, ignored inside a planet's Atmosphere (render/fog-with-atmosphere); add: extra ground fog on top of the atmosphere's haze."
|
|
178
|
+
})
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
description: "Exponential height fog along world Y, lit by the environment (or ambient light) and the sun. Applied to everything, sky included. On planets, Atmosphere hazes distance instead.",
|
|
182
|
+
requires: [Camera3d]
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
const ColorGrading = defineComponent(
|
|
186
|
+
"render/ColorGrading",
|
|
187
|
+
{
|
|
188
|
+
temperature: t.f32({
|
|
189
|
+
min: -1,
|
|
190
|
+
max: 1,
|
|
191
|
+
description: "White balance: -1 cool (blue), +1 warm (orange)."
|
|
192
|
+
}),
|
|
193
|
+
tint: t.f32({ min: -1, max: 1, description: "White balance: -1 green, +1 magenta." }),
|
|
194
|
+
saturation: t.f32({ default: 1, min: 0, max: 2, description: "0 gray, 1 unchanged." }),
|
|
195
|
+
contrast: t.f32({ default: 1, min: 0, max: 2, description: "Around mid gray; 1 unchanged." }),
|
|
196
|
+
lift: t.vec3({ description: "Added to shadows (per channel)." }),
|
|
197
|
+
gamma: t.vec3({ default: [1, 1, 1], min: 0.01, description: "Midtone power (per channel)." }),
|
|
198
|
+
gain: t.vec3({
|
|
199
|
+
default: [1, 1, 1],
|
|
200
|
+
min: 0,
|
|
201
|
+
description: "Highlight multiplier (per channel)."
|
|
202
|
+
}),
|
|
203
|
+
lut: t.handle("Texture", {
|
|
204
|
+
description: "A 32\xB3 look-up table as a 1024\xD732 PNG strip (32 slices of red \xD7 green, blue across slices), applied after tonemapping."
|
|
205
|
+
})
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
description: "The look: white balance, saturation, contrast, lift/gamma/gain in HDR before the tonemap curve, then an optional LUT.",
|
|
209
|
+
requires: [Camera3d]
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
const Vignette = defineComponent(
|
|
213
|
+
"render/Vignette",
|
|
214
|
+
{
|
|
215
|
+
intensity: t.f32({
|
|
216
|
+
default: 0.3,
|
|
217
|
+
min: 0,
|
|
218
|
+
max: 1,
|
|
219
|
+
description: "Darkening at the corners."
|
|
220
|
+
}),
|
|
221
|
+
smoothness: t.f32({
|
|
222
|
+
default: 0.5,
|
|
223
|
+
min: 0.01,
|
|
224
|
+
max: 1,
|
|
225
|
+
description: "How gradually it falls off."
|
|
226
|
+
})
|
|
227
|
+
},
|
|
228
|
+
{ description: "Darkens the edges of the image.", requires: [Camera3d] }
|
|
229
|
+
);
|
|
230
|
+
const PostEffect = {
|
|
231
|
+
Fog: 1,
|
|
232
|
+
Taa: 2,
|
|
233
|
+
MotionBlur: 4,
|
|
234
|
+
DepthOfField: 8,
|
|
235
|
+
Bloom: 16,
|
|
236
|
+
AutoExposure: 32,
|
|
237
|
+
Fxaa: 64,
|
|
238
|
+
Ssao: 128,
|
|
239
|
+
Grading: 256,
|
|
240
|
+
Vignette: 512,
|
|
241
|
+
/** Aerial perspective of the camera's atmospheres (spec 0044). */
|
|
242
|
+
Atmosphere: 1024
|
|
243
|
+
};
|
|
244
|
+
const CORE_EFFECTS = PostEffect.Grading | PostEffect.Vignette;
|
|
245
|
+
const PostFeatures = defineResource("render/PostFeatures", {
|
|
246
|
+
description: "Post effects whose passes are installed (bits of PostEffect).",
|
|
247
|
+
init: () => ({ effects: CORE_EFFECTS })
|
|
248
|
+
});
|
|
249
|
+
const HDR_CHAIN = [
|
|
250
|
+
["atmosphere", PostEffect.Atmosphere],
|
|
251
|
+
["fog", PostEffect.Fog],
|
|
252
|
+
["taa", PostEffect.Taa],
|
|
253
|
+
["motion-blur", PostEffect.MotionBlur],
|
|
254
|
+
["dof", PostEffect.DepthOfField],
|
|
255
|
+
["bloom", PostEffect.Bloom]
|
|
256
|
+
];
|
|
257
|
+
function createPostSettings() {
|
|
258
|
+
return {
|
|
259
|
+
effects: 0,
|
|
260
|
+
bloom: { intensity: 0, threshold: 0, knee: 0, radius: 0 },
|
|
261
|
+
exposure: { minEv: 0, maxEv: 0, compensation: 0, speedUp: 1, speedDown: 1, metering: 0 },
|
|
262
|
+
dof: { mode: 0, focusDistance: 10, maxBlur: 0, aperture: 2.8, focalLength: 50, sensor: 24 },
|
|
263
|
+
motionBlur: { samples: 8, maxBlur: 0, shutter: 0.5 },
|
|
264
|
+
ssao: { radius: 0.5, intensity: 1, quality: 1 },
|
|
265
|
+
fog: {
|
|
266
|
+
color: new Float32Array(4),
|
|
267
|
+
density: 0,
|
|
268
|
+
heightFalloff: 0,
|
|
269
|
+
start: 0,
|
|
270
|
+
sunScattering: 0,
|
|
271
|
+
mode: 0
|
|
272
|
+
},
|
|
273
|
+
grading: {
|
|
274
|
+
temperature: 0,
|
|
275
|
+
tint: 0,
|
|
276
|
+
saturation: 1,
|
|
277
|
+
contrast: 1,
|
|
278
|
+
lift: new Float32Array(3),
|
|
279
|
+
gamma: new Float32Array([1, 1, 1]),
|
|
280
|
+
gain: new Float32Array([1, 1, 1]),
|
|
281
|
+
lut: null
|
|
282
|
+
},
|
|
283
|
+
vignette: { intensity: 0, smoothness: 0.5 },
|
|
284
|
+
jitter: new Float32Array(2)
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
const vec = (out, column, row, n) => {
|
|
288
|
+
for (let k = 0; k < n; k++) out[k] = column[row * n + k];
|
|
289
|
+
};
|
|
290
|
+
function antialiasingOf(table, row) {
|
|
291
|
+
return table.has(Antialiasing) ? table.column(Antialiasing, "mode")[row] : -1;
|
|
292
|
+
}
|
|
293
|
+
function extractPost(table, row, cam, delta, taaAllowed, installed = CORE_EFFECTS) {
|
|
294
|
+
const post = cam.post;
|
|
295
|
+
let effects = 0;
|
|
296
|
+
if (table.has(Bloom)) {
|
|
297
|
+
effects |= PostEffect.Bloom;
|
|
298
|
+
post.bloom.intensity = table.column(Bloom, "intensity")[row];
|
|
299
|
+
post.bloom.threshold = table.column(Bloom, "threshold")[row];
|
|
300
|
+
post.bloom.knee = table.column(Bloom, "knee")[row];
|
|
301
|
+
post.bloom.radius = table.column(Bloom, "radius")[row];
|
|
302
|
+
}
|
|
303
|
+
if (table.has(AutoExposure)) {
|
|
304
|
+
effects |= PostEffect.AutoExposure;
|
|
305
|
+
const e = post.exposure;
|
|
306
|
+
e.minEv = table.column(AutoExposure, "minEv")[row];
|
|
307
|
+
e.maxEv = table.column(AutoExposure, "maxEv")[row];
|
|
308
|
+
e.compensation = table.column(AutoExposure, "compensation")[row];
|
|
309
|
+
e.speedUp = table.column(AutoExposure, "speedUp")[row];
|
|
310
|
+
e.speedDown = table.column(AutoExposure, "speedDown")[row];
|
|
311
|
+
e.metering = table.column(AutoExposure, "metering")[row];
|
|
312
|
+
}
|
|
313
|
+
const physical = table.has(PhysicalCamera);
|
|
314
|
+
if (table.has(DepthOfField)) {
|
|
315
|
+
effects |= PostEffect.DepthOfField;
|
|
316
|
+
const d = post.dof;
|
|
317
|
+
d.mode = table.column(DepthOfField, "mode")[row];
|
|
318
|
+
d.focusDistance = table.column(DepthOfField, "focusDistance")[row];
|
|
319
|
+
d.maxBlur = table.column(DepthOfField, "maxBlur")[row];
|
|
320
|
+
const sensor = physical ? table.column(PhysicalCamera, "sensorHeight")[row] : 24;
|
|
321
|
+
const focal = physical ? table.column(PhysicalCamera, "focalLength")[row] : 0;
|
|
322
|
+
d.aperture = physical ? table.column(PhysicalCamera, "aperture")[row] : 2.8;
|
|
323
|
+
d.focalLength = focal > 0 ? focal : sensor / (2 * Math.tan(cam.fovY / 2));
|
|
324
|
+
d.sensor = sensor;
|
|
325
|
+
}
|
|
326
|
+
if (table.has(MotionBlur)) {
|
|
327
|
+
effects |= PostEffect.MotionBlur;
|
|
328
|
+
post.motionBlur.samples = table.column(MotionBlur, "samples")[row];
|
|
329
|
+
post.motionBlur.maxBlur = table.column(MotionBlur, "maxBlur")[row];
|
|
330
|
+
const shutter = physical ? table.column(PhysicalCamera, "shutterSpeed")[row] : 0;
|
|
331
|
+
post.motionBlur.shutter = shutter > 0 && delta > 0 ? Math.min(1, shutter / delta) : 0.5;
|
|
332
|
+
}
|
|
333
|
+
if (table.has(Ssao)) {
|
|
334
|
+
effects |= PostEffect.Ssao;
|
|
335
|
+
post.ssao.radius = table.column(Ssao, "radius")[row];
|
|
336
|
+
post.ssao.intensity = table.column(Ssao, "intensity")[row];
|
|
337
|
+
post.ssao.quality = table.column(Ssao, "quality")[row];
|
|
338
|
+
}
|
|
339
|
+
if (table.has(Fog)) {
|
|
340
|
+
effects |= PostEffect.Fog;
|
|
341
|
+
const f = post.fog;
|
|
342
|
+
vec(f.color, table.column(Fog, "color"), row, 4);
|
|
343
|
+
f.density = table.column(Fog, "density")[row];
|
|
344
|
+
f.heightFalloff = table.column(Fog, "heightFalloff")[row];
|
|
345
|
+
f.start = table.column(Fog, "start")[row];
|
|
346
|
+
f.sunScattering = table.column(Fog, "sunScattering")[row];
|
|
347
|
+
f.mode = table.column(Fog, "mode")[row];
|
|
348
|
+
}
|
|
349
|
+
if (table.has(ColorGrading)) {
|
|
350
|
+
effects |= PostEffect.Grading;
|
|
351
|
+
const g = post.grading;
|
|
352
|
+
g.temperature = table.column(ColorGrading, "temperature")[row];
|
|
353
|
+
g.tint = table.column(ColorGrading, "tint")[row];
|
|
354
|
+
g.saturation = table.column(ColorGrading, "saturation")[row];
|
|
355
|
+
g.contrast = table.column(ColorGrading, "contrast")[row];
|
|
356
|
+
vec(g.lift, table.column(ColorGrading, "lift"), row, 3);
|
|
357
|
+
vec(g.gamma, table.column(ColorGrading, "gamma"), row, 3);
|
|
358
|
+
vec(g.gain, table.column(ColorGrading, "gain"), row, 3);
|
|
359
|
+
g.lut = table.column(ColorGrading, "lut")[row] ?? null;
|
|
360
|
+
}
|
|
361
|
+
if (table.has(Vignette)) {
|
|
362
|
+
effects |= PostEffect.Vignette;
|
|
363
|
+
post.vignette.intensity = table.column(Vignette, "intensity")[row];
|
|
364
|
+
post.vignette.smoothness = table.column(Vignette, "smoothness")[row];
|
|
365
|
+
}
|
|
366
|
+
const aa = antialiasingOf(table, row);
|
|
367
|
+
if (aa === 1) effects |= PostEffect.Fxaa;
|
|
368
|
+
if (aa === 2 && taaAllowed) effects |= PostEffect.Taa;
|
|
369
|
+
post.effects = effects & installed;
|
|
370
|
+
return effects & ~installed;
|
|
371
|
+
}
|
|
372
|
+
function cocRadiusPixels(cam, distance) {
|
|
373
|
+
const d = cam.post.dof;
|
|
374
|
+
const f = d.focalLength / 1e3;
|
|
375
|
+
const s = Math.max(d.focusDistance, f * 1.001);
|
|
376
|
+
const aperture = f / d.aperture;
|
|
377
|
+
const diameter = aperture * Math.abs(distance - s) * f / (distance * (s - f));
|
|
378
|
+
const sensor = d.sensor / 1e3;
|
|
379
|
+
const radius = diameter / sensor * cam.height * 0.5;
|
|
380
|
+
return Math.min(radius, d.maxBlur * cam.height);
|
|
381
|
+
}
|
|
382
|
+
function cocParams(cam, out) {
|
|
383
|
+
const d = cam.post.dof;
|
|
384
|
+
const f = d.focalLength / 1e3;
|
|
385
|
+
const s = Math.max(d.focusDistance, f * 1.001);
|
|
386
|
+
const sensor = d.sensor / 1e3;
|
|
387
|
+
const k = f / d.aperture * f / (s - f) / sensor * cam.height * 0.5;
|
|
388
|
+
out[0] = -k * s;
|
|
389
|
+
out[1] = k;
|
|
390
|
+
out[2] = d.maxBlur * cam.height;
|
|
391
|
+
out[3] = d.mode;
|
|
392
|
+
return out;
|
|
393
|
+
}
|
|
394
|
+
const aliasCache = /* @__PURE__ */ new Map();
|
|
395
|
+
function postAliases(cam, base) {
|
|
396
|
+
const effects = cam.post.effects;
|
|
397
|
+
const chain = effects & 255 | (effects & PostEffect.Atmosphere ? 256 : 0);
|
|
398
|
+
const key = chain * 8 + (cam.msaa > 1 ? 1 : 0) + (cam.deferred ? 2 : 0) + (isScaled(cam) ? 4 : 0);
|
|
399
|
+
let aliases = aliasCache.get(key);
|
|
400
|
+
if (!aliases) {
|
|
401
|
+
const out = { ...base };
|
|
402
|
+
let current = "hdr";
|
|
403
|
+
let flip = false;
|
|
404
|
+
for (const [name, bit] of HDR_CHAIN) {
|
|
405
|
+
if ((effects & bit) === 0) continue;
|
|
406
|
+
const next = flip ? "post-b" : "post-a";
|
|
407
|
+
flip = !flip;
|
|
408
|
+
out[`${name}-in`] = current;
|
|
409
|
+
out[`${name}-out`] = next;
|
|
410
|
+
current = next;
|
|
411
|
+
}
|
|
412
|
+
out["post-hdr"] = current;
|
|
413
|
+
if (effects & PostEffect.Fxaa) out.ldr = "fxaa-in";
|
|
414
|
+
out["ssao-normal"] = cam.deferred ? "gbuffer1" : "prepass-normal";
|
|
415
|
+
out["ssao-depth"] = cam.deferred ? "scene-depth" : "prepass-depth";
|
|
416
|
+
aliases = Object.freeze(out);
|
|
417
|
+
aliasCache.set(key, aliases);
|
|
418
|
+
}
|
|
419
|
+
return aliases;
|
|
420
|
+
}
|
|
421
|
+
const hasEffect = (bit) => (view) => ((cameraOf(view)?.post.effects ?? 0) & bit) !== 0;
|
|
422
|
+
function needsPrepass(view) {
|
|
423
|
+
const cam = cameraOf(view);
|
|
424
|
+
if (!cam) return false;
|
|
425
|
+
const e = cam.post.effects;
|
|
426
|
+
return (e & (PostEffect.Taa | PostEffect.MotionBlur)) !== 0 || !cam.deferred && (e & PostEffect.Ssao) !== 0;
|
|
427
|
+
}
|
|
428
|
+
export {
|
|
429
|
+
ANTIALIASING_MODES,
|
|
430
|
+
Antialiasing,
|
|
431
|
+
AutoExposure,
|
|
432
|
+
Bloom,
|
|
433
|
+
CORE_EFFECTS,
|
|
434
|
+
ColorGrading,
|
|
435
|
+
DepthOfField,
|
|
436
|
+
Fog,
|
|
437
|
+
HDR_CHAIN,
|
|
438
|
+
METERING_MODES,
|
|
439
|
+
MotionBlur,
|
|
440
|
+
PostEffect,
|
|
441
|
+
PostFeatures,
|
|
442
|
+
SSAO_QUALITIES,
|
|
443
|
+
Ssao,
|
|
444
|
+
Vignette,
|
|
445
|
+
antialiasingOf,
|
|
446
|
+
cocParams,
|
|
447
|
+
cocRadiusPixels,
|
|
448
|
+
createPostSettings,
|
|
449
|
+
extractPost,
|
|
450
|
+
hasEffect,
|
|
451
|
+
needsPrepass,
|
|
452
|
+
postAliases
|
|
453
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Readback helpers: bytes per texel and conversion of any readable format to floats. */
|
|
2
|
+
export declare const BYTES_PER_TEXEL: Partial<Record<GPUTextureFormat, number>>;
|
|
3
|
+
/** Unpacks a readback row of any supported format into 4 floats per pixel. */
|
|
4
|
+
export declare function toFloats(src: ArrayBuffer, format: GPUTextureFormat, count: number, out: Float32Array, o: number): void;
|