@driftengine/core 4.12.0 → 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 +66 -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 +3 -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 +17 -4
- package/dist/render/backend/webgl2/renderer.js +82 -47
- 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 +19 -8
- package/dist/render/backend/webgpu/renderer.js +94 -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/layerLooks.js +11 -19
- package/dist/render/shaders/flat/layered.js +33 -18
- 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.js +23 -23
- 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 +16 -4
- package/dist/render/surfaceLayerLooks.js +33 -14
- package/dist/render/surfaceLayers.d.ts +2 -2
- 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/src/geometry/meshBuilder.ts +21 -2
- package/src/index.ts +11 -2
- package/src/math/color.ts +39 -0
- package/src/render/backend/webgl2/renderer.ts +134 -44
- 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 +104 -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/layerLooks.ts +11 -19
- package/src/render/shaders/flat/layered.ts +33 -18
- 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 +23 -23
- 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 +49 -18
- package/src/render/surfaceLayers.ts +2 -2
- 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
|
@@ -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
|
`;
|
|
@@ -22,10 +22,9 @@ float layerExtras() { return uLayers[1].y; }
|
|
|
22
22
|
vec3 layerTint(int i) { return vec3(1.0); }
|
|
23
23
|
vec2 layerRanges(int i, vec2 roughMetal) { return roughMetal; }
|
|
24
24
|
vec3 layerStrengthen(int i, vec3 texel) { return texel; }
|
|
25
|
-
float
|
|
25
|
+
float layerNamedSpecular(int i) { return -1.0; }
|
|
26
26
|
float layerRepeatDown(int i, float across) { return across; }
|
|
27
|
-
|
|
28
|
-
bool layerOcclusionAmbient() { return false; }
|
|
27
|
+
vec2 layerOcclusionStrengths() { return vec2(0.0); }
|
|
29
28
|
vec2 layerOcclusionRange() { return vec2(0.0, 1.0); }
|
|
30
29
|
`;
|
|
31
30
|
}
|
|
@@ -35,7 +34,7 @@ const bool LAYER_LOOKS = true; // wgsl:override
|
|
|
35
34
|
/*
|
|
36
35
|
* Fifteen vectors, as surfaceLayerLooks.ts packs them: the array layer each of the five reads, base
|
|
37
36
|
* first (floats 0 to 4); where the maps beyond the layers start (5), the mesh occlusion's strength
|
|
38
|
-
* (6) and
|
|
37
|
+
* on the colour, from 0 up (6), and on the ambient light (7); then two vectors a
|
|
39
38
|
* layer, base first: its tint (x y z) and normal strength (w), then its roughness range (x to y)
|
|
40
39
|
* and metalness range (z to w); then each layer's specular, -1 for the surface's own (48 to 52), its
|
|
41
40
|
* repeat down (53 to 57), and the occlusion's range (58 to 59).
|
|
@@ -83,13 +82,10 @@ vec3 layerStrengthen(int i, vec3 texel) {
|
|
|
83
82
|
return texel;
|
|
84
83
|
}
|
|
85
84
|
|
|
86
|
-
/* The layer
|
|
87
|
-
float
|
|
88
|
-
if (LAYER_LOOKS)
|
|
89
|
-
|
|
90
|
-
return named < 0.0 ? own : named;
|
|
91
|
-
}
|
|
92
|
-
return own;
|
|
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;
|
|
93
89
|
}
|
|
94
90
|
|
|
95
91
|
/* The layer's repeat down, which is its repeat across unless it gave two. */
|
|
@@ -98,14 +94,10 @@ float layerRepeatDown(int i, float across) {
|
|
|
98
94
|
return across;
|
|
99
95
|
}
|
|
100
96
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
bool layerOcclusionAmbient() {
|
|
107
|
-
if (LAYER_LOOKS) return uLayerLooks[1].w > 0.5;
|
|
108
|
-
return false;
|
|
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);
|
|
109
101
|
}
|
|
110
102
|
|
|
111
103
|
vec2 layerOcclusionRange() {
|
|
@@ -61,8 +61,12 @@ ${layerLooksGlsl(looks)}
|
|
|
61
61
|
/* Each layer's share of this point, the base's and layers 1 to 4's: worked out once, in layeredBegin. */
|
|
62
62
|
float lShareBase;
|
|
63
63
|
vec4 lShare;
|
|
64
|
-
/*
|
|
65
|
-
|
|
64
|
+
/*
|
|
65
|
+
* What an occlusion read at the mesh's coordinates leaves of this point's colour and of its ambient
|
|
66
|
+
* light, 1 where none: layeredBegin.
|
|
67
|
+
*/
|
|
68
|
+
float lColorOcclusion;
|
|
69
|
+
float lAmbientOcclusion;
|
|
66
70
|
|
|
67
71
|
bool layered() {
|
|
68
72
|
return uLayers[1].y > 0.5;
|
|
@@ -103,15 +107,18 @@ vec4 layerPick(float layer) {
|
|
|
103
107
|
void layeredBegin() {
|
|
104
108
|
/*
|
|
105
109
|
* The occlusion at the mesh's coordinates, once: the ORM array's layer past the layers and past
|
|
106
|
-
* any mask and added mask it carries, spread over its range and taken at
|
|
110
|
+
* any mask and added mask it carries, spread over its range and taken at each strength. The
|
|
111
|
+
* colour's may pass 1, darkening faster than the occlusion does, and is held at black.
|
|
107
112
|
*/
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
lColorOcclusion = 1.0;
|
|
114
|
+
lAmbientOcclusion = 1.0;
|
|
115
|
+
vec2 strength = layerOcclusionStrengths();
|
|
116
|
+
if (strength.x > 0.0 || strength.y > 0.0) {
|
|
111
117
|
float at = layerExtras() + (abs(uLayers[1].w - 1.0) < 0.5 ? 1.0 : 0.0) + (uLayers[2].z > 0.5 ? 1.0 : 0.0);
|
|
112
118
|
vec2 range = layerOcclusionRange();
|
|
113
|
-
float
|
|
114
|
-
|
|
119
|
+
float bare = 1.0 - mix(range.x, range.y, texture(uOrmMap, vec3(vUv.xy, at)).r);
|
|
120
|
+
lColorOcclusion = max(0.0, 1.0 - strength.x * bare);
|
|
121
|
+
lAmbientOcclusion = 1.0 - strength.y * bare;
|
|
115
122
|
}
|
|
116
123
|
vec4 m = layerWeights();
|
|
117
124
|
if (uLayers[2].z > 0.5) {
|
|
@@ -158,7 +165,7 @@ vec3 layeredColor(vec3 color) {
|
|
|
158
165
|
|
|
159
166
|
/*
|
|
160
167
|
* Colour by the shares, each layer's tinted, and the base layer's coverage, which a cutout reads;
|
|
161
|
-
* then darkened by the occlusion at the mesh's coordinates,
|
|
168
|
+
* then darkened by the occlusion at the mesh's coordinates, at the colour's strength.
|
|
162
169
|
*/
|
|
163
170
|
vec4 layeredAlbedo() {
|
|
164
171
|
vec4 sum = vec4(0.0);
|
|
@@ -168,28 +175,36 @@ vec4 layeredAlbedo() {
|
|
|
168
175
|
sum.rgb += t.rgb * layerTint(i) * layerShare(i);
|
|
169
176
|
if (i == 0) sum.a = t.a;
|
|
170
177
|
}
|
|
171
|
-
|
|
178
|
+
sum.rgb *= lColorOcclusion;
|
|
172
179
|
return sum;
|
|
173
180
|
}
|
|
174
181
|
|
|
175
|
-
/* What the ambient light keeps: the occlusion at the mesh's coordinates,
|
|
182
|
+
/* What the ambient light keeps: the occlusion at the mesh's coordinates, at the ambient's strength. */
|
|
176
183
|
float layeredAmbient() {
|
|
177
|
-
return
|
|
184
|
+
return lAmbientOcclusion;
|
|
178
185
|
}
|
|
179
186
|
|
|
180
187
|
/*
|
|
181
|
-
* The specular by the shares
|
|
182
|
-
*
|
|
183
|
-
*
|
|
188
|
+
* The specular by the shares: each layer's named one at its share, and the surface's own over the
|
|
189
|
+
* layers naming none, once at most. Under a summed blend the shares add past 1 where the weights
|
|
190
|
+
* do, and a surface whose layers leave the specular to it reflects its own, not its own times that
|
|
191
|
+
* sum; under a blend laid over, the shares never pass 1 and this is the sum it always was. What it
|
|
192
|
+
* gives up: named speculars still add as their colours do, so a summed blend that names them
|
|
193
|
+
* reflects their sum. The surface's own, untouched, where no material has asked for looks: shares
|
|
194
|
+
* summing to one in floating point are not quite one, and a layered material that names nothing
|
|
195
|
+
* must draw exactly as before.
|
|
184
196
|
*/
|
|
185
197
|
float layeredSpecular(float own) {
|
|
186
198
|
if (LAYER_LOOKS) {
|
|
187
|
-
float
|
|
199
|
+
float named = 0.0;
|
|
200
|
+
float unnamed = 0.0;
|
|
188
201
|
for (int i = 0; i < 5; i++) {
|
|
189
202
|
if (float(i) >= uLayers[1].y) break;
|
|
190
|
-
|
|
203
|
+
float specular = layerNamedSpecular(i);
|
|
204
|
+
if (specular < 0.0) unnamed += layerShare(i);
|
|
205
|
+
else named += specular * layerShare(i);
|
|
191
206
|
}
|
|
192
|
-
return
|
|
207
|
+
return named + own * min(unnamed, 1.0);
|
|
193
208
|
}
|
|
194
209
|
return own;
|
|
195
210
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OUTPUT_TRANSFORM_GLSL } from './outputTransform.ts';
|
|
1
2
|
/**
|
|
2
3
|
* Birds: two triangles each, circling on a path computed entirely in the vertex
|
|
3
4
|
* shader.
|
|
@@ -96,8 +97,10 @@ precision highp float;
|
|
|
96
97
|
in float vShade;
|
|
97
98
|
uniform vec3 uTint;
|
|
98
99
|
out vec4 outColor;
|
|
100
|
+
${OUTPUT_TRANSFORM_GLSL}
|
|
99
101
|
|
|
100
102
|
void main() {
|
|
101
|
-
|
|
103
|
+
/* Graded where nothing after this will grade it, as every pass is. */
|
|
104
|
+
outColor = vec4(applyOutputTransform(uTint * vShade), 1.0);
|
|
102
105
|
}
|
|
103
106
|
`;
|