@hyperframes/core 0.8.70 → 0.8.71
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/generated/runtime-inline.js +1 -1
- package/dist/generated/runtime-inline.js.map +1 -1
- package/dist/hyperframe.runtime.iife.js +143 -39
- package/dist/vfx/displacementMap.frag.d.ts +10 -7
- package/dist/vfx/displacementMap.frag.d.ts.map +1 -1
- package/dist/vfx/displacementMap.frag.js +15 -8
- package/dist/vfx/displacementMap.frag.js.map +1 -1
- package/dist/vfx/lumaMatte.frag.d.ts +43 -0
- package/dist/vfx/lumaMatte.frag.d.ts.map +1 -0
- package/dist/vfx/lumaMatte.frag.js +73 -0
- package/dist/vfx/lumaMatte.frag.js.map +1 -0
- package/dist/vfx/noise.frag.d.ts +96 -0
- package/dist/vfx/noise.frag.d.ts.map +1 -0
- package/dist/vfx/noise.frag.js +169 -0
- package/dist/vfx/noise.frag.js.map +1 -0
- package/dist/vfx/refs/lumaMatte.d.ts +24 -0
- package/dist/vfx/refs/lumaMatte.d.ts.map +1 -0
- package/dist/vfx/refs/lumaMatte.js +33 -0
- package/dist/vfx/refs/lumaMatte.js.map +1 -0
- package/dist/vfx/refs/noise.d.ts +33 -0
- package/dist/vfx/refs/noise.d.ts.map +1 -0
- package/dist/vfx/refs/noise.js +67 -0
- package/dist/vfx/refs/noise.js.map +1 -0
- package/dist/vfx.d.ts +8 -0
- package/dist/vfx.d.ts.map +1 -1
- package/dist/vfx.js +71 -0
- package/dist/vfx.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `displacement-map` kernel — GLSL ES 3.00, capture `self`.
|
|
3
3
|
*
|
|
4
|
-
* **
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* **The map layer.** Every corpus instance points its Displacement Map Layer
|
|
5
|
+
* at **the layer itself** (retro-wave `Main/Text` → idx 5 = Text; `Logo Anim/
|
|
6
|
+
* Text Site` and `Logo Anim/Logo` likewise), so `u_src` is both the source and
|
|
7
|
+
* the map and no second capture is needed — that is what the `map` ref param
|
|
8
|
+
* being EMPTY means, and it stays the default. An external map layer is the
|
|
9
|
+
* same kernel reading `u_src2`: the exporter names that element in `map` and
|
|
10
|
+
* wraps it in its own `.hf-vfx-src` capture, and `u_hasSrc2` switches the
|
|
11
|
+
* sampler. The two inputs are read at the same `v_uv`, so an external map is
|
|
12
|
+
* scaled into the host's box (see `captureSource`), not placed in composition
|
|
13
|
+
* space.
|
|
11
14
|
*
|
|
12
15
|
* Per axis: `d = (channel(map) − 0.5) · 2 · max`, then sample `u_src` at
|
|
13
16
|
* `uv + d/u_size` with **clamp-to-transparent** edges (Edge = Off, the only
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"displacementMap.frag.d.ts","sourceRoot":"","sources":["../../src/vfx/displacementMap.frag.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"displacementMap.frag.d.ts","sourceRoot":"","sources":["../../src/vfx/displacementMap.frag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,4EAA4E;AAC5E,eAAO,MAAM,0BAA0B;;;;CAI7B,CAAC;AAIX,eAAO,MAAM,qBAAqB,QA+CjC,CAAC"}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `displacement-map` kernel — GLSL ES 3.00, capture `self`.
|
|
3
3
|
*
|
|
4
|
-
* **
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* **The map layer.** Every corpus instance points its Displacement Map Layer
|
|
5
|
+
* at **the layer itself** (retro-wave `Main/Text` → idx 5 = Text; `Logo Anim/
|
|
6
|
+
* Text Site` and `Logo Anim/Logo` likewise), so `u_src` is both the source and
|
|
7
|
+
* the map and no second capture is needed — that is what the `map` ref param
|
|
8
|
+
* being EMPTY means, and it stays the default. An external map layer is the
|
|
9
|
+
* same kernel reading `u_src2`: the exporter names that element in `map` and
|
|
10
|
+
* wraps it in its own `.hf-vfx-src` capture, and `u_hasSrc2` switches the
|
|
11
|
+
* sampler. The two inputs are read at the same `v_uv`, so an external map is
|
|
12
|
+
* scaled into the host's box (see `captureSource`), not placed in composition
|
|
13
|
+
* space.
|
|
11
14
|
*
|
|
12
15
|
* Per axis: `d = (channel(map) − 0.5) · 2 · max`, then sample `u_src` at
|
|
13
16
|
* `uv + d/u_size` with **clamp-to-transparent** edges (Edge = Off, the only
|
|
@@ -48,6 +51,10 @@ uniform vec2 u_size;
|
|
|
48
51
|
uniform float u_t;
|
|
49
52
|
uniform float u_fps;
|
|
50
53
|
uniform sampler2D u_src;
|
|
54
|
+
uniform sampler2D u_src2;
|
|
55
|
+
// 1 when the map ref named another element, 0 when the map is the layer
|
|
56
|
+
// itself. Set by the runtime for every pass, from whether a ref resolved.
|
|
57
|
+
uniform float u_hasSrc2;
|
|
51
58
|
uniform float u_useH;
|
|
52
59
|
uniform float u_maxH;
|
|
53
60
|
uniform float u_useV;
|
|
@@ -75,7 +82,7 @@ float hfMapChannel(vec4 premultiplied, float selector) {
|
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
void main() {
|
|
78
|
-
vec4 mapTexel = texture(u_src, v_uv);
|
|
85
|
+
vec4 mapTexel = u_hasSrc2 > 0.5 ? texture(u_src2, v_uv) : texture(u_src, v_uv);
|
|
79
86
|
float h = hfMapChannel(mapTexel, u_useH);
|
|
80
87
|
float v = hfMapChannel(mapTexel, u_useV);
|
|
81
88
|
vec2 d = vec2((h - 0.5) * 2.0 * u_maxH, (v - 0.5) * 2.0 * u_maxV);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"displacementMap.frag.js","sourceRoot":"","sources":["../../src/vfx/displacementMap.frag.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"displacementMap.frag.js","sourceRoot":"","sources":["../../src/vfx/displacementMap.frag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,4EAA4E;AAC5E,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;CACJ,CAAC;AAEX,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,0BAA0B,CAAC;AAE3D,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CAmCQ,KAAK,KAAK,KAAK,KAAK,KAAK;;;;;;;;;;;;CAYrE,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `luma-matte` kernel — GLSL ES 3.00, capture `self` plus a `ref` second
|
|
3
|
+
* source.
|
|
4
|
+
*
|
|
5
|
+
* **What it ports.** Not a single After Effects effect: this is the runtime
|
|
6
|
+
* form of every matte the exporter cannot express as CSS — a track matte whose
|
|
7
|
+
* source layer is unsupported (`matte-source-unsupported:*`), a stencil or
|
|
8
|
+
* silhouette (`stencil-*`), and Set Matte. All of them are the same
|
|
9
|
+
* per-pixel operation, `out = src · coverage(matte)`, differing only in which
|
|
10
|
+
* element is the source and which is the matte. The exporter decides that by
|
|
11
|
+
* choosing which element the host wraps and which the `matte` ref names; a
|
|
12
|
+
* stencil is this kernel with the host's own content as the matte.
|
|
13
|
+
*
|
|
14
|
+
* **Coverage.** `src` arrives premultiplied, so scaling all four channels by a
|
|
15
|
+
* single coverage value is the whole operation — no unpremultiply/repremultiply
|
|
16
|
+
* round trip, and a coverage of 0 yields a genuinely empty pixel rather than a
|
|
17
|
+
* black one.
|
|
18
|
+
*
|
|
19
|
+
* - Alpha (1) / Alpha Inverted (2): the matte's alpha.
|
|
20
|
+
* - Luma (3) / Luma Inverted (4): the matte's luminance **composited over
|
|
21
|
+
* black**, which is what the premultiplied texel already holds — a matte that
|
|
22
|
+
* is 50 % grey at 50 % opacity reads as 0.25, matching After Effects, where a
|
|
23
|
+
* luma matte's transparent regions are black rather than ignored.
|
|
24
|
+
*
|
|
25
|
+
* Rec.601 weights, shared with `displacement-map`'s Luminance channel selector
|
|
26
|
+
* so the two agree on what "luminance" means.
|
|
27
|
+
*
|
|
28
|
+
* **Out of scope in v1, recorded rather than implied:** the matte is sampled at
|
|
29
|
+
* the host's own `v_uv`, so the runtime captures it into the host's box (see
|
|
30
|
+
* `captureSource`). After Effects places a matte layer in composition space
|
|
31
|
+
* with its own transform; a matte whose box differs from the layer's is
|
|
32
|
+
* therefore stretched here, not positioned. Every corpus matte is a
|
|
33
|
+
* full-frame sibling of its layer, where the two agree.
|
|
34
|
+
*/
|
|
35
|
+
/** The `mode` enum, named once so the def, the shader and the reference agree. */
|
|
36
|
+
export declare const LUMA_MATTE_MODES: {
|
|
37
|
+
readonly alpha: 1;
|
|
38
|
+
readonly alphaInverted: 2;
|
|
39
|
+
readonly luma: 3;
|
|
40
|
+
readonly lumaInverted: 4;
|
|
41
|
+
};
|
|
42
|
+
export declare const LUMA_MATTE_FRAG: string;
|
|
43
|
+
//# sourceMappingURL=lumaMatte.frag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lumaMatte.frag.d.ts","sourceRoot":"","sources":["../../src/vfx/lumaMatte.frag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAMH,kFAAkF;AAClF,eAAO,MAAM,gBAAgB;;;;;CAKnB,CAAC;AAEX,eAAO,MAAM,eAAe,QA4B3B,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `luma-matte` kernel — GLSL ES 3.00, capture `self` plus a `ref` second
|
|
3
|
+
* source.
|
|
4
|
+
*
|
|
5
|
+
* **What it ports.** Not a single After Effects effect: this is the runtime
|
|
6
|
+
* form of every matte the exporter cannot express as CSS — a track matte whose
|
|
7
|
+
* source layer is unsupported (`matte-source-unsupported:*`), a stencil or
|
|
8
|
+
* silhouette (`stencil-*`), and Set Matte. All of them are the same
|
|
9
|
+
* per-pixel operation, `out = src · coverage(matte)`, differing only in which
|
|
10
|
+
* element is the source and which is the matte. The exporter decides that by
|
|
11
|
+
* choosing which element the host wraps and which the `matte` ref names; a
|
|
12
|
+
* stencil is this kernel with the host's own content as the matte.
|
|
13
|
+
*
|
|
14
|
+
* **Coverage.** `src` arrives premultiplied, so scaling all four channels by a
|
|
15
|
+
* single coverage value is the whole operation — no unpremultiply/repremultiply
|
|
16
|
+
* round trip, and a coverage of 0 yields a genuinely empty pixel rather than a
|
|
17
|
+
* black one.
|
|
18
|
+
*
|
|
19
|
+
* - Alpha (1) / Alpha Inverted (2): the matte's alpha.
|
|
20
|
+
* - Luma (3) / Luma Inverted (4): the matte's luminance **composited over
|
|
21
|
+
* black**, which is what the premultiplied texel already holds — a matte that
|
|
22
|
+
* is 50 % grey at 50 % opacity reads as 0.25, matching After Effects, where a
|
|
23
|
+
* luma matte's transparent regions are black rather than ignored.
|
|
24
|
+
*
|
|
25
|
+
* Rec.601 weights, shared with `displacement-map`'s Luminance channel selector
|
|
26
|
+
* so the two agree on what "luminance" means.
|
|
27
|
+
*
|
|
28
|
+
* **Out of scope in v1, recorded rather than implied:** the matte is sampled at
|
|
29
|
+
* the host's own `v_uv`, so the runtime captures it into the host's box (see
|
|
30
|
+
* `captureSource`). After Effects places a matte layer in composition space
|
|
31
|
+
* with its own transform; a matte whose box differs from the layer's is
|
|
32
|
+
* therefore stretched here, not positioned. Every corpus matte is a
|
|
33
|
+
* full-frame sibling of its layer, where the two agree.
|
|
34
|
+
*/
|
|
35
|
+
import { DISPLACEMENT_MAP_CONSTANTS } from "./displacementMap.frag.js";
|
|
36
|
+
const { lumaR, lumaG, lumaB } = DISPLACEMENT_MAP_CONSTANTS;
|
|
37
|
+
/** The `mode` enum, named once so the def, the shader and the reference agree. */
|
|
38
|
+
export const LUMA_MATTE_MODES = {
|
|
39
|
+
alpha: 1,
|
|
40
|
+
alphaInverted: 2,
|
|
41
|
+
luma: 3,
|
|
42
|
+
lumaInverted: 4,
|
|
43
|
+
};
|
|
44
|
+
export const LUMA_MATTE_FRAG = `#version 300 es
|
|
45
|
+
precision highp float;
|
|
46
|
+
|
|
47
|
+
in vec2 v_uv;
|
|
48
|
+
out vec4 fragColor;
|
|
49
|
+
|
|
50
|
+
uniform vec2 u_size;
|
|
51
|
+
uniform float u_t;
|
|
52
|
+
uniform float u_fps;
|
|
53
|
+
uniform sampler2D u_src;
|
|
54
|
+
uniform sampler2D u_src2;
|
|
55
|
+
uniform float u_mode;
|
|
56
|
+
|
|
57
|
+
// The matte texel is premultiplied, so its rgb is already "over black" — the
|
|
58
|
+
// composite After Effects reads a luma matte through.
|
|
59
|
+
float hfCoverage(vec4 matte, float mode) {
|
|
60
|
+
if (mode < 1.5) return matte.a;
|
|
61
|
+
if (mode < 2.5) return 1.0 - matte.a;
|
|
62
|
+
float luma = dot(matte.rgb, vec3(${lumaR}, ${lumaG}, ${lumaB}));
|
|
63
|
+
if (mode < 3.5) return luma;
|
|
64
|
+
return 1.0 - luma;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
void main() {
|
|
68
|
+
vec4 src = texture(u_src, v_uv);
|
|
69
|
+
vec4 matte = texture(u_src2, v_uv);
|
|
70
|
+
fragColor = src * clamp(hfCoverage(matte, u_mode), 0.0, 1.0);
|
|
71
|
+
}
|
|
72
|
+
`;
|
|
73
|
+
//# sourceMappingURL=lumaMatte.frag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lumaMatte.frag.js","sourceRoot":"","sources":["../../src/vfx/lumaMatte.frag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,0BAA0B,CAAC;AAE3D,kFAAkF;AAClF,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,KAAK,EAAE,CAAC;IACR,aAAa,EAAE,CAAC;IAChB,IAAI,EAAE,CAAC;IACP,YAAY,EAAE,CAAC;CACP,CAAC;AAEX,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;qCAkBM,KAAK,KAAK,KAAK,KAAK,KAAK;;;;;;;;;;CAU7D,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `noise` kernel — GLSL ES 3.00, capture `self`.
|
|
3
|
+
*
|
|
4
|
+
* A port of After Effects' `ADBE Noise`, decoded from `AEFX_Noise.metallib`
|
|
5
|
+
* (`docs/superpowers/specs/ae-metal-ir/AEFX_Noise.metallib.ll` in the exporter
|
|
6
|
+
* repo, helper `_Z5Noise8PixelRGBiifiiff`). The kernel is a pure integer hash of
|
|
7
|
+
* `(x, y, seed)` — no lookup table, no state between frames — so it ports
|
|
8
|
+
* exactly and stays seek-safe by construction.
|
|
9
|
+
*
|
|
10
|
+
* **What the IR says, read from the struct metadata rather than from prose.**
|
|
11
|
+
* `NoiseKernelValues` is `{ inDeviceFormat, inNoiseAmount, inUseColorNoise,
|
|
12
|
+
* inClipNoiseOutput, inRandomSeed_High, inRandomSeed_Low, inNoiseOffsetX,
|
|
13
|
+
* inNoiseOffsetY, … }`. So `ADBE Noise-0002` is **Use Color Noise**, a
|
|
14
|
+
* checkbox — not the "Noise Type (Uniform / Gaussian)" popup the deep dive
|
|
15
|
+
* guessed — and the two mystery seed floats are the halves of one 32-bit
|
|
16
|
+
* random seed. Both params are named here the way the metadata names them.
|
|
17
|
+
*
|
|
18
|
+
* Per channel:
|
|
19
|
+
*
|
|
20
|
+
* seed32 = (uint(seedHigh) << 16) | (uint(seedLow) & 0xFFFF)
|
|
21
|
+
* h = jenkinsMix(a, y, seed32) // Bob Jenkins' 1997 mix, verbatim
|
|
22
|
+
* t2 = h * 1103515245 + 12345
|
|
23
|
+
* t4 = t2 * 12996205 + 12345
|
|
24
|
+
* byte = ((t4 >> 16) & 0xFF) ^ ((t2 >> 9) & 0x7F80)
|
|
25
|
+
* noise = amount · (byte / 32704 − 0.5)
|
|
26
|
+
*
|
|
27
|
+
* with `a = x` for monochrome noise and `a = 3x + channel` (R, G, B) for colour
|
|
28
|
+
* noise — four separate hash blocks in the IR, three of them consecutive in
|
|
29
|
+
* `3x`. `32704` is the reciprocal constant `0x3F00002000000000` spelled as a
|
|
30
|
+
* fraction. The noise is ADDED to the buffer's colour and, when Clip Result
|
|
31
|
+
* Values is on, all four channels are clamped to [0, 1] — alpha is clamped but
|
|
32
|
+
* never noised.
|
|
33
|
+
*
|
|
34
|
+
* **Interim seed (plan Task 2.7, pending the Task 4.3 probe).** What the CPU
|
|
35
|
+
* puts in `inRandomSeed_High`/`inRandomSeed_Low` per frame is still unknown —
|
|
36
|
+
* it is the effect's Random Seed combined with something frame-derived, which
|
|
37
|
+
* is why the noise animates with no keyframed property. Until the probe pins
|
|
38
|
+
* it, this kernel seeds the low half with the frame index and leaves the high
|
|
39
|
+
* half at zero, so the pattern is deterministic per frame and different between
|
|
40
|
+
* frames. Switching to the decoded packing is a change to two lines here and
|
|
41
|
+
* two in the reference; nothing else depends on it, and the tests assert the
|
|
42
|
+
* byte distribution and determinism rather than After Effects parity.
|
|
43
|
+
*
|
|
44
|
+
* **Pixel space.** `x` and `y` are integer pixel coordinates with y measured
|
|
45
|
+
* from the TOP, which is how After Effects indexes the buffer — the shader's
|
|
46
|
+
* `v_uv` is y-up, so the row is flipped back here. `inNoiseOffsetX/Y` (the
|
|
47
|
+
* layer's origin inside the source buffer) are not modelled: a HyperFrames host
|
|
48
|
+
* always captures its own box, so its origin is (0, 0).
|
|
49
|
+
*
|
|
50
|
+
* **Premultiplication.** The noise is added to the captured texel as it is,
|
|
51
|
+
* which is premultiplied — the literal port, and After Effects' own buffers are
|
|
52
|
+
* premultiplied too. The consequence is worth stating: on a layer with
|
|
53
|
+
* transparency the noise lands in the transparent region as well, exactly as
|
|
54
|
+
* the effect does in After Effects.
|
|
55
|
+
*
|
|
56
|
+
* **`rgb ≤ a` is enforced regardless of `Clip Result Values`, and that is a
|
|
57
|
+
* deliberate DEPARTURE from AE, not a port of it.** A valid premultiplied
|
|
58
|
+
* colour always has `rgb ≤ a` component-wise (it is `straightRgb · a`); adding
|
|
59
|
+
* noise to `src.rgb` can push it above `src.a` on a near-transparent texel,
|
|
60
|
+
* and `clamp(out4, 0, 1)` alone does not fix that — it clamps each channel to
|
|
61
|
+
* [0, 1] independently, never rgb to a. After Effects can carry that
|
|
62
|
+
* transient state through its float pipeline because everything downstream of
|
|
63
|
+
* it is float too; every render target this runtime writes is 8-bit RGBA
|
|
64
|
+
* (`GL_ATTRS`, `makePingTarget`), and an invalid premultiplied texel read back
|
|
65
|
+
* later (e.g. straight-alpha `rgb / a` for display) reads as a blown-out
|
|
66
|
+
* bright fringe rather than the visible defect After Effects itself never
|
|
67
|
+
* produces. So the clamp to `a` runs unconditionally, on both the `Clip
|
|
68
|
+
* Result Values` on and off paths.
|
|
69
|
+
*
|
|
70
|
+
* **`Clip Result Values` off is otherwise inert here, and that is a real,
|
|
71
|
+
* currently permanent limitation, not a bug to fix in this file.** Every
|
|
72
|
+
* render target in this runtime — the visible `.hf-vfx-out` canvas AND the
|
|
73
|
+
* ping-pong intermediates a multi-node chain reads between passes — is 8-bit
|
|
74
|
+
* `UNSIGNED_BYTE` RGBA, and the GL spec clamps a float fragment output to
|
|
75
|
+
* [0, 1] on conversion to a normalized integer target regardless of what the
|
|
76
|
+
* shader computes. `u_clipping = 0` therefore cannot produce an unclamped
|
|
77
|
+
* value anywhere in this pipeline today; it would take a floating-point
|
|
78
|
+
* render target (a real infrastructure change, not a one-line fix) to give it
|
|
79
|
+
* one. Recorded rather than silently accepted: a reviewer who mutates this
|
|
80
|
+
* shader and finds `u_clipping` untestable is finding a known limitation, not
|
|
81
|
+
* a fresh bug.
|
|
82
|
+
*/
|
|
83
|
+
/**
|
|
84
|
+
* The constants the reference has to agree with, named once. `byteScale` is
|
|
85
|
+
* `0x3F00002000000000` from the IR — (1 + 2⁻⁹) · 2⁻¹⁵, i.e. 1/32704.
|
|
86
|
+
*/
|
|
87
|
+
export declare const NOISE_CONSTANTS: {
|
|
88
|
+
readonly lcgMulA: 1103515245;
|
|
89
|
+
readonly lcgMulB: 12996205;
|
|
90
|
+
readonly lcgAdd: 12345;
|
|
91
|
+
readonly highMask: 32640;
|
|
92
|
+
readonly lowMask: 255;
|
|
93
|
+
readonly byteScale: 32704;
|
|
94
|
+
};
|
|
95
|
+
export declare const NOISE_FRAG: string;
|
|
96
|
+
//# sourceMappingURL=noise.frag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noise.frag.d.ts","sourceRoot":"","sources":["../../src/vfx/noise.frag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiFG;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;CAOlB,CAAC;AAIX,eAAO,MAAM,UAAU,QAwEtB,CAAC"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `noise` kernel — GLSL ES 3.00, capture `self`.
|
|
3
|
+
*
|
|
4
|
+
* A port of After Effects' `ADBE Noise`, decoded from `AEFX_Noise.metallib`
|
|
5
|
+
* (`docs/superpowers/specs/ae-metal-ir/AEFX_Noise.metallib.ll` in the exporter
|
|
6
|
+
* repo, helper `_Z5Noise8PixelRGBiifiiff`). The kernel is a pure integer hash of
|
|
7
|
+
* `(x, y, seed)` — no lookup table, no state between frames — so it ports
|
|
8
|
+
* exactly and stays seek-safe by construction.
|
|
9
|
+
*
|
|
10
|
+
* **What the IR says, read from the struct metadata rather than from prose.**
|
|
11
|
+
* `NoiseKernelValues` is `{ inDeviceFormat, inNoiseAmount, inUseColorNoise,
|
|
12
|
+
* inClipNoiseOutput, inRandomSeed_High, inRandomSeed_Low, inNoiseOffsetX,
|
|
13
|
+
* inNoiseOffsetY, … }`. So `ADBE Noise-0002` is **Use Color Noise**, a
|
|
14
|
+
* checkbox — not the "Noise Type (Uniform / Gaussian)" popup the deep dive
|
|
15
|
+
* guessed — and the two mystery seed floats are the halves of one 32-bit
|
|
16
|
+
* random seed. Both params are named here the way the metadata names them.
|
|
17
|
+
*
|
|
18
|
+
* Per channel:
|
|
19
|
+
*
|
|
20
|
+
* seed32 = (uint(seedHigh) << 16) | (uint(seedLow) & 0xFFFF)
|
|
21
|
+
* h = jenkinsMix(a, y, seed32) // Bob Jenkins' 1997 mix, verbatim
|
|
22
|
+
* t2 = h * 1103515245 + 12345
|
|
23
|
+
* t4 = t2 * 12996205 + 12345
|
|
24
|
+
* byte = ((t4 >> 16) & 0xFF) ^ ((t2 >> 9) & 0x7F80)
|
|
25
|
+
* noise = amount · (byte / 32704 − 0.5)
|
|
26
|
+
*
|
|
27
|
+
* with `a = x` for monochrome noise and `a = 3x + channel` (R, G, B) for colour
|
|
28
|
+
* noise — four separate hash blocks in the IR, three of them consecutive in
|
|
29
|
+
* `3x`. `32704` is the reciprocal constant `0x3F00002000000000` spelled as a
|
|
30
|
+
* fraction. The noise is ADDED to the buffer's colour and, when Clip Result
|
|
31
|
+
* Values is on, all four channels are clamped to [0, 1] — alpha is clamped but
|
|
32
|
+
* never noised.
|
|
33
|
+
*
|
|
34
|
+
* **Interim seed (plan Task 2.7, pending the Task 4.3 probe).** What the CPU
|
|
35
|
+
* puts in `inRandomSeed_High`/`inRandomSeed_Low` per frame is still unknown —
|
|
36
|
+
* it is the effect's Random Seed combined with something frame-derived, which
|
|
37
|
+
* is why the noise animates with no keyframed property. Until the probe pins
|
|
38
|
+
* it, this kernel seeds the low half with the frame index and leaves the high
|
|
39
|
+
* half at zero, so the pattern is deterministic per frame and different between
|
|
40
|
+
* frames. Switching to the decoded packing is a change to two lines here and
|
|
41
|
+
* two in the reference; nothing else depends on it, and the tests assert the
|
|
42
|
+
* byte distribution and determinism rather than After Effects parity.
|
|
43
|
+
*
|
|
44
|
+
* **Pixel space.** `x` and `y` are integer pixel coordinates with y measured
|
|
45
|
+
* from the TOP, which is how After Effects indexes the buffer — the shader's
|
|
46
|
+
* `v_uv` is y-up, so the row is flipped back here. `inNoiseOffsetX/Y` (the
|
|
47
|
+
* layer's origin inside the source buffer) are not modelled: a HyperFrames host
|
|
48
|
+
* always captures its own box, so its origin is (0, 0).
|
|
49
|
+
*
|
|
50
|
+
* **Premultiplication.** The noise is added to the captured texel as it is,
|
|
51
|
+
* which is premultiplied — the literal port, and After Effects' own buffers are
|
|
52
|
+
* premultiplied too. The consequence is worth stating: on a layer with
|
|
53
|
+
* transparency the noise lands in the transparent region as well, exactly as
|
|
54
|
+
* the effect does in After Effects.
|
|
55
|
+
*
|
|
56
|
+
* **`rgb ≤ a` is enforced regardless of `Clip Result Values`, and that is a
|
|
57
|
+
* deliberate DEPARTURE from AE, not a port of it.** A valid premultiplied
|
|
58
|
+
* colour always has `rgb ≤ a` component-wise (it is `straightRgb · a`); adding
|
|
59
|
+
* noise to `src.rgb` can push it above `src.a` on a near-transparent texel,
|
|
60
|
+
* and `clamp(out4, 0, 1)` alone does not fix that — it clamps each channel to
|
|
61
|
+
* [0, 1] independently, never rgb to a. After Effects can carry that
|
|
62
|
+
* transient state through its float pipeline because everything downstream of
|
|
63
|
+
* it is float too; every render target this runtime writes is 8-bit RGBA
|
|
64
|
+
* (`GL_ATTRS`, `makePingTarget`), and an invalid premultiplied texel read back
|
|
65
|
+
* later (e.g. straight-alpha `rgb / a` for display) reads as a blown-out
|
|
66
|
+
* bright fringe rather than the visible defect After Effects itself never
|
|
67
|
+
* produces. So the clamp to `a` runs unconditionally, on both the `Clip
|
|
68
|
+
* Result Values` on and off paths.
|
|
69
|
+
*
|
|
70
|
+
* **`Clip Result Values` off is otherwise inert here, and that is a real,
|
|
71
|
+
* currently permanent limitation, not a bug to fix in this file.** Every
|
|
72
|
+
* render target in this runtime — the visible `.hf-vfx-out` canvas AND the
|
|
73
|
+
* ping-pong intermediates a multi-node chain reads between passes — is 8-bit
|
|
74
|
+
* `UNSIGNED_BYTE` RGBA, and the GL spec clamps a float fragment output to
|
|
75
|
+
* [0, 1] on conversion to a normalized integer target regardless of what the
|
|
76
|
+
* shader computes. `u_clipping = 0` therefore cannot produce an unclamped
|
|
77
|
+
* value anywhere in this pipeline today; it would take a floating-point
|
|
78
|
+
* render target (a real infrastructure change, not a one-line fix) to give it
|
|
79
|
+
* one. Recorded rather than silently accepted: a reviewer who mutates this
|
|
80
|
+
* shader and finds `u_clipping` untestable is finding a known limitation, not
|
|
81
|
+
* a fresh bug.
|
|
82
|
+
*/
|
|
83
|
+
/**
|
|
84
|
+
* The constants the reference has to agree with, named once. `byteScale` is
|
|
85
|
+
* `0x3F00002000000000` from the IR — (1 + 2⁻⁹) · 2⁻¹⁵, i.e. 1/32704.
|
|
86
|
+
*/
|
|
87
|
+
export const NOISE_CONSTANTS = {
|
|
88
|
+
lcgMulA: 1103515245,
|
|
89
|
+
lcgMulB: 12996205,
|
|
90
|
+
lcgAdd: 12345,
|
|
91
|
+
highMask: 0x7f80,
|
|
92
|
+
lowMask: 0xff,
|
|
93
|
+
byteScale: 32704,
|
|
94
|
+
};
|
|
95
|
+
const { lcgMulA, lcgMulB, lcgAdd, highMask, lowMask, byteScale } = NOISE_CONSTANTS;
|
|
96
|
+
export const NOISE_FRAG = `#version 300 es
|
|
97
|
+
precision highp float;
|
|
98
|
+
// NOT decoration: a fragment shader's default integer precision is mediump,
|
|
99
|
+
// and a mediump uint is only guaranteed 16 bits (ESSL 3.00 §4.5.2). Every step
|
|
100
|
+
// below — the Jenkins mix, both LCG rounds — is defined by 32-bit wraparound,
|
|
101
|
+
// so without this the hash is a different function on any implementation that
|
|
102
|
+
// honours the minimum. ANGLE and SwiftShader both use 32-bit ints, which is
|
|
103
|
+
// exactly why no test on this machine would catch it.
|
|
104
|
+
precision highp int;
|
|
105
|
+
|
|
106
|
+
in vec2 v_uv;
|
|
107
|
+
out vec4 fragColor;
|
|
108
|
+
|
|
109
|
+
uniform vec2 u_size;
|
|
110
|
+
uniform float u_t;
|
|
111
|
+
uniform float u_fps;
|
|
112
|
+
uniform sampler2D u_src;
|
|
113
|
+
uniform float u_amount;
|
|
114
|
+
uniform float u_useColorNoise;
|
|
115
|
+
uniform float u_clipping;
|
|
116
|
+
|
|
117
|
+
// Bob Jenkins' 1997 integer mix, the six-round shift/xor/subtract sequence the
|
|
118
|
+
// metallib runs verbatim. uint arithmetic wraps in GLSL ES 3.00, which is what
|
|
119
|
+
// makes this bit-identical to the C original.
|
|
120
|
+
uint hfJenkinsMix(uint a, uint b, uint c) {
|
|
121
|
+
a -= b; a -= c; a ^= (c >> 13u);
|
|
122
|
+
b -= c; b -= a; b ^= (a << 8u);
|
|
123
|
+
c -= a; c -= b; c ^= (b >> 13u);
|
|
124
|
+
a -= b; a -= c; a ^= (c >> 12u);
|
|
125
|
+
b -= c; b -= a; b ^= (a << 16u);
|
|
126
|
+
c -= a; c -= b; c ^= (b >> 5u);
|
|
127
|
+
a -= b; a -= c; a ^= (c >> 3u);
|
|
128
|
+
b -= c; b -= a; b ^= (a << 10u);
|
|
129
|
+
c -= a; c -= b; c ^= (b >> 15u);
|
|
130
|
+
return c;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// The hash's 15-bit output byte for one channel.
|
|
134
|
+
float hfNoiseByte(uint a, uint y, uint seed) {
|
|
135
|
+
uint h = hfJenkinsMix(a, y, seed);
|
|
136
|
+
uint t2 = h * ${lcgMulA}u + ${lcgAdd}u;
|
|
137
|
+
uint t4 = t2 * ${lcgMulB}u + ${lcgAdd}u;
|
|
138
|
+
return float(((t4 >> 16u) & ${lowMask}u) ^ ((t2 >> 9u) & ${highMask}u));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
void main() {
|
|
142
|
+
vec4 src = texture(u_src, v_uv);
|
|
143
|
+
vec2 px = floor(v_uv * u_size);
|
|
144
|
+
uint x = uint(max(px.x, 0.0));
|
|
145
|
+
// After Effects indexes rows from the top; v_uv is y-up.
|
|
146
|
+
uint y = uint(max(u_size.y - 1.0 - px.y, 0.0));
|
|
147
|
+
float frame = floor(u_t * u_fps + 0.5);
|
|
148
|
+
uint seed = uint(max(frame, 0.0)) & 0xFFFFu;
|
|
149
|
+
|
|
150
|
+
float amount = u_amount * 0.01;
|
|
151
|
+
vec3 nz;
|
|
152
|
+
if (u_useColorNoise > 0.5) {
|
|
153
|
+
uint a = x * 3u;
|
|
154
|
+
nz = vec3(hfNoiseByte(a, y, seed), hfNoiseByte(a + 1u, y, seed), hfNoiseByte(a + 2u, y, seed));
|
|
155
|
+
} else {
|
|
156
|
+
nz = vec3(hfNoiseByte(x, y, seed));
|
|
157
|
+
}
|
|
158
|
+
nz = amount * (nz / ${byteScale}.0 - 0.5);
|
|
159
|
+
|
|
160
|
+
vec4 out4 = vec4(src.rgb + nz, src.a);
|
|
161
|
+
// A valid premultiplied colour needs rgb <= a component-wise; noise on a
|
|
162
|
+
// near-transparent texel can push rgb above it, which our fixed 8-bit RGBA
|
|
163
|
+
// storage cannot carry safely the way AE's float pipeline can (see the doc
|
|
164
|
+
// comment above). This runs before, and independently of, u_clipping.
|
|
165
|
+
out4.rgb = min(out4.rgb, out4.a);
|
|
166
|
+
fragColor = u_clipping > 0.5 ? clamp(out4, 0.0, 1.0) : out4;
|
|
167
|
+
}
|
|
168
|
+
`;
|
|
169
|
+
//# sourceMappingURL=noise.frag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noise.frag.js","sourceRoot":"","sources":["../../src/vfx/noise.frag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiFG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,OAAO,EAAE,UAAU;IACnB,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE,KAAK;IACb,QAAQ,EAAE,MAAM;IAChB,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,KAAK;CACR,CAAC;AAEX,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,eAAe,CAAC;AAEnF,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAwCR,OAAO,OAAO,MAAM;mBACnB,OAAO,OAAO,MAAM;gCACP,OAAO,sBAAsB,QAAQ;;;;;;;;;;;;;;;;;;;;wBAoB7C,SAAS;;;;;;;;;;CAUhC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CPU reference for the `luma-matte` kernel. Unlike `wave-warp`'s and
|
|
3
|
+
* `displacement-map`'s, which return the coordinate they sample, this one
|
|
4
|
+
* returns the colour: the kernel's whole decision is a per-pixel scale, and a
|
|
5
|
+
* caller with both texels can check it exactly.
|
|
6
|
+
*
|
|
7
|
+
* Both texels are **premultiplied**, matching the textures the runtime uploads.
|
|
8
|
+
*/
|
|
9
|
+
import { type HfVfxParamValues } from "../../vfx";
|
|
10
|
+
export interface Rgba {
|
|
11
|
+
r: number;
|
|
12
|
+
g: number;
|
|
13
|
+
b: number;
|
|
14
|
+
a: number;
|
|
15
|
+
}
|
|
16
|
+
/** The shader's `hfCoverage`. */
|
|
17
|
+
export declare function lumaMatteCoverageRef(matte: Rgba, mode: number): number;
|
|
18
|
+
/**
|
|
19
|
+
* The colour the kernel paints. `t` is part of the call shape every kernel
|
|
20
|
+
* reference shares; a matte is time-invariant — its animation arrives as
|
|
21
|
+
* movement in the matte element itself.
|
|
22
|
+
*/
|
|
23
|
+
export declare function lumaMatteSampleRef(src: Rgba, matte: Rgba, t: number, params: HfVfxParamValues): Rgba;
|
|
24
|
+
//# sourceMappingURL=lumaMatte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lumaMatte.d.ts","sourceRoot":"","sources":["../../../src/vfx/refs/lumaMatte.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAMtE,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,iCAAiC;AACjC,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKtE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,IAAI,EACT,KAAK,EAAE,IAAI,EACX,CAAC,EAAE,MAAM,EACT,MAAM,EAAE,gBAAgB,GACvB,IAAI,CAKN"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CPU reference for the `luma-matte` kernel. Unlike `wave-warp`'s and
|
|
3
|
+
* `displacement-map`'s, which return the coordinate they sample, this one
|
|
4
|
+
* returns the colour: the kernel's whole decision is a per-pixel scale, and a
|
|
5
|
+
* caller with both texels can check it exactly.
|
|
6
|
+
*
|
|
7
|
+
* Both texels are **premultiplied**, matching the textures the runtime uploads.
|
|
8
|
+
*/
|
|
9
|
+
import { normalizeVfxParams } from "../../vfx.js";
|
|
10
|
+
import { DISPLACEMENT_MAP_CONSTANTS } from "../displacementMap.frag.js";
|
|
11
|
+
import { LUMA_MATTE_MODES } from "../lumaMatte.frag.js";
|
|
12
|
+
const { lumaR, lumaG, lumaB } = DISPLACEMENT_MAP_CONSTANTS;
|
|
13
|
+
/** The shader's `hfCoverage`. */
|
|
14
|
+
export function lumaMatteCoverageRef(matte, mode) {
|
|
15
|
+
if (mode < LUMA_MATTE_MODES.alphaInverted)
|
|
16
|
+
return matte.a;
|
|
17
|
+
if (mode < LUMA_MATTE_MODES.luma)
|
|
18
|
+
return 1 - matte.a;
|
|
19
|
+
const luma = matte.r * lumaR + matte.g * lumaG + matte.b * lumaB;
|
|
20
|
+
return mode < LUMA_MATTE_MODES.lumaInverted ? luma : 1 - luma;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The colour the kernel paints. `t` is part of the call shape every kernel
|
|
24
|
+
* reference shares; a matte is time-invariant — its animation arrives as
|
|
25
|
+
* movement in the matte element itself.
|
|
26
|
+
*/
|
|
27
|
+
export function lumaMatteSampleRef(src, matte, t, params) {
|
|
28
|
+
void t;
|
|
29
|
+
const n = normalizeVfxParams("luma-matte", params);
|
|
30
|
+
const coverage = Math.min(1, Math.max(0, lumaMatteCoverageRef(matte, Number(n["mode"]))));
|
|
31
|
+
return { r: src.r * coverage, g: src.g * coverage, b: src.b * coverage, a: src.a * coverage };
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=lumaMatte.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lumaMatte.js","sourceRoot":"","sources":["../../../src/vfx/refs/lumaMatte.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,kBAAkB,EAAyB,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,0BAA0B,CAAC;AAS3D,iCAAiC;AACjC,MAAM,UAAU,oBAAoB,CAAC,KAAW,EAAE,IAAY;IAC5D,IAAI,IAAI,GAAG,gBAAgB,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC;IAC1D,IAAI,IAAI,GAAG,gBAAgB,CAAC,IAAI;QAAE,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC;IACjE,OAAO,IAAI,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;AAChE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,GAAS,EACT,KAAW,EACX,CAAS,EACT,MAAwB;IAExB,KAAK,CAAC,CAAC;IACP,MAAM,CAAC,GAAG,kBAAkB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1F,OAAO,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,QAAQ,EAAE,CAAC;AAChG,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CPU reference for the `noise` kernel — the same integer hash the shader
|
|
3
|
+
* runs, in 32-bit wrapping arithmetic. JavaScript's `>>> 0` and `Math.imul`
|
|
4
|
+
* reproduce C's `unsigned int` overflow exactly, which is the property the
|
|
5
|
+
* whole port rests on.
|
|
6
|
+
*
|
|
7
|
+
* Returns the noise OFFSET applied to a pixel, not the colour: the offset is
|
|
8
|
+
* the entirety of what the kernel computes, and the add-and-clip around it is
|
|
9
|
+
* two lines a caller can apply itself.
|
|
10
|
+
*/
|
|
11
|
+
import { type HfVfxParamValues } from "../../vfx";
|
|
12
|
+
/** The hash's 15-bit output byte for one channel index `a`. */
|
|
13
|
+
export declare function noiseByteRef(a: number, y: number, seed: number): number;
|
|
14
|
+
/**
|
|
15
|
+
* The 32-bit seed the kernel hashes with. Interim, pending the Task 4.3 probe:
|
|
16
|
+
* the frame index goes in the low half and the high half is zero. The packing
|
|
17
|
+
* itself is the metallib's (`inRandomSeed_High` << 16 | `inRandomSeed_Low`), so
|
|
18
|
+
* the probe's answer replaces the arguments, not the shape.
|
|
19
|
+
*/
|
|
20
|
+
export declare function noiseSeedRef(t: number, fps: number): number;
|
|
21
|
+
/**
|
|
22
|
+
* The per-channel noise offset the kernel adds at pixel `(x, y)` — `y` counted
|
|
23
|
+
* from the TOP of the layer, as After Effects indexes its buffer.
|
|
24
|
+
*/
|
|
25
|
+
export declare function noiseOffsetRef(p: {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
}, t: number, fps: number, params: HfVfxParamValues): {
|
|
29
|
+
r: number;
|
|
30
|
+
g: number;
|
|
31
|
+
b: number;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=noise.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noise.d.ts","sourceRoot":"","sources":["../../../src/vfx/refs/noise.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAsBtE,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,CAAC,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAC3B,CAAC,EAAE,MAAM,EACT,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,gBAAgB,GACvB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAerC"}
|