@driftengine/core 4.11.1 → 4.13.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/CHANGELOG.json +102 -0
- package/README.md +18 -9
- package/dist/geometry/meshBuilder.d.ts +10 -0
- package/dist/geometry/meshBuilder.js +11 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -2
- package/dist/math/color.d.ts +25 -0
- package/dist/math/color.js +37 -0
- package/dist/render/backend/webgl2/renderer.d.ts +33 -5
- package/dist/render/backend/webgl2/renderer.js +123 -49
- package/dist/render/backend/webgl2/skinScatter.d.ts +3 -1
- package/dist/render/backend/webgl2/skinScatter.js +5 -1
- package/dist/render/backend/webgpu/boltPass.d.ts +1 -1
- package/dist/render/backend/webgpu/causticsPass.d.ts +1 -1
- package/dist/render/backend/webgpu/filmPass.d.ts +1 -1
- package/dist/render/backend/webgpu/flockPass.d.ts +1 -1
- package/dist/render/backend/webgpu/giFieldPass.d.ts +3 -1
- package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +10 -1
- package/dist/render/backend/webgpu/gpuDrivenPass.js +28 -11
- package/dist/render/backend/webgpu/panelPass.d.ts +1 -1
- package/dist/render/backend/webgpu/postPass.d.ts +2 -2
- package/dist/render/backend/webgpu/renderer.d.ts +21 -8
- package/dist/render/backend/webgpu/renderer.js +103 -38
- package/dist/render/backend/webgpu/scatterPass.d.ts +1 -1
- package/dist/render/backend/webgpu/skinScatterPass.d.ts +5 -1
- package/dist/render/backend/webgpu/skinScatterPass.js +9 -3
- package/dist/render/backend/webgpu/skyPass.d.ts +11 -1
- package/dist/render/backend/webgpu/waterPass.d.ts +1 -1
- package/dist/render/backend/webgpu/windStreakPass.d.ts +1 -1
- package/dist/render/causticsRenderer.d.ts +3 -1
- package/dist/render/causticsRenderer.js +5 -1
- package/dist/render/decalPass.d.ts +3 -1
- package/dist/render/decalPass.js +4 -1
- package/dist/render/flockRenderer.d.ts +1 -1
- package/dist/render/flockRenderer.js +4 -1
- package/dist/render/globalMediumPass.d.ts +3 -1
- package/dist/render/globalMediumPass.js +5 -1
- package/dist/render/gradeColor.d.ts +21 -0
- package/dist/render/gradeColor.js +64 -0
- package/dist/render/lightMatrix.d.ts +13 -0
- package/dist/render/lightMatrix.js +17 -0
- package/dist/render/passGrade.d.ts +13 -0
- package/dist/render/passGrade.js +47 -0
- package/dist/render/plumeRenderer.d.ts +1 -1
- package/dist/render/plumeRenderer.js +4 -1
- package/dist/render/renderQuality.d.ts +57 -18
- package/dist/render/renderQuality.js +3 -3
- package/dist/render/sceneTarget.d.ts +2 -0
- package/dist/render/sceneTarget.js +1 -0
- package/dist/render/sdfTextRenderer.d.ts +1 -1
- package/dist/render/sdfTextRenderer.js +1 -1
- package/dist/render/shaders/arcane.d.ts +1 -1
- package/dist/render/shaders/arcane.js +5 -1
- package/dist/render/shaders/bolt.d.ts +1 -1
- package/dist/render/shaders/bolt.js +4 -1
- package/dist/render/shaders/caustics.d.ts +1 -1
- package/dist/render/shaders/caustics.js +4 -1
- package/dist/render/shaders/decalProject.js +12 -2
- package/dist/render/shaders/film.d.ts +1 -1
- package/dist/render/shaders/film.js +22 -9
- package/dist/render/shaders/fire.d.ts +1 -1
- package/dist/render/shaders/fire.js +4 -1
- package/dist/render/shaders/flat/areaLight.d.ts +1 -1
- package/dist/render/shaders/flat/areaLight.js +1 -1
- package/dist/render/shaders/flat/glassTint.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.js +1 -0
- package/dist/render/shaders/flat/index.d.ts +5 -0
- package/dist/render/shaders/flat/index.js +1 -1
- package/dist/render/shaders/flat/layerLooks.d.ts +16 -0
- package/dist/render/shaders/flat/layerLooks.js +108 -0
- package/dist/render/shaders/flat/layered.d.ts +6 -4
- package/dist/render/shaders/flat/layered.js +77 -13
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +7 -2
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/preamble.js +6 -0
- package/dist/render/shaders/flock.d.ts +1 -1
- package/dist/render/shaders/flock.js +4 -1
- package/dist/render/shaders/generated/arcane.wgsl.d.ts +11 -1
- package/dist/render/shaders/generated/arcane.wgsl.js +11 -1
- package/dist/render/shaders/generated/bolt.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/bolt.wgsl.js +12 -2
- package/dist/render/shaders/generated/caustics.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/caustics.wgsl.js +12 -2
- package/dist/render/shaders/generated/decalProject.wgsl.d.ts +6 -1
- package/dist/render/shaders/generated/decalProject.wgsl.js +6 -1
- package/dist/render/shaders/generated/film.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/film.wgsl.js +12 -2
- package/dist/render/shaders/generated/fire.wgsl.d.ts +11 -1
- package/dist/render/shaders/generated/fire.wgsl.js +11 -1
- package/dist/render/shaders/generated/flat.wgsl.d.ts +144 -16
- package/dist/render/shaders/generated/flat.wgsl.js +183 -55
- package/dist/render/shaders/generated/flock.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/flock.wgsl.js +12 -2
- package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/globalMedium.wgsl.js +12 -2
- package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +36 -16
- package/dist/render/shaders/generated/lightVolume.wgsl.js +39 -19
- package/dist/render/shaders/generated/panel.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/panel.wgsl.js +12 -2
- package/dist/render/shaders/generated/rush.wgsl.d.ts +31 -26
- package/dist/render/shaders/generated/rush.wgsl.js +31 -26
- package/dist/render/shaders/generated/scatter.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/scatter.wgsl.js +12 -2
- package/dist/render/shaders/generated/skinBlur.wgsl.d.ts +11 -1
- package/dist/render/shaders/generated/skinBlur.wgsl.js +11 -1
- package/dist/render/shaders/generated/sky.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/sky.wgsl.js +12 -2
- package/dist/render/shaders/generated/smoke.wgsl.d.ts +11 -1
- package/dist/render/shaders/generated/smoke.wgsl.js +11 -1
- package/dist/render/shaders/generated/text.wgsl.d.ts +11 -1
- package/dist/render/shaders/generated/text.wgsl.js +11 -1
- package/dist/render/shaders/generated/water.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/water.wgsl.js +12 -2
- package/dist/render/shaders/generated/windStreaks.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/windStreaks.wgsl.js +12 -2
- package/dist/render/shaders/globalMedium.js +14 -1
- package/dist/render/shaders/gpudriven/present.wgsl.d.ts +15 -6
- package/dist/render/shaders/gpudriven/present.wgsl.js +71 -8
- package/dist/render/shaders/lightVolume.js +4 -1
- package/dist/render/shaders/line.d.ts +1 -1
- package/dist/render/shaders/outputTransform.d.ts +8 -2
- package/dist/render/shaders/outputTransform.js +18 -11
- package/dist/render/shaders/panel.d.ts +1 -1
- package/dist/render/shaders/panel.js +5 -1
- package/dist/render/shaders/particle.d.ts +3 -3
- package/dist/render/shaders/rush.js +8 -0
- package/dist/render/shaders/scatter.d.ts +1 -1
- package/dist/render/shaders/scatter.js +4 -1
- package/dist/render/shaders/sdfText.d.ts +1 -1
- package/dist/render/shaders/skinBlur.js +5 -1
- package/dist/render/shaders/sky.d.ts +1 -1
- package/dist/render/shaders/sky.js +5 -1
- package/dist/render/shaders/smoke.d.ts +1 -1
- package/dist/render/shaders/smoke.js +4 -1
- package/dist/render/shaders/text.d.ts +1 -1
- package/dist/render/shaders/text.js +4 -1
- package/dist/render/shaders/water.d.ts +1 -1
- package/dist/render/shaders/water.js +12 -2
- package/dist/render/shaders/windStreaks.d.ts +1 -1
- package/dist/render/shaders/windStreaks.js +4 -1
- package/dist/render/surfaceLayerLooks.d.ts +92 -0
- package/dist/render/surfaceLayerLooks.js +102 -0
- package/dist/render/surfaceLayers.d.ts +47 -6
- package/dist/render/surfaceLayers.js +5 -1
- package/dist/render/textRenderer.d.ts +3 -1
- package/dist/render/textRenderer.js +7 -1
- package/dist/render/vertexDefaults.d.ts +1 -1
- package/dist/render/vertexDefaults.js +1 -1
- package/dist/render/waterRenderer.d.ts +1 -1
- package/dist/render/waterRenderer.js +4 -1
- package/dist/render/windStreakRenderer.d.ts +3 -1
- package/dist/render/windStreakRenderer.js +5 -1
- package/package.json +6 -6
- package/scripts/browser.d.mts +5 -0
- package/scripts/browser.mjs +68 -14
- package/scripts/look.d.mts +81 -0
- package/scripts/look.mjs +380 -0
- package/src/geometry/meshBuilder.ts +21 -2
- package/src/index.ts +13 -2
- package/src/math/color.ts +39 -0
- package/src/render/backend/webgl2/renderer.ts +174 -46
- package/src/render/backend/webgl2/skinScatter.ts +5 -0
- package/src/render/backend/webgpu/giFieldPass.ts +3 -1
- package/src/render/backend/webgpu/gpuDrivenPass.ts +29 -13
- package/src/render/backend/webgpu/renderer.ts +112 -37
- package/src/render/backend/webgpu/skinScatterPass.ts +17 -1
- package/src/render/causticsRenderer.ts +5 -0
- package/src/render/decalPass.ts +3 -0
- package/src/render/flockRenderer.ts +5 -0
- package/src/render/globalMediumPass.ts +10 -1
- package/src/render/gradeColor.ts +90 -0
- package/src/render/lightMatrix.ts +32 -0
- package/src/render/passGrade.ts +58 -0
- package/src/render/plumeRenderer.ts +5 -0
- package/src/render/renderQuality.ts +60 -21
- package/src/render/sceneTarget.ts +3 -0
- package/src/render/sdfTextRenderer.ts +1 -1
- package/src/render/shaders/arcane.ts +5 -1
- package/src/render/shaders/bolt.ts +4 -1
- package/src/render/shaders/caustics.ts +4 -1
- package/src/render/shaders/decalProject.ts +12 -2
- package/src/render/shaders/film.ts +22 -9
- package/src/render/shaders/fire.ts +4 -1
- package/src/render/shaders/flat/areaLight.ts +1 -1
- package/src/render/shaders/flat/glassTint.ts +3 -1
- package/src/render/shaders/flat/index.ts +6 -1
- package/src/render/shaders/flat/layerLooks.ts +108 -0
- package/src/render/shaders/flat/layered.ts +78 -13
- package/src/render/shaders/flat/main.ts +7 -2
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/preamble.ts +6 -0
- package/src/render/shaders/flock.ts +4 -1
- package/src/render/shaders/generated/arcane.wgsl.ts +11 -1
- package/src/render/shaders/generated/bolt.wgsl.ts +12 -2
- package/src/render/shaders/generated/caustics.wgsl.ts +12 -2
- package/src/render/shaders/generated/decalProject.wgsl.ts +6 -1
- package/src/render/shaders/generated/film.wgsl.ts +12 -2
- package/src/render/shaders/generated/fire.wgsl.ts +11 -1
- package/src/render/shaders/generated/flat.wgsl.ts +183 -55
- package/src/render/shaders/generated/flock.wgsl.ts +12 -2
- package/src/render/shaders/generated/globalMedium.wgsl.ts +12 -2
- package/src/render/shaders/generated/lightVolume.wgsl.ts +39 -19
- package/src/render/shaders/generated/panel.wgsl.ts +12 -2
- package/src/render/shaders/generated/rush.wgsl.ts +31 -26
- package/src/render/shaders/generated/scatter.wgsl.ts +12 -2
- package/src/render/shaders/generated/skinBlur.wgsl.ts +11 -1
- package/src/render/shaders/generated/sky.wgsl.ts +12 -2
- package/src/render/shaders/generated/smoke.wgsl.ts +11 -1
- package/src/render/shaders/generated/text.wgsl.ts +11 -1
- package/src/render/shaders/generated/water.wgsl.ts +12 -2
- package/src/render/shaders/generated/windStreaks.wgsl.ts +12 -2
- package/src/render/shaders/globalMedium.ts +14 -1
- package/src/render/shaders/gpudriven/present.wgsl.ts +72 -8
- package/src/render/shaders/lightVolume.ts +4 -1
- package/src/render/shaders/outputTransform.ts +19 -11
- package/src/render/shaders/panel.ts +5 -1
- package/src/render/shaders/rush.ts +8 -0
- package/src/render/shaders/scatter.ts +4 -1
- package/src/render/shaders/skinBlur.ts +5 -1
- package/src/render/shaders/sky.ts +5 -1
- package/src/render/shaders/smoke.ts +4 -1
- package/src/render/shaders/text.ts +4 -1
- package/src/render/shaders/water.ts +12 -2
- package/src/render/shaders/windStreaks.ts +4 -1
- package/src/render/surfaceLayerLooks.ts +186 -0
- package/src/render/surfaceLayers.ts +52 -7
- package/src/render/textRenderer.ts +6 -0
- package/src/render/vertexDefaults.ts +1 -1
- package/src/render/waterRenderer.ts +5 -0
- package/src/render/windStreakRenderer.ts +5 -0
|
@@ -36,6 +36,8 @@ export class SkinScatterPass {
|
|
|
36
36
|
layout;
|
|
37
37
|
uniforms;
|
|
38
38
|
staging = new Float32Array((SLOT * 2) / 4);
|
|
39
|
+
/** The same blocks' ints: the frame's grade, which the second axis applies. */
|
|
40
|
+
stagingInts = new Int32Array(this.staging.buffer);
|
|
39
41
|
linear;
|
|
40
42
|
nearest;
|
|
41
43
|
commands = createCommandPool(16);
|
|
@@ -182,7 +184,9 @@ export class SkinScatterPass {
|
|
|
182
184
|
* attachment its pass draws into, `resolve` where a multisampled one resolves, `samples` its
|
|
183
185
|
* count. `projection` is the frame's, `height` the frame's height in pixels.
|
|
184
186
|
*/
|
|
185
|
-
spread(encoder, pipelines, depth, frame, resolve, samples, projection, inverseProjection, timestampWrites
|
|
187
|
+
spread(encoder, pipelines, depth, frame, resolve, samples, projection, inverseProjection, timestampWrites,
|
|
188
|
+
/** The frame's grade, which the second axis applies to the light it adds. */
|
|
189
|
+
outputTransform = 0, outputExposure = 1) {
|
|
186
190
|
const diffuse = this.diffuse;
|
|
187
191
|
if (diffuse === null || this.diffuseView === null || this.acrossView === null)
|
|
188
192
|
return;
|
|
@@ -193,7 +197,7 @@ export class SkinScatterPass {
|
|
|
193
197
|
this.groupDown = this.group('skin.blurDown', this.acrossView, depth);
|
|
194
198
|
this.groupsDepth = depth;
|
|
195
199
|
}
|
|
196
|
-
this.writeUniforms(diffuse.width, diffuse.height, projection, inverseProjection);
|
|
200
|
+
this.writeUniforms(diffuse.width, diffuse.height, projection, inverseProjection, outputTransform, outputExposure);
|
|
197
201
|
const across = postPipeline(pipelines, this.device, this.layout, 'skin.blurAcross', SKIN_BLUR_FRAG_WGSL, SKIN_TARGET_FORMAT);
|
|
198
202
|
const down = postPipelineTargets(pipelines, this.device, this.layout, `skin.blurDown:${pipelines.format}:${samples}`, SKIN_BLUR_FRAG_WGSL, [
|
|
199
203
|
{
|
|
@@ -261,7 +265,7 @@ export class SkinScatterPass {
|
|
|
261
265
|
});
|
|
262
266
|
}
|
|
263
267
|
/** Both axes' blocks: the step along each, and what they share. Column-major matrices. */
|
|
264
|
-
writeUniforms(width, height, projection, inverse) {
|
|
268
|
+
writeUniforms(width, height, projection, inverse, outputTransform, outputExposure) {
|
|
265
269
|
const f = this.staging;
|
|
266
270
|
const fields = BINDINGS.fields;
|
|
267
271
|
for (let axis = 0; axis < 2; axis += 1) {
|
|
@@ -280,6 +284,8 @@ export class SkinScatterPass {
|
|
|
280
284
|
f.set(this.profiles, base + fields.uProfiles.offset / 4);
|
|
281
285
|
/* The colour is applied once, on the axis that adds into the frame. */
|
|
282
286
|
f[base + fields.uApplyAlbedo.offset / 4] = axis;
|
|
287
|
+
this.stagingInts[base + fields.uOutputTransform.offset / 4] = outputTransform;
|
|
288
|
+
f[base + fields.uOutputExposure.offset / 4] = outputExposure;
|
|
283
289
|
}
|
|
284
290
|
this.device.queue.writeBuffer(this.uniforms, 0, f);
|
|
285
291
|
}
|
|
@@ -88,8 +88,18 @@ export declare const SKY_FIELDS: {
|
|
|
88
88
|
readonly size: 4;
|
|
89
89
|
readonly type: "float";
|
|
90
90
|
};
|
|
91
|
+
readonly uOutputTransform: {
|
|
92
|
+
readonly offset: 224;
|
|
93
|
+
readonly size: 4;
|
|
94
|
+
readonly type: "int";
|
|
95
|
+
};
|
|
96
|
+
readonly uOutputExposure: {
|
|
97
|
+
readonly offset: 228;
|
|
98
|
+
readonly size: 4;
|
|
99
|
+
readonly type: "float";
|
|
100
|
+
};
|
|
91
101
|
};
|
|
92
|
-
export declare const SKY_UNIFORM_SIZE:
|
|
102
|
+
export declare const SKY_UNIFORM_SIZE: 240;
|
|
93
103
|
export declare function createSkyBindGroupLayout(device: GPUDevice): GPUBindGroupLayout;
|
|
94
104
|
export declare function createSkyBindGroup(device: GPUDevice, layout: GPUBindGroupLayout, uniforms: GPUBuffer): GPUBindGroup;
|
|
95
105
|
/**
|
|
@@ -11,7 +11,7 @@ import type { UniformFields } from './scatterPass.ts';
|
|
|
11
11
|
export declare const WATER_VERT_FIELDS: UniformFields;
|
|
12
12
|
export declare const WATER_VERT_SIZE: 208;
|
|
13
13
|
export declare const WATER_FRAG_FIELDS: UniformFields;
|
|
14
|
-
export declare const WATER_FRAG_SIZE:
|
|
14
|
+
export declare const WATER_FRAG_SIZE: 1520;
|
|
15
15
|
/** The two meshes and the numbers the grid decided, behind the surface's opaque handle. */
|
|
16
16
|
export interface GpuWater {
|
|
17
17
|
/** The ocean: near sheet and far skirt in one buffer. */
|
|
@@ -14,7 +14,7 @@ import type { PipelineCache } from './pipelineCache.ts';
|
|
|
14
14
|
export declare const WIND_STREAK_VERT_FIELDS: UniformFields;
|
|
15
15
|
export declare const WIND_STREAK_VERT_SIZE: 128;
|
|
16
16
|
export declare const WIND_STREAK_FRAG_FIELDS: UniformFields;
|
|
17
|
-
export declare const WIND_STREAK_FRAG_SIZE:
|
|
17
|
+
export declare const WIND_STREAK_FRAG_SIZE: 32;
|
|
18
18
|
/** A lattice on the device, behind the surface's opaque handle. */
|
|
19
19
|
export interface GpuWindStreaks {
|
|
20
20
|
readonly corners: GPUBuffer;
|
|
@@ -60,6 +60,8 @@ export declare class CausticsRenderer {
|
|
|
60
60
|
*
|
|
61
61
|
* Answers whether it drew, which the renderer counts on its frame budget.
|
|
62
62
|
*/
|
|
63
|
-
draw(gl: WebGL2RenderingContext, camera: FrameView, timeSeconds: number, directionalDir: Vec3, directionalColor: Vec3, ambient: Vec3, atmosphere: Atmosphere, underwaterEnabled: boolean, windX?: number, windZ?: number, strength?: number
|
|
63
|
+
draw(gl: WebGL2RenderingContext, camera: FrameView, timeSeconds: number, directionalDir: Vec3, directionalColor: Vec3, ambient: Vec3, atmosphere: Atmosphere, underwaterEnabled: boolean, windX?: number, windZ?: number, strength?: number,
|
|
64
|
+
/** The renderer's `passGrade`: the frame's, but none in a probe's face or a capture. */
|
|
65
|
+
outputTransform?: number, outputExposure?: number): boolean;
|
|
64
66
|
dispose(gl: WebGL2RenderingContext): void;
|
|
65
67
|
}
|
|
@@ -66,11 +66,15 @@ export class CausticsRenderer {
|
|
|
66
66
|
*
|
|
67
67
|
* Answers whether it drew, which the renderer counts on its frame budget.
|
|
68
68
|
*/
|
|
69
|
-
draw(gl, camera, timeSeconds, directionalDir, directionalColor, ambient, atmosphere, underwaterEnabled, windX = 0, windZ = 0, strength = 1
|
|
69
|
+
draw(gl, camera, timeSeconds, directionalDir, directionalColor, ambient, atmosphere, underwaterEnabled, windX = 0, windZ = 0, strength = 1,
|
|
70
|
+
/** The renderer's `passGrade`: the frame's, but none in a probe's face or a capture. */
|
|
71
|
+
outputTransform = 0, outputExposure = 1) {
|
|
70
72
|
if (this.vertexCount === 0)
|
|
71
73
|
return false;
|
|
72
74
|
const u = this.uniforms;
|
|
73
75
|
gl.useProgram(this.program);
|
|
76
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, outputTransform);
|
|
77
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, outputExposure);
|
|
74
78
|
gl.uniformMatrix4fv(u['uViewProj'] ?? null, false, camera.viewProjection);
|
|
75
79
|
gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
|
|
76
80
|
gl.uniform1f(u['uTime'] ?? null, timeSeconds);
|
|
@@ -29,6 +29,8 @@ export declare class DecalPass {
|
|
|
29
29
|
* turns a stored depth back into the clip space that matrix was built in, and pairing it with
|
|
30
30
|
* the corrected one applies the remap twice. `lightVolumeDraw.ts` carries that derivation.
|
|
31
31
|
*/
|
|
32
|
-
drawDecals(queue: DecalQueue, depth: WebGLTexture, viewProjection: ReadonlyMat4, eye: ArrayLike<number>, width: number, height: number
|
|
32
|
+
drawDecals(queue: DecalQueue, depth: WebGLTexture, viewProjection: ReadonlyMat4, eye: ArrayLike<number>, width: number, height: number,
|
|
33
|
+
/** The renderer's `passGrade`: how the frame under the marks was graded, 0 for not yet. */
|
|
34
|
+
outputTransform?: number): void;
|
|
33
35
|
dispose(): void;
|
|
34
36
|
}
|
package/dist/render/decalPass.js
CHANGED
|
@@ -42,7 +42,9 @@ export class DecalPass {
|
|
|
42
42
|
* turns a stored depth back into the clip space that matrix was built in, and pairing it with
|
|
43
43
|
* the corrected one applies the remap twice. `lightVolumeDraw.ts` carries that derivation.
|
|
44
44
|
*/
|
|
45
|
-
drawDecals(queue, depth, viewProjection, eye, width, height
|
|
45
|
+
drawDecals(queue, depth, viewProjection, eye, width, height,
|
|
46
|
+
/** The renderer's `passGrade`: how the frame under the marks was graded, 0 for not yet. */
|
|
47
|
+
outputTransform = 0) {
|
|
46
48
|
if (queue.length === 0)
|
|
47
49
|
return;
|
|
48
50
|
const { gl } = this;
|
|
@@ -50,6 +52,7 @@ export class DecalPass {
|
|
|
50
52
|
mat4.invert(this.depthToWorld, viewProjection);
|
|
51
53
|
mat4.multiply(this.depthToWorld, this.depthToWorld, DEPTH_01_TO_CLIP);
|
|
52
54
|
gl.useProgram(this.program);
|
|
55
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, outputTransform);
|
|
53
56
|
gl.bindVertexArray(this.vao);
|
|
54
57
|
gl.disable(gl.DEPTH_TEST);
|
|
55
58
|
gl.depthMask(false);
|
|
@@ -32,6 +32,6 @@ export declare class FlockRenderer {
|
|
|
32
32
|
private readonly buffers;
|
|
33
33
|
private readonly vertexCount;
|
|
34
34
|
constructor(gl: WebGL2RenderingContext, count: number);
|
|
35
|
-
draw(gl: WebGL2RenderingContext, camera: FrameView, timeSeconds: number, params: FlockParams, tint: Vec3, windX?: number, windZ?: number): void;
|
|
35
|
+
draw(gl: WebGL2RenderingContext, camera: FrameView, timeSeconds: number, params: FlockParams, tint: Vec3, windX?: number, windZ?: number, outputTransform?: number, outputExposure?: number): void;
|
|
36
36
|
dispose(gl: WebGL2RenderingContext): void;
|
|
37
37
|
}
|
|
@@ -34,9 +34,12 @@ export class FlockRenderer {
|
|
|
34
34
|
attach(indices, 2, 1);
|
|
35
35
|
gl.bindVertexArray(null);
|
|
36
36
|
}
|
|
37
|
-
draw(gl, camera, timeSeconds, params, tint, windX = 0, windZ = 0) {
|
|
37
|
+
draw(gl, camera, timeSeconds, params, tint, windX = 0, windZ = 0, outputTransform = 0, outputExposure = 1) {
|
|
38
38
|
const u = this.uniforms;
|
|
39
39
|
gl.useProgram(this.program);
|
|
40
|
+
/* The renderer's `passGrade`: the frame's, but none in a probe's face or a capture. */
|
|
41
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, outputTransform);
|
|
42
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, outputExposure);
|
|
40
43
|
gl.uniformMatrix4fv(u['uViewProj'] ?? null, false, camera.viewProjection);
|
|
41
44
|
/*
|
|
42
45
|
* No `uCameraPos` here, and the shader no longer declares one. It fed the banking that
|
|
@@ -97,6 +97,8 @@ export declare class GlobalMediumPass {
|
|
|
97
97
|
* `(ONE, SRC_ALPHA)` on colour is `dst * transmittance + inscatter`; alpha is left alone with
|
|
98
98
|
* `(ZERO, ONE)`, because the frame's own alpha is not the medium's to spend.
|
|
99
99
|
*/
|
|
100
|
-
compositeMedium(depth: WebGLTexture, frameWidth: number, frameHeight: number
|
|
100
|
+
compositeMedium(depth: WebGLTexture, frameWidth: number, frameHeight: number,
|
|
101
|
+
/** The renderer's `passGrade`: how the frame under the medium was graded. */
|
|
102
|
+
outputTransform?: number, outputExposure?: number): void;
|
|
101
103
|
dispose(): void;
|
|
102
104
|
}
|
|
@@ -192,7 +192,9 @@ export class GlobalMediumPass {
|
|
|
192
192
|
* `(ONE, SRC_ALPHA)` on colour is `dst * transmittance + inscatter`; alpha is left alone with
|
|
193
193
|
* `(ZERO, ONE)`, because the frame's own alpha is not the medium's to spend.
|
|
194
194
|
*/
|
|
195
|
-
compositeMedium(depth, frameWidth, frameHeight
|
|
195
|
+
compositeMedium(depth, frameWidth, frameHeight,
|
|
196
|
+
/** The renderer's `passGrade`: how the frame under the medium was graded. */
|
|
197
|
+
outputTransform = 0, outputExposure = 1) {
|
|
196
198
|
if (this.target === null || this.unavailable)
|
|
197
199
|
return;
|
|
198
200
|
const { gl } = this;
|
|
@@ -215,6 +217,8 @@ export class GlobalMediumPass {
|
|
|
215
217
|
this.mediumTexel[1] = 1 / Math.max(1, this.height);
|
|
216
218
|
gl.uniform2fv(u['uMediumTexel'] ?? null, this.mediumTexel);
|
|
217
219
|
gl.uniform4fv(u['uDepthToViewZ'] ?? null, this.depthToViewZ);
|
|
220
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, outputTransform);
|
|
221
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, outputExposure);
|
|
218
222
|
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
219
223
|
gl.bindVertexArray(null);
|
|
220
224
|
gl.activeTexture(gl.TEXTURE1);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The forward grade on the CPU: what `applyOutputTransform` in `shaders/outputTransform.ts` does to
|
|
3
|
+
* a colour, for a colour no shader draws — a clear colour, written to a target before any pass runs.
|
|
4
|
+
*
|
|
5
|
+
* **Why a clear colour is graded at all.** Every pass grades what it draws when nothing after it
|
|
6
|
+
* will, so a colour handed to the renderer means one thing wherever it lands: linear light. A clear
|
|
7
|
+
* left as it was given is the one colour in the frame read as a display value, so a scene whose fog
|
|
8
|
+
* fades to its background colour fades to a different colour than the background it meets; with
|
|
9
|
+
* `hdrScene` the resolve grades the clear with everything else, and a frame without it has to agree.
|
|
10
|
+
*
|
|
11
|
+
* **A second copy of the curve, and what holds the two together** is the hand-derived values in
|
|
12
|
+
* `gradeColor.test.ts`, the same ones the shader's own constants give: the sRGB encode's two
|
|
13
|
+
* segments, the ACES fit through its two matrices, and the highlight shoulder. Code 4, the filmic
|
|
14
|
+
* curve, is the composite's alone, so a forward code never carries it (`forwardTransformCode`).
|
|
15
|
+
*/
|
|
16
|
+
import type { Vec3 } from '../math/color.ts';
|
|
17
|
+
/**
|
|
18
|
+
* `color` graded by forward code `code` at `exposure` into `out`, which may be `color`: 0 leaves it
|
|
19
|
+
* as it is, 1 encodes it as sRGB, 2 runs ACES first and 3 the highlight shoulder. Allocates nothing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function gradeColorInto(code: number, exposure: number, color: Readonly<Vec3>, out: Vec3): Vec3;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/* Columns as the shader's `mat3` reads them, written here as rows of the product. */
|
|
2
|
+
const IN_R = [0.59719, 0.35458, 0.04823];
|
|
3
|
+
const IN_G = [0.076, 0.90834, 0.01566];
|
|
4
|
+
const IN_B = [0.0284, 0.13383, 0.83777];
|
|
5
|
+
const OUT_R = [1.60475, -0.53108, -0.07367];
|
|
6
|
+
const OUT_G = [-0.10208, 1.10813, -0.00605];
|
|
7
|
+
const OUT_B = [-0.00327, -0.07276, 1.07602];
|
|
8
|
+
/**
|
|
9
|
+
* `color` graded by forward code `code` at `exposure` into `out`, which may be `color`: 0 leaves it
|
|
10
|
+
* as it is, 1 encodes it as sRGB, 2 runs ACES first and 3 the highlight shoulder. Allocates nothing.
|
|
11
|
+
*/
|
|
12
|
+
export function gradeColorInto(code, exposure, color, out) {
|
|
13
|
+
let r = color[0];
|
|
14
|
+
let g = color[1];
|
|
15
|
+
let b = color[2];
|
|
16
|
+
if (code === 0) {
|
|
17
|
+
out[0] = r;
|
|
18
|
+
out[1] = g;
|
|
19
|
+
out[2] = b;
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
if (code === 2) {
|
|
23
|
+
const x = r * exposure;
|
|
24
|
+
const y = g * exposure;
|
|
25
|
+
const z = b * exposure;
|
|
26
|
+
const ir = fit(dot(IN_R, x, y, z));
|
|
27
|
+
const ig = fit(dot(IN_G, x, y, z));
|
|
28
|
+
const ib = fit(dot(IN_B, x, y, z));
|
|
29
|
+
r = clamp01(dot(OUT_R, ir, ig, ib));
|
|
30
|
+
g = clamp01(dot(OUT_G, ir, ig, ib));
|
|
31
|
+
b = clamp01(dot(OUT_B, ir, ig, ib));
|
|
32
|
+
}
|
|
33
|
+
else if (code === 3) {
|
|
34
|
+
r *= exposure;
|
|
35
|
+
g *= exposure;
|
|
36
|
+
b *= exposure;
|
|
37
|
+
const m = Math.max(r, g, b);
|
|
38
|
+
if (m > 0.8) {
|
|
39
|
+
const e = m - 0.8;
|
|
40
|
+
const k = (0.8 + (0.2 * e) / (e + 0.2)) / m;
|
|
41
|
+
r *= k;
|
|
42
|
+
g *= k;
|
|
43
|
+
b *= k;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
out[0] = encode(r);
|
|
47
|
+
out[1] = encode(g);
|
|
48
|
+
out[2] = encode(b);
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
function dot(row, x, y, z) {
|
|
52
|
+
return row[0] * x + row[1] * y + row[2] * z;
|
|
53
|
+
}
|
|
54
|
+
/** The RRT and ODT fit, `rrtAndOdtFit` in the shader. */
|
|
55
|
+
function fit(v) {
|
|
56
|
+
return (v * (v + 0.0245786) - 0.000090537) / (v * (0.983729 * v + 0.432951) + 0.238081);
|
|
57
|
+
}
|
|
58
|
+
/** Linear to sRGB, the piecewise form the shader uses. */
|
|
59
|
+
function encode(c) {
|
|
60
|
+
return c <= 0.0031308 ? c * 12.92 : 1.055 * Math.max(c, 0) ** (1 / 2.4) - 0.055;
|
|
61
|
+
}
|
|
62
|
+
function clamp01(v) {
|
|
63
|
+
return v < 0 ? 0 : v > 1 ? 1 : v;
|
|
64
|
+
}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { mat4 } from 'gl-matrix';
|
|
2
2
|
import type { Vec3 } from '../math/color.ts';
|
|
3
3
|
export declare function computeLightMatrix(lightDir: Vec3, focusX: number, focusY: number, focusZ: number, radius: number, shadowMapSize: number, out: mat4): number;
|
|
4
|
+
/**
|
|
5
|
+
* A directional light's matrix covering a box of known size whole: a model, a level, a room. The
|
|
6
|
+
* sphere around the box, at its centre, through `computeLightMatrix`, widened by the half texel the
|
|
7
|
+
* centre's snap may move it so a corner on the sphere stays inside. Returns the depth span, as that
|
|
8
|
+
* does.
|
|
9
|
+
*
|
|
10
|
+
* **For a scene whose extent is known rather than one that follows a viewer.** A radius chosen by
|
|
11
|
+
* eye around a guessed centre leaves part of the model outside the map, where it casts nothing; the
|
|
12
|
+
* bounds are the answer, and a loader has them. **What it gives up** is resolution where the box is
|
|
13
|
+
* large: the map's texels are spread over all of it, so a building's shadows are coarser than a
|
|
14
|
+
* focus on the viewer would draw them, which is what `computeLightMatrix` around the viewer is for.
|
|
15
|
+
*/
|
|
16
|
+
export declare function computeLightMatrixForBounds(lightDir: Vec3, min: Readonly<Vec3>, max: Readonly<Vec3>, shadowMapSize: number, out: mat4): number;
|
|
4
17
|
/**
|
|
5
18
|
* The depth an orthographic light matrix spans, in metres: what `computeLightMatrix` returns, read
|
|
6
19
|
* back off any such matrix. Its depth row is the light's axis scaled by two over the span, so the
|
|
@@ -43,6 +43,23 @@ export function computeLightMatrix(lightDir, focusX, focusY, focusZ, radius, sha
|
|
|
43
43
|
// to express its residual depth tolerance in stable world-space metres.
|
|
44
44
|
return radius * 6;
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* A directional light's matrix covering a box of known size whole: a model, a level, a room. The
|
|
48
|
+
* sphere around the box, at its centre, through `computeLightMatrix`, widened by the half texel the
|
|
49
|
+
* centre's snap may move it so a corner on the sphere stays inside. Returns the depth span, as that
|
|
50
|
+
* does.
|
|
51
|
+
*
|
|
52
|
+
* **For a scene whose extent is known rather than one that follows a viewer.** A radius chosen by
|
|
53
|
+
* eye around a guessed centre leaves part of the model outside the map, where it casts nothing; the
|
|
54
|
+
* bounds are the answer, and a loader has them. **What it gives up** is resolution where the box is
|
|
55
|
+
* large: the map's texels are spread over all of it, so a building's shadows are coarser than a
|
|
56
|
+
* focus on the viewer would draw them, which is what `computeLightMatrix` around the viewer is for.
|
|
57
|
+
*/
|
|
58
|
+
export function computeLightMatrixForBounds(lightDir, min, max, shadowMapSize, out) {
|
|
59
|
+
const half = Math.hypot(max[0] - min[0], max[1] - min[1], max[2] - min[2]) / 2;
|
|
60
|
+
const radius = Math.max(half, 1e-3) * (1 + 2 / Math.max(shadowMapSize, 1));
|
|
61
|
+
return computeLightMatrix(lightDir, (min[0] + max[0]) / 2, (min[1] + max[1]) / 2, (min[2] + max[2]) / 2, radius, shadowMapSize, out);
|
|
62
|
+
}
|
|
46
63
|
/**
|
|
47
64
|
* The depth an orthographic light matrix spans, in metres: what `computeLightMatrix` returns, read
|
|
48
65
|
* back off any such matrix. Its depth row is the light's axis scaled by two over the span, so the
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `uOutputTransform` a pass uploads: `storing` inside a probe's face or a capture, `presented`
|
|
3
|
+
* once the frame's resolve has run, `resolveGrades` where that resolve applies the transform.
|
|
4
|
+
*/
|
|
5
|
+
export declare function passGradeCode(storing: boolean, presented: boolean, resolveGrades: boolean, outputTransform: string): number;
|
|
6
|
+
/** The `uOutputExposure` beside it: the frame's exposure wherever the pass grades, else one. */
|
|
7
|
+
export declare function passGradeExposure(storing: boolean, presented: boolean, resolveGrades: boolean, exposure: number): number;
|
|
8
|
+
/**
|
|
9
|
+
* The code an interface draws with, given the pass's: the screen encode wherever the pass grades at
|
|
10
|
+
* all, and nothing where it does not. Never a curve, so never an exposure either: a screen-space
|
|
11
|
+
* caption, a panel or a 2D layer keeps the colour it was picked as whatever the scene is graded by.
|
|
12
|
+
*/
|
|
13
|
+
export declare function interfaceGrade(passCode: number): number;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which grade a pass applies to what it draws, decided once for both backends.
|
|
3
|
+
*
|
|
4
|
+
* **Every pass grades where nothing after it will**, so a colour handed to the renderer means linear
|
|
5
|
+
* light wherever it lands. Three facts decide where that is:
|
|
6
|
+
*
|
|
7
|
+
* - **A probe's face or a capture stores radiance** for something else to light with or to show, so
|
|
8
|
+
* it is never graded. The frame grades what it reads of one; graded at the bake as well, the curve
|
|
9
|
+
* would be applied twice.
|
|
10
|
+
* - **A frame whose resolve grades** (`hdrScene` over a scene target) leaves every pass before the
|
|
11
|
+
* resolve linear, because grading early throws away the range the float target exists to keep.
|
|
12
|
+
* - **Past the present, a pass lands on the canvas the resolve has already written**, so nothing
|
|
13
|
+
* after it will grade it and it grades itself with the frame's forward code, composite or not. An
|
|
14
|
+
* interface drawn after `endFrame` escapes the screen-space chain; it does not escape the grade.
|
|
15
|
+
*
|
|
16
|
+
* **An interface takes the screen encode and not the curve** (`interfaceGrade`). A tone curve and
|
|
17
|
+
* an exposure are how a scene's light is brought to the screen, and a caption or a panel is not
|
|
18
|
+
* light: its colour was picked for the screen, so it is encoded wherever the frame is and comes out
|
|
19
|
+
* as picked under every transform, at every exposure. What it gives up is an interface drawn inside
|
|
20
|
+
* a frame whose resolve grades (`hdrScene`): that one is part of the picture the resolve tone maps,
|
|
21
|
+
* and is drawn after `endFrame` to stay out of it. What would make any of this wrong is a composite
|
|
22
|
+
* step running after the present, which none does.
|
|
23
|
+
*/
|
|
24
|
+
import { forwardTransformCode } from './vertexDefaults.js';
|
|
25
|
+
/**
|
|
26
|
+
* The `uOutputTransform` a pass uploads: `storing` inside a probe's face or a capture, `presented`
|
|
27
|
+
* once the frame's resolve has run, `resolveGrades` where that resolve applies the transform.
|
|
28
|
+
*/
|
|
29
|
+
export function passGradeCode(storing, presented, resolveGrades, outputTransform) {
|
|
30
|
+
if (storing)
|
|
31
|
+
return 0;
|
|
32
|
+
return presented || !resolveGrades ? forwardTransformCode(outputTransform) : 0;
|
|
33
|
+
}
|
|
34
|
+
/** The `uOutputExposure` beside it: the frame's exposure wherever the pass grades, else one. */
|
|
35
|
+
export function passGradeExposure(storing, presented, resolveGrades, exposure) {
|
|
36
|
+
if (storing)
|
|
37
|
+
return 1;
|
|
38
|
+
return presented || !resolveGrades ? exposure : 1;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The code an interface draws with, given the pass's: the screen encode wherever the pass grades at
|
|
42
|
+
* all, and nothing where it does not. Never a curve, so never an exposure either: a screen-space
|
|
43
|
+
* caption, a panel or a 2D layer keeps the colour it was picked as whatever the scene is graded by.
|
|
44
|
+
*/
|
|
45
|
+
export function interfaceGrade(passCode) {
|
|
46
|
+
return passCode === 0 ? 0 : 1;
|
|
47
|
+
}
|
|
@@ -89,7 +89,7 @@ export declare class PlumeRenderer {
|
|
|
89
89
|
* the sky at depth 1.0 under LEQUAL would otherwise overwrite anything drawn
|
|
90
90
|
* against open background.
|
|
91
91
|
*/
|
|
92
|
-
draw(gl: WebGL2RenderingContext, camera: FrameView, timeSeconds: number, atmosphere: Atmosphere, underwaterEnabled: boolean, atmosphereCameraY: number, clipPlane: Float32Array | null, windX?: number, windZ?: number, originX?: number, originY?: number, originZ?: number): void;
|
|
92
|
+
draw(gl: WebGL2RenderingContext, camera: FrameView, timeSeconds: number, atmosphere: Atmosphere, underwaterEnabled: boolean, atmosphereCameraY: number, clipPlane: Float32Array | null, windX?: number, windZ?: number, originX?: number, originY?: number, originZ?: number, outputTransform?: number, outputExposure?: number): void;
|
|
93
93
|
dispose(gl: WebGL2RenderingContext): void;
|
|
94
94
|
/** Uploads one attribute and returns its buffer, for the rare one a caller can change. */
|
|
95
95
|
private attach;
|
|
@@ -93,7 +93,7 @@ export class PlumeRenderer {
|
|
|
93
93
|
* the sky at depth 1.0 under LEQUAL would otherwise overwrite anything drawn
|
|
94
94
|
* against open background.
|
|
95
95
|
*/
|
|
96
|
-
draw(gl, camera, timeSeconds, atmosphere, underwaterEnabled, atmosphereCameraY, clipPlane, windX = 0, windZ = 0, originX = 0, originY = 0, originZ = 0) {
|
|
96
|
+
draw(gl, camera, timeSeconds, atmosphere, underwaterEnabled, atmosphereCameraY, clipPlane, windX = 0, windZ = 0, originX = 0, originY = 0, originZ = 0, outputTransform = 0, outputExposure = 1) {
|
|
97
97
|
if (this.indexCount === 0)
|
|
98
98
|
return;
|
|
99
99
|
const u = this.uniforms;
|
|
@@ -121,6 +121,9 @@ export class PlumeRenderer {
|
|
|
121
121
|
gl.uniform1i(u['uClipEnabled'] ?? null, clipPlane === null ? 0 : 1);
|
|
122
122
|
if (clipPlane !== null)
|
|
123
123
|
gl.uniform4fv(u['uClipPlane'] ?? null, clipPlane);
|
|
124
|
+
/* The renderer's `passGrade`: the frame's, but none in a probe's face or a capture. */
|
|
125
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, outputTransform);
|
|
126
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, outputExposure);
|
|
124
127
|
bindAtmosphere(gl, u, atmosphere, atmosphereCameraY, underwaterEnabled);
|
|
125
128
|
gl.enable(gl.BLEND);
|
|
126
129
|
if (this.blend === 'additive')
|
|
@@ -50,22 +50,35 @@ export type GlassShadows = 'full' | 'half' | 'off';
|
|
|
50
50
|
export type SkinScattering = 'pre-integrated' | 'screen-space';
|
|
51
51
|
export interface RenderQuality {
|
|
52
52
|
/**
|
|
53
|
-
* The transfer curve applied at the end of every shaded pass.
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
53
|
+
* The transfer curve applied at the end of every shaded pass. Construction-time, like every
|
|
54
|
+
* other quality control here.
|
|
55
|
+
*
|
|
56
|
+
* **`srgb` by default since 4.13.0, the encoding a display expects**: the light the renderer
|
|
57
|
+
* computes is linear, and a texture's colours are decoded to linear when they are read, so a
|
|
58
|
+
* frame written without encoding them back is a frame of linear values read as display values —
|
|
59
|
+
* every midtone far too dark. It is the encoding most renderers apply by default, so a model
|
|
60
|
+
* drawn here with no options reads as it does elsewhere. **What it gives up** is a highlight's
|
|
61
|
+
* colour: above 1 each channel clips on its own, so a bright saturated source goes to white
|
|
62
|
+
* rather than rolling off, which a curve with a shoulder (`aces`, `shoulder`) is for.
|
|
63
|
+
*
|
|
64
|
+
* **`none` was the default until 4.13.0, and it is the frame that reads as dark**: values
|
|
65
|
+
* written as they are computed, which is right only for a world whose colours were chosen by
|
|
66
|
+
* eye as display values and lit to match. It was reported by eye as "dark", "flat" or "not
|
|
67
|
+
* vivid", which sounds like a lighting problem, so that is where people looked; a consumer
|
|
68
|
+
* built, tuned and shipped six worlds under it before anybody said the word, and a model drawn
|
|
69
|
+
* from the manual came out darker than in any other engine. A world graded under it says
|
|
70
|
+
* `outputTransform: 'none'` and draws exactly as it did. **What would make `srgb` the wrong
|
|
71
|
+
* default** is a renderer whose colours are not linear, which this one's are not.
|
|
72
|
+
*
|
|
73
|
+
* **Every pass applies it where nothing after it will**, and the clear colour with them, so a
|
|
74
|
+
* colour handed to the renderer is linear wherever it lands: a frame with `hdrScene` is graded
|
|
75
|
+
* once at the resolve, and one without it is graded pass by pass to the same curve. A colour
|
|
76
|
+
* picked by eye is a display value, so it is stated through `srgbColor` (or a mesh built with
|
|
77
|
+
* `colorSpace: 'srgb'`), which gives back exactly the colour picked where a surface is lit at 1
|
|
78
|
+
* under `srgb`, and through the curve under a tone curve. **An interface** (screen text, a panel,
|
|
79
|
+
* the 2D layer) takes the screen encode and never the curve or the exposure, so its colours come
|
|
80
|
+
* out as picked under every transform; inside an `hdrScene` frame it is part of the picture the
|
|
81
|
+
* resolve grades, and is drawn after `endFrame` to stay out of the curve.
|
|
69
82
|
*/
|
|
70
83
|
readonly outputTransform: OutputTransform;
|
|
71
84
|
/**
|
|
@@ -259,9 +272,35 @@ export interface RenderQuality {
|
|
|
259
272
|
* at a shadow's edge — that is what the blur is for.
|
|
260
273
|
*/
|
|
261
274
|
readonly skinScattering: SkinScattering;
|
|
262
|
-
/**
|
|
275
|
+
/**
|
|
276
|
+
* How far a sun shadow may reach along the ground from its caster, in metres, before it
|
|
277
|
+
* dissolves. **Not a distance from the camera**: a shadow's own length, from where it leaves its
|
|
278
|
+
* caster to where it lands, fading from 35% of this to all of it.
|
|
279
|
+
*
|
|
280
|
+
* **1,000 since 4.13.0, so no building's shadow dissolves**: the fade starts at 350 m, past any
|
|
281
|
+
* wall, tower or canyon a shadow map covers at a useful resolution, so what bounds a shadow is
|
|
282
|
+
* its map, whose edge already fades. **What it gives up** is a way to hide a long shadow's
|
|
283
|
+
* stair-stepping at a low sun, which is what a short reach was for. It was 6 until 4.13.0: a
|
|
284
|
+
* tuning for short casters, which left a building's walls and arcades casting nothing on its
|
|
285
|
+
* floor under a high sun — the shadows vanished silently and read as random lighting. **What
|
|
286
|
+
* would make it wrong** is a scene whose shadows are too coarse to show at their full length;
|
|
287
|
+
* there a reach of the length that looks right is the setting, and the map around the viewer
|
|
288
|
+
* (`computeLightMatrix`) the better fix.
|
|
289
|
+
*/
|
|
263
290
|
readonly directionalShadowMaxDistance: number;
|
|
264
|
-
/**
|
|
291
|
+
/**
|
|
292
|
+
* How low the sun may stand before its shadows fade, as the ground a metre of height may shadow:
|
|
293
|
+
* the sun's horizontal reach per vertical metre, so 1 is 45° of elevation and 60 about 1°. Every
|
|
294
|
+
* sun shadow fades from 65% of this to all of it.
|
|
295
|
+
*
|
|
296
|
+
* **60 since 4.13.0: shadows hold until the sun is about a degree above the horizon**, the
|
|
297
|
+
* stretch of a day when they are longest and most worth seeing. **What it gives up**: a sun on
|
|
298
|
+
* the horizon throws shadows kilometres long that a map can hold only as stripes, and the
|
|
299
|
+
* last degree is where they fade rather than show. It was 3 until 4.13.0, which dropped every
|
|
300
|
+
* sun shadow below about 18° — an evening without shadows. **What would make it wrong** is a
|
|
301
|
+
* scene whose low sun streaks; a smaller number here is the setting, at the cost of the
|
|
302
|
+
* shadows going earlier in the evening.
|
|
303
|
+
*/
|
|
265
304
|
readonly directionalShadowMaxSlope: number;
|
|
266
305
|
/**
|
|
267
306
|
* Metres a point light may drift from where its shadow was baked before re-baking.
|
|
@@ -17,7 +17,7 @@ export const DIRECTIONAL_SHADOW_FADE_START = 0.65;
|
|
|
17
17
|
* six times, while the directional map spends all of it on one focused area.
|
|
18
18
|
*/
|
|
19
19
|
export const DEFAULT_RENDER_QUALITY = Object.freeze({
|
|
20
|
-
outputTransform: '
|
|
20
|
+
outputTransform: 'srgb',
|
|
21
21
|
outputExposure: 1,
|
|
22
22
|
pointLightFalloff: 'smooth',
|
|
23
23
|
/**
|
|
@@ -65,8 +65,8 @@ export const DEFAULT_RENDER_QUALITY = Object.freeze({
|
|
|
65
65
|
glassShadows: 'full',
|
|
66
66
|
pipelineCompile: 'wait',
|
|
67
67
|
skinScattering: 'pre-integrated',
|
|
68
|
-
directionalShadowMaxDistance:
|
|
69
|
-
directionalShadowMaxSlope:
|
|
68
|
+
directionalShadowMaxDistance: 1000,
|
|
69
|
+
directionalShadowMaxSlope: 60,
|
|
70
70
|
pointShadowRebakeDistance: 0.001,
|
|
71
71
|
pointShadowFacesPerFrame: 2,
|
|
72
72
|
/*
|
|
@@ -303,6 +303,8 @@ export declare class SceneTarget {
|
|
|
303
303
|
readonly transform: number;
|
|
304
304
|
readonly exposure: number;
|
|
305
305
|
readonly film?: Float32Array;
|
|
306
|
+
/** Whether the forward passes graded the scene because this resolve does not. */
|
|
307
|
+
readonly sceneGraded?: boolean;
|
|
306
308
|
}, motion?: {
|
|
307
309
|
readonly reprojection: Float32Array;
|
|
308
310
|
readonly strength: number;
|
|
@@ -819,6 +819,7 @@ export class SceneTarget {
|
|
|
819
819
|
gl.uniform1f(this.uniforms['uReach'] ?? null, reachUv);
|
|
820
820
|
gl.uniform1i(this.uniforms['uOutputTransform'] ?? null, grade.transform);
|
|
821
821
|
gl.uniform1f(this.uniforms['uOutputExposure'] ?? null, grade.exposure);
|
|
822
|
+
gl.uniform1i(this.uniforms['uSceneGraded'] ?? null, grade.sceneGraded === true ? 1 : 0);
|
|
822
823
|
if (grade.film !== undefined) {
|
|
823
824
|
gl.uniform4fv(this.uniforms['uFilmA'] ?? null, grade.film, 0, 4);
|
|
824
825
|
gl.uniform4fv(this.uniforms['uFilmB'] ?? null, grade.film, 4, 4);
|
|
@@ -65,7 +65,7 @@ export declare class SdfTextRenderer {
|
|
|
65
65
|
*/
|
|
66
66
|
/**
|
|
67
67
|
* `outputTransform` and `outputExposure` come from the renderer rather than from here, because
|
|
68
|
-
* whether this pass grades depends on whether anything after it will. See `
|
|
68
|
+
* whether this pass grades depends on whether anything after it will. See `passGrade.ts`.
|
|
69
69
|
*/
|
|
70
70
|
draw(viewProj: ReadonlyMat4, model: Float32Array, color: Vec3, opacity: number, outputTransform: number, outputExposure: number): boolean;
|
|
71
71
|
dispose(): void;
|
|
@@ -103,7 +103,7 @@ export class SdfTextRenderer {
|
|
|
103
103
|
*/
|
|
104
104
|
/**
|
|
105
105
|
* `outputTransform` and `outputExposure` come from the renderer rather than from here, because
|
|
106
|
-
* whether this pass grades depends on whether anything after it will. See `
|
|
106
|
+
* whether this pass grades depends on whether anything after it will. See `passGrade.ts`.
|
|
107
107
|
*/
|
|
108
108
|
draw(viewProj, model, color, opacity, outputTransform, outputExposure) {
|
|
109
109
|
if (this.layout.quadCount === 0 || opacity <= 0 || this.font === null || this.atlas === null) {
|