reze-engine 0.23.0 → 0.23.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 +10 -3
- package/dist/asset-reader.d.ts.map +1 -1
- package/dist/asset-reader.js +12 -0
- package/dist/engine.d.ts +29 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +136 -18
- package/dist/shaders/passes/composite.d.ts +1 -1
- package/dist/shaders/passes/composite.d.ts.map +1 -1
- package/dist/shaders/passes/composite.js +23 -2
- package/dist/shaders/passes/ground.d.ts +1 -1
- package/dist/shaders/passes/ground.d.ts.map +1 -1
- package/dist/shaders/passes/ground.js +12 -5
- package/package.json +1 -1
- package/src/asset-reader.ts +12 -0
- package/src/engine.ts +145 -17
- package/src/shaders/passes/composite.ts +23 -2
- package/src/shaders/passes/ground.ts +12 -5
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ npm install reze-engine
|
|
|
19
19
|
- **VMD animation** — MMD IK, morphs on a GPU compute path, and VMD export
|
|
20
20
|
- **Interactive editing** — GPU picking, transform gizmo, bone/material selection
|
|
21
21
|
- **Camera** — orbit, bone-follow, or a driven MMD camera VMD; ground + PCF shadows, multi-model scenes
|
|
22
|
+
- **Offline rendering** — frame-accurate stepping (`renderFrame`) at any resolution (`setRenderSize`) for video export; background color, 360° equirect backdrop, ground shadow-catcher
|
|
22
23
|
|
|
23
24
|
See [Physics](#physics) and [Rendering](#rendering) for the internals.
|
|
24
25
|
|
|
@@ -117,13 +118,17 @@ engine.loadCameraVmd(url) / loadCameraVmdFromBuffer(buffer) // MMD camera trac
|
|
|
117
118
|
engine.setCameraVmdEnabled(on) / isCameraVmdEnabled() / hasCameraVmd() / clearCameraVmd() // toggle the shot; while it drives, orbit/pan/zoom is inert — toggle off to hand control back
|
|
118
119
|
|
|
119
120
|
engine.setWorld({ color?, strength? }) / setSun({ color?, strength?, direction? }) // runtime lighting
|
|
120
|
-
engine.
|
|
121
|
+
engine.setBackgroundColor(color | null) // canvas background (display-space sRGB 0–1, composited post-tonemap so it matches a CSS color of the same value exactly); null = transparent canvas (DOM shows through)
|
|
122
|
+
engine.setBackdropEquirect(source | null) // 360° backdrop from an equirect (2:1) image — PhotoDome-style dome at infinity, follows the camera, display-only (no lighting/bloom influence); oversized panoramas auto-downscale to the device texture limit
|
|
123
|
+
engine.addGround(options?) // options include opacity (0–1): fades the SURFACE while the received shadow persists (shadow catcher — models stay grounded on photo backdrops); shadowStrength 0 disables the shadow
|
|
121
124
|
engine.runRenderLoop(callback?) / stopRenderLoop()
|
|
125
|
+
engine.renderFrame(deltaSeconds) // offline rendering: render one frame advancing EVERY clock (animation, physics, camera VMD) by exactly dt — wall-clock independent; call N times with 1/fps for deterministic video export
|
|
126
|
+
engine.setRenderSize(w, h) / setRenderSize(null) // pin render resolution (all targets) independent of the canvas CSS size, e.g. 3840×2160 for export; null returns to CSS-size × devicePixelRatio tracking
|
|
122
127
|
engine.getStats() // fps + smoothness metrics (frameTimeMax, fps1PercentLow, jitter)
|
|
123
128
|
engine.dispose()
|
|
124
129
|
```
|
|
125
130
|
|
|
126
|
-
**Options** — Blender-style scene config: `world` = environment lighting, `sun` = directional lamp (`direction` points from sun into the scene), `camera` = framing (`fov` in radians). Callbacks: `onRaycast`, `onGizmoDrag`. The shadow map is cast from `sun.direction` — the same vector the shader lights with — so shading and cast shadows stay coupled.
|
|
131
|
+
**Options** — Blender-style scene config: `world` = environment lighting, `sun` = directional lamp (`direction` points from sun into the scene), `camera` = framing (`fov` in radians), `background` = canvas background (display-space sRGB, same semantics as `setBackgroundColor`). Callbacks: `onRaycast`, `onGizmoDrag`. The shadow map is cast from `sun.direction` — the same vector the shader lights with — so shading and cast shadows stay coupled.
|
|
127
132
|
|
|
128
133
|
### Model
|
|
129
134
|
|
|
@@ -160,6 +165,8 @@ if (picked.status === "single")
|
|
|
160
165
|
|
|
161
166
|
VMD and other assets still load by URL when the path starts with `/` or `http(s):`; relative paths resolve against the PMX directory.
|
|
162
167
|
|
|
168
|
+
**Flat multi-file picks work too** (mobile pickers can't select folders): files map by name, and texture paths fall back to **basename matching** — a PMX referencing `tex/body.png` finds a flat-selected `body.png`. The same fallback rescues wrongly-cased directory names.
|
|
169
|
+
|
|
163
170
|
### Interactive pose editing
|
|
164
171
|
|
|
165
172
|
Double-click picks a bone or material (per-triangle dominant-joint from the GPU pick, so one handler serves both modes); a local-axis transform gizmo drags it. **The engine only reports — it never writes the skeleton itself**, so the host chooses the write policy.
|
|
@@ -296,7 +303,7 @@ Each built-in shader graph mixes an NPR stack with a Principled-style BSDF, so c
|
|
|
296
303
|
| `metal` | Toon + emission overlay (×8), Voronoi base, metallic 1 |
|
|
297
304
|
| `stockings` | Gradient × facing mask + HSV emission (×5), sheen 0.7, **alpha-hashed** |
|
|
298
305
|
|
|
299
|
-
**Post & output.** Directional shadow map (
|
|
306
|
+
**Post & output.** Directional shadow map (4096², depth32float, PCF) → HDR main pass at 4× MSAA (`rg11b10ufloat` color + `rg8unorm` aux MRT for bloom mask + alpha; fits Apple-Silicon TBDR tile memory so MSAA resolves in-tile, `rgba16float` fallback) → bloom mip pyramid → Filmic tone map (Blender 3.6 "Filmic / Medium High Contrast" LUT) → composite over the background color / 360 equirect backdrop (display space) → inverted-hull outline.
|
|
300
307
|
|
|
301
308
|
- **Alpha-hashed transparency** (`stockings`) — Wyman & McGuire 2017 derivative-aware stochastic discard in object space, so self-overlapping meshes resolve under MSAA with opaque depth writes and the dither doesn't swim.
|
|
302
309
|
- **See-through hair over eyes** — stencil-gated extra pass: the eye stamps `EYE_VALUE`, main hair skips it, an extra pass matches it and blends hair at 25% in linear HDR so eyes stay readable.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset-reader.d.ts","sourceRoot":"","sources":["../src/asset-reader.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;CACtD,CAAA;AAED,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED,2GAA2G;AAC3G,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED,wBAAgB,sBAAsB,IAAI,WAAW,CAQpD;AAED,8FAA8F;AAC9F,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"asset-reader.d.ts","sourceRoot":"","sources":["../src/asset-reader.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;CACtD,CAAA;AAED,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED,2GAA2G;AAC3G,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED,wBAAgB,sBAAsB,IAAI,WAAW,CAQpD;AAED,8FAA8F;AAC9F,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,WAAW,CA8B9E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAOzE;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,CAS5E"}
|
package/dist/asset-reader.js
CHANGED
|
@@ -47,6 +47,18 @@ export function createFileMapAssetReader(files) {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
+
if (!file) {
|
|
51
|
+
// Last resort: basename match. Mobile pickers can't select folders — a flat
|
|
52
|
+
// multi-file selection loses directory structure, so `tex/body.png` must
|
|
53
|
+
// find a bare `body.png`. Also rescues wrongly-cased directory names.
|
|
54
|
+
const base = key.split("/").pop().toLowerCase();
|
|
55
|
+
for (const [k, f] of files) {
|
|
56
|
+
if (k.split("/").pop().toLowerCase() === base) {
|
|
57
|
+
file = f;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
50
62
|
if (!file)
|
|
51
63
|
throw new Error(`Missing file in folder: ${key}`);
|
|
52
64
|
return file.arrayBuffer();
|
package/dist/engine.d.ts
CHANGED
|
@@ -90,6 +90,9 @@ export type EngineOptions = {
|
|
|
90
90
|
world?: WorldOptions;
|
|
91
91
|
sun?: SunOptions;
|
|
92
92
|
camera?: CameraOptions;
|
|
93
|
+
/** Canvas background (display-space sRGB 0–1), composited under the scene after
|
|
94
|
+
* tonemapping. Omit/null = transparent canvas (see setBackgroundColor). */
|
|
95
|
+
background?: Vec3 | null;
|
|
93
96
|
/** Initial EEVEE-style bloom; tune at runtime with `setBloomOptions`. */
|
|
94
97
|
bloom?: Partial<BloomOptions>;
|
|
95
98
|
/** View transform (exposure/gamma) applied in composite before/after Filmic. */
|
|
@@ -212,6 +215,13 @@ export declare class Engine {
|
|
|
212
215
|
private compositeBindGroup;
|
|
213
216
|
private compositeUniformBuffer;
|
|
214
217
|
private readonly compositeUniformData;
|
|
218
|
+
/** Composite background (display-space sRGB 0–1) — null = transparent canvas. */
|
|
219
|
+
private backgroundColor;
|
|
220
|
+
private backdropEquirectTexture;
|
|
221
|
+
private backdropEquirectView;
|
|
222
|
+
private fallbackEquirectTexture;
|
|
223
|
+
private fallbackEquirectView;
|
|
224
|
+
private compositeBloomView;
|
|
215
225
|
private bloomSampler;
|
|
216
226
|
private bloomBlitUniformBuffer;
|
|
217
227
|
private bloomUpsampleUniformBuffer;
|
|
@@ -300,6 +310,23 @@ export declare class Engine {
|
|
|
300
310
|
getViewTransformOptions(): ViewTransformOptions;
|
|
301
311
|
setViewTransformOptions(patch: Partial<ViewTransformOptions>): void;
|
|
302
312
|
private writeCompositeViewUniforms;
|
|
313
|
+
/**
|
|
314
|
+
* Set the canvas background color (display-space sRGB, 0–1 per channel — the
|
|
315
|
+
* same value a CSS background of that color shows, applied after tonemapping).
|
|
316
|
+
* Pass null for a transparent canvas (the page/DOM shows through — e.g. when a
|
|
317
|
+
* backdrop image layer sits behind the canvas). Applies on the next frame.
|
|
318
|
+
* A 360 backdrop (setBackdropEquirect) takes precedence while set.
|
|
319
|
+
*/
|
|
320
|
+
setBackgroundColor(color: Vec3 | null): void;
|
|
321
|
+
private rebuildCompositeBindGroup;
|
|
322
|
+
/**
|
|
323
|
+
* Set a 360° backdrop from an equirectangular (2:1) image — a PhotoDome-style
|
|
324
|
+
* skybox at infinity, sampled per-pixel by view direction so it follows the
|
|
325
|
+
* camera. Display-only: composited in display space behind the scene, it never
|
|
326
|
+
* affects lighting, bloom, or tonemapping. Pass null to remove (the background
|
|
327
|
+
* color, or transparency, takes over again).
|
|
328
|
+
*/
|
|
329
|
+
setBackdropEquirect(source: ImageBitmap | HTMLImageElement | HTMLCanvasElement | null): void;
|
|
303
330
|
/** Patch bloom; GPU uniforms update immediately if `init()` has run. */
|
|
304
331
|
setBloomOptions(patch: Partial<BloomOptions>): void;
|
|
305
332
|
private writeBloomUniforms;
|
|
@@ -386,6 +413,8 @@ export declare class Engine {
|
|
|
386
413
|
gridLineOpacity?: number;
|
|
387
414
|
gridLineColor?: Vec3;
|
|
388
415
|
noiseStrength?: number;
|
|
416
|
+
/** Whole-ground opacity, 0–1 (multiplies the radial edge fade). Default 1. */
|
|
417
|
+
opacity?: number;
|
|
389
418
|
}): void;
|
|
390
419
|
private updateLightBuffer;
|
|
391
420
|
getStats(): EngineStats;
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.js
CHANGED
|
@@ -188,7 +188,13 @@ export class Engine {
|
|
|
188
188
|
// unchanged).
|
|
189
189
|
this.hdrFormat = "rgba16float";
|
|
190
190
|
// [exposure, invGamma, _, _, bloomTint.x, bloomTint.y, bloomTint.z, bloomIntensity]
|
|
191
|
-
this.compositeUniformData = new Float32Array(
|
|
191
|
+
this.compositeUniformData = new Float32Array(24);
|
|
192
|
+
/** Composite background (display-space sRGB 0–1) — null = transparent canvas. */
|
|
193
|
+
this.backgroundColor = null;
|
|
194
|
+
// 360 backdrop (equirectangular skybox, sampled by view ray in composite).
|
|
195
|
+
this.backdropEquirectTexture = null;
|
|
196
|
+
this.backdropEquirectView = null;
|
|
197
|
+
this.compositeBloomView = null;
|
|
192
198
|
this.bloomBlitUniformData = new Float32Array(4);
|
|
193
199
|
this.bloomUpsampleUniformData = new Float32Array(4);
|
|
194
200
|
this.bloomMipCount = 0;
|
|
@@ -453,6 +459,8 @@ export class Engine {
|
|
|
453
459
|
this.onGizmoDrag = options?.onGizmoDrag;
|
|
454
460
|
this.bloomSettings = Engine.mergeBloomDefaults(options?.bloom);
|
|
455
461
|
this.viewTransform = Engine.mergeViewTransformDefaults(options?.view);
|
|
462
|
+
const bg = options?.background;
|
|
463
|
+
this.backgroundColor = bg ? new Vec3(bg.x, bg.y, bg.z) : null;
|
|
456
464
|
}
|
|
457
465
|
/** Merge partial bloom with EEVEE defaults (same as constructor). */
|
|
458
466
|
static mergeBloomDefaults(partial) {
|
|
@@ -521,8 +529,90 @@ export class Engine {
|
|
|
521
529
|
u[5] = b.color.y;
|
|
522
530
|
u[6] = b.color.z;
|
|
523
531
|
u[7] = effIntensity;
|
|
532
|
+
// Background composited UNDER the scene in display space (post-tonemap), so it
|
|
533
|
+
// matches a CSS color of the same value exactly. Mode (u[11]): 0 = transparent
|
|
534
|
+
// (DOM shows), 1 = solid color, 2 = 360 equirect (sampled by view ray; the
|
|
535
|
+
// camera basis at u[12..23] is refreshed per frame by updateCameraUniforms).
|
|
536
|
+
const bg = this.backgroundColor;
|
|
537
|
+
u[8] = bg?.x ?? 0;
|
|
538
|
+
u[9] = bg?.y ?? 0;
|
|
539
|
+
u[10] = bg?.z ?? 0;
|
|
540
|
+
u[11] = this.backdropEquirectView ? 2 : bg ? 1 : 0;
|
|
524
541
|
this.device.queue.writeBuffer(this.compositeUniformBuffer, 0, u);
|
|
525
542
|
}
|
|
543
|
+
/**
|
|
544
|
+
* Set the canvas background color (display-space sRGB, 0–1 per channel — the
|
|
545
|
+
* same value a CSS background of that color shows, applied after tonemapping).
|
|
546
|
+
* Pass null for a transparent canvas (the page/DOM shows through — e.g. when a
|
|
547
|
+
* backdrop image layer sits behind the canvas). Applies on the next frame.
|
|
548
|
+
* A 360 backdrop (setBackdropEquirect) takes precedence while set.
|
|
549
|
+
*/
|
|
550
|
+
setBackgroundColor(color) {
|
|
551
|
+
this.backgroundColor = color ? new Vec3(color.x, color.y, color.z) : null;
|
|
552
|
+
if (this.device && this.compositeUniformBuffer)
|
|
553
|
+
this.writeCompositeViewUniforms();
|
|
554
|
+
}
|
|
555
|
+
rebuildCompositeBindGroup() {
|
|
556
|
+
if (!this.device || !this.hdrResolveTexture || !this.compositeBloomView)
|
|
557
|
+
return;
|
|
558
|
+
this.compositeBindGroup = this.device.createBindGroup({
|
|
559
|
+
label: "composite bind group",
|
|
560
|
+
layout: this.compositeBindGroupLayout,
|
|
561
|
+
entries: [
|
|
562
|
+
{ binding: 0, resource: this.hdrResolveTexture.createView() },
|
|
563
|
+
{ binding: 1, resource: this.compositeBloomView },
|
|
564
|
+
{ binding: 2, resource: this.bloomSampler },
|
|
565
|
+
{ binding: 3, resource: { buffer: this.compositeUniformBuffer } },
|
|
566
|
+
{ binding: 4, resource: this.maskResolveView },
|
|
567
|
+
{ binding: 5, resource: this.filmicLutView },
|
|
568
|
+
{ binding: 6, resource: this.backdropEquirectView ?? this.fallbackEquirectView },
|
|
569
|
+
],
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Set a 360° backdrop from an equirectangular (2:1) image — a PhotoDome-style
|
|
574
|
+
* skybox at infinity, sampled per-pixel by view direction so it follows the
|
|
575
|
+
* camera. Display-only: composited in display space behind the scene, it never
|
|
576
|
+
* affects lighting, bloom, or tonemapping. Pass null to remove (the background
|
|
577
|
+
* color, or transparency, takes over again).
|
|
578
|
+
*/
|
|
579
|
+
setBackdropEquirect(source) {
|
|
580
|
+
this.backdropEquirectTexture?.destroy();
|
|
581
|
+
this.backdropEquirectTexture = null;
|
|
582
|
+
this.backdropEquirectView = null;
|
|
583
|
+
if (source && this.device) {
|
|
584
|
+
let width = Math.max(1, "naturalWidth" in source ? source.naturalWidth : source.width);
|
|
585
|
+
let height = Math.max(1, "naturalHeight" in source ? source.naturalHeight : source.height);
|
|
586
|
+
let upload = source;
|
|
587
|
+
// Panoramas routinely exceed maxTextureDimension2D (e.g. 10000×5000 vs the
|
|
588
|
+
// default 8192) — quietly downscale to fit rather than surfacing an error.
|
|
589
|
+
const limit = this.device.limits.maxTextureDimension2D;
|
|
590
|
+
if (width > limit || height > limit) {
|
|
591
|
+
const scale = Math.min(limit / width, limit / height);
|
|
592
|
+
const w = Math.max(1, Math.floor(width * scale));
|
|
593
|
+
const h = Math.max(1, Math.floor(height * scale));
|
|
594
|
+
const canvas = new OffscreenCanvas(w, h);
|
|
595
|
+
const cx = canvas.getContext("2d");
|
|
596
|
+
cx.imageSmoothingQuality = "high";
|
|
597
|
+
cx.drawImage(source, 0, 0, w, h);
|
|
598
|
+
upload = canvas;
|
|
599
|
+
width = w;
|
|
600
|
+
height = h;
|
|
601
|
+
}
|
|
602
|
+
const tex = this.device.createTexture({
|
|
603
|
+
label: "backdrop equirect",
|
|
604
|
+
size: [width, height],
|
|
605
|
+
format: "rgba8unorm",
|
|
606
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
607
|
+
});
|
|
608
|
+
this.device.queue.copyExternalImageToTexture({ source: upload }, { texture: tex }, [width, height]);
|
|
609
|
+
this.backdropEquirectTexture = tex;
|
|
610
|
+
this.backdropEquirectView = tex.createView();
|
|
611
|
+
}
|
|
612
|
+
this.rebuildCompositeBindGroup();
|
|
613
|
+
if (this.device && this.compositeUniformBuffer)
|
|
614
|
+
this.writeCompositeViewUniforms();
|
|
615
|
+
}
|
|
526
616
|
/** Patch bloom; GPU uniforms update immediately if `init()` has run. */
|
|
527
617
|
setBloomOptions(patch) {
|
|
528
618
|
const b = this.bloomSettings;
|
|
@@ -1260,7 +1350,9 @@ export class Engine {
|
|
|
1260
1350
|
// mirroring EEVEE where bloom color/intensity are combine-stage params, not prefilter).
|
|
1261
1351
|
this.compositeUniformBuffer = this.device.createBuffer({
|
|
1262
1352
|
label: "composite view uniforms",
|
|
1263
|
-
|
|
1353
|
+
// 6 × vec4f: (exposure, invGamma, _, _) · (bloom tint, intensity) ·
|
|
1354
|
+
// (bg rgb, mode) · camera right/up/forward basis for the 360 skybox ray.
|
|
1355
|
+
size: 96,
|
|
1264
1356
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
1265
1357
|
});
|
|
1266
1358
|
this.compositeBindGroupLayout = this.device.createBindGroupLayout({
|
|
@@ -1275,8 +1367,17 @@ export class Engine {
|
|
|
1275
1367
|
{ binding: 4, visibility: GPUShaderStage.FRAGMENT, texture: {} },
|
|
1276
1368
|
// Filmic tone LUT (r16float, filterable) — sampled with the binding-2 sampler.
|
|
1277
1369
|
{ binding: 5, visibility: GPUShaderStage.FRAGMENT, texture: {} },
|
|
1370
|
+
// 360 backdrop equirect (PhotoDome-style skybox) — 1×1 fallback when unset.
|
|
1371
|
+
{ binding: 6, visibility: GPUShaderStage.FRAGMENT, texture: {} },
|
|
1278
1372
|
],
|
|
1279
1373
|
});
|
|
1374
|
+
this.fallbackEquirectTexture = this.device.createTexture({
|
|
1375
|
+
label: "equirect fallback",
|
|
1376
|
+
size: [1, 1],
|
|
1377
|
+
format: "rgba8unorm",
|
|
1378
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
|
|
1379
|
+
});
|
|
1380
|
+
this.fallbackEquirectView = this.fallbackEquirectTexture.createView();
|
|
1280
1381
|
const compositeShader = this.device.createShaderModule({
|
|
1281
1382
|
label: "composite shader",
|
|
1282
1383
|
code: COMPOSITE_SHADER_WGSL,
|
|
@@ -1615,19 +1716,8 @@ export class Engine {
|
|
|
1615
1716
|
}));
|
|
1616
1717
|
}
|
|
1617
1718
|
// Composite reads bloomUp mip 0 (full pyramid collapsed); fallback to bloomDown mip 0 if no upsample level.
|
|
1618
|
-
|
|
1619
|
-
this.
|
|
1620
|
-
label: "composite bind group",
|
|
1621
|
-
layout: this.compositeBindGroupLayout,
|
|
1622
|
-
entries: [
|
|
1623
|
-
{ binding: 0, resource: this.hdrResolveTexture.createView() },
|
|
1624
|
-
{ binding: 1, resource: compositeBloomView },
|
|
1625
|
-
{ binding: 2, resource: this.bloomSampler },
|
|
1626
|
-
{ binding: 3, resource: { buffer: this.compositeUniformBuffer } },
|
|
1627
|
-
{ binding: 4, resource: this.maskResolveView },
|
|
1628
|
-
{ binding: 5, resource: this.filmicLutView },
|
|
1629
|
-
],
|
|
1630
|
-
});
|
|
1719
|
+
this.compositeBloomView = this.bloomMipCount > 1 ? this.bloomUpMipViews[0] : this.bloomDownMipViews[0];
|
|
1720
|
+
this.rebuildCompositeBindGroup();
|
|
1631
1721
|
}
|
|
1632
1722
|
this.writeCompositeViewUniforms();
|
|
1633
1723
|
this.camera.aspect = width / height;
|
|
@@ -1991,6 +2081,7 @@ export class Engine {
|
|
|
1991
2081
|
gridLineOpacity: 0.4,
|
|
1992
2082
|
gridLineColor: new Vec3(0.85, 0.85, 0.85),
|
|
1993
2083
|
noiseStrength: 0.05,
|
|
2084
|
+
opacity: 1.0,
|
|
1994
2085
|
...options,
|
|
1995
2086
|
};
|
|
1996
2087
|
this.createGroundGeometry(opts.width, opts.height);
|
|
@@ -2532,7 +2623,7 @@ export class Engine {
|
|
|
2532
2623
|
this.device.queue.writeBuffer(this.groundIndexBuffer, 0, indices);
|
|
2533
2624
|
}
|
|
2534
2625
|
createShadowGroundResources(opts) {
|
|
2535
|
-
const { diffuseColor, fadeStart, fadeEnd, shadowStrength, gridSpacing, gridLineWidth, gridLineOpacity, gridLineColor, noiseStrength, } = opts;
|
|
2626
|
+
const { diffuseColor, fadeStart, fadeEnd, shadowStrength, gridSpacing, gridLineWidth, gridLineOpacity, gridLineColor, noiseStrength, opacity, } = opts;
|
|
2536
2627
|
// Shadow map is already created in setupPipelines()
|
|
2537
2628
|
const gb = new Float32Array(16);
|
|
2538
2629
|
gb[0] = diffuseColor.x;
|
|
@@ -2546,7 +2637,7 @@ export class Engine {
|
|
|
2546
2637
|
gb[8] = gridLineWidth;
|
|
2547
2638
|
gb[9] = gridLineOpacity;
|
|
2548
2639
|
gb[10] = noiseStrength;
|
|
2549
|
-
gb[11] =
|
|
2640
|
+
gb[11] = opacity;
|
|
2550
2641
|
gb[12] = gridLineColor.x;
|
|
2551
2642
|
gb[13] = gridLineColor.y;
|
|
2552
2643
|
gb[14] = gridLineColor.z;
|
|
@@ -3796,6 +3887,30 @@ export class Engine {
|
|
|
3796
3887
|
this.cameraMatrixData[33] = cameraPos.y;
|
|
3797
3888
|
this.cameraMatrixData[34] = cameraPos.z;
|
|
3798
3889
|
this.device.queue.writeBuffer(this.cameraUniformBuffer, 0, this.cameraMatrixData);
|
|
3890
|
+
// 360 backdrop: the composite reconstructs each pixel's view ray from the
|
|
3891
|
+
// camera basis — refresh it every frame the skybox is active. The view matrix
|
|
3892
|
+
// is LEFT-HANDED (+Z forward, see Mat4.lookAtInto), so the world-space
|
|
3893
|
+
// right/up/FORWARD vectors are rows 0/1/2 of its rotation block directly
|
|
3894
|
+
// (column-major storage: row i = values[i], values[i+4], values[i+8]).
|
|
3895
|
+
if (this.backdropEquirectView && this.compositeUniformBuffer) {
|
|
3896
|
+
const v = viewMatrix.values;
|
|
3897
|
+
const u = this.compositeUniformData;
|
|
3898
|
+
const tanHalf = Math.tan((this.camera.fov ?? Math.PI / 4) / 2);
|
|
3899
|
+
const aspect = this.canvas.width / Math.max(1, this.canvas.height);
|
|
3900
|
+
u[12] = v[0];
|
|
3901
|
+
u[13] = v[4];
|
|
3902
|
+
u[14] = v[8];
|
|
3903
|
+
u[15] = tanHalf * aspect;
|
|
3904
|
+
u[16] = v[1];
|
|
3905
|
+
u[17] = v[5];
|
|
3906
|
+
u[18] = v[9];
|
|
3907
|
+
u[19] = tanHalf;
|
|
3908
|
+
u[20] = v[2];
|
|
3909
|
+
u[21] = v[6];
|
|
3910
|
+
u[22] = v[10];
|
|
3911
|
+
u[23] = 0;
|
|
3912
|
+
this.device.queue.writeBuffer(this.compositeUniformBuffer, 0, u);
|
|
3913
|
+
}
|
|
3799
3914
|
}
|
|
3800
3915
|
updateSkinMatrices() {
|
|
3801
3916
|
this.forEachInstance((inst) => {
|
|
@@ -3872,7 +3987,10 @@ Engine.BLOOM_MASK_FORMAT = "rg8unorm";
|
|
|
3872
3987
|
Engine.BLOOM_MAX_LEVELS = 5;
|
|
3873
3988
|
// Width of the baked Filmic tone LUT (composite.ts FILMIC_LUT_W must match).
|
|
3874
3989
|
Engine.FILMIC_LUT_WIDTH = 256;
|
|
3875
|
-
|
|
3990
|
+
// 4096² over the 64-unit light box ≈ 64 texels/world-unit — crisp contact
|
|
3991
|
+
// shadows on the ground catcher (2048 read visibly blurry). ~64 MB depth,
|
|
3992
|
+
// acceptable for WebGPU-class hardware; deliberately NOT user-configurable.
|
|
3993
|
+
Engine.SHADOW_MAP_SIZE = 4096;
|
|
3876
3994
|
// Smoothness metrics are computed over a ring buffer of true frame intervals
|
|
3877
3995
|
// (vsync-to-vsync), recomputed at STATS_REFRESH_MS so the readout doesn't flicker.
|
|
3878
3996
|
Engine.STATS_WINDOW = 120;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const COMPOSITE_SHADER_WGSL = "\n// Pipeline-override constant: the engine creates two composite pipelines, one\n// with APPLY_GAMMA=false (gamma=1 fast path) and one with APPLY_GAMMA=true.\n// The 'if (APPLY_GAMMA)' below is resolved at pipeline-compile time \u2014 the\n// dead branch is dropped by the shader compiler (no runtime branch, no pow\n// invocation on Safari's Metal backend in the common case).\noverride APPLY_GAMMA: bool = true;\n\n@group(0) @binding(0) var hdrTex: texture_2d<f32>;\n@group(0) @binding(1) var bloomTex: texture_2d<f32>; // bloomUpTexture mip 0 (full pyramid top)\n@group(0) @binding(2) var bloomSamp: sampler;\n@group(0) @binding(3) var<uniform> viewU: array<vec4<f32>,
|
|
1
|
+
export declare const COMPOSITE_SHADER_WGSL = "\n// Pipeline-override constant: the engine creates two composite pipelines, one\n// with APPLY_GAMMA=false (gamma=1 fast path) and one with APPLY_GAMMA=true.\n// The 'if (APPLY_GAMMA)' below is resolved at pipeline-compile time \u2014 the\n// dead branch is dropped by the shader compiler (no runtime branch, no pow\n// invocation on Safari's Metal backend in the common case).\noverride APPLY_GAMMA: bool = true;\n\n@group(0) @binding(0) var hdrTex: texture_2d<f32>;\n@group(0) @binding(1) var bloomTex: texture_2d<f32>; // bloomUpTexture mip 0 (full pyramid top)\n@group(0) @binding(2) var bloomSamp: sampler;\n@group(0) @binding(3) var<uniform> viewU: array<vec4<f32>, 6>;\n// Aux mask/alpha texture. .r = bloom mask (unused here; bloom blit uses it).\n// .g = accumulated canvas alpha (what hdr.a carried before the HDR format\n// became rg11b10ufloat). We unpremultiply HDR by this alpha for tonemap, then\n// re-premultiply the tonemapped color for output so the premultiplied canvas\n// alphaMode composites the WebGPU surface over the page background correctly.\n@group(0) @binding(4) var maskTex: texture_2d<f32>;\n// Filmic tone curve baked to a WIDTH\u00D71 r16float LUT (bakeFilmicLut on the CPU side).\n// Domain: log2(linear) mapped to [0,13]. Replaces the old array<f32,14> that was indexed\n// by a runtime u32 (a Metal-backend smell \u2014 dynamic local-array indexing lowers to a\n// per-invocation copy/switch) and interpolated piecewise-linearly (C0, so segment slope\n// discontinuities showed as Mach bands in smooth skin/shadow gradients). The LUT is a\n// monotone-cubic (Fritsch\u2013Carlson) fit through the same 14 anchors \u2014 same values, C1\n// continuity kills the banding \u2014 sampled with hardware linear filtering.\n@group(0) @binding(5) var filmicLut: texture_2d<f32>;\n// viewU[0] = (exposure, invGamma, _, _); viewU[1] = (tint.rgb, intensity)\n// viewU[2] = (background.rgb, mode) \u2014 display-space sRGB, composited UNDER the\n// scene post-tonemap. mode: 0 transparent (DOM shows), 1 solid color,\n// 2 = 360 equirect skybox sampled by view ray.\n// viewU[3] = (camera right, tanHalfFov\u00B7aspect); viewU[4] = (camera up, tanHalfFov);\n// viewU[5] = (camera forward, _) \u2014 refreshed per frame while the skybox is active.\n// invGamma = 1/gamma precomputed on CPU \u2014 avoids a per-pixel divide.\n@group(0) @binding(6) var bgEquirect: texture_2d<f32>;\n\n// Must match FILMIC_LUT_WIDTH in engine.ts (bakeFilmicLut).\nconst FILMIC_LUT_W: f32 = 256.0;\n\nfn filmic(x: f32) -> f32 {\n // Reference checkpoints (Blender 3.6 Filmic MHC, sobotka/filmic-blender\n // look_medium-high-contrast.spi1d): linear 0.18 \u2192 ~0.395, linear 1.0 \u2192 ~0.83.\n // NOTE: version-pinned to Blender 3.6 \u2014 4.x defaults to AgX, not Filmic.\n let t = clamp(log2(max(x, 1e-10)) + 10.0, 0.0, 13.0);\n // Map t\u2208[0,13] to the texel-center of baked sample j = t\u00B7(W-1)/13.\n let u = (t * (FILMIC_LUT_W - 1.0) / 13.0 + 0.5) / FILMIC_LUT_W;\n // textureSampleLevel (explicit LOD, no derivatives) is legal in non-uniform flow.\n return textureSampleLevel(filmicLut, bloomSamp, vec2f(u, 0.5), 0.0).r;\n}\n\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}\n\n@fragment fn fs(@builtin(position) fragCoord: vec4f) -> @location(0) vec4f {\n let coord = vec2<i32>(fragCoord.xy);\n let hdr = textureLoad(hdrTex, coord, 0);\n let alpha = textureLoad(maskTex, coord, 0).g;\n let a = max(alpha, 1e-6);\n let straight = hdr.rgb / a;\n let fullSz = vec2f(textureDimensions(hdrTex));\n // Bloom is at half-res (pyramid mip 0). Sampler interpolates back to full-res UVs.\n // fragCoord.xy is already at pixel center (e.g. 0.5, 0.5 for first pixel).\n let bloomUv = fragCoord.xy / max(fullSz, vec2f(1.0));\n let tint = viewU[1].xyz;\n let intensity = viewU[1].w;\n let bloom = textureSampleLevel(bloomTex, bloomSamp, bloomUv, 0.0).rgb * tint * intensity;\n let combined = straight + bloom;\n let exposed = combined * exp2(viewU[0].x);\n let tm = vec3f(filmic(exposed.r), filmic(exposed.g), filmic(exposed.b));\n var disp = max(tm, vec3f(0.0));\n if (APPLY_GAMMA) {\n disp = pow(disp, vec3f(viewU[0].y));\n }\n // Composite over the background in display space (premultiplied out).\n let bg = viewU[2];\n var bgRgb = bg.rgb;\n var bgA = select(0.0, 1.0, bg.w > 0.5);\n if (bg.w > 1.5) {\n // 360 equirect: rebuild this pixel's world-space view ray from the camera\n // basis, then latitude/longitude-map into the panorama. The dome sits at\n // infinity (no parallax) \u2014 PhotoDome-style, display-only.\n let ndc = vec2f(fragCoord.x / fullSz.x * 2.0 - 1.0, 1.0 - fragCoord.y / fullSz.y * 2.0);\n let dir = normalize(viewU[5].xyz + ndc.x * viewU[3].w * viewU[3].xyz + ndc.y * viewU[4].w * viewU[4].xyz);\n // LH world (+Z forward): longitude = atan2(x, z), Babylon-PhotoDome convention.\n let su = 0.5 + atan2(dir.x, dir.z) * 0.15915494309; // 1/(2\u03C0)\n let sv = 0.5 - asin(clamp(dir.y, -1.0, 1.0)) * 0.31830988618; // 1/\u03C0\n bgRgb = textureSampleLevel(bgEquirect, bloomSamp, vec2f(su, sv), 0.0).rgb;\n }\n return vec4f(disp * alpha + bgRgb * bgA * (1.0 - alpha), alpha + bgA * (1.0 - alpha));\n}\n";
|
|
2
2
|
//# sourceMappingURL=composite.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composite.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/composite.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"composite.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/composite.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB,yvKA4FjC,CAAA"}
|
|
@@ -11,7 +11,7 @@ override APPLY_GAMMA: bool = true;
|
|
|
11
11
|
@group(0) @binding(0) var hdrTex: texture_2d<f32>;
|
|
12
12
|
@group(0) @binding(1) var bloomTex: texture_2d<f32>; // bloomUpTexture mip 0 (full pyramid top)
|
|
13
13
|
@group(0) @binding(2) var bloomSamp: sampler;
|
|
14
|
-
@group(0) @binding(3) var<uniform> viewU: array<vec4<f32>,
|
|
14
|
+
@group(0) @binding(3) var<uniform> viewU: array<vec4<f32>, 6>;
|
|
15
15
|
// Aux mask/alpha texture. .r = bloom mask (unused here; bloom blit uses it).
|
|
16
16
|
// .g = accumulated canvas alpha (what hdr.a carried before the HDR format
|
|
17
17
|
// became rg11b10ufloat). We unpremultiply HDR by this alpha for tonemap, then
|
|
@@ -27,7 +27,13 @@ override APPLY_GAMMA: bool = true;
|
|
|
27
27
|
// continuity kills the banding — sampled with hardware linear filtering.
|
|
28
28
|
@group(0) @binding(5) var filmicLut: texture_2d<f32>;
|
|
29
29
|
// viewU[0] = (exposure, invGamma, _, _); viewU[1] = (tint.rgb, intensity)
|
|
30
|
+
// viewU[2] = (background.rgb, mode) — display-space sRGB, composited UNDER the
|
|
31
|
+
// scene post-tonemap. mode: 0 transparent (DOM shows), 1 solid color,
|
|
32
|
+
// 2 = 360 equirect skybox sampled by view ray.
|
|
33
|
+
// viewU[3] = (camera right, tanHalfFov·aspect); viewU[4] = (camera up, tanHalfFov);
|
|
34
|
+
// viewU[5] = (camera forward, _) — refreshed per frame while the skybox is active.
|
|
30
35
|
// invGamma = 1/gamma precomputed on CPU — avoids a per-pixel divide.
|
|
36
|
+
@group(0) @binding(6) var bgEquirect: texture_2d<f32>;
|
|
31
37
|
|
|
32
38
|
// Must match FILMIC_LUT_WIDTH in engine.ts (bakeFilmicLut).
|
|
33
39
|
const FILMIC_LUT_W: f32 = 256.0;
|
|
@@ -69,6 +75,21 @@ fn filmic(x: f32) -> f32 {
|
|
|
69
75
|
if (APPLY_GAMMA) {
|
|
70
76
|
disp = pow(disp, vec3f(viewU[0].y));
|
|
71
77
|
}
|
|
72
|
-
|
|
78
|
+
// Composite over the background in display space (premultiplied out).
|
|
79
|
+
let bg = viewU[2];
|
|
80
|
+
var bgRgb = bg.rgb;
|
|
81
|
+
var bgA = select(0.0, 1.0, bg.w > 0.5);
|
|
82
|
+
if (bg.w > 1.5) {
|
|
83
|
+
// 360 equirect: rebuild this pixel's world-space view ray from the camera
|
|
84
|
+
// basis, then latitude/longitude-map into the panorama. The dome sits at
|
|
85
|
+
// infinity (no parallax) — PhotoDome-style, display-only.
|
|
86
|
+
let ndc = vec2f(fragCoord.x / fullSz.x * 2.0 - 1.0, 1.0 - fragCoord.y / fullSz.y * 2.0);
|
|
87
|
+
let dir = normalize(viewU[5].xyz + ndc.x * viewU[3].w * viewU[3].xyz + ndc.y * viewU[4].w * viewU[4].xyz);
|
|
88
|
+
// LH world (+Z forward): longitude = atan2(x, z), Babylon-PhotoDome convention.
|
|
89
|
+
let su = 0.5 + atan2(dir.x, dir.z) * 0.15915494309; // 1/(2π)
|
|
90
|
+
let sv = 0.5 - asin(clamp(dir.y, -1.0, 1.0)) * 0.31830988618; // 1/π
|
|
91
|
+
bgRgb = textureSampleLevel(bgEquirect, bloomSamp, vec2f(su, sv), 0.0).rgb;
|
|
92
|
+
}
|
|
93
|
+
return vec4f(disp * alpha + bgRgb * bgA * (1.0 - alpha), alpha + bgA * (1.0 - alpha));
|
|
73
94
|
}
|
|
74
95
|
`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const GROUND_SHADOW_SHADER_WGSL = "\nstruct CameraUniforms { view: mat4x4f, projection: mat4x4f, viewPos: vec3f, _p: f32, };\nstruct Light { direction: vec4f, color: vec4f, };\nstruct LightUniforms { ambientColor: vec4f, lights: array<Light, 4>, };\nstruct GroundShadowMat {\n diffuseColor: vec3f, fadeStart: f32,\n fadeEnd: f32, shadowStrength: f32, pcfTexel: f32, gridSpacing: f32,\n gridLineWidth: f32, gridLineOpacity: f32, noiseStrength: f32,
|
|
1
|
+
export declare const GROUND_SHADOW_SHADER_WGSL = "\nstruct CameraUniforms { view: mat4x4f, projection: mat4x4f, viewPos: vec3f, _p: f32, };\nstruct Light { direction: vec4f, color: vec4f, };\nstruct LightUniforms { ambientColor: vec4f, lights: array<Light, 4>, };\nstruct GroundShadowMat {\n diffuseColor: vec3f, fadeStart: f32,\n fadeEnd: f32, shadowStrength: f32, pcfTexel: f32, gridSpacing: f32,\n gridLineWidth: f32, gridLineOpacity: f32, noiseStrength: f32, opacity: f32,\n gridLineColor: vec3f, _pad2: f32,\n};\nstruct LightVP { viewProj: mat4x4f, };\n@group(0) @binding(0) var<uniform> camera: CameraUniforms;\n@group(0) @binding(1) var<uniform> light: LightUniforms;\n@group(0) @binding(2) var shadowMap: texture_depth_2d;\n@group(0) @binding(3) var shadowSampler: sampler_comparison;\n@group(0) @binding(4) var<uniform> material: GroundShadowMat;\n@group(0) @binding(5) var<uniform> lightVP: LightVP;\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 valueNoise(p: vec2f) -> 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(i), hash2(i + vec2f(1.0, 0.0)), u.x),\n mix(hash2(i + vec2f(0.0, 1.0)), hash2(i + vec2f(1.0, 1.0)), u.x), u.y);\n}\nfn fbmNoise(p: vec2f) -> f32 {\n var v = 0.0;\n var a = 0.5;\n var pp = p;\n for (var i = 0; i < 4; i++) {\n v += a * valueNoise(pp);\n pp *= 2.0;\n a *= 0.5;\n }\n return v;\n}\n\nstruct VO { @builtin(position) position: vec4f, @location(0) worldPos: vec3f, @location(1) normal: vec3f, };\n@vertex fn vs(@location(0) position: vec3f, @location(1) normal: vec3f, @location(2) uv: vec2f) -> VO {\n var o: VO; o.worldPos = position; o.normal = normal;\n o.position = camera.projection * camera.view * vec4f(position, 1.0); return o;\n}\nstruct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };\n@fragment fn fs(i: VO) -> FSOut {\n let n = normalize(i.normal);\n let centerDist = length(i.worldPos.xz);\n let edgeFade = 1.0 - smoothstep(0.0, 1.0, clamp((centerDist - material.fadeStart) / max(material.fadeEnd - material.fadeStart, 0.001), 0.0, 1.0));\n\n let lclip = lightVP.viewProj * vec4f(i.worldPos, 1.0);\n let ndc = lclip.xyz / max(lclip.w, 1e-6);\n let suv = vec2f(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);\n let suv_c = clamp(suv, vec2f(0.02), vec2f(0.98));\n let st = material.pcfTexel;\n let compareZ = ndc.z - 0.0035;\n var vis = 0.0;\n for (var y = -2; y <= 2; y++) {\n for (var x = -2; x <= 2; x++) {\n vis += textureSampleCompare(shadowMap, shadowSampler, suv_c + vec2f(f32(x), f32(y)) * st, compareZ);\n }\n }\n vis *= 0.04;\n\n // Frosted/matte micro-texture\n let noiseVal = fbmNoise(i.worldPos.xz * 3.0);\n let noiseTint = 1.0 + (noiseVal - 0.5) * material.noiseStrength;\n\n // Grid lines \u2014 anti-aliased via screen-space derivatives\n let gp = i.worldPos.xz / material.gridSpacing;\n let gridFrac = abs(fract(gp - 0.5) - 0.5);\n let gridDeriv = fwidth(gp);\n let halfLine = material.gridLineWidth * 0.5;\n let gridLine = 1.0 - min(\n smoothstep(halfLine - gridDeriv.x, halfLine + gridDeriv.x, gridFrac.x),\n smoothstep(halfLine - gridDeriv.y, halfLine + gridDeriv.y, gridFrac.y)\n );\n let sun = light.ambientColor.xyz + light.lights[0].color.xyz * light.lights[0].color.w * max(dot(n, -light.lights[0].direction.xyz), 0.0);\n let dark = (1.0 - vis) * material.shadowStrength;\n var baseColor = material.diffuseColor * sun * (1.0 - dark * 0.65);\n baseColor *= noiseTint;\n let finalColor = mix(baseColor, material.gridLineColor, gridLine * material.gridLineOpacity * edgeFade);\n // Whole-ground opacity fades the SURFACE (color, grid) but the shadow stays \u2014\n // as opacity drops, the received shadow becomes a translucent dark layer\n // (Blender's Shadow Catcher), so models still feel grounded on a photo or\n // 360 backdrop. At opacity 1 this reduces exactly to the plain surface.\n let surfA = edgeFade * material.opacity;\n let catchA = dark * 0.65 * edgeFade * (1.0 - material.opacity);\n let outA = surfA + catchA;\n var out: FSOut;\n out.color = vec4f(finalColor * surfA, outA);\n // mask.r = 0: ground never contributes to bloom. mask.g = 1.0 with src.a =\n // outA turns the aux blend into alpha-over, so the drawable alpha goes\n // from outA at the center to 0 at the radial edge \u2014 letting the page\n // background show through under the premultiplied canvas alphaMode.\n out.mask = vec4f(0.0, 1.0, 0.0, outA);\n return out;\n}\n";
|
|
2
2
|
//# sourceMappingURL=ground.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ground.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/ground.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"ground.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/ground.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,yBAAyB,2+IAqGrC,CAAA"}
|
|
@@ -7,7 +7,7 @@ struct LightUniforms { ambientColor: vec4f, lights: array<Light, 4>, };
|
|
|
7
7
|
struct GroundShadowMat {
|
|
8
8
|
diffuseColor: vec3f, fadeStart: f32,
|
|
9
9
|
fadeEnd: f32, shadowStrength: f32, pcfTexel: f32, gridSpacing: f32,
|
|
10
|
-
gridLineWidth: f32, gridLineOpacity: f32, noiseStrength: f32,
|
|
10
|
+
gridLineWidth: f32, gridLineOpacity: f32, noiseStrength: f32, opacity: f32,
|
|
11
11
|
gridLineColor: vec3f, _pad2: f32,
|
|
12
12
|
};
|
|
13
13
|
struct LightVP { viewProj: mat4x4f, };
|
|
@@ -85,13 +85,20 @@ struct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };
|
|
|
85
85
|
var baseColor = material.diffuseColor * sun * (1.0 - dark * 0.65);
|
|
86
86
|
baseColor *= noiseTint;
|
|
87
87
|
let finalColor = mix(baseColor, material.gridLineColor, gridLine * material.gridLineOpacity * edgeFade);
|
|
88
|
+
// Whole-ground opacity fades the SURFACE (color, grid) but the shadow stays —
|
|
89
|
+
// as opacity drops, the received shadow becomes a translucent dark layer
|
|
90
|
+
// (Blender's Shadow Catcher), so models still feel grounded on a photo or
|
|
91
|
+
// 360 backdrop. At opacity 1 this reduces exactly to the plain surface.
|
|
92
|
+
let surfA = edgeFade * material.opacity;
|
|
93
|
+
let catchA = dark * 0.65 * edgeFade * (1.0 - material.opacity);
|
|
94
|
+
let outA = surfA + catchA;
|
|
88
95
|
var out: FSOut;
|
|
89
|
-
out.color = vec4f(finalColor *
|
|
96
|
+
out.color = vec4f(finalColor * surfA, outA);
|
|
90
97
|
// mask.r = 0: ground never contributes to bloom. mask.g = 1.0 with src.a =
|
|
91
|
-
//
|
|
92
|
-
// from
|
|
98
|
+
// outA turns the aux blend into alpha-over, so the drawable alpha goes
|
|
99
|
+
// from outA at the center to 0 at the radial edge — letting the page
|
|
93
100
|
// background show through under the premultiplied canvas alphaMode.
|
|
94
|
-
out.mask = vec4f(0.0, 1.0, 0.0,
|
|
101
|
+
out.mask = vec4f(0.0, 1.0, 0.0, outA);
|
|
95
102
|
return out;
|
|
96
103
|
}
|
|
97
104
|
`;
|
package/package.json
CHANGED
package/src/asset-reader.ts
CHANGED
|
@@ -52,6 +52,18 @@ export function createFileMapAssetReader(files: Map<string, File>): AssetReader
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
+
if (!file) {
|
|
56
|
+
// Last resort: basename match. Mobile pickers can't select folders — a flat
|
|
57
|
+
// multi-file selection loses directory structure, so `tex/body.png` must
|
|
58
|
+
// find a bare `body.png`. Also rescues wrongly-cased directory names.
|
|
59
|
+
const base = key.split("/").pop()!.toLowerCase()
|
|
60
|
+
for (const [k, f] of files) {
|
|
61
|
+
if (k.split("/").pop()!.toLowerCase() === base) {
|
|
62
|
+
file = f
|
|
63
|
+
break
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
55
67
|
if (!file) throw new Error(`Missing file in folder: ${key}`)
|
|
56
68
|
return file.arrayBuffer()
|
|
57
69
|
},
|
package/src/engine.ts
CHANGED
|
@@ -301,6 +301,9 @@ export type EngineOptions = {
|
|
|
301
301
|
world?: WorldOptions
|
|
302
302
|
sun?: SunOptions
|
|
303
303
|
camera?: CameraOptions
|
|
304
|
+
/** Canvas background (display-space sRGB 0–1), composited under the scene after
|
|
305
|
+
* tonemapping. Omit/null = transparent canvas (see setBackgroundColor). */
|
|
306
|
+
background?: Vec3 | null
|
|
304
307
|
/** Initial EEVEE-style bloom; tune at runtime with `setBloomOptions`. */
|
|
305
308
|
bloom?: Partial<BloomOptions>
|
|
306
309
|
/** View transform (exposure/gamma) applied in composite before/after Filmic. */
|
|
@@ -542,7 +545,15 @@ export class Engine {
|
|
|
542
545
|
private compositeBindGroup!: GPUBindGroup
|
|
543
546
|
private compositeUniformBuffer!: GPUBuffer
|
|
544
547
|
// [exposure, invGamma, _, _, bloomTint.x, bloomTint.y, bloomTint.z, bloomIntensity]
|
|
545
|
-
private readonly compositeUniformData = new Float32Array(
|
|
548
|
+
private readonly compositeUniformData = new Float32Array(24)
|
|
549
|
+
/** Composite background (display-space sRGB 0–1) — null = transparent canvas. */
|
|
550
|
+
private backgroundColor: Vec3 | null = null
|
|
551
|
+
// 360 backdrop (equirectangular skybox, sampled by view ray in composite).
|
|
552
|
+
private backdropEquirectTexture: GPUTexture | null = null
|
|
553
|
+
private backdropEquirectView: GPUTextureView | null = null
|
|
554
|
+
private fallbackEquirectTexture!: GPUTexture
|
|
555
|
+
private fallbackEquirectView!: GPUTextureView
|
|
556
|
+
private compositeBloomView: GPUTextureView | null = null
|
|
546
557
|
|
|
547
558
|
// EEVEE-style bloom pyramid (mirrors Blender 3.6 effect_bloom_frag.glsl):
|
|
548
559
|
// blit (HDR → half-res, 4-tap Karis + soft threshold/knee)
|
|
@@ -585,7 +596,10 @@ export class Engine {
|
|
|
585
596
|
private filmicLutView!: GPUTextureView
|
|
586
597
|
// Width of the baked Filmic tone LUT (composite.ts FILMIC_LUT_W must match).
|
|
587
598
|
private static readonly FILMIC_LUT_WIDTH = 256
|
|
588
|
-
|
|
599
|
+
// 4096² over the 64-unit light box ≈ 64 texels/world-unit — crisp contact
|
|
600
|
+
// shadows on the ground catcher (2048 read visibly blurry). ~64 MB depth,
|
|
601
|
+
// acceptable for WebGPU-class hardware; deliberately NOT user-configurable.
|
|
602
|
+
private static readonly SHADOW_MAP_SIZE = 4096
|
|
589
603
|
private shadowDepthPipeline!: GPURenderPipeline
|
|
590
604
|
private shadowLightVPBuffer!: GPUBuffer
|
|
591
605
|
private shadowLightVPMatrix = new Float32Array(16)
|
|
@@ -674,6 +688,8 @@ export class Engine {
|
|
|
674
688
|
this.onGizmoDrag = options?.onGizmoDrag
|
|
675
689
|
this.bloomSettings = Engine.mergeBloomDefaults(options?.bloom)
|
|
676
690
|
this.viewTransform = Engine.mergeViewTransformDefaults(options?.view)
|
|
691
|
+
const bg = options?.background
|
|
692
|
+
this.backgroundColor = bg ? new Vec3(bg.x, bg.y, bg.z) : null
|
|
677
693
|
}
|
|
678
694
|
|
|
679
695
|
/** Merge partial bloom with EEVEE defaults (same as constructor). */
|
|
@@ -745,9 +761,91 @@ export class Engine {
|
|
|
745
761
|
u[5] = b.color.y
|
|
746
762
|
u[6] = b.color.z
|
|
747
763
|
u[7] = effIntensity
|
|
764
|
+
// Background composited UNDER the scene in display space (post-tonemap), so it
|
|
765
|
+
// matches a CSS color of the same value exactly. Mode (u[11]): 0 = transparent
|
|
766
|
+
// (DOM shows), 1 = solid color, 2 = 360 equirect (sampled by view ray; the
|
|
767
|
+
// camera basis at u[12..23] is refreshed per frame by updateCameraUniforms).
|
|
768
|
+
const bg = this.backgroundColor
|
|
769
|
+
u[8] = bg?.x ?? 0
|
|
770
|
+
u[9] = bg?.y ?? 0
|
|
771
|
+
u[10] = bg?.z ?? 0
|
|
772
|
+
u[11] = this.backdropEquirectView ? 2 : bg ? 1 : 0
|
|
748
773
|
this.device.queue.writeBuffer(this.compositeUniformBuffer, 0, u)
|
|
749
774
|
}
|
|
750
775
|
|
|
776
|
+
/**
|
|
777
|
+
* Set the canvas background color (display-space sRGB, 0–1 per channel — the
|
|
778
|
+
* same value a CSS background of that color shows, applied after tonemapping).
|
|
779
|
+
* Pass null for a transparent canvas (the page/DOM shows through — e.g. when a
|
|
780
|
+
* backdrop image layer sits behind the canvas). Applies on the next frame.
|
|
781
|
+
* A 360 backdrop (setBackdropEquirect) takes precedence while set.
|
|
782
|
+
*/
|
|
783
|
+
setBackgroundColor(color: Vec3 | null): void {
|
|
784
|
+
this.backgroundColor = color ? new Vec3(color.x, color.y, color.z) : null
|
|
785
|
+
if (this.device && this.compositeUniformBuffer) this.writeCompositeViewUniforms()
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
private rebuildCompositeBindGroup(): void {
|
|
789
|
+
if (!this.device || !this.hdrResolveTexture || !this.compositeBloomView) return
|
|
790
|
+
this.compositeBindGroup = this.device.createBindGroup({
|
|
791
|
+
label: "composite bind group",
|
|
792
|
+
layout: this.compositeBindGroupLayout,
|
|
793
|
+
entries: [
|
|
794
|
+
{ binding: 0, resource: this.hdrResolveTexture.createView() },
|
|
795
|
+
{ binding: 1, resource: this.compositeBloomView },
|
|
796
|
+
{ binding: 2, resource: this.bloomSampler },
|
|
797
|
+
{ binding: 3, resource: { buffer: this.compositeUniformBuffer } },
|
|
798
|
+
{ binding: 4, resource: this.maskResolveView },
|
|
799
|
+
{ binding: 5, resource: this.filmicLutView },
|
|
800
|
+
{ binding: 6, resource: this.backdropEquirectView ?? this.fallbackEquirectView },
|
|
801
|
+
],
|
|
802
|
+
})
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Set a 360° backdrop from an equirectangular (2:1) image — a PhotoDome-style
|
|
807
|
+
* skybox at infinity, sampled per-pixel by view direction so it follows the
|
|
808
|
+
* camera. Display-only: composited in display space behind the scene, it never
|
|
809
|
+
* affects lighting, bloom, or tonemapping. Pass null to remove (the background
|
|
810
|
+
* color, or transparency, takes over again).
|
|
811
|
+
*/
|
|
812
|
+
setBackdropEquirect(source: ImageBitmap | HTMLImageElement | HTMLCanvasElement | null): void {
|
|
813
|
+
this.backdropEquirectTexture?.destroy()
|
|
814
|
+
this.backdropEquirectTexture = null
|
|
815
|
+
this.backdropEquirectView = null
|
|
816
|
+
if (source && this.device) {
|
|
817
|
+
let width = Math.max(1, "naturalWidth" in source ? source.naturalWidth : source.width)
|
|
818
|
+
let height = Math.max(1, "naturalHeight" in source ? source.naturalHeight : source.height)
|
|
819
|
+
let upload: ImageBitmap | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas = source
|
|
820
|
+
// Panoramas routinely exceed maxTextureDimension2D (e.g. 10000×5000 vs the
|
|
821
|
+
// default 8192) — quietly downscale to fit rather than surfacing an error.
|
|
822
|
+
const limit = this.device.limits.maxTextureDimension2D
|
|
823
|
+
if (width > limit || height > limit) {
|
|
824
|
+
const scale = Math.min(limit / width, limit / height)
|
|
825
|
+
const w = Math.max(1, Math.floor(width * scale))
|
|
826
|
+
const h = Math.max(1, Math.floor(height * scale))
|
|
827
|
+
const canvas = new OffscreenCanvas(w, h)
|
|
828
|
+
const cx = canvas.getContext("2d")!
|
|
829
|
+
cx.imageSmoothingQuality = "high"
|
|
830
|
+
cx.drawImage(source, 0, 0, w, h)
|
|
831
|
+
upload = canvas
|
|
832
|
+
width = w
|
|
833
|
+
height = h
|
|
834
|
+
}
|
|
835
|
+
const tex = this.device.createTexture({
|
|
836
|
+
label: "backdrop equirect",
|
|
837
|
+
size: [width, height],
|
|
838
|
+
format: "rgba8unorm",
|
|
839
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
840
|
+
})
|
|
841
|
+
this.device.queue.copyExternalImageToTexture({ source: upload }, { texture: tex }, [width, height])
|
|
842
|
+
this.backdropEquirectTexture = tex
|
|
843
|
+
this.backdropEquirectView = tex.createView()
|
|
844
|
+
}
|
|
845
|
+
this.rebuildCompositeBindGroup()
|
|
846
|
+
if (this.device && this.compositeUniformBuffer) this.writeCompositeViewUniforms()
|
|
847
|
+
}
|
|
848
|
+
|
|
751
849
|
/** Patch bloom; GPU uniforms update immediately if `init()` has run. */
|
|
752
850
|
setBloomOptions(patch: Partial<BloomOptions>): void {
|
|
753
851
|
const b = this.bloomSettings
|
|
@@ -1545,7 +1643,9 @@ export class Engine {
|
|
|
1545
1643
|
// mirroring EEVEE where bloom color/intensity are combine-stage params, not prefilter).
|
|
1546
1644
|
this.compositeUniformBuffer = this.device.createBuffer({
|
|
1547
1645
|
label: "composite view uniforms",
|
|
1548
|
-
|
|
1646
|
+
// 6 × vec4f: (exposure, invGamma, _, _) · (bloom tint, intensity) ·
|
|
1647
|
+
// (bg rgb, mode) · camera right/up/forward basis for the 360 skybox ray.
|
|
1648
|
+
size: 96,
|
|
1549
1649
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
1550
1650
|
})
|
|
1551
1651
|
this.compositeBindGroupLayout = this.device.createBindGroupLayout({
|
|
@@ -1560,8 +1660,17 @@ export class Engine {
|
|
|
1560
1660
|
{ binding: 4, visibility: GPUShaderStage.FRAGMENT, texture: {} },
|
|
1561
1661
|
// Filmic tone LUT (r16float, filterable) — sampled with the binding-2 sampler.
|
|
1562
1662
|
{ binding: 5, visibility: GPUShaderStage.FRAGMENT, texture: {} },
|
|
1663
|
+
// 360 backdrop equirect (PhotoDome-style skybox) — 1×1 fallback when unset.
|
|
1664
|
+
{ binding: 6, visibility: GPUShaderStage.FRAGMENT, texture: {} },
|
|
1563
1665
|
],
|
|
1564
1666
|
})
|
|
1667
|
+
this.fallbackEquirectTexture = this.device.createTexture({
|
|
1668
|
+
label: "equirect fallback",
|
|
1669
|
+
size: [1, 1],
|
|
1670
|
+
format: "rgba8unorm",
|
|
1671
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
|
|
1672
|
+
})
|
|
1673
|
+
this.fallbackEquirectView = this.fallbackEquirectTexture.createView()
|
|
1565
1674
|
|
|
1566
1675
|
const compositeShader = this.device.createShaderModule({
|
|
1567
1676
|
label: "composite shader",
|
|
@@ -1949,19 +2058,8 @@ export class Engine {
|
|
|
1949
2058
|
)
|
|
1950
2059
|
}
|
|
1951
2060
|
// Composite reads bloomUp mip 0 (full pyramid collapsed); fallback to bloomDown mip 0 if no upsample level.
|
|
1952
|
-
|
|
1953
|
-
this.
|
|
1954
|
-
label: "composite bind group",
|
|
1955
|
-
layout: this.compositeBindGroupLayout,
|
|
1956
|
-
entries: [
|
|
1957
|
-
{ binding: 0, resource: this.hdrResolveTexture.createView() },
|
|
1958
|
-
{ binding: 1, resource: compositeBloomView },
|
|
1959
|
-
{ binding: 2, resource: this.bloomSampler },
|
|
1960
|
-
{ binding: 3, resource: { buffer: this.compositeUniformBuffer } },
|
|
1961
|
-
{ binding: 4, resource: this.maskResolveView },
|
|
1962
|
-
{ binding: 5, resource: this.filmicLutView },
|
|
1963
|
-
],
|
|
1964
|
-
})
|
|
2061
|
+
this.compositeBloomView = this.bloomMipCount > 1 ? this.bloomUpMipViews[0] : this.bloomDownMipViews[0]
|
|
2062
|
+
this.rebuildCompositeBindGroup()
|
|
1965
2063
|
}
|
|
1966
2064
|
|
|
1967
2065
|
this.writeCompositeViewUniforms()
|
|
@@ -2357,6 +2455,8 @@ export class Engine {
|
|
|
2357
2455
|
gridLineOpacity?: number
|
|
2358
2456
|
gridLineColor?: Vec3
|
|
2359
2457
|
noiseStrength?: number
|
|
2458
|
+
/** Whole-ground opacity, 0–1 (multiplies the radial edge fade). Default 1. */
|
|
2459
|
+
opacity?: number
|
|
2360
2460
|
}): void {
|
|
2361
2461
|
const opts = {
|
|
2362
2462
|
width: 160,
|
|
@@ -2370,6 +2470,7 @@ export class Engine {
|
|
|
2370
2470
|
gridLineOpacity: 0.4,
|
|
2371
2471
|
gridLineColor: new Vec3(0.85, 0.85, 0.85),
|
|
2372
2472
|
noiseStrength: 0.05,
|
|
2473
|
+
opacity: 1.0,
|
|
2373
2474
|
...options,
|
|
2374
2475
|
}
|
|
2375
2476
|
this.createGroundGeometry(opts.width, opts.height)
|
|
@@ -2990,6 +3091,7 @@ export class Engine {
|
|
|
2990
3091
|
gridLineOpacity: number
|
|
2991
3092
|
gridLineColor: Vec3
|
|
2992
3093
|
noiseStrength: number
|
|
3094
|
+
opacity: number
|
|
2993
3095
|
}) {
|
|
2994
3096
|
const {
|
|
2995
3097
|
diffuseColor,
|
|
@@ -3001,6 +3103,7 @@ export class Engine {
|
|
|
3001
3103
|
gridLineOpacity,
|
|
3002
3104
|
gridLineColor,
|
|
3003
3105
|
noiseStrength,
|
|
3106
|
+
opacity,
|
|
3004
3107
|
} = opts
|
|
3005
3108
|
// Shadow map is already created in setupPipelines()
|
|
3006
3109
|
const gb = new Float32Array(16)
|
|
@@ -3015,7 +3118,7 @@ export class Engine {
|
|
|
3015
3118
|
gb[8] = gridLineWidth
|
|
3016
3119
|
gb[9] = gridLineOpacity
|
|
3017
3120
|
gb[10] = noiseStrength
|
|
3018
|
-
gb[11] =
|
|
3121
|
+
gb[11] = opacity
|
|
3019
3122
|
gb[12] = gridLineColor.x
|
|
3020
3123
|
gb[13] = gridLineColor.y
|
|
3021
3124
|
gb[14] = gridLineColor.z
|
|
@@ -4577,6 +4680,31 @@ export class Engine {
|
|
|
4577
4680
|
this.cameraMatrixData[33] = cameraPos.y
|
|
4578
4681
|
this.cameraMatrixData[34] = cameraPos.z
|
|
4579
4682
|
this.device.queue.writeBuffer(this.cameraUniformBuffer, 0, this.cameraMatrixData)
|
|
4683
|
+
|
|
4684
|
+
// 360 backdrop: the composite reconstructs each pixel's view ray from the
|
|
4685
|
+
// camera basis — refresh it every frame the skybox is active. The view matrix
|
|
4686
|
+
// is LEFT-HANDED (+Z forward, see Mat4.lookAtInto), so the world-space
|
|
4687
|
+
// right/up/FORWARD vectors are rows 0/1/2 of its rotation block directly
|
|
4688
|
+
// (column-major storage: row i = values[i], values[i+4], values[i+8]).
|
|
4689
|
+
if (this.backdropEquirectView && this.compositeUniformBuffer) {
|
|
4690
|
+
const v = viewMatrix.values
|
|
4691
|
+
const u = this.compositeUniformData
|
|
4692
|
+
const tanHalf = Math.tan((this.camera.fov ?? Math.PI / 4) / 2)
|
|
4693
|
+
const aspect = this.canvas.width / Math.max(1, this.canvas.height)
|
|
4694
|
+
u[12] = v[0]
|
|
4695
|
+
u[13] = v[4]
|
|
4696
|
+
u[14] = v[8]
|
|
4697
|
+
u[15] = tanHalf * aspect
|
|
4698
|
+
u[16] = v[1]
|
|
4699
|
+
u[17] = v[5]
|
|
4700
|
+
u[18] = v[9]
|
|
4701
|
+
u[19] = tanHalf
|
|
4702
|
+
u[20] = v[2]
|
|
4703
|
+
u[21] = v[6]
|
|
4704
|
+
u[22] = v[10]
|
|
4705
|
+
u[23] = 0
|
|
4706
|
+
this.device.queue.writeBuffer(this.compositeUniformBuffer, 0, u)
|
|
4707
|
+
}
|
|
4580
4708
|
}
|
|
4581
4709
|
|
|
4582
4710
|
private updateSkinMatrices() {
|
|
@@ -12,7 +12,7 @@ override APPLY_GAMMA: bool = true;
|
|
|
12
12
|
@group(0) @binding(0) var hdrTex: texture_2d<f32>;
|
|
13
13
|
@group(0) @binding(1) var bloomTex: texture_2d<f32>; // bloomUpTexture mip 0 (full pyramid top)
|
|
14
14
|
@group(0) @binding(2) var bloomSamp: sampler;
|
|
15
|
-
@group(0) @binding(3) var<uniform> viewU: array<vec4<f32>,
|
|
15
|
+
@group(0) @binding(3) var<uniform> viewU: array<vec4<f32>, 6>;
|
|
16
16
|
// Aux mask/alpha texture. .r = bloom mask (unused here; bloom blit uses it).
|
|
17
17
|
// .g = accumulated canvas alpha (what hdr.a carried before the HDR format
|
|
18
18
|
// became rg11b10ufloat). We unpremultiply HDR by this alpha for tonemap, then
|
|
@@ -28,7 +28,13 @@ override APPLY_GAMMA: bool = true;
|
|
|
28
28
|
// continuity kills the banding — sampled with hardware linear filtering.
|
|
29
29
|
@group(0) @binding(5) var filmicLut: texture_2d<f32>;
|
|
30
30
|
// viewU[0] = (exposure, invGamma, _, _); viewU[1] = (tint.rgb, intensity)
|
|
31
|
+
// viewU[2] = (background.rgb, mode) — display-space sRGB, composited UNDER the
|
|
32
|
+
// scene post-tonemap. mode: 0 transparent (DOM shows), 1 solid color,
|
|
33
|
+
// 2 = 360 equirect skybox sampled by view ray.
|
|
34
|
+
// viewU[3] = (camera right, tanHalfFov·aspect); viewU[4] = (camera up, tanHalfFov);
|
|
35
|
+
// viewU[5] = (camera forward, _) — refreshed per frame while the skybox is active.
|
|
31
36
|
// invGamma = 1/gamma precomputed on CPU — avoids a per-pixel divide.
|
|
37
|
+
@group(0) @binding(6) var bgEquirect: texture_2d<f32>;
|
|
32
38
|
|
|
33
39
|
// Must match FILMIC_LUT_WIDTH in engine.ts (bakeFilmicLut).
|
|
34
40
|
const FILMIC_LUT_W: f32 = 256.0;
|
|
@@ -70,6 +76,21 @@ fn filmic(x: f32) -> f32 {
|
|
|
70
76
|
if (APPLY_GAMMA) {
|
|
71
77
|
disp = pow(disp, vec3f(viewU[0].y));
|
|
72
78
|
}
|
|
73
|
-
|
|
79
|
+
// Composite over the background in display space (premultiplied out).
|
|
80
|
+
let bg = viewU[2];
|
|
81
|
+
var bgRgb = bg.rgb;
|
|
82
|
+
var bgA = select(0.0, 1.0, bg.w > 0.5);
|
|
83
|
+
if (bg.w > 1.5) {
|
|
84
|
+
// 360 equirect: rebuild this pixel's world-space view ray from the camera
|
|
85
|
+
// basis, then latitude/longitude-map into the panorama. The dome sits at
|
|
86
|
+
// infinity (no parallax) — PhotoDome-style, display-only.
|
|
87
|
+
let ndc = vec2f(fragCoord.x / fullSz.x * 2.0 - 1.0, 1.0 - fragCoord.y / fullSz.y * 2.0);
|
|
88
|
+
let dir = normalize(viewU[5].xyz + ndc.x * viewU[3].w * viewU[3].xyz + ndc.y * viewU[4].w * viewU[4].xyz);
|
|
89
|
+
// LH world (+Z forward): longitude = atan2(x, z), Babylon-PhotoDome convention.
|
|
90
|
+
let su = 0.5 + atan2(dir.x, dir.z) * 0.15915494309; // 1/(2π)
|
|
91
|
+
let sv = 0.5 - asin(clamp(dir.y, -1.0, 1.0)) * 0.31830988618; // 1/π
|
|
92
|
+
bgRgb = textureSampleLevel(bgEquirect, bloomSamp, vec2f(su, sv), 0.0).rgb;
|
|
93
|
+
}
|
|
94
|
+
return vec4f(disp * alpha + bgRgb * bgA * (1.0 - alpha), alpha + bgA * (1.0 - alpha));
|
|
74
95
|
}
|
|
75
96
|
`
|
|
@@ -8,7 +8,7 @@ struct LightUniforms { ambientColor: vec4f, lights: array<Light, 4>, };
|
|
|
8
8
|
struct GroundShadowMat {
|
|
9
9
|
diffuseColor: vec3f, fadeStart: f32,
|
|
10
10
|
fadeEnd: f32, shadowStrength: f32, pcfTexel: f32, gridSpacing: f32,
|
|
11
|
-
gridLineWidth: f32, gridLineOpacity: f32, noiseStrength: f32,
|
|
11
|
+
gridLineWidth: f32, gridLineOpacity: f32, noiseStrength: f32, opacity: f32,
|
|
12
12
|
gridLineColor: vec3f, _pad2: f32,
|
|
13
13
|
};
|
|
14
14
|
struct LightVP { viewProj: mat4x4f, };
|
|
@@ -86,13 +86,20 @@ struct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };
|
|
|
86
86
|
var baseColor = material.diffuseColor * sun * (1.0 - dark * 0.65);
|
|
87
87
|
baseColor *= noiseTint;
|
|
88
88
|
let finalColor = mix(baseColor, material.gridLineColor, gridLine * material.gridLineOpacity * edgeFade);
|
|
89
|
+
// Whole-ground opacity fades the SURFACE (color, grid) but the shadow stays —
|
|
90
|
+
// as opacity drops, the received shadow becomes a translucent dark layer
|
|
91
|
+
// (Blender's Shadow Catcher), so models still feel grounded on a photo or
|
|
92
|
+
// 360 backdrop. At opacity 1 this reduces exactly to the plain surface.
|
|
93
|
+
let surfA = edgeFade * material.opacity;
|
|
94
|
+
let catchA = dark * 0.65 * edgeFade * (1.0 - material.opacity);
|
|
95
|
+
let outA = surfA + catchA;
|
|
89
96
|
var out: FSOut;
|
|
90
|
-
out.color = vec4f(finalColor *
|
|
97
|
+
out.color = vec4f(finalColor * surfA, outA);
|
|
91
98
|
// mask.r = 0: ground never contributes to bloom. mask.g = 1.0 with src.a =
|
|
92
|
-
//
|
|
93
|
-
// from
|
|
99
|
+
// outA turns the aux blend into alpha-over, so the drawable alpha goes
|
|
100
|
+
// from outA at the center to 0 at the radial edge — letting the page
|
|
94
101
|
// background show through under the premultiplied canvas alphaMode.
|
|
95
|
-
out.mask = vec4f(0.0, 1.0, 0.0,
|
|
102
|
+
out.mask = vec4f(0.0, 1.0, 0.0, outA);
|
|
96
103
|
return out;
|
|
97
104
|
}
|
|
98
105
|
`
|