reze-engine 0.50.3 → 0.50.4
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/dist/engine.d.ts +237 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +793 -64
- package/dist/physics/autofit.d.ts +147 -0
- package/dist/physics/autofit.d.ts.map +1 -0
- package/dist/physics/autofit.js +501 -0
- package/dist/shaders/cast-api.d.ts +1 -1
- package/dist/shaders/cast-api.d.ts.map +1 -1
- package/dist/shaders/cast-layout.d.ts +44 -1
- package/dist/shaders/cast-layout.d.ts.map +1 -1
- package/dist/shaders/cast-layout.js +44 -1
- package/dist/shaders/materials/common.d.ts.map +1 -1
- package/dist/shaders/materials/common.js +7 -1
- package/dist/shaders/materials/nodes.d.ts +1 -1
- package/dist/shaders/materials/nodes.d.ts.map +1 -1
- package/dist/shaders/materials/nodes.js +17 -9
- package/dist/shaders/passes/composite.d.ts +1 -1
- package/dist/shaders/passes/composite.d.ts.map +1 -1
- package/dist/shaders/passes/depth-prepass.d.ts +1 -1
- package/dist/shaders/passes/depth-prepass.d.ts.map +1 -1
- package/dist/shaders/passes/depth-prepass.js +52 -12
- package/dist/shaders/passes/field-blit.d.ts +26 -0
- package/dist/shaders/passes/field-blit.d.ts.map +1 -0
- package/dist/shaders/passes/field-blit.js +65 -0
- package/dist/shaders/passes/ground-noise.d.ts +7 -0
- package/dist/shaders/passes/ground-noise.d.ts.map +1 -0
- package/dist/shaders/passes/ground-noise.js +88 -0
- package/dist/shaders/passes/ground.d.ts +16 -0
- package/dist/shaders/passes/ground.d.ts.map +1 -1
- package/dist/shaders/passes/ground.js +131 -27
- package/dist/shaders/passes/outline.d.ts +1 -1
- package/dist/shaders/passes/outline.d.ts.map +1 -1
- package/dist/shaders/passes/outline.js +12 -3
- package/dist/shaders/passes/particles.d.ts.map +1 -1
- package/dist/shaders/passes/particles.js +6 -2
- package/dist/shaders/passes/scene-contract.d.ts +38 -6
- package/dist/shaders/passes/scene-contract.d.ts.map +1 -1
- package/dist/shaders/passes/scene-contract.js +53 -16
- package/dist/shaders/passes/sim.d.ts +34 -0
- package/dist/shaders/passes/sim.d.ts.map +1 -0
- package/dist/shaders/passes/sim.js +169 -0
- package/dist/shaders/passes/trails.d.ts.map +1 -1
- package/dist/shaders/passes/trails.js +36 -8
- package/dist/shaders/score-api.d.ts +10 -0
- package/dist/shaders/score-api.d.ts.map +1 -0
- package/dist/shaders/score-api.js +114 -0
- package/package.json +1 -1
- package/src/engine.ts +839 -56
- package/src/shaders/cast-layout.ts +44 -1
- package/src/shaders/materials/common.ts +7 -1
- package/src/shaders/materials/nodes.ts +17 -9
- package/src/shaders/passes/depth-prepass.ts +53 -12
- package/src/shaders/passes/ground.ts +133 -27
- package/src/shaders/passes/outline.ts +14 -3
- package/src/shaders/passes/particles.ts +6 -2
- package/src/shaders/passes/scene-contract.ts +55 -16
- package/src/shaders/passes/trails.ts +36 -8
- package/dist/physics-debug.d.ts +0 -30
- package/dist/physics-debug.d.ts.map +0 -1
- package/dist/physics-debug.js +0 -526
- package/dist/shaders/materials/body.d.ts +0 -2
- package/dist/shaders/materials/body.d.ts.map +0 -1
- package/dist/shaders/materials/body.js +0 -95
- package/dist/shaders/materials/cloth_rough.d.ts +0 -2
- package/dist/shaders/materials/cloth_rough.d.ts.map +0 -1
- package/dist/shaders/materials/cloth_rough.js +0 -69
- package/dist/shaders/materials/cloth_smooth.d.ts +0 -2
- package/dist/shaders/materials/cloth_smooth.d.ts.map +0 -1
- package/dist/shaders/materials/cloth_smooth.js +0 -61
- package/dist/shaders/materials/default.d.ts +0 -2
- package/dist/shaders/materials/default.d.ts.map +0 -1
- package/dist/shaders/materials/default.js +0 -43
- package/dist/shaders/materials/eye.d.ts +0 -2
- package/dist/shaders/materials/eye.d.ts.map +0 -1
- package/dist/shaders/materials/eye.js +0 -60
- package/dist/shaders/materials/face.d.ts +0 -2
- package/dist/shaders/materials/face.d.ts.map +0 -1
- package/dist/shaders/materials/face.js +0 -95
- package/dist/shaders/materials/hair.d.ts +0 -2
- package/dist/shaders/materials/hair.d.ts.map +0 -1
- package/dist/shaders/materials/hair.js +0 -90
- package/dist/shaders/materials/metal.d.ts +0 -2
- package/dist/shaders/materials/metal.d.ts.map +0 -1
- package/dist/shaders/materials/metal.js +0 -77
- package/dist/shaders/materials/mmd_classic.d.ts +0 -2
- package/dist/shaders/materials/mmd_classic.d.ts.map +0 -1
- package/dist/shaders/materials/mmd_classic.js +0 -66
- package/dist/shaders/materials/stockings.d.ts +0 -2
- package/dist/shaders/materials/stockings.d.ts.map +0 -1
- package/dist/shaders/materials/stockings.js +0 -122
- package/dist/shaders/passes/physics-debug.d.ts +0 -2
- package/dist/shaders/passes/physics-debug.d.ts.map +0 -1
- package/dist/shaders/passes/physics-debug.js +0 -69
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The field layer, drawn INTO the scene.
|
|
3
|
+
*
|
|
4
|
+
* Field effects render into their own targets at their own resolution — that
|
|
5
|
+
* part was always right. What was wrong was where the result landed: the
|
|
6
|
+
* composite sampled it AFTER tone mapping, which is why a field effect could
|
|
7
|
+
* never bloom, could never light anything, and tone mapped differently from the
|
|
8
|
+
* particle and ribbon mounts drawing the same kind of glow.
|
|
9
|
+
*
|
|
10
|
+
* Two draws inside the scene pass — background before any geometry, foreground
|
|
11
|
+
* after all of it — so the bloom pyramid sees field effects and one tone map
|
|
12
|
+
* covers the whole frame.
|
|
13
|
+
*
|
|
14
|
+
* NO DEPTH, neither written nor tested. A foreground is handed the scene's
|
|
15
|
+
* depth as a parameter and does its own occlusion; testing it here would
|
|
16
|
+
* occlude it a second time, and a background has nothing to test against.
|
|
17
|
+
*
|
|
18
|
+
* COVERAGE IS CLAMPED HERE. Additive field effects SUM their coverage into the
|
|
19
|
+
* layer (see FIELD_LAYER_BLEND_ADDITIVE), which is what stops the composite's
|
|
20
|
+
* unpremultiply from dividing colour by nothing — but N additive effects can
|
|
21
|
+
* sum past 1, and the layer is rgba16float so nothing stopped it on the way in.
|
|
22
|
+
* A coverage above 1 would darken what the layer is drawn over by more than
|
|
23
|
+
* fully covering it.
|
|
24
|
+
*/
|
|
25
|
+
export declare function fieldBlitShaderWgsl(): string;
|
|
26
|
+
//# sourceMappingURL=field-blit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-blit.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/field-blit.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAuC5C"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { sceneFsOutWgsl } from "./scene-contract";
|
|
2
|
+
/**
|
|
3
|
+
* The field layer, drawn INTO the scene.
|
|
4
|
+
*
|
|
5
|
+
* Field effects render into their own targets at their own resolution — that
|
|
6
|
+
* part was always right. What was wrong was where the result landed: the
|
|
7
|
+
* composite sampled it AFTER tone mapping, which is why a field effect could
|
|
8
|
+
* never bloom, could never light anything, and tone mapped differently from the
|
|
9
|
+
* particle and ribbon mounts drawing the same kind of glow.
|
|
10
|
+
*
|
|
11
|
+
* Two draws inside the scene pass — background before any geometry, foreground
|
|
12
|
+
* after all of it — so the bloom pyramid sees field effects and one tone map
|
|
13
|
+
* covers the whole frame.
|
|
14
|
+
*
|
|
15
|
+
* NO DEPTH, neither written nor tested. A foreground is handed the scene's
|
|
16
|
+
* depth as a parameter and does its own occlusion; testing it here would
|
|
17
|
+
* occlude it a second time, and a background has nothing to test against.
|
|
18
|
+
*
|
|
19
|
+
* COVERAGE IS CLAMPED HERE. Additive field effects SUM their coverage into the
|
|
20
|
+
* layer (see FIELD_LAYER_BLEND_ADDITIVE), which is what stops the composite's
|
|
21
|
+
* unpremultiply from dividing colour by nothing — but N additive effects can
|
|
22
|
+
* sum past 1, and the layer is rgba16float so nothing stopped it on the way in.
|
|
23
|
+
* A coverage above 1 would darken what the layer is drawn over by more than
|
|
24
|
+
* fully covering it.
|
|
25
|
+
*/
|
|
26
|
+
export function fieldBlitShaderWgsl() {
|
|
27
|
+
return /* wgsl */ `
|
|
28
|
+
@group(0) @binding(0) var _rzLayer: texture_2d<f32>;
|
|
29
|
+
@group(0) @binding(1) var _rzLayerSamp: sampler;
|
|
30
|
+
// (bloom, _, fullW, fullH). The size is the SCENE target's, not the layer's:
|
|
31
|
+
// the layer is often half resolution, and normalised uv is what makes that
|
|
32
|
+
// invisible.
|
|
33
|
+
@group(0) @binding(2) var<uniform> _rzBlitU: vec4f;
|
|
34
|
+
|
|
35
|
+
@vertex fn vs(@builtin(vertex_index) vi: u32) -> @builtin(position) vec4f {
|
|
36
|
+
let x = f32((vi & 1u) << 2u) - 1.0;
|
|
37
|
+
let y = f32((vi & 2u) << 1u) - 1.0;
|
|
38
|
+
return vec4f(x, y, 0.0, 1.0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
${sceneFsOutWgsl()}
|
|
42
|
+
@fragment fn fs(@builtin(position) fragCoord: vec4f) -> FSOut {
|
|
43
|
+
var out: FSOut;
|
|
44
|
+
// Bilinear, because the layer is usually half resolution and the whole point
|
|
45
|
+
// of that choice is that low-frequency effects upsample invisibly.
|
|
46
|
+
let uv = fragCoord.xy / max(_rzBlitU.zw, vec2f(1.0));
|
|
47
|
+
let c = textureSampleLevel(_rzLayer, _rzLayerSamp, uv, 0.0);
|
|
48
|
+
let cov = clamp(c.a, 0.0, 1.0);
|
|
49
|
+
// PREMULTIPLIED, and blitted with a premultiplied-over blend — the field
|
|
50
|
+
// targets have been premultiplied since N effects had to compose into them
|
|
51
|
+
// associatively. Handing this to the material blend would scale rgb by alpha
|
|
52
|
+
// a second time and every layer would come out dark.
|
|
53
|
+
out.color = vec4f(max(c.rgb, vec3f(0.0)), cov);
|
|
54
|
+
// The aux target: bloom mask, then coverage. THIS is what finally makes
|
|
55
|
+
// // @bloom mean something on a field effect — the flag has been parsed and
|
|
56
|
+
// ignored for every mount but particles and ribbons, which is the kind of
|
|
57
|
+
// author-surface lie the install-time guards exist to kill.
|
|
58
|
+
//
|
|
59
|
+
// The mask is written UNWEIGHTED and the blend weights it by src.a — the
|
|
60
|
+
// convention the materials already follow (they write vec4f(1, 1, 0, alpha)).
|
|
61
|
+
out.mask = vec4f(_rzBlitU.x, 1.0, 0.0, cov);
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tile as 8-bit luminance, plus its mip chain (box-filtered, which is exact
|
|
3
|
+
* for a repeating texture). Mips are the point as much as the speed: procedural
|
|
4
|
+
* noise has no mip chain, so at grazing angles it shimmered.
|
|
5
|
+
*/
|
|
6
|
+
export declare function buildGroundNoiseMips(): Uint8Array[];
|
|
7
|
+
//# sourceMappingURL=ground-noise.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ground-noise.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/ground-noise.ts"],"names":[],"mappings":"AAkDA;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,UAAU,EAAE,CAsCnD"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Bakes the ground's frosted micro-texture into a seamless, mipmapped tile.
|
|
2
|
+
//
|
|
3
|
+
// The shader used to evaluate four octaves of value noise per pixel — sixteen
|
|
4
|
+
// hash rounds — and the ground covers the entire screen as soon as the camera
|
|
5
|
+
// tilts toward the horizon. This produces the same character of pattern once, at
|
|
6
|
+
// load, so the fragment shader pays one filtered fetch instead.
|
|
7
|
+
//
|
|
8
|
+
// SEAMLESS BY CONSTRUCTION. The original hash was not periodic, so a finite
|
|
9
|
+
// crop of it could never tile. Here every octave's lattice wraps at a whole
|
|
10
|
+
// number of cells across the tile, which makes the result repeat exactly at the
|
|
11
|
+
// edges. The pattern is therefore not pixel-identical to the analytic version —
|
|
12
|
+
// it is the same kind of noise, not the same noise. At the default strength of
|
|
13
|
+
// 0.05 it modulates brightness by ±2.5%, where the repeat is not findable by eye.
|
|
14
|
+
import { GROUND_NOISE_RES, GROUND_NOISE_TILE_WORLD } from "./ground";
|
|
15
|
+
/** Lattice cells across the tile at octave 0. The analytic version sampled fbm
|
|
16
|
+
* at worldXZ × 3, so a tile spanning 8 world units covers 24 base cells — the
|
|
17
|
+
* same spatial frequency the surface had before. */
|
|
18
|
+
const BASE_CELLS = GROUND_NOISE_TILE_WORLD * 3;
|
|
19
|
+
const OCTAVES = 4;
|
|
20
|
+
/** Deterministic lattice hash. Integer coordinates are wrapped by the caller,
|
|
21
|
+
* which is what makes the tile seamless. */
|
|
22
|
+
function hash(ix, iy) {
|
|
23
|
+
let h = Math.imul(ix, 374761393) + Math.imul(iy, 668265263);
|
|
24
|
+
h = Math.imul(h ^ (h >>> 13), 1274126177);
|
|
25
|
+
return ((h ^ (h >>> 16)) >>> 0) / 4294967296;
|
|
26
|
+
}
|
|
27
|
+
/** Value noise on a lattice that repeats every `period` cells. */
|
|
28
|
+
function periodicValueNoise(x, y, period) {
|
|
29
|
+
const ix = Math.floor(x);
|
|
30
|
+
const iy = Math.floor(y);
|
|
31
|
+
const fx = x - ix;
|
|
32
|
+
const fy = y - iy;
|
|
33
|
+
// Smoothstep weights — same curve the WGSL used.
|
|
34
|
+
const ux = fx * fx * (3 - 2 * fx);
|
|
35
|
+
const uy = fy * fy * (3 - 2 * fy);
|
|
36
|
+
const x0 = ((ix % period) + period) % period;
|
|
37
|
+
const y0 = ((iy % period) + period) % period;
|
|
38
|
+
const x1 = (x0 + 1) % period;
|
|
39
|
+
const y1 = (y0 + 1) % period;
|
|
40
|
+
const a = hash(x0, y0);
|
|
41
|
+
const b = hash(x1, y0);
|
|
42
|
+
const c = hash(x0, y1);
|
|
43
|
+
const d = hash(x1, y1);
|
|
44
|
+
return (a + (b - a) * ux) * (1 - uy) + (c + (d - c) * ux) * uy;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The tile as 8-bit luminance, plus its mip chain (box-filtered, which is exact
|
|
48
|
+
* for a repeating texture). Mips are the point as much as the speed: procedural
|
|
49
|
+
* noise has no mip chain, so at grazing angles it shimmered.
|
|
50
|
+
*/
|
|
51
|
+
export function buildGroundNoiseMips() {
|
|
52
|
+
const levels = [];
|
|
53
|
+
const res = GROUND_NOISE_RES;
|
|
54
|
+
const base = new Uint8Array(res * res);
|
|
55
|
+
for (let py = 0; py < res; py++) {
|
|
56
|
+
for (let px = 0; px < res; px++) {
|
|
57
|
+
// Texel centre, in units of octave-0 lattice cells.
|
|
58
|
+
const x = ((px + 0.5) / res) * BASE_CELLS;
|
|
59
|
+
const y = ((py + 0.5) / res) * BASE_CELLS;
|
|
60
|
+
let v = 0;
|
|
61
|
+
let amp = 0.5;
|
|
62
|
+
let freq = 1;
|
|
63
|
+
for (let o = 0; o < OCTAVES; o++) {
|
|
64
|
+
v += amp * periodicValueNoise(x * freq, y * freq, BASE_CELLS * freq);
|
|
65
|
+
freq *= 2;
|
|
66
|
+
amp *= 0.5;
|
|
67
|
+
}
|
|
68
|
+
base[py * res + px] = Math.max(0, Math.min(255, Math.round(v * 255)));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
levels.push(base);
|
|
72
|
+
let src = base;
|
|
73
|
+
let size = res;
|
|
74
|
+
while (size > 1) {
|
|
75
|
+
const half = size >> 1;
|
|
76
|
+
const dst = new Uint8Array(half * half);
|
|
77
|
+
for (let y = 0; y < half; y++) {
|
|
78
|
+
for (let x = 0; x < half; x++) {
|
|
79
|
+
const s = y * 2 * size + x * 2;
|
|
80
|
+
dst[y * half + x] = (src[s] + src[s + 1] + src[s + size] + src[s + size + 1] + 2) >> 2;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
levels.push(dst);
|
|
84
|
+
src = dst;
|
|
85
|
+
size = half;
|
|
86
|
+
}
|
|
87
|
+
return levels;
|
|
88
|
+
}
|
|
@@ -11,4 +11,20 @@ export declare function groundShaderWgsl(): string;
|
|
|
11
11
|
*/
|
|
12
12
|
export declare const GROUND_MATERIAL_ID = 65535;
|
|
13
13
|
export declare const GROUND_OBJECT_ID = 65535;
|
|
14
|
+
/** Texel edge of the baked frost tile. 1024 over a 64-p-unit period is two
|
|
15
|
+
* texels per finest-octave noise cell — the bake resolves everything the
|
|
16
|
+
* evaluation produced. r8unorm: the value lives in [0,1] and feeds a 0.05
|
|
17
|
+
* tint; eight bits is already 5x below what that tint can show. */
|
|
18
|
+
export declare const GROUND_NOISE_SIZE = 1024;
|
|
19
|
+
/**
|
|
20
|
+
* The frost fbm as a bake: identical math, periodic lattice.
|
|
21
|
+
*
|
|
22
|
+
* hash2/valueNoise/fbm are the ground's old helpers verbatim, with one change —
|
|
23
|
+
* each octave's lattice wraps at its own period (64 p-units at octave 0,
|
|
24
|
+
* doubling with frequency), so the tile is seamless under the repeat sampler.
|
|
25
|
+
* Wrapping only renames lattice cells on the seam; every interior cell hashes
|
|
26
|
+
* exactly as before, which is what makes the bake a relocation of the old
|
|
27
|
+
* pixels rather than a new look.
|
|
28
|
+
*/
|
|
29
|
+
export declare const GROUND_NOISE_BAKE_WGSL = "\n@vertex fn vs(@builtin(vertex_index) vi: u32) -> @builtin(position) vec4f {\n let x = f32((vi & 1u) << 2u) - 1.0;\n let y = f32((vi & 2u) << 1u) - 1.0;\n return vec4f(x, y, 0.0, 1.0);\n}\nfn hash2(p: vec2f) -> f32 {\n var p3 = fract(vec3f(p.x, p.y, p.x) * 0.1031);\n p3 += dot(p3, vec3f(p3.y + 33.33, p3.z + 33.33, p3.x + 33.33));\n return fract((p3.x + p3.y) * p3.z);\n}\nfn wrapCell(i: vec2f, period: f32) -> vec2f { return i - period * floor(i / period); }\nfn valueNoiseP(p: vec2f, period: f32) -> f32 {\n let i = floor(p);\n let f = fract(p);\n let u = f * f * (3.0 - 2.0 * f);\n return mix(mix(hash2(wrapCell(i, period)), hash2(wrapCell(i + vec2f(1.0, 0.0), period)), u.x),\n mix(hash2(wrapCell(i + vec2f(0.0, 1.0), period)), hash2(wrapCell(i + vec2f(1.0, 1.0), period)), u.x), u.y);\n}\n@fragment fn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {\n let p = pos.xy * (64.0 / 1024.0);\n var v = 0.0;\n var a = 0.5;\n var pp = p;\n var period = 64.0;\n for (var o = 0; o < 4; o++) {\n v += a * valueNoiseP(pp, period);\n pp *= 2.0;\n period *= 2.0;\n a *= 0.5;\n }\n return vec4f(v, 0.0, 0.0, 1.0);\n}\n";
|
|
14
30
|
//# sourceMappingURL=ground.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ground.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/ground.ts"],"names":[],"mappings":"AAYA,wBAAgB,gBAAgB,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"ground.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/ground.ts"],"names":[],"mappings":"AAYA,wBAAgB,gBAAgB,IAAI,MAAM,CAkUzC;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,QAAS,CAAA;AACxC,eAAO,MAAM,gBAAgB,QAAS,CAAA;AAEtC;;;oEAGoE;AACpE,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAErC;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,+oCAiClC,CAAA"}
|
|
@@ -18,7 +18,13 @@ struct GroundShadowMat {
|
|
|
18
18
|
fadeEnd: f32, shadowStrength: f32, pcfTexel: f32, gridSpacing: f32,
|
|
19
19
|
gridLineWidth: f32, gridLineOpacity: f32, noiseStrength: f32, opacity: f32,
|
|
20
20
|
gridLineColor: vec3f, mirror: f32,
|
|
21
|
-
|
|
21
|
+
// farCascade: 1 while a stage is loaded, 0 otherwise. See the branch below —
|
|
22
|
+
// with no stage the far map is never drawn into, so its taps are known.
|
|
23
|
+
mirrorBlur: f32, farCascade: f32, _mb1: f32, _mb2: f32,
|
|
24
|
+
// Every shadow caster in one sphere, refreshed per frame. w = radius; 0 means
|
|
25
|
+
// nothing casts, negative means "do not use this" (a rigid caster has no
|
|
26
|
+
// sphere, so a scene with a stage keeps the taps). See rzShadowPossible.
|
|
27
|
+
casterSphere: vec4f,
|
|
22
28
|
};
|
|
23
29
|
// One view-projection per shadow cascade, inner to outer — same buffer and
|
|
24
30
|
// same order the materials read.
|
|
@@ -40,33 +46,12 @@ struct MirrorVP { viewProj: mat4x4f, params: vec4f, };
|
|
|
40
46
|
@group(0) @binding(9) var mirrorTex: texture_2d<f32>;
|
|
41
47
|
@group(0) @binding(10) var linearSampler: sampler;
|
|
42
48
|
@group(0) @binding(11) var mirrorDepth: texture_depth_multisampled_2d;
|
|
49
|
+
// The frost noise, PRE-BAKED — see GROUND_NOISE_BAKE_WGSL below. Sampled with
|
|
50
|
+
// the repeat sampler already at binding 10.
|
|
51
|
+
@group(0) @binding(12) var noiseTex: texture_2d<f32>;
|
|
43
52
|
${WORLD_AMBIENT_WGSL}
|
|
44
53
|
${lightsApi(0, 6)}
|
|
45
54
|
|
|
46
|
-
fn hash2(p: vec2f) -> f32 {
|
|
47
|
-
var p3 = fract(vec3f(p.x, p.y, p.x) * 0.1031);
|
|
48
|
-
p3 += dot(p3, vec3f(p3.y + 33.33, p3.z + 33.33, p3.x + 33.33));
|
|
49
|
-
return fract((p3.x + p3.y) * p3.z);
|
|
50
|
-
}
|
|
51
|
-
fn valueNoise(p: vec2f) -> f32 {
|
|
52
|
-
let i = floor(p);
|
|
53
|
-
let f = fract(p);
|
|
54
|
-
let u = f * f * (3.0 - 2.0 * f);
|
|
55
|
-
return mix(mix(hash2(i), hash2(i + vec2f(1.0, 0.0)), u.x),
|
|
56
|
-
mix(hash2(i + vec2f(0.0, 1.0)), hash2(i + vec2f(1.0, 1.0)), u.x), u.y);
|
|
57
|
-
}
|
|
58
|
-
fn fbmNoise(p: vec2f) -> f32 {
|
|
59
|
-
var v = 0.0;
|
|
60
|
-
var a = 0.5;
|
|
61
|
-
var pp = p;
|
|
62
|
-
for (var i = 0; i < 4; i++) {
|
|
63
|
-
v += a * valueNoise(pp);
|
|
64
|
-
pp *= 2.0;
|
|
65
|
-
a *= 0.5;
|
|
66
|
-
}
|
|
67
|
-
return v;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
55
|
struct VO { @builtin(position) position: vec4f, @location(0) worldPos: vec3f, @location(1) normal: vec3f, };
|
|
71
56
|
@vertex fn vs(@location(0) position: vec3f, @location(1) normal: vec3f, @location(2) uv: vec2f) -> VO {
|
|
72
57
|
var o: VO; o.worldPos = position; o.normal = normal;
|
|
@@ -119,8 +104,63 @@ ${sceneFsOutWgsl()}@fragment fn fs(i: VO) -> FSOut {
|
|
|
119
104
|
// The far cascade's taps run ONLY where the near one is fading or absent
|
|
120
105
|
// (frustum < 1), so a pixel in the near core costs exactly what it did with
|
|
121
106
|
// one cascade — and that core is where the camera usually looks.
|
|
107
|
+
// Can anything cast a shadow ONTO this point at all?
|
|
108
|
+
//
|
|
109
|
+
// The ground is vastly larger than what stands on it, and the answer for most
|
|
110
|
+
// of it is no. A point is shadowed only if the ray from it toward the light
|
|
111
|
+
// meets a caster, so testing that ray against one bounding sphere decides in a
|
|
112
|
+
// few ALU ops what nine hardware-bilinear depth comparisons would otherwise be
|
|
113
|
+
// spent discovering. Same pixels: outside the sphere vis stays 1.0, which is
|
|
114
|
+
// exactly what the taps return.
|
|
115
|
+
//
|
|
116
|
+
// Conservative in all three directions that matter. The sphere is a union of
|
|
117
|
+
// per-model bounds built from POSED bones plus the skin margin, so a jump or a
|
|
118
|
+
// flying skirt is inside it. A negative radius disables the test outright. And
|
|
119
|
+
// the halfspace check uses -R rather than 0, so a caster the point is standing
|
|
120
|
+
// inside still counts.
|
|
121
|
+
var shadowPossible = material.casterSphere.w > 0.0;
|
|
122
|
+
if (shadowPossible) {
|
|
123
|
+
let toLight = normalize(-light.lights[0].direction.xyz);
|
|
124
|
+
let toCaster = material.casterSphere.xyz - i.worldPos;
|
|
125
|
+
let along = dot(toCaster, toLight);
|
|
126
|
+
let perp = length(toCaster - toLight * along);
|
|
127
|
+
shadowPossible = along > -material.casterSphere.w && perp <= material.casterSphere.w;
|
|
128
|
+
} else {
|
|
129
|
+
// Negative radius is the opt-out, not "nothing casts".
|
|
130
|
+
shadowPossible = material.casterSphere.w < 0.0;
|
|
131
|
+
}
|
|
132
|
+
|
|
122
133
|
var vis = 1.0;
|
|
123
|
-
|
|
134
|
+
// The whole cascade lookup, behind the strength dial.
|
|
135
|
+
//
|
|
136
|
+
// This is a FULL-COVERAGE draw and each branch below is nine comparison-sampler
|
|
137
|
+
// taps per pixel — eighteen where the cascades overlap — so on a retina canvas
|
|
138
|
+
// it is tens of millions of shadow-map fetches a frame. All of it was computed
|
|
139
|
+
// and then multiplied by material.shadowStrength, which is ZERO whenever the
|
|
140
|
+
// host turns the ground's shadow catcher off. Turning shadows off in the UI
|
|
141
|
+
// therefore cost exactly what leaving them on cost, which is what a report of
|
|
142
|
+
// "no fps gain from disabling shadows" looks like from the outside.
|
|
143
|
+
//
|
|
144
|
+
// shadowStrength is a uniform, so this branch is uniform across the draw:
|
|
145
|
+
// every invocation takes the same side and the taps are genuinely skipped
|
|
146
|
+
// rather than merely masked. The dark term below is (1.0 - vis) * strength, so
|
|
147
|
+
// with strength at zero the result is identical either way — a pure
|
|
148
|
+
// deletion of work, not a change of look.
|
|
149
|
+
//
|
|
150
|
+
// The same reasoning the noise tint below already got, applied to the term
|
|
151
|
+
// that costs a hundred times more.
|
|
152
|
+
if (material.shadowStrength > 0.0 && shadowPossible) {
|
|
153
|
+
// The far cascade's taps, skipped entirely when nothing ever drew into it.
|
|
154
|
+
//
|
|
155
|
+
// This branch is the expensive one on a wide floor: it runs wherever the NEAR
|
|
156
|
+
// cascade does not reach, and the near cascade is a 64-unit box around the
|
|
157
|
+
// camera target, so a floor receding to the horizon takes it almost
|
|
158
|
+
// everywhere. Nine comparison taps, per pixel, on the largest draw in the
|
|
159
|
+
// frame — against a map that is cleared unless a stage is in the scene.
|
|
160
|
+
//
|
|
161
|
+
// Cleared depth compares as "no occluder", so the skipped path leaves vis at
|
|
162
|
+
// 1.0, which is exactly what the taps returned. Free, not cheaper.
|
|
163
|
+
if (material.farCascade > 0.0 && frustum < 1.0 && frustum1 > 0.0) {
|
|
124
164
|
let suv1 = vec2f(ndc1.x * 0.5 + 0.5, 0.5 - ndc1.y * 0.5);
|
|
125
165
|
let suv1_c = clamp(suv1, vec2f(0.02), vec2f(0.98));
|
|
126
166
|
let st1 = ${1 / SHADOW_CASCADES[SHADOW_CASCADES.length - 1].mapSize} * 2.0;
|
|
@@ -150,12 +190,27 @@ ${sceneFsOutWgsl()}@fragment fn fs(i: VO) -> FSOut {
|
|
|
150
190
|
// cascade to cascade rather than snapping to lit mid-floor.
|
|
151
191
|
vis = mix(vis, acc * (1.0 / 9.0), frustum);
|
|
152
192
|
}
|
|
193
|
+
}
|
|
153
194
|
|
|
154
195
|
// Frosted/matte micro-texture. Scenes leaving it at zero were still paying
|
|
155
196
|
// sixteen hash rounds a pixel for a tint of exactly 1.
|
|
156
197
|
var noiseTint = 1.0;
|
|
157
198
|
if (material.noiseStrength != 0.0) {
|
|
158
|
-
|
|
199
|
+
// One texture sample where four octaves of value noise used to be
|
|
200
|
+
// EVALUATED — sixteen hash rounds per pixel, on the largest draw in the
|
|
201
|
+
// frame. Bisection on the device that was slow pinned the ground's whole
|
|
202
|
+
// cost here: flat colour was smooth, the shader minus its shadow taps was
|
|
203
|
+
// still slow, and the shader minus only this was smooth. (0.33.2 built
|
|
204
|
+
// this same bake and measured no win — the cost then was the PCF. The
|
|
205
|
+
// instrument was right both times; the term changed.)
|
|
206
|
+
//
|
|
207
|
+
// The tile is the SAME fbm, baked once at init over a 64-p-unit period
|
|
208
|
+
// (~21 world units before it repeats — invisible at frost strengths), and
|
|
209
|
+
// the interior of the tile is bit-identical to the old evaluation because
|
|
210
|
+
// only lattice cells on the seam are wrapped. Sampled at level 0 with the
|
|
211
|
+
// repeat sampler: the old evaluation had no filtering either, so distant
|
|
212
|
+
// sparkle is unchanged rather than quietly "improved".
|
|
213
|
+
let noiseVal = textureSampleLevel(noiseTex, linearSampler, i.worldPos.xz * ${3 / 64}, 0.0).r;
|
|
159
214
|
noiseTint = 1.0 + (noiseVal - 0.5) * material.noiseStrength;
|
|
160
215
|
}
|
|
161
216
|
|
|
@@ -288,3 +343,52 @@ ${sceneIdWriteWgsl("out", `${GROUND_MATERIAL_ID}u`, `${GROUND_OBJECT_ID}u`)} re
|
|
|
288
343
|
*/
|
|
289
344
|
export const GROUND_MATERIAL_ID = 0xffff;
|
|
290
345
|
export const GROUND_OBJECT_ID = 0xffff;
|
|
346
|
+
/** Texel edge of the baked frost tile. 1024 over a 64-p-unit period is two
|
|
347
|
+
* texels per finest-octave noise cell — the bake resolves everything the
|
|
348
|
+
* evaluation produced. r8unorm: the value lives in [0,1] and feeds a 0.05
|
|
349
|
+
* tint; eight bits is already 5x below what that tint can show. */
|
|
350
|
+
export const GROUND_NOISE_SIZE = 1024;
|
|
351
|
+
/**
|
|
352
|
+
* The frost fbm as a bake: identical math, periodic lattice.
|
|
353
|
+
*
|
|
354
|
+
* hash2/valueNoise/fbm are the ground's old helpers verbatim, with one change —
|
|
355
|
+
* each octave's lattice wraps at its own period (64 p-units at octave 0,
|
|
356
|
+
* doubling with frequency), so the tile is seamless under the repeat sampler.
|
|
357
|
+
* Wrapping only renames lattice cells on the seam; every interior cell hashes
|
|
358
|
+
* exactly as before, which is what makes the bake a relocation of the old
|
|
359
|
+
* pixels rather than a new look.
|
|
360
|
+
*/
|
|
361
|
+
export const GROUND_NOISE_BAKE_WGSL = /* wgsl */ `
|
|
362
|
+
@vertex fn vs(@builtin(vertex_index) vi: u32) -> @builtin(position) vec4f {
|
|
363
|
+
let x = f32((vi & 1u) << 2u) - 1.0;
|
|
364
|
+
let y = f32((vi & 2u) << 1u) - 1.0;
|
|
365
|
+
return vec4f(x, y, 0.0, 1.0);
|
|
366
|
+
}
|
|
367
|
+
fn hash2(p: vec2f) -> f32 {
|
|
368
|
+
var p3 = fract(vec3f(p.x, p.y, p.x) * 0.1031);
|
|
369
|
+
p3 += dot(p3, vec3f(p3.y + 33.33, p3.z + 33.33, p3.x + 33.33));
|
|
370
|
+
return fract((p3.x + p3.y) * p3.z);
|
|
371
|
+
}
|
|
372
|
+
fn wrapCell(i: vec2f, period: f32) -> vec2f { return i - period * floor(i / period); }
|
|
373
|
+
fn valueNoiseP(p: vec2f, period: f32) -> f32 {
|
|
374
|
+
let i = floor(p);
|
|
375
|
+
let f = fract(p);
|
|
376
|
+
let u = f * f * (3.0 - 2.0 * f);
|
|
377
|
+
return mix(mix(hash2(wrapCell(i, period)), hash2(wrapCell(i + vec2f(1.0, 0.0), period)), u.x),
|
|
378
|
+
mix(hash2(wrapCell(i + vec2f(0.0, 1.0), period)), hash2(wrapCell(i + vec2f(1.0, 1.0), period)), u.x), u.y);
|
|
379
|
+
}
|
|
380
|
+
@fragment fn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {
|
|
381
|
+
let p = pos.xy * (64.0 / ${GROUND_NOISE_SIZE}.0);
|
|
382
|
+
var v = 0.0;
|
|
383
|
+
var a = 0.5;
|
|
384
|
+
var pp = p;
|
|
385
|
+
var period = 64.0;
|
|
386
|
+
for (var o = 0; o < 4; o++) {
|
|
387
|
+
v += a * valueNoiseP(pp, period);
|
|
388
|
+
pp *= 2.0;
|
|
389
|
+
period *= 2.0;
|
|
390
|
+
a *= 0.5;
|
|
391
|
+
}
|
|
392
|
+
return vec4f(v, 0.0, 0.0, 1.0);
|
|
393
|
+
}
|
|
394
|
+
`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare function outlineShaderWgsl(): string;
|
|
2
2
|
//# sourceMappingURL=outline.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outline.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/outline.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"outline.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/outline.ts"],"names":[],"mappings":"AAoBA,wBAAgB,iBAAiB,IAAI,MAAM,CAqG1C"}
|
|
@@ -11,7 +11,12 @@
|
|
|
11
11
|
// MODULATES the rim's alpha by it (discarding only near-zero cut-out
|
|
12
12
|
// margins) — sheer fabric gets a proportional rim, never a solid black
|
|
13
13
|
// hull, without dropping the author's edge flag.
|
|
14
|
-
|
|
14
|
+
// A FUNCTION rather than a constant, for the reason commonFsOutWgsl is one: the
|
|
15
|
+
// fragment outputs depend on whether the device carries the id attachment, and
|
|
16
|
+
// a string baked at import cannot know what the device said.
|
|
17
|
+
import { sceneFsOutWgsl, sceneIdPadWgsl } from "./scene-contract";
|
|
18
|
+
export function outlineShaderWgsl() {
|
|
19
|
+
return /* wgsl */ `
|
|
15
20
|
struct CameraUniforms {
|
|
16
21
|
view: mat4x4f,
|
|
17
22
|
projection: mat4x4f,
|
|
@@ -90,7 +95,10 @@ struct VertexOutput {
|
|
|
90
95
|
return output;
|
|
91
96
|
}
|
|
92
97
|
|
|
93
|
-
|
|
98
|
+
// The id output is declared and padded, never written for real: a hull would
|
|
99
|
+
// overwrite the id of the body it traces, so the pipeline takes the id target at
|
|
100
|
+
// writeMask 0. Declared all the same — see sceneFsOutWgsl.
|
|
101
|
+
${sceneFsOutWgsl({ name: "FSOut", aux: "mask" })}
|
|
94
102
|
@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
95
103
|
// Rim alpha FOLLOWS the fabric's texture alpha instead of a hard alpha test:
|
|
96
104
|
// MMD draws blend-material edges solid (only cutout materials alpha-test), so
|
|
@@ -105,6 +113,7 @@ struct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };
|
|
|
105
113
|
var out: FSOut;
|
|
106
114
|
out.color = vec4f(material.edgeColor.rgb, material.edgeColor.a * texA);
|
|
107
115
|
out.mask = vec4f(1.0, 1.0, 0.0, out.color.a);
|
|
108
|
-
return out;
|
|
116
|
+
${sceneIdPadWgsl("out")} return out;
|
|
109
117
|
}
|
|
110
118
|
`;
|
|
119
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particles.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/particles.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"particles.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/particles.ts"],"names":[],"mappings":"AAyBA,sEAAsE;AACtE,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAA;IACb;;mFAE+E;IAC/E,UAAU,EAAE,MAAM,CAAA;IAClB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB,CAAA;AAiCD,qDAAqD;AACrD,KAAK,aAAa,GAAG,OAAO,GAAG,UAAU,CAAA;AAEzC,KAAK,cAAc,GAAG;IACpB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,aAAa,CAAA;IACpB,qEAAqE;IACrE,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,oEAAoE;AACpE,eAAO,MAAM,eAAe,KAAK,CAAA;AAkDjC,oDAAoD;AACpD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAOpE;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wDAAwD;AACxD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAE9D;AAED,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAMlG;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CA0CxF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAgHvF"}
|
|
@@ -5,6 +5,7 @@ import { anchorAliasWgsl } from "../anchor-table";
|
|
|
5
5
|
import { midiApi } from "../midi-api";
|
|
6
6
|
import { CAST_API } from "../cast-api";
|
|
7
7
|
import { clockApi, EFFECT_MATH_API, PARTICLE_STRUCT_WGSL, trailSlotsApi, viewportApi } from "./hosted-api";
|
|
8
|
+
import { sceneIdFieldWgsl, sceneIdPadWgsl } from "./scene-contract";
|
|
8
9
|
/**
|
|
9
10
|
* The trail accessors, in the PARTICLE module.
|
|
10
11
|
*
|
|
@@ -247,7 +248,10 @@ struct FSOut {
|
|
|
247
248
|
// rejected outright — "reading alpha but it is missing from fragment output".
|
|
248
249
|
// The material shaders declare vec4f here for the same reason.
|
|
249
250
|
@location(1) mask: vec4f,
|
|
250
|
-
|
|
251
|
+
// Declared whenever the pass carries the attachment, and padded rather than
|
|
252
|
+
// written: a particle is not a thing you would address by id, so its pipeline
|
|
253
|
+
// takes this target at writeMask 0. Declared anyway — see sceneFsOutWgsl.
|
|
254
|
+
${sceneIdFieldWgsl()}}
|
|
251
255
|
|
|
252
256
|
@fragment
|
|
253
257
|
fn fs(in: VSOut) -> FSOut {
|
|
@@ -273,7 +277,7 @@ fn fs(in: VSOut) -> FSOut {
|
|
|
273
277
|
// not geometry, was the banding that survived every geometry fix.
|
|
274
278
|
let mg = select(vec2f(select(0.0, 1.0, BLOOM), 1.0), vec2f(select(0.0, c.a, BLOOM), c.a), ADDITIVE);
|
|
275
279
|
out.mask = vec4f(mg.x, mg.y, 0.0, c.a);
|
|
276
|
-
return out;
|
|
280
|
+
${sceneIdPadWgsl("out")} return out;
|
|
277
281
|
}
|
|
278
282
|
`);
|
|
279
283
|
}
|
|
@@ -105,12 +105,19 @@ export declare function sceneColorFormats(formats: SceneFormats): GPUTextureForm
|
|
|
105
105
|
* author. The struct and the targets above have to agree on count and order,
|
|
106
106
|
* and they now disagree in one file rather than in five.
|
|
107
107
|
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
108
|
+
* EVERY scene-pass shader takes this — outline, particles, ribbons and the
|
|
109
|
+
* depth prepass included, none of which write a meaningful id (and the prepass
|
|
110
|
+
* no meaningful colour either). They did not, once. The reasoning was that a
|
|
111
|
+
* target at writeMask 0 needs no matching output: true of Dawn, and the reading
|
|
112
|
+
* of gpuweb#1918 this file used to assert. It is not a reading every browser
|
|
113
|
+
* shares, and the failure mode when a browser disagrees is the worst kind —
|
|
114
|
+
* createRenderPipeline does not throw, it returns a pipeline that is already
|
|
115
|
+
* invalid, and the pass that binds it is dropped whole. Missing geometry, clean
|
|
116
|
+
* console, and a bug that reproduces on one vendor's browser only.
|
|
117
|
+
*
|
|
118
|
+
* So the rule is now the strict one, and it costs nothing to hold: declare
|
|
119
|
+
* every output the pass has attachments for, and let writeMask decide what is
|
|
120
|
+
* kept. A shader with no id to write pads it — see sceneIdPadWgsl.
|
|
114
121
|
*/
|
|
115
122
|
export declare function sceneFsOutWgsl(opts?: {
|
|
116
123
|
name?: string;
|
|
@@ -124,5 +131,30 @@ export declare function sceneFsOutWgsl(opts?: {
|
|
|
124
131
|
* ask the device what it supports.
|
|
125
132
|
*/
|
|
126
133
|
export declare function sceneIdWriteWgsl(out: string, material: string, object: string): string;
|
|
134
|
+
/**
|
|
135
|
+
* Just the id FIELD, for a shader that keeps its own struct.
|
|
136
|
+
*
|
|
137
|
+
* Particles and ribbons declare their outputs by hand because the comments on
|
|
138
|
+
* their aux field are about their own blend and belong beside it — taking the
|
|
139
|
+
* whole struct from sceneFsOutWgsl would move that prose away from what it
|
|
140
|
+
* explains. They still need the id output when the pass has the attachment, so
|
|
141
|
+
* they splice this in and pad it with sceneIdPadWgsl.
|
|
142
|
+
*/
|
|
143
|
+
export declare function sceneIdFieldWgsl(): string;
|
|
144
|
+
/**
|
|
145
|
+
* The id assignment for a shader that has no id to give.
|
|
146
|
+
*
|
|
147
|
+
* The counterpart to the strict rule on sceneFsOutWgsl: outline hulls,
|
|
148
|
+
* particles, ribbons and the depth prepass all declare the output because the
|
|
149
|
+
* pass has the attachment, and all of them take writeMask 0, so what they
|
|
150
|
+
* assign is never stored. Zero, which is the reserved "nothing" id the pass
|
|
151
|
+
* clears to — so if one of these ever did reach the target, it would read as
|
|
152
|
+
* absence rather than as a plausible wrong answer pointing at material 0.
|
|
153
|
+
*
|
|
154
|
+
* A separate function from sceneIdWriteWgsl rather than a call to it with "0u"
|
|
155
|
+
* twice, because the two say different things: that one records an identity,
|
|
156
|
+
* this one satisfies a declaration.
|
|
157
|
+
*/
|
|
158
|
+
export declare function sceneIdPadWgsl(out: string): string;
|
|
127
159
|
export {};
|
|
128
160
|
//# sourceMappingURL=scene-contract.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene-contract.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/scene-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;uDAEuD;AACvD,MAAM,MAAM,YAAY,GAAG;IACzB,+CAA+C;IAC/C,GAAG,EAAE,gBAAgB,CAAA;IACrB,iEAAiE;IACjE,GAAG,EAAE,gBAAgB,CAAA;CACtB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,gBAA6B,CAAA;AAkB3D,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAE3C;AAED,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;;;;;GAMG;AACH,KAAK,gBAAgB;AACnB,2DAA2D;AACzD,UAAU;AACZ;;+CAE+C;GAC7C,QAAQ;AACV,uEAAuE;GACrE,SAAS;AACX,iEAAiE;GAC/D,UAAU;AACZ;;;mDAGmD;GACjD,mBAAmB;AACrB;;;oCAGoC;GAClC,OAAO;AACT;;;kDAGkD;GAChD,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"scene-contract.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/scene-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;uDAEuD;AACvD,MAAM,MAAM,YAAY,GAAG;IACzB,+CAA+C;IAC/C,GAAG,EAAE,gBAAgB,CAAA;IACrB,iEAAiE;IACjE,GAAG,EAAE,gBAAgB,CAAA;CACtB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,gBAA6B,CAAA;AAkB3D,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAE3C;AAED,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;;;;;GAMG;AACH,KAAK,gBAAgB;AACnB,2DAA2D;AACzD,UAAU;AACZ;;+CAE+C;GAC7C,QAAQ;AACV,uEAAuE;GACrE,SAAS;AACX,iEAAiE;GAC/D,UAAU;AACZ;;;mDAGmD;GACjD,mBAAmB;AACrB;;;oCAGoC;GAClC,OAAO;AACT;;;kDAGkD;GAChD,eAAe,CAAA;AA0EnB;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,YAAY,GAAG,mBAAmB,EAAE,CAoBhG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,GAAG,gBAAgB,EAAE,CAE3E;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAmB7E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtF;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAElD"}
|