@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
|
@@ -68,6 +68,38 @@ export function computeLightMatrix(
|
|
|
68
68
|
return radius * 6;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* A directional light's matrix covering a box of known size whole: a model, a level, a room. The
|
|
73
|
+
* sphere around the box, at its centre, through `computeLightMatrix`, widened by the half texel the
|
|
74
|
+
* centre's snap may move it so a corner on the sphere stays inside. Returns the depth span, as that
|
|
75
|
+
* does.
|
|
76
|
+
*
|
|
77
|
+
* **For a scene whose extent is known rather than one that follows a viewer.** A radius chosen by
|
|
78
|
+
* eye around a guessed centre leaves part of the model outside the map, where it casts nothing; the
|
|
79
|
+
* bounds are the answer, and a loader has them. **What it gives up** is resolution where the box is
|
|
80
|
+
* large: the map's texels are spread over all of it, so a building's shadows are coarser than a
|
|
81
|
+
* focus on the viewer would draw them, which is what `computeLightMatrix` around the viewer is for.
|
|
82
|
+
*/
|
|
83
|
+
export function computeLightMatrixForBounds(
|
|
84
|
+
lightDir: Vec3,
|
|
85
|
+
min: Readonly<Vec3>,
|
|
86
|
+
max: Readonly<Vec3>,
|
|
87
|
+
shadowMapSize: number,
|
|
88
|
+
out: mat4,
|
|
89
|
+
): number {
|
|
90
|
+
const half = Math.hypot(max[0] - min[0], max[1] - min[1], max[2] - min[2]) / 2;
|
|
91
|
+
const radius = Math.max(half, 1e-3) * (1 + 2 / Math.max(shadowMapSize, 1));
|
|
92
|
+
return computeLightMatrix(
|
|
93
|
+
lightDir,
|
|
94
|
+
(min[0] + max[0]) / 2,
|
|
95
|
+
(min[1] + max[1]) / 2,
|
|
96
|
+
(min[2] + max[2]) / 2,
|
|
97
|
+
radius,
|
|
98
|
+
shadowMapSize,
|
|
99
|
+
out,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
71
103
|
/**
|
|
72
104
|
* The depth an orthographic light matrix spans, in metres: what `computeLightMatrix` returns, read
|
|
73
105
|
* back off any such matrix. Its depth row is the light's axis scaled by two over the span, so the
|
|
@@ -0,0 +1,58 @@
|
|
|
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.ts';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The `uOutputTransform` a pass uploads: `storing` inside a probe's face or a capture, `presented`
|
|
28
|
+
* once the frame's resolve has run, `resolveGrades` where that resolve applies the transform.
|
|
29
|
+
*/
|
|
30
|
+
export function passGradeCode(
|
|
31
|
+
storing: boolean,
|
|
32
|
+
presented: boolean,
|
|
33
|
+
resolveGrades: boolean,
|
|
34
|
+
outputTransform: string,
|
|
35
|
+
): number {
|
|
36
|
+
if (storing) return 0;
|
|
37
|
+
return presented || !resolveGrades ? forwardTransformCode(outputTransform) : 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The `uOutputExposure` beside it: the frame's exposure wherever the pass grades, else one. */
|
|
41
|
+
export function passGradeExposure(
|
|
42
|
+
storing: boolean,
|
|
43
|
+
presented: boolean,
|
|
44
|
+
resolveGrades: boolean,
|
|
45
|
+
exposure: number,
|
|
46
|
+
): number {
|
|
47
|
+
if (storing) return 1;
|
|
48
|
+
return presented || !resolveGrades ? exposure : 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The code an interface draws with, given the pass's: the screen encode wherever the pass grades at
|
|
53
|
+
* all, and nothing where it does not. Never a curve, so never an exposure either: a screen-space
|
|
54
|
+
* caption, a panel or a 2D layer keeps the colour it was picked as whatever the scene is graded by.
|
|
55
|
+
*/
|
|
56
|
+
export function interfaceGrade(passCode: number): number {
|
|
57
|
+
return passCode === 0 ? 0 : 1;
|
|
58
|
+
}
|
|
@@ -173,6 +173,8 @@ export class PlumeRenderer {
|
|
|
173
173
|
originX = 0,
|
|
174
174
|
originY = 0,
|
|
175
175
|
originZ = 0,
|
|
176
|
+
outputTransform = 0,
|
|
177
|
+
outputExposure = 1,
|
|
176
178
|
): void {
|
|
177
179
|
if (this.indexCount === 0) return;
|
|
178
180
|
const u = this.uniforms;
|
|
@@ -200,6 +202,9 @@ export class PlumeRenderer {
|
|
|
200
202
|
gl.uniform3f(u['uTint'] ?? null, this.tint[0], this.tint[1], this.tint[2]);
|
|
201
203
|
gl.uniform1i(u['uClipEnabled'] ?? null, clipPlane === null ? 0 : 1);
|
|
202
204
|
if (clipPlane !== null) gl.uniform4fv(u['uClipPlane'] ?? null, clipPlane);
|
|
205
|
+
/* The renderer's `passGrade`: the frame's, but none in a probe's face or a capture. */
|
|
206
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, outputTransform);
|
|
207
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, outputExposure);
|
|
203
208
|
bindAtmosphere(gl, u, atmosphere, atmosphereCameraY, underwaterEnabled);
|
|
204
209
|
|
|
205
210
|
gl.enable(gl.BLEND);
|
|
@@ -61,22 +61,35 @@ export type SkinScattering = 'pre-integrated' | 'screen-space';
|
|
|
61
61
|
|
|
62
62
|
export interface RenderQuality {
|
|
63
63
|
/**
|
|
64
|
-
* The transfer curve applied at the end of every shaded pass.
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
64
|
+
* The transfer curve applied at the end of every shaded pass. Construction-time, like every
|
|
65
|
+
* other quality control here.
|
|
66
|
+
*
|
|
67
|
+
* **`srgb` by default since 4.13.0, the encoding a display expects**: the light the renderer
|
|
68
|
+
* computes is linear, and a texture's colours are decoded to linear when they are read, so a
|
|
69
|
+
* frame written without encoding them back is a frame of linear values read as display values —
|
|
70
|
+
* every midtone far too dark. It is the encoding most renderers apply by default, so a model
|
|
71
|
+
* drawn here with no options reads as it does elsewhere. **What it gives up** is a highlight's
|
|
72
|
+
* colour: above 1 each channel clips on its own, so a bright saturated source goes to white
|
|
73
|
+
* rather than rolling off, which a curve with a shoulder (`aces`, `shoulder`) is for.
|
|
74
|
+
*
|
|
75
|
+
* **`none` was the default until 4.13.0, and it is the frame that reads as dark**: values
|
|
76
|
+
* written as they are computed, which is right only for a world whose colours were chosen by
|
|
77
|
+
* eye as display values and lit to match. It was reported by eye as "dark", "flat" or "not
|
|
78
|
+
* vivid", which sounds like a lighting problem, so that is where people looked; a consumer
|
|
79
|
+
* built, tuned and shipped six worlds under it before anybody said the word, and a model drawn
|
|
80
|
+
* from the manual came out darker than in any other engine. A world graded under it says
|
|
81
|
+
* `outputTransform: 'none'` and draws exactly as it did. **What would make `srgb` the wrong
|
|
82
|
+
* default** is a renderer whose colours are not linear, which this one's are not.
|
|
83
|
+
*
|
|
84
|
+
* **Every pass applies it where nothing after it will**, and the clear colour with them, so a
|
|
85
|
+
* colour handed to the renderer is linear wherever it lands: a frame with `hdrScene` is graded
|
|
86
|
+
* once at the resolve, and one without it is graded pass by pass to the same curve. A colour
|
|
87
|
+
* picked by eye is a display value, so it is stated through `srgbColor` (or a mesh built with
|
|
88
|
+
* `colorSpace: 'srgb'`), which gives back exactly the colour picked where a surface is lit at 1
|
|
89
|
+
* under `srgb`, and through the curve under a tone curve. **An interface** (screen text, a panel,
|
|
90
|
+
* the 2D layer) takes the screen encode and never the curve or the exposure, so its colours come
|
|
91
|
+
* out as picked under every transform; inside an `hdrScene` frame it is part of the picture the
|
|
92
|
+
* resolve grades, and is drawn after `endFrame` to stay out of the curve.
|
|
80
93
|
*/
|
|
81
94
|
readonly outputTransform: OutputTransform;
|
|
82
95
|
/**
|
|
@@ -270,9 +283,35 @@ export interface RenderQuality {
|
|
|
270
283
|
* at a shadow's edge — that is what the blur is for.
|
|
271
284
|
*/
|
|
272
285
|
readonly skinScattering: SkinScattering;
|
|
273
|
-
/**
|
|
286
|
+
/**
|
|
287
|
+
* How far a sun shadow may reach along the ground from its caster, in metres, before it
|
|
288
|
+
* dissolves. **Not a distance from the camera**: a shadow's own length, from where it leaves its
|
|
289
|
+
* caster to where it lands, fading from 35% of this to all of it.
|
|
290
|
+
*
|
|
291
|
+
* **1,000 since 4.13.0, so no building's shadow dissolves**: the fade starts at 350 m, past any
|
|
292
|
+
* wall, tower or canyon a shadow map covers at a useful resolution, so what bounds a shadow is
|
|
293
|
+
* its map, whose edge already fades. **What it gives up** is a way to hide a long shadow's
|
|
294
|
+
* stair-stepping at a low sun, which is what a short reach was for. It was 6 until 4.13.0: a
|
|
295
|
+
* tuning for short casters, which left a building's walls and arcades casting nothing on its
|
|
296
|
+
* floor under a high sun — the shadows vanished silently and read as random lighting. **What
|
|
297
|
+
* would make it wrong** is a scene whose shadows are too coarse to show at their full length;
|
|
298
|
+
* there a reach of the length that looks right is the setting, and the map around the viewer
|
|
299
|
+
* (`computeLightMatrix`) the better fix.
|
|
300
|
+
*/
|
|
274
301
|
readonly directionalShadowMaxDistance: number;
|
|
275
|
-
/**
|
|
302
|
+
/**
|
|
303
|
+
* How low the sun may stand before its shadows fade, as the ground a metre of height may shadow:
|
|
304
|
+
* the sun's horizontal reach per vertical metre, so 1 is 45° of elevation and 60 about 1°. Every
|
|
305
|
+
* sun shadow fades from 65% of this to all of it.
|
|
306
|
+
*
|
|
307
|
+
* **60 since 4.13.0: shadows hold until the sun is about a degree above the horizon**, the
|
|
308
|
+
* stretch of a day when they are longest and most worth seeing. **What it gives up**: a sun on
|
|
309
|
+
* the horizon throws shadows kilometres long that a map can hold only as stripes, and the
|
|
310
|
+
* last degree is where they fade rather than show. It was 3 until 4.13.0, which dropped every
|
|
311
|
+
* sun shadow below about 18° — an evening without shadows. **What would make it wrong** is a
|
|
312
|
+
* scene whose low sun streaks; a smaller number here is the setting, at the cost of the
|
|
313
|
+
* shadows going earlier in the evening.
|
|
314
|
+
*/
|
|
276
315
|
readonly directionalShadowMaxSlope: number;
|
|
277
316
|
/**
|
|
278
317
|
* Metres a point light may drift from where its shadow was baked before re-baking.
|
|
@@ -958,7 +997,7 @@ export const DIRECTIONAL_SHADOW_FADE_START = 0.65;
|
|
|
958
997
|
* six times, while the directional map spends all of it on one focused area.
|
|
959
998
|
*/
|
|
960
999
|
export const DEFAULT_RENDER_QUALITY: Readonly<RenderQuality> = Object.freeze({
|
|
961
|
-
outputTransform: '
|
|
1000
|
+
outputTransform: 'srgb',
|
|
962
1001
|
outputExposure: 1,
|
|
963
1002
|
pointLightFalloff: 'smooth',
|
|
964
1003
|
/**
|
|
@@ -1006,8 +1045,8 @@ export const DEFAULT_RENDER_QUALITY: Readonly<RenderQuality> = Object.freeze({
|
|
|
1006
1045
|
glassShadows: 'full',
|
|
1007
1046
|
pipelineCompile: 'wait',
|
|
1008
1047
|
skinScattering: 'pre-integrated',
|
|
1009
|
-
directionalShadowMaxDistance:
|
|
1010
|
-
directionalShadowMaxSlope:
|
|
1048
|
+
directionalShadowMaxDistance: 1000,
|
|
1049
|
+
directionalShadowMaxSlope: 60,
|
|
1011
1050
|
pointShadowRebakeDistance: 0.001,
|
|
1012
1051
|
pointShadowFacesPerFrame: 2,
|
|
1013
1052
|
/*
|
|
@@ -785,6 +785,8 @@ export class SceneTarget {
|
|
|
785
785
|
readonly transform: number;
|
|
786
786
|
readonly exposure: number;
|
|
787
787
|
readonly film?: Float32Array;
|
|
788
|
+
/** Whether the forward passes graded the scene because this resolve does not. */
|
|
789
|
+
readonly sceneGraded?: boolean;
|
|
788
790
|
} = {
|
|
789
791
|
transform: 0,
|
|
790
792
|
exposure: 1,
|
|
@@ -1030,6 +1032,7 @@ export class SceneTarget {
|
|
|
1030
1032
|
gl.uniform1f(this.uniforms['uReach'] ?? null, reachUv);
|
|
1031
1033
|
gl.uniform1i(this.uniforms['uOutputTransform'] ?? null, grade.transform);
|
|
1032
1034
|
gl.uniform1f(this.uniforms['uOutputExposure'] ?? null, grade.exposure);
|
|
1035
|
+
gl.uniform1i(this.uniforms['uSceneGraded'] ?? null, grade.sceneGraded === true ? 1 : 0);
|
|
1033
1036
|
if (grade.film !== undefined) {
|
|
1034
1037
|
gl.uniform4fv(this.uniforms['uFilmA'] ?? null, grade.film, 0, 4);
|
|
1035
1038
|
gl.uniform4fv(this.uniforms['uFilmB'] ?? null, grade.film, 4, 4);
|
|
@@ -112,7 +112,7 @@ export class SdfTextRenderer {
|
|
|
112
112
|
*/
|
|
113
113
|
/**
|
|
114
114
|
* `outputTransform` and `outputExposure` come from the renderer rather than from here, because
|
|
115
|
-
* whether this pass grades depends on whether anything after it will. See `
|
|
115
|
+
* whether this pass grades depends on whether anything after it will. See `passGrade.ts`.
|
|
116
116
|
*/
|
|
117
117
|
draw(
|
|
118
118
|
viewProj: ReadonlyMat4,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FOG_GLSL } from './fog.ts';
|
|
2
|
+
import { OUTPUT_TRANSFORM_GLSL } from './outputTransform.ts';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* An arcane aura: the volume a floating object sits inside.
|
|
@@ -31,6 +32,8 @@ ${FOG_GLSL}
|
|
|
31
32
|
uniform int uNoiseOctaves;
|
|
32
33
|
uniform vec4 uClipPlane;
|
|
33
34
|
uniform int uClipEnabled;
|
|
35
|
+
/* Before \`uTint\`, where fire and smoke declare it, so one field table serves all three. */
|
|
36
|
+
${OUTPUT_TRANSFORM_GLSL}
|
|
34
37
|
/** The caller's colour, so an aura shifts with the world's own palette. */
|
|
35
38
|
uniform vec3 uTint;
|
|
36
39
|
|
|
@@ -98,6 +101,7 @@ void main() {
|
|
|
98
101
|
col = mix(col, mediumColor(), fog);
|
|
99
102
|
alpha *= 1.0 - fog;
|
|
100
103
|
|
|
101
|
-
|
|
104
|
+
/* Graded where nothing after this will grade it, as every pass is. The alpha is coverage. */
|
|
105
|
+
outColor = vec4(applyOutputTransform(col), alpha);
|
|
102
106
|
}
|
|
103
107
|
`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FOG_GLSL } from './fog.ts';
|
|
2
|
+
import { OUTPUT_TRANSFORM_GLSL } from './outputTransform.ts';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Electrical arcs: a filament with a saturating core and a wide soft glow.
|
|
@@ -95,6 +96,7 @@ ${FOG_GLSL}
|
|
|
95
96
|
uniform vec3 uCameraPos;
|
|
96
97
|
|
|
97
98
|
out vec4 outColor;
|
|
99
|
+
${OUTPUT_TRANSFORM_GLSL}
|
|
98
100
|
|
|
99
101
|
float hash11(float p) {
|
|
100
102
|
return fract(sin(p * 12.9898) * 43758.5453123);
|
|
@@ -165,6 +167,7 @@ void main() {
|
|
|
165
167
|
* faint: at a typical energy of 0.5 it delivered a quarter of what it asked for.
|
|
166
168
|
* Every emissive material here has to pick one channel and mean it.
|
|
167
169
|
*/
|
|
168
|
-
|
|
170
|
+
/* Graded where nothing after this will grade it, as every pass is, light added included. */
|
|
171
|
+
outColor = vec4(applyOutputTransform(lit * energy * (1.0 - fog)), 1.0);
|
|
169
172
|
}
|
|
170
173
|
`;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { GERSTNER_GLSL } from './gerstner.ts';
|
|
2
2
|
import { FOG_GLSL } from './fog.ts';
|
|
3
|
+
import { OUTPUT_TRANSFORM_GLSL } from './outputTransform.ts';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Light off water, projected onto what covers it.
|
|
@@ -78,6 +79,7 @@ uniform float uMaxDrop;
|
|
|
78
79
|
${FOG_GLSL}
|
|
79
80
|
|
|
80
81
|
out vec4 outColor;
|
|
82
|
+
${OUTPUT_TRANSFORM_GLSL}
|
|
81
83
|
|
|
82
84
|
${GERSTNER_GLSL}
|
|
83
85
|
|
|
@@ -164,6 +166,7 @@ void main() {
|
|
|
164
166
|
float fog = mediumFog(distance(vWorldPos, uCameraPos), vWorldPos.y);
|
|
165
167
|
|
|
166
168
|
// Additive: this is light arriving at a surface that is already shaded.
|
|
167
|
-
|
|
169
|
+
/* Graded where nothing after this will grade it, as every pass is, light added included. */
|
|
170
|
+
outColor = vec4(applyOutputTransform(uTint * (caustic * uStrength * reach * (1.0 - fog))), 1.0);
|
|
168
171
|
}
|
|
169
172
|
`;
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import { glslIsFarDepth } from '../depthConvention.ts';
|
|
27
|
+
import { LINEAR_TO_SRGB_GLSL } from './outputTransform.ts';
|
|
27
28
|
|
|
28
29
|
export const DECAL_PROJECT_FRAG = `#version 300 es
|
|
29
30
|
precision highp float;
|
|
@@ -63,7 +64,9 @@ uniform float uDecalOpacity;
|
|
|
63
64
|
uniform float uDecalFacingCos;
|
|
64
65
|
/** How much of the mark's radius is edge. */
|
|
65
66
|
uniform float uDecalSoftness;
|
|
66
|
-
|
|
67
|
+
/** How the frame under the marks was graded, 0 where the resolve grades it. See renderQuality.ts. */
|
|
68
|
+
uniform int uOutputTransform;
|
|
69
|
+
${LINEAR_TO_SRGB_GLSL}
|
|
67
70
|
out vec4 fragColor;
|
|
68
71
|
|
|
69
72
|
void main() {
|
|
@@ -122,6 +125,13 @@ void main() {
|
|
|
122
125
|
mark *= ${glslIsFarDepth('stored')} ? 0.0 : 1.0;
|
|
123
126
|
|
|
124
127
|
/* White is the identity of a multiply, so a pixel the projector missed changes nothing. */
|
|
125
|
-
|
|
128
|
+
vec3 multiply = mix(vec3(1.0), uDecalColor, mark * uDecalOpacity);
|
|
129
|
+
/*
|
|
130
|
+
* **The multiply as an encoded pixel takes it**, where the frame was graded before this: the
|
|
131
|
+
* receiver is a display value, and darkening its light by a factor is darkening the display value
|
|
132
|
+
* by that factor encoded — exact through the sRGB encode, whose power carries a product through,
|
|
133
|
+
* and close through a curve, which bends it. A frame graded at the resolve multiplies linear light.
|
|
134
|
+
*/
|
|
135
|
+
fragColor = vec4(mix(multiply, linearToSrgb(multiply), float(uOutputTransform != 0)), 1.0);
|
|
126
136
|
}
|
|
127
137
|
`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FOG_GLSL } from './fog.ts';
|
|
2
|
+
import { OUTPUT_TRANSFORM_GLSL } from './outputTransform.ts';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* A thin, wet, iridescent film lying on a surface.
|
|
@@ -122,6 +123,7 @@ uniform float uFilmRoughness;
|
|
|
122
123
|
uniform float uFilmRoughnessCycles;
|
|
123
124
|
|
|
124
125
|
out vec4 fragColor;
|
|
126
|
+
${OUTPUT_TRANSFORM_GLSL}
|
|
125
127
|
|
|
126
128
|
/** A hue wheel, without a texture. Standard 6-segment ramp. */
|
|
127
129
|
vec3 hue(float h) {
|
|
@@ -199,6 +201,19 @@ void main() {
|
|
|
199
201
|
vec3 base = vTint * 0.9;
|
|
200
202
|
vec3 color = base + sheen * uSheen * (0.22 + grazing * 0.75);
|
|
201
203
|
|
|
204
|
+
/*
|
|
205
|
+
* **Graded before the mirror is mixed in**, as every pass grades what it draws when nothing after
|
|
206
|
+
* it will, because the mirror's own passes graded what it holds. The fog that used to follow the
|
|
207
|
+
* mirror distributes over the mix, so the film's own colour is fogged and graded here, and what
|
|
208
|
+
* the mirror shows is fogged toward the same air, graded, where it is mixed in below.
|
|
209
|
+
*/
|
|
210
|
+
// The same fog every other pass applies — and now literally the same code, which
|
|
211
|
+
// it was not: this ran its own curve while claiming otherwise, so a slick receded
|
|
212
|
+
// at a different rate than the deck it was lying on.
|
|
213
|
+
float fog = mediumFog(length(uCameraPos - vWorld), vWorld.y);
|
|
214
|
+
vec3 gradedAir = applyOutputTransform(mediumColor());
|
|
215
|
+
vec3 graded = applyOutputTransform(mix(color, mediumColor(), fog));
|
|
216
|
+
|
|
202
217
|
/*
|
|
203
218
|
* The mirrored scene, under the sheen rather than instead of it.
|
|
204
219
|
*
|
|
@@ -208,7 +223,7 @@ void main() {
|
|
|
208
223
|
*
|
|
209
224
|
* Weighted by the grazing term as well as by strength, because that is what a reflection does:
|
|
210
225
|
* a wet surface underfoot shows almost nothing and the same surface down the street shows the
|
|
211
|
-
* whole scene.
|
|
226
|
+
* whole scene. Fogged as the film is, so the image recedes with everything else in the frame.
|
|
212
227
|
*/
|
|
213
228
|
if (uReflectionEnabled != 0 && uReflectionStrength > 0.0 && vReflectionClip.w > 0.0) {
|
|
214
229
|
vec2 reflectionUv = vReflectionClip.xy / vReflectionClip.w * 0.5 + 0.5;
|
|
@@ -254,15 +269,13 @@ void main() {
|
|
|
254
269
|
valid = min(valid, smoothstep(0.0, 0.025, min(movedBorder.x, movedBorder.y)));
|
|
255
270
|
}
|
|
256
271
|
vec3 mirrored = textureLod(uReflectionMap, clamp(reflectionUv, 0.0, 1.0), 0.0).rgb;
|
|
257
|
-
|
|
272
|
+
graded = mix(
|
|
273
|
+
graded,
|
|
274
|
+
mix(mirrored, gradedAir, fog),
|
|
275
|
+
valid * uReflectionStrength * (0.25 + grazing * 0.75)
|
|
276
|
+
);
|
|
258
277
|
}
|
|
259
278
|
|
|
260
|
-
// The same fog every other pass applies — and now literally the same code, which
|
|
261
|
-
// it was not: this ran its own curve while claiming otherwise, so a slick receded
|
|
262
|
-
// at a different rate than the deck it was lying on.
|
|
263
|
-
float fog = mediumFog(length(uCameraPos - vWorld), vWorld.y);
|
|
264
|
-
color = mix(color, mediumColor(), fog);
|
|
265
|
-
|
|
266
279
|
/*
|
|
267
280
|
* Alpha from coverage, squared.
|
|
268
281
|
*
|
|
@@ -280,6 +293,6 @@ void main() {
|
|
|
280
293
|
*/
|
|
281
294
|
float coverage = clamp(vCoverage, 0.0, 1.0);
|
|
282
295
|
float alpha = mix(coverage * coverage, coverage, 0.65) * 0.92;
|
|
283
|
-
fragColor = vec4(
|
|
296
|
+
fragColor = vec4(graded, alpha);
|
|
284
297
|
}
|
|
285
298
|
`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FOG_GLSL } from './fog.ts';
|
|
2
|
+
import { OUTPUT_TRANSFORM_GLSL } from './outputTransform.ts';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Procedural flames: camera-facing quads whose shape and colour come entirely
|
|
@@ -116,6 +117,7 @@ uniform vec4 uClipPlane;
|
|
|
116
117
|
uniform int uClipEnabled;
|
|
117
118
|
|
|
118
119
|
out vec4 outColor;
|
|
120
|
+
${OUTPUT_TRANSFORM_GLSL}
|
|
119
121
|
|
|
120
122
|
float hash21(vec2 p) {
|
|
121
123
|
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
|
|
@@ -175,6 +177,7 @@ void main() {
|
|
|
175
177
|
col = mix(col, mediumColor(), fog);
|
|
176
178
|
alpha *= 1.0 - fog;
|
|
177
179
|
|
|
178
|
-
|
|
180
|
+
/* Graded where nothing after this will grade it, as every pass is. The alpha is coverage. */
|
|
181
|
+
outColor = vec4(applyOutputTransform(col), alpha);
|
|
179
182
|
}
|
|
180
183
|
`;
|
|
@@ -123,7 +123,7 @@ void areaLightAdd(
|
|
|
123
123
|
lampOpen += areaDiffuse;
|
|
124
124
|
lampShadowed += areaDiffuse * occl * glass;
|
|
125
125
|
|
|
126
|
-
if (
|
|
126
|
+
if (surfaceSpecular > 0.0 || metal > 0.0) {
|
|
127
127
|
vec3 c0 = centre - right * halfSize.x + up * halfSize.y;
|
|
128
128
|
vec3 c1 = centre + right * halfSize.x + up * halfSize.y;
|
|
129
129
|
vec3 c2 = centre + right * halfSize.x - up * halfSize.y;
|
|
@@ -39,7 +39,8 @@ export type LitSwitch =
|
|
|
39
39
|
| 'REFLECTION_MAPS'
|
|
40
40
|
| 'WORLD_UVS'
|
|
41
41
|
| 'MOVING_SUN'
|
|
42
|
-
| 'LAYERED'
|
|
42
|
+
| 'LAYERED'
|
|
43
|
+
| 'LAYER_LOOKS';
|
|
43
44
|
|
|
44
45
|
/** Every switch off: what a renderer starts from before its profile and its content say otherwise. */
|
|
45
46
|
export function noLitSwitches(): Record<LitSwitch, boolean> {
|
|
@@ -55,6 +56,7 @@ export function noLitSwitches(): Record<LitSwitch, boolean> {
|
|
|
55
56
|
WORLD_UVS: false,
|
|
56
57
|
MOVING_SUN: false,
|
|
57
58
|
LAYERED: false,
|
|
59
|
+
LAYER_LOOKS: false,
|
|
58
60
|
};
|
|
59
61
|
}
|
|
60
62
|
|
|
@@ -534,6 +534,11 @@ export interface FlatShaderOptions {
|
|
|
534
534
|
* True when absent. See \`layeredGlsl\`.
|
|
535
535
|
*/
|
|
536
536
|
readonly layered?: boolean;
|
|
537
|
+
/**
|
|
538
|
+
* Whether a layered material's layers are picked from shared arrays and given looks of their own,
|
|
539
|
+
* \`uLayerLooks\` and all. True when absent; nothing without \`layered\`. See \`layerLooksGlsl\`.
|
|
540
|
+
*/
|
|
541
|
+
readonly layerLooks?: boolean;
|
|
537
542
|
/**
|
|
538
543
|
* How many point lights this build declares room for. `MAX_POINT_LIGHTS` when absent.
|
|
539
544
|
*
|
|
@@ -686,7 +691,7 @@ export function flatFrag(options: FlatShaderOptions): string {
|
|
|
686
691
|
/* After the reflection maps, so its switch takes the next id; main calls it. worldUv.ts. */
|
|
687
692
|
worldUvGlsl(options.worldUvs ?? true),
|
|
688
693
|
/* After the projection, so its switch takes the next id; the normal map below calls it. */
|
|
689
|
-
layeredGlsl(options.layered ?? true),
|
|
694
|
+
layeredGlsl(options.layered ?? true, options.layerLooks ?? true),
|
|
690
695
|
/* Where each map is read, after both of the ways it can be read otherwise. See mapReads.ts. */
|
|
691
696
|
MAP_READS_GLSL,
|
|
692
697
|
/* After the frame and the projection it calls, unconditional for the same reason as the
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which layer of the shared arrays each of a layered material's layers reads, and how each looks:
|
|
3
|
+
* `uLayerLooks`, packed by `surfaceLayerLooks.ts`, read by `layered.ts`.
|
|
4
|
+
*
|
|
5
|
+
* **Every helper is the identity where the switch is off**, written as a branch on `LAYER_LOOKS`
|
|
6
|
+
* itself because the generated WGSL carries one string for both values of an override: layer `i`
|
|
7
|
+
* reads layer `i`, the maps beyond the layers start at the layer count, a tint is white, a range is
|
|
8
|
+
* 0 to 1, a normal is as stored, a specular is the surface's own, a repeat down is the repeat
|
|
9
|
+
* across, and nothing is occluded — exactly what `layered.ts` did before this existed, which is what
|
|
10
|
+
* a layered material that asks for none of it has to keep drawing.
|
|
11
|
+
*
|
|
12
|
+
* **A lit switch, `LAYER_LOOKS`**, off until a material first asks and declared after `LAYERED`, so
|
|
13
|
+
* every switch before it keeps its id. It is only ever compiled beside `LAYERED`, whose `uLayers`
|
|
14
|
+
* it reads.
|
|
15
|
+
*/
|
|
16
|
+
export function layerLooksGlsl(on: boolean): string {
|
|
17
|
+
if (!on) {
|
|
18
|
+
return /* glsl */ `
|
|
19
|
+
const bool LAYER_LOOKS = false; // wgsl:override
|
|
20
|
+
float layerArray(int i) { return float(i); }
|
|
21
|
+
float layerExtras() { return uLayers[1].y; }
|
|
22
|
+
vec3 layerTint(int i) { return vec3(1.0); }
|
|
23
|
+
vec2 layerRanges(int i, vec2 roughMetal) { return roughMetal; }
|
|
24
|
+
vec3 layerStrengthen(int i, vec3 texel) { return texel; }
|
|
25
|
+
float layerNamedSpecular(int i) { return -1.0; }
|
|
26
|
+
float layerRepeatDown(int i, float across) { return across; }
|
|
27
|
+
vec2 layerOcclusionStrengths() { return vec2(0.0); }
|
|
28
|
+
vec2 layerOcclusionRange() { return vec2(0.0, 1.0); }
|
|
29
|
+
`;
|
|
30
|
+
}
|
|
31
|
+
return /* glsl */ `
|
|
32
|
+
/* Whether layers are picked from shared arrays and given looks of their own: layerLooks.ts. */
|
|
33
|
+
const bool LAYER_LOOKS = true; // wgsl:override
|
|
34
|
+
/*
|
|
35
|
+
* Fifteen vectors, as surfaceLayerLooks.ts packs them: the array layer each of the five reads, base
|
|
36
|
+
* first (floats 0 to 4); where the maps beyond the layers start (5), the mesh occlusion's strength
|
|
37
|
+
* on the colour, from 0 up (6), and on the ambient light (7); then two vectors a
|
|
38
|
+
* layer, base first: its tint (x y z) and normal strength (w), then its roughness range (x to y)
|
|
39
|
+
* and metalness range (z to w); then each layer's specular, -1 for the surface's own (48 to 52), its
|
|
40
|
+
* repeat down (53 to 57), and the occlusion's range (58 to 59).
|
|
41
|
+
*/
|
|
42
|
+
uniform vec4 uLayerLooks[15]; // wgsl:material
|
|
43
|
+
|
|
44
|
+
/* Float k of the fifteen vectors. */
|
|
45
|
+
float layerLook(int k) {
|
|
46
|
+
return uLayerLooks[k / 4][k % 4];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* The layer of the albedo, normal and ORM arrays a material's layer i reads. */
|
|
50
|
+
float layerArray(int i) {
|
|
51
|
+
if (LAYER_LOOKS) return layerLook(i);
|
|
52
|
+
return float(i);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Where the maps beyond the layers start in each array. */
|
|
56
|
+
float layerExtras() {
|
|
57
|
+
if (LAYER_LOOKS) return uLayerLooks[1].y;
|
|
58
|
+
return uLayers[1].y;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
vec3 layerTint(int i) {
|
|
62
|
+
if (LAYER_LOOKS) return uLayerLooks[2 + i * 2].xyz;
|
|
63
|
+
return vec3(1.0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* The ORM's roughness and metalness, each spread over the layer's own range. */
|
|
67
|
+
vec2 layerRanges(int i, vec2 roughMetal) {
|
|
68
|
+
if (LAYER_LOOKS) {
|
|
69
|
+
vec4 range = uLayerLooks[3 + i * 2];
|
|
70
|
+
return vec2(mix(range.x, range.y, roughMetal.x), mix(range.z, range.w, roughMetal.y));
|
|
71
|
+
}
|
|
72
|
+
return roughMetal;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/*
|
|
76
|
+
* A tangent-space texel bent further or less by the layer's strength: its x and y scaled, its z
|
|
77
|
+
* kept, so 0 lies flat and a strength above 1 steepens every slope the map holds. z is held above
|
|
78
|
+
* zero so a texel lying exactly flat on its surface cannot normalise to nothing at strength 0.
|
|
79
|
+
*/
|
|
80
|
+
vec3 layerStrengthen(int i, vec3 texel) {
|
|
81
|
+
if (LAYER_LOOKS) return normalize(vec3(texel.xy * uLayerLooks[2 + i * 2].w, max(texel.z, 1e-4)));
|
|
82
|
+
return texel;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* The specular the layer names, or -1 where it names none and the surface's own stands. */
|
|
86
|
+
float layerNamedSpecular(int i) {
|
|
87
|
+
if (LAYER_LOOKS) return layerLook(48 + i);
|
|
88
|
+
return -1.0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* The layer's repeat down, which is its repeat across unless it gave two. */
|
|
92
|
+
float layerRepeatDown(int i, float across) {
|
|
93
|
+
if (LAYER_LOOKS) return layerLook(53 + i);
|
|
94
|
+
return across;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* The mesh occlusion's strength on the colour (x), from 0 up, and on the ambient light (y). */
|
|
98
|
+
vec2 layerOcclusionStrengths() {
|
|
99
|
+
if (LAYER_LOOKS) return uLayerLooks[1].zw;
|
|
100
|
+
return vec2(0.0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
vec2 layerOcclusionRange() {
|
|
104
|
+
if (LAYER_LOOKS) return uLayerLooks[14].zw;
|
|
105
|
+
return vec2(0.0, 1.0);
|
|
106
|
+
}
|
|
107
|
+
`;
|
|
108
|
+
}
|