reze-engine 0.41.0 → 0.41.2
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/README.md +4 -2
- package/dist/engine.d.ts +31 -3
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +190 -18
- package/dist/graph/presets/body.js +2 -2
- package/dist/graph/presets/cloth_rough.js +2 -2
- package/dist/graph/presets/cloth_smooth.js +2 -2
- package/dist/graph/presets/default.js +2 -2
- package/dist/graph/presets/eye.js +2 -2
- package/dist/graph/presets/face.js +2 -2
- package/dist/graph/presets/hair.js +2 -2
- package/dist/graph/presets/metal.js +2 -2
- package/dist/graph/presets/stockings.js +3 -3
- package/dist/graph/registry.d.ts.map +1 -1
- package/dist/graph/registry.js +426 -10
- package/dist/graph/style-group.d.ts +46 -0
- package/dist/graph/style-group.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/shaders/agx-lut.d.ts +11 -0
- package/dist/shaders/agx-lut.d.ts.map +1 -0
- package/dist/shaders/agx-lut.js +29 -0
- package/dist/shaders/materials/common.d.ts +1 -1
- package/dist/shaders/materials/common.d.ts.map +1 -1
- package/dist/shaders/materials/common.js +10 -0
- 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 +957 -576
- package/dist/shaders/passes/composite.d.ts.map +1 -1
- package/dist/shaders/passes/composite.js +76 -4
- package/package.json +1 -1
- package/src/engine.ts +211 -17
- package/src/graph/presets/body.ts +2 -2
- package/src/graph/presets/cloth_rough.ts +2 -2
- package/src/graph/presets/cloth_smooth.ts +2 -2
- package/src/graph/presets/default.ts +2 -2
- package/src/graph/presets/eye.ts +2 -2
- package/src/graph/presets/face.ts +2 -2
- package/src/graph/presets/hair.ts +2 -2
- package/src/graph/presets/metal.ts +2 -2
- package/src/graph/presets/stockings.ts +3 -3
- package/src/graph/registry.ts +439 -10
- package/src/graph/style-group.ts +44 -0
- package/src/index.ts +2 -0
- package/src/shaders/agx-lut.ts +30 -0
- package/src/shaders/materials/common.ts +10 -0
- package/src/shaders/materials/nodes.ts +962 -581
- package/src/shaders/passes/composite.ts +76 -4
|
@@ -60,7 +60,7 @@ override APPLY_GAMMA: bool = true;
|
|
|
60
60
|
@group(0) @binding(0) var hdrTex: texture_2d<f32>;
|
|
61
61
|
@group(0) @binding(1) var bloomTex: texture_2d<f32>; // bloomUpTexture mip 0 (full pyramid top)
|
|
62
62
|
@group(0) @binding(2) var bloomSamp: sampler;
|
|
63
|
-
@group(0) @binding(3) var<uniform> viewU: array<vec4<f32>,
|
|
63
|
+
@group(0) @binding(3) var<uniform> viewU: array<vec4<f32>, 15>;
|
|
64
64
|
// Aux mask/alpha texture. .r = bloom mask (unused here; bloom blit uses it).
|
|
65
65
|
// .g = accumulated canvas alpha (what hdr.a carried before the HDR format
|
|
66
66
|
// became rg11b10ufloat). We unpremultiply HDR by this alpha for tonemap, then
|
|
@@ -84,7 +84,7 @@ override APPLY_GAMMA: bool = true;
|
|
|
84
84
|
// the compiled variant IS the flag.
|
|
85
85
|
// viewU[3] = (camera right, tanHalfFov·aspect); viewU[4] = (camera up, tanHalfFov);
|
|
86
86
|
// viewU[5] = (camera forward, _) — refreshed per frame while skybox/effect active.
|
|
87
|
-
// viewU[6] = (time seconds,
|
|
87
|
+
// viewU[6] = (time seconds, view transform id, canvas width, canvas height).
|
|
88
88
|
// viewU[7] = (grade offset.rgb, contrast); viewU[8] = (grade power.rgb, saturation);
|
|
89
89
|
// viewU[9] = (grade slope.rgb, grade on/off) — see grade() below.
|
|
90
90
|
// viewU[10] = (camera world position, _) — refreshed with the basis above.
|
|
@@ -104,6 +104,9 @@ override APPLY_GAMMA: bool = true;
|
|
|
104
104
|
// track the camera radius. Cleared depth (1.0) inverts to the far
|
|
105
105
|
// plane, so empty sky reads as maximally defocused background.
|
|
106
106
|
@group(0) @binding(9) var<uniform> dofU: array<vec4<f32>, 3>;
|
|
107
|
+
// Blender's AgX, as the 57³ lookup it ships as rather than a reconstruction of
|
|
108
|
+
// it. Sampled in the log-encoded E-Gamut space the cube expects — see agxTransform.
|
|
109
|
+
@group(0) @binding(10) var agxLut: texture_3d<f32>;
|
|
107
110
|
|
|
108
111
|
// Must match FILMIC_LUT_WIDTH in engine.ts (bakeFilmicLut).
|
|
109
112
|
const FILMIC_LUT_W: f32 = 256.0;
|
|
@@ -147,12 +150,82 @@ fn filmic(x: f32) -> f32 {
|
|
|
147
150
|
return textureSampleLevel(filmicLut, bloomSamp, vec2f(u, 0.5), 0.0).r;
|
|
148
151
|
}
|
|
149
152
|
|
|
153
|
+
/** The sRGB display encoding — Blender's "Standard" view transform, which is what
|
|
154
|
+
* NPR work uses: no film curve at all, so the colours a graph computes are the
|
|
155
|
+
* colours that land. Not a 2.2 power law; sRGB has a linear toe. */
|
|
156
|
+
fn srgb_encode(x: f32) -> f32 {
|
|
157
|
+
let c = max(x, 0.0);
|
|
158
|
+
return select(1.055 * pow(c, 1.0 / 2.4) - 0.055, c * 12.92, c <= 0.0031308);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* AgX, the chain config.ocio states for "AgX Base Rec.1886" on an sRGB display:
|
|
163
|
+
*
|
|
164
|
+
* scene-linear Rec.709 → 3x3 into FilmLight E-Gamut
|
|
165
|
+
* → log2 across 25 stops, [-12.47393, +12.5261] → 0..1
|
|
166
|
+
* → the 57³ cube
|
|
167
|
+
* → Rec.1886 (pure γ2.4) decoded, then re-encoded as sRGB for the swapchain
|
|
168
|
+
*
|
|
169
|
+
* The last step is not pedantry: Rec.1886 is a pure power law and sRGB has a
|
|
170
|
+
* linear toe, so skipping it lifts the darkest few code values.
|
|
171
|
+
*
|
|
172
|
+
* Blender interpolates the cube tetrahedrally and a GPU sampler is trilinear.
|
|
173
|
+
* The difference is small and confined to saturated gradients; if it ever shows,
|
|
174
|
+
* tetrahedral is a dozen lines here.
|
|
175
|
+
*/
|
|
176
|
+
fn agxTransform(c: vec3f) -> vec3f {
|
|
177
|
+
let m = mat3x3<f32>(
|
|
178
|
+
vec3f(0.55937113, 0.07622071, 0.06552670),
|
|
179
|
+
vec3f(0.30478326, 0.78797183, 0.16454675),
|
|
180
|
+
vec3f(0.13584556, 0.13580748, 0.76992653),
|
|
181
|
+
);
|
|
182
|
+
let e = m * max(c, vec3f(0.0));
|
|
183
|
+
// The cube's domain: an unlit pixel would take log2 to -inf, so floor it at
|
|
184
|
+
// the bottom stop rather than sampling outside the LUT.
|
|
185
|
+
let t = clamp((log2(max(e, vec3f(1e-10))) + vec3f(12.47393)) / 25.0, vec3f(0.0), vec3f(1.0));
|
|
186
|
+
// Half-texel inset, so the end stops are the cube's own values and not a blend
|
|
187
|
+
// with the clamp-to-edge border.
|
|
188
|
+
let n = 57.0;
|
|
189
|
+
let uvw = t * ((n - 1.0) / n) + (0.5 / n);
|
|
190
|
+
let formed = textureSampleLevel(agxLut, bloomSamp, uvw, 0.0).rgb;
|
|
191
|
+
let linear = pow(max(formed, vec3f(0.0)), vec3f(2.4));
|
|
192
|
+
return vec3f(srgb_encode(linear.r), srgb_encode(linear.g), srgb_encode(linear.b));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Which display transform, chosen per frame at viewU[6].y (0 filmic, 1 standard, 2 agx).
|
|
196
|
+
* A uniform branch rather than a pipeline variant: switching is rare, and both
|
|
197
|
+
* arms are cheap enough that specialising the pipeline would buy nothing. */
|
|
198
|
+
fn viewTransform(c: vec3f) -> vec3f {
|
|
199
|
+
let mode = viewU[6].y;
|
|
200
|
+
if (mode > 1.5) { return agxTransform(c); }
|
|
201
|
+
if (mode > 0.5) { return vec3f(srgb_encode(c.r), srgb_encode(c.g), srgb_encode(c.b)); }
|
|
202
|
+
return vec3f(filmic(c.r), filmic(c.g), filmic(c.b));
|
|
203
|
+
}
|
|
204
|
+
|
|
150
205
|
/** Canvas size in pixels — for user effects (aspect correction). */
|
|
151
206
|
fn bgResolution() -> vec2f { return viewU[6].zw; }
|
|
152
207
|
|
|
153
208
|
/** The camera's world position. */
|
|
154
209
|
fn bgCameraPos() -> vec3f { return viewU[10].xyz; }
|
|
155
210
|
|
|
211
|
+
/** How many characters are in the scene, up to four. */
|
|
212
|
+
fn bgSubjectCount() -> i32 { return i32(viewU[10].w); }
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Where a character is standing, in world space.
|
|
216
|
+
*
|
|
217
|
+
* An effect that wants to RESPOND to the cast — ripples under the feet, a glow
|
|
218
|
+
* that follows someone, dust kicked up where they are — needs to know where
|
|
219
|
+
* they are, and the ray and the depth cannot tell it: they describe the pixel,
|
|
220
|
+
* not the scene. This is the model's root, which for a PMX is between the feet
|
|
221
|
+
* on the floor, so it is already the contact point a ripple wants.
|
|
222
|
+
*
|
|
223
|
+
* Clamped rather than bounds-checked: an effect looping past the count reads the
|
|
224
|
+
* last subject instead of sampling whatever follows the array, which is a wrong
|
|
225
|
+
* ripple rather than an undefined one.
|
|
226
|
+
*/
|
|
227
|
+
fn bgSubjectPos(i: i32) -> vec3f { return viewU[11 + clamp(i, 0, 3)].xyz; }
|
|
228
|
+
|
|
156
229
|
/** Where in the WORLD the scene drew this pixel — the depth handed to
|
|
157
230
|
* foreground() turned into a place. Without it an effect can only think in
|
|
158
231
|
* distances from the lens, which is no use to anything that belongs somewhere:
|
|
@@ -260,8 +333,7 @@ const COMPOSITE_BODY = /* wgsl */ `
|
|
|
260
333
|
let sceneStraight = scenePm.rgb / max(sceneAlpha, 1e-6);
|
|
261
334
|
|
|
262
335
|
let exposed = sceneStraight * exp2(viewU[0].x);
|
|
263
|
-
|
|
264
|
-
var disp = max(tm, vec3f(0.0));
|
|
336
|
+
var disp = max(viewTransform(exposed), vec3f(0.0));
|
|
265
337
|
// Grade the SCENE only, before the display gamma. Deliberately not applied to
|
|
266
338
|
// the background: it keeps a picked background color exactly as picked, and —
|
|
267
339
|
// load-bearing — leaves green-screen mode's key color unshifted so chroma
|