@vgai/engine 0.5.41 → 0.5.44
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/adapter/adapter-module.d.ts +28 -29
- package/dist/adapter/adapter-module.d.ts.map +1 -1
- package/dist/adapter/adapter-module.js +11 -34
- package/dist/adapter/authoring-seam-contract.d.ts +10 -0
- package/dist/adapter/authoring-seam-contract.d.ts.map +1 -1
- package/dist/adapter/authoring-seam-contract.js +2 -0
- package/dist/adapter/authoring.d.ts +31 -0
- package/dist/adapter/authoring.d.ts.map +1 -1
- package/dist/adapter/finders/finder-result.d.ts +2 -2
- package/dist/adapter/finders/finder-result.d.ts.map +1 -1
- package/dist/adapter/finders/index.d.ts +15 -2
- package/dist/adapter/finders/index.d.ts.map +1 -1
- package/dist/adapter/finders/index.js +38 -10
- package/dist/adapter/finders/prefabs-from-stories.d.ts.map +1 -1
- package/dist/adapter/finders/registry.d.ts +45 -0
- package/dist/adapter/finders/registry.d.ts.map +1 -0
- package/dist/adapter/finders/registry.js +56 -0
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
- package/dist/adapter/ingest/scene-capture.js +50 -20
- package/dist/adapter/system-adapter.d.ts +3 -1
- package/dist/adapter/system-adapter.d.ts.map +1 -1
- package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -1
- package/dist/canvas-react/pixi-react-root-factory.js +21 -11
- package/dist/data/vite-plugin-data.d.ts +1 -1
- package/dist/data/vite-plugin-data.d.ts.map +1 -1
- package/dist/data/vite-plugin-data.js +2 -2
- package/dist/ecs/user-data.d.ts +6 -0
- package/dist/ecs/user-data.d.ts.map +1 -1
- package/dist/ecs/user-data.js +4 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/input/host-pointer.d.ts +18 -0
- package/dist/input/host-pointer.d.ts.map +1 -1
- package/dist/input/host-pointer.js +54 -5
- package/dist/input/input-manager.d.ts +83 -1
- package/dist/input/input-manager.d.ts.map +1 -1
- package/dist/input/input-manager.js +357 -8
- package/dist/manifest/configuration-kinds.d.ts +97 -0
- package/dist/manifest/configuration-kinds.d.ts.map +1 -0
- package/dist/manifest/configuration-kinds.js +148 -0
- package/dist/manifest/index.d.ts +2 -1
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/manifest/index.js +4 -3
- package/dist/manifest/kind-modules.d.ts +18 -0
- package/dist/manifest/kind-modules.d.ts.map +1 -0
- package/dist/manifest/kind-modules.js +58 -0
- package/dist/manifest/load-file.d.ts +3 -3
- package/dist/manifest/load-file.d.ts.map +1 -1
- package/dist/manifest/load-file.js +4 -4
- package/dist/manifest/load.d.ts +17 -12
- package/dist/manifest/load.d.ts.map +1 -1
- package/dist/manifest/load.js +29 -19
- package/dist/manifest/runtime-environment.d.ts +11 -0
- package/dist/manifest/runtime-environment.d.ts.map +1 -0
- package/dist/manifest/runtime-environment.js +44 -0
- package/dist/manifest/schema.d.ts +10 -9
- package/dist/manifest/schema.d.ts.map +1 -1
- package/dist/manifest/schema.js +32 -27
- package/dist/react/use-data.d.ts +1 -1
- package/dist/react/use-data.js +1 -1
- package/dist/render/environment-capture.d.ts +10 -1
- package/dist/render/environment-capture.d.ts.map +1 -1
- package/dist/render/environment-capture.js +25 -0
- package/dist/render/ibl-override-material.d.ts +11 -2
- package/dist/render/ibl-override-material.d.ts.map +1 -1
- package/dist/render/ibl-override-material.js +16 -2
- package/dist/render/matcap-texture.d.ts +5 -0
- package/dist/render/matcap-texture.d.ts.map +1 -0
- package/dist/render/matcap-texture.js +82 -0
- package/dist/render/soft-particle-depth.d.ts +14 -8
- package/dist/render/soft-particle-depth.d.ts.map +1 -1
- package/dist/render/soft-particle-depth.js +37 -14
- package/dist/render/viewport-shading.d.ts +11 -1
- package/dist/render/viewport-shading.d.ts.map +1 -1
- package/dist/render/viewport-shading.js +25 -0
- package/dist/runtime/create-runtime.js +6 -5
- package/dist/runtime/debug-bridge.d.ts.map +1 -1
- package/dist/runtime/debug-bridge.js +17 -3
- package/dist/runtime/mount-manifest.d.ts.map +1 -1
- package/dist/runtime/mount-manifest.js +11 -2
- package/dist/settings/schema.d.ts +99 -0
- package/dist/settings/schema.d.ts.map +1 -0
- package/dist/settings/schema.js +110 -0
- package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -1
- package/dist/world3d-react/r3f-root-factory.js +34 -36
- package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
- package/dist/world3d-react/rapier-physics-bridge.js +21 -6
- package/dist-config/config.js +1 -1
- package/dist-config/config.js.map +2 -2
- package/package.json +2 -1
- package/schemas/engine-capabilities.json +4 -4
- package/schemas/vgai-project.schema.json +41 -36
- package/schemas/vgai-settings.schema.json +112 -0
- package/src/adapter/adapter-module.ts +33 -51
- package/src/adapter/authoring-seam-contract.ts +2 -0
- package/src/adapter/authoring.ts +31 -0
- package/src/adapter/finders/finder-result.ts +2 -2
- package/src/adapter/finders/index.ts +68 -12
- package/src/adapter/finders/prefabs-from-stories.ts +2 -2
- package/src/adapter/finders/registry.ts +95 -0
- package/src/adapter/finders/scenes-from-entrypoint-selection.ts +4 -4
- package/src/adapter/ingest/scene-capture.ts +48 -19
- package/src/adapter/system-adapter.ts +3 -1
- package/src/canvas-react/pixi-react-root-factory.tsx +21 -11
- package/src/data/vite-plugin-data.ts +4 -2
- package/src/ecs/user-data.ts +6 -0
- package/src/index.ts +1 -1
- package/src/input/host-pointer.ts +84 -5
- package/src/input/input-manager.ts +404 -7
- package/src/manifest/configuration-kinds.ts +241 -0
- package/src/manifest/index.ts +4 -3
- package/src/manifest/kind-modules.ts +58 -0
- package/src/manifest/load-file.ts +11 -5
- package/src/manifest/load.ts +53 -22
- package/src/manifest/runtime-environment.ts +48 -0
- package/src/manifest/schema.ts +39 -33
- package/src/react/use-data.ts +1 -1
- package/src/render/environment-capture.ts +30 -1
- package/src/render/ibl-override-material.ts +32 -2
- package/src/render/matcap-texture.ts +92 -0
- package/src/render/soft-particle-depth.ts +43 -14
- package/src/render/viewport-shading.ts +33 -1
- package/src/runtime/create-runtime.ts +6 -5
- package/src/runtime/debug-bridge.ts +21 -3
- package/src/runtime/mount-manifest.ts +13 -2
- package/src/settings/schema.ts +127 -0
- package/src/world3d-react/r3f-root-factory.tsx +45 -39
- package/src/world3d-react/rapier-physics-bridge.tsx +22 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/manifest/schema.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAG,CAAU,CAAC;AAsFhD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;qBA0H3B,CAAC;AACJ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAM5D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAqFnB,CAAC;AACZ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAkB5D,eAAO,MAAM,eAAe;;;;;EAMzB,CAAC;AACJ,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,qBAAqB;;;;EAEa,CAAC;AAChD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;kBAqC7B,CAAC;AACJ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/manifest/schema.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAG,CAAU,CAAC;AAsFhD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;qBA0H3B,CAAC;AACJ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAM5D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAqFnB,CAAC;AACZ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAkB5D,eAAO,MAAM,eAAe;;;;;EAMzB,CAAC;AACJ,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,qBAAqB;;;;EAEa,CAAC;AAChD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;kBAqC7B,CAAC;AACJ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAchE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4TyD,CAAC;AAEzF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
|
package/dist/manifest/schema.js
CHANGED
|
@@ -328,6 +328,13 @@ export const LearnMetadataSchema = z
|
|
|
328
328
|
// ---------------------------------------------------------------------------
|
|
329
329
|
// Game manifest (vgai.project.json)
|
|
330
330
|
// ---------------------------------------------------------------------------
|
|
331
|
+
/** The envelope of one run configuration; the kind's schema takes the rest. */
|
|
332
|
+
const ConfigurationEnvelopeSchema = z
|
|
333
|
+
.object({
|
|
334
|
+
id: z.string().min(1).describe('Configuration id, unique in the manifest'),
|
|
335
|
+
kind: z.string().min(1).describe('A registered run kind'),
|
|
336
|
+
})
|
|
337
|
+
.passthrough();
|
|
331
338
|
export const GameManifestSchema = z
|
|
332
339
|
.object({
|
|
333
340
|
$schema: z
|
|
@@ -354,7 +361,6 @@ export const GameManifestSchema = z
|
|
|
354
361
|
.describe('Engine version pin'),
|
|
355
362
|
roots: z
|
|
356
363
|
.array(AdapterRootSchema)
|
|
357
|
-
.min(1)
|
|
358
364
|
.superRefine((roots, ctx) => {
|
|
359
365
|
// D-V6 (debt): root ids are described as unique above but that was
|
|
360
366
|
// describe-only at the SCHEMA level — only load.ts's loader-level
|
|
@@ -410,7 +416,7 @@ export const GameManifestSchema = z
|
|
|
410
416
|
});
|
|
411
417
|
}
|
|
412
418
|
})
|
|
413
|
-
.describe("The
|
|
419
|
+
.describe("The project's explicit adapter-root composition — ZERO OR MORE roots, and no implicit root: a project with no roots mounts nothing (a library of models, a folder of documents) and the editor derives its chrome from what IS declared. " +
|
|
414
420
|
'Root ids are unique, and a project declares at most ONE world root per medium — ' +
|
|
415
421
|
'one `three`, one `dom`, one canvas-surface root (first-party canvas, canvas ingest ' +
|
|
416
422
|
'and canvas module are the same medium).'),
|
|
@@ -443,40 +449,39 @@ export const GameManifestSchema = z
|
|
|
443
449
|
.strict()
|
|
444
450
|
.optional()
|
|
445
451
|
.describe('Editor-only authoring metadata; never runtime ownership'),
|
|
446
|
-
|
|
452
|
+
configurations: z
|
|
453
|
+
.array(ConfigurationEnvelopeSchema)
|
|
454
|
+
.optional()
|
|
455
|
+
.describe("The project's run configurations — its ENTRYPOINTS beyond the host mount (`play`): each an " +
|
|
456
|
+
'id and a registered kind (`process`, `compound`, and whatever a capability registers) with ' +
|
|
457
|
+
"that kind's own fields. The editor's transport, `vgai run <id>` and a harness start the same declaration."),
|
|
458
|
+
relay: z
|
|
447
459
|
.object({
|
|
448
|
-
|
|
449
|
-
endpoint: z
|
|
460
|
+
signalingUrl: z
|
|
450
461
|
.string()
|
|
451
462
|
.optional()
|
|
452
|
-
.describe('
|
|
453
|
-
|
|
454
|
-
"`server/colyseus-setup.ts` listens on. Stated here because the endpoint is the game's " +
|
|
455
|
-
'own deployment fact, not something the editor may guess'),
|
|
456
|
-
module: z
|
|
463
|
+
.describe('Managed relay signaling URL to prefer over the client default; omitted when the deploy did not pin one'),
|
|
464
|
+
grant: z
|
|
457
465
|
.string()
|
|
458
466
|
.optional()
|
|
459
|
-
.describe('
|
|
460
|
-
|
|
461
|
-
.
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
.number()
|
|
471
|
-
.describe('Token expiry as epoch milliseconds; the client falls back to a tokenless join once elapsed'),
|
|
472
|
-
})
|
|
473
|
-
.strict()
|
|
467
|
+
.describe('Room-scoped managed-relay GRANT minted at `vgai deploy`; players exchange it for a fresh token at `sessionUrl`'),
|
|
468
|
+
sessionUrl: z
|
|
469
|
+
.string()
|
|
470
|
+
.optional()
|
|
471
|
+
.describe('Public session endpoint where a deployed client exchanges the grant for a short-lived relay token'),
|
|
472
|
+
accessToken: z
|
|
473
|
+
.string()
|
|
474
|
+
.optional()
|
|
475
|
+
.describe('A baked relay token (older deploys); used directly while unexpired'),
|
|
476
|
+
expiresAt: z
|
|
477
|
+
.number()
|
|
474
478
|
.optional()
|
|
475
|
-
.describe('
|
|
479
|
+
.describe('Token expiry as epoch milliseconds; the client falls back to a tokenless join once elapsed'),
|
|
476
480
|
})
|
|
477
481
|
.strict()
|
|
478
482
|
.optional()
|
|
479
|
-
.describe('
|
|
483
|
+
.describe('Deploy-baked managed-relay credentials — a DEPLOYMENT fact. NEVER hand-authored in source: written only into ' +
|
|
484
|
+
'the staged manifest by `vgai deploy` and read by the deployed client at connect time.'),
|
|
480
485
|
resolution: z
|
|
481
486
|
.object({
|
|
482
487
|
width: z.number().describe('Canvas width in pixels'),
|
package/dist/react/use-data.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export declare function useData<T>(handle: DataHandle<T>): T;
|
|
|
48
48
|
* runtime state belongs in your game's own store, never written back into
|
|
49
49
|
* data files. Outside a running editor there is no `/__editor` server, so
|
|
50
50
|
* this rejects with a teaching error (a shipped game could never reach the
|
|
51
|
-
* route anyway — builds strip `src/tools/` entirely, §4).
|
|
51
|
+
* route anyway — builds strip `src/contributions/` and `src/tools/` entirely, §4).
|
|
52
52
|
*
|
|
53
53
|
* The body is PARSED VALUES, never serialized text: the dev server's fold
|
|
54
54
|
* (`packages/editor/server/data-file-serialize.ts`) owns key order and the
|
package/dist/react/use-data.js
CHANGED
|
@@ -50,7 +50,7 @@ export function useData(handle) {
|
|
|
50
50
|
* runtime state belongs in your game's own store, never written back into
|
|
51
51
|
* data files. Outside a running editor there is no `/__editor` server, so
|
|
52
52
|
* this rejects with a teaching error (a shipped game could never reach the
|
|
53
|
-
* route anyway — builds strip `src/tools/` entirely, §4).
|
|
53
|
+
* route anyway — builds strip `src/contributions/` and `src/tools/` entirely, §4).
|
|
54
54
|
*
|
|
55
55
|
* The body is PARSED VALUES, never serialized text: the dev server's fold
|
|
56
56
|
* (`packages/editor/server/data-file-serialize.ts`) owns key order and the
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* game altered.
|
|
11
11
|
*
|
|
12
12
|
* Consumers today: the `reflections` capability's native probe system, and
|
|
13
|
-
* `godot-compat`'s Godot
|
|
13
|
+
* `godot-compat`'s versioned Godot `ReflectionProbe` binding.
|
|
14
14
|
*/
|
|
15
15
|
import type { Scene, WebGLRenderer } from 'three';
|
|
16
16
|
/**
|
|
@@ -56,6 +56,15 @@ export declare function withCaptureMask(scene: Scene, mask: number, capture: ()
|
|
|
56
56
|
* cannot outlive the `finally` that restores it.
|
|
57
57
|
*/
|
|
58
58
|
export declare function withCaptureShadows(scene: Scene, enabled: boolean, capture: () => void): void;
|
|
59
|
+
/**
|
|
60
|
+
* Include or suppress the scene's global sky/environment for one cube capture.
|
|
61
|
+
*
|
|
62
|
+
* This is renderer plumbing rather than a Godot policy: the caller decides whether the capture is
|
|
63
|
+
* interior. Clearing both properties is necessary because Three uses `background` for the cube's
|
|
64
|
+
* visible pixels and `environment` for the materials being photographed. Restoring only one makes
|
|
65
|
+
* a nominally isolated capture retain half of the outside lighting.
|
|
66
|
+
*/
|
|
67
|
+
export declare function withCaptureSceneEnvironment(scene: Scene, enabled: boolean, capture: () => void): void;
|
|
59
68
|
/**
|
|
60
69
|
* Whether this renderer can run an environment capture at all.
|
|
61
70
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"environment-capture.d.ts","sourceRoot":"","sources":["../../src/render/environment-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAmB,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEnE;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAYrF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAiB5F;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAGtE"}
|
|
1
|
+
{"version":3,"file":"environment-capture.d.ts","sourceRoot":"","sources":["../../src/render/environment-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAmB,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEnE;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAYrF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAiB5F;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,IAAI,GAClB,IAAI,CAeN;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAGtE"}
|
|
@@ -76,6 +76,31 @@ export function withCaptureShadows(scene, enabled, capture) {
|
|
|
76
76
|
entry.shadow.intensity = entry.intensity;
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Include or suppress the scene's global sky/environment for one cube capture.
|
|
81
|
+
*
|
|
82
|
+
* This is renderer plumbing rather than a Godot policy: the caller decides whether the capture is
|
|
83
|
+
* interior. Clearing both properties is necessary because Three uses `background` for the cube's
|
|
84
|
+
* visible pixels and `environment` for the materials being photographed. Restoring only one makes
|
|
85
|
+
* a nominally isolated capture retain half of the outside lighting.
|
|
86
|
+
*/
|
|
87
|
+
export function withCaptureSceneEnvironment(scene, enabled, capture) {
|
|
88
|
+
if (enabled) {
|
|
89
|
+
capture();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const background = scene.background;
|
|
93
|
+
const environment = scene.environment;
|
|
94
|
+
scene.background = null;
|
|
95
|
+
scene.environment = null;
|
|
96
|
+
try {
|
|
97
|
+
capture();
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
scene.background = background;
|
|
101
|
+
scene.environment = environment;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
79
104
|
/**
|
|
80
105
|
* Whether this renderer can run an environment capture at all.
|
|
81
106
|
*
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
* hands back three's own shader object and gets out of the way.
|
|
25
25
|
*
|
|
26
26
|
* Consumers today: the `reflections` capability's native probe system, and
|
|
27
|
-
* `godot-compat`'s Godot
|
|
27
|
+
* `godot-compat`'s Godot `ReflectionProbe`, whose per-fragment models are
|
|
28
28
|
* deliberately different renderers over this one splice.
|
|
29
29
|
*/
|
|
30
|
-
import { type Mesh, type MeshStandardMaterial } from 'three';
|
|
30
|
+
import { type Mesh, type MeshStandardMaterial, type Texture } from 'three';
|
|
31
31
|
/** The shader object three hands to `onBeforeCompile`. */
|
|
32
32
|
export type IblOverrideShader = Parameters<MeshStandardMaterial['onBeforeCompile']>[0];
|
|
33
33
|
/**
|
|
@@ -53,6 +53,15 @@ export declare function baseIblFunctions(): string;
|
|
|
53
53
|
* intent: both compile the physical IBL chunk this module replaces.
|
|
54
54
|
*/
|
|
55
55
|
export declare function standardMaterialsOf(mesh: Mesh): readonly MeshStandardMaterial[];
|
|
56
|
+
/**
|
|
57
|
+
* A black native texture whose only job is to compile Three's IBL branch.
|
|
58
|
+
*
|
|
59
|
+
* Local reflection systems can light a scene from captured probes when neither
|
|
60
|
+
* `scene.environment` nor a material `envMap` exists. Three removes both IBL
|
|
61
|
+
* entry points from that program unless one native input is present, so the
|
|
62
|
+
* caller temporarily assigns this neutral texture and restores what it found.
|
|
63
|
+
*/
|
|
64
|
+
export declare function createIblSentinelTexture(): Texture;
|
|
56
65
|
export interface IblOverrideOptions {
|
|
57
66
|
/**
|
|
58
67
|
* The GLSL that replaces `#include <envmap_physical_pars_fragment>`. Read at
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ibl-override-material.d.ts","sourceRoot":"","sources":["../../src/render/ibl-override-material.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"ibl-override-material.d.ts","sourceRoot":"","sources":["../../src/render/ibl-override-material.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAGL,KAAK,IAAI,EACT,KAAK,oBAAoB,EAGzB,KAAK,OAAO,EAEb,MAAM,OAAO,CAAC;AAEf,0DAA0D;AAC1D,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEvF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,yBAAyB,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAIzC;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,oBAAoB,EAAE,CAK/E;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAWlD;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,MAAM,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,MAAM,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC1D;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC1C,6EAA6E;IAC7E,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,EAAE,kBAAkB,GAC1B,WAAW,CAsCb"}
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
* hands back three's own shader object and gets out of the way.
|
|
25
25
|
*
|
|
26
26
|
* Consumers today: the `reflections` capability's native probe system, and
|
|
27
|
-
* `godot-compat`'s Godot
|
|
27
|
+
* `godot-compat`'s Godot `ReflectionProbe`, whose per-fragment models are
|
|
28
28
|
* deliberately different renderers over this one splice.
|
|
29
29
|
*/
|
|
30
|
-
import { ShaderChunk } from 'three';
|
|
30
|
+
import { CubeUVReflectionMapping, DataTexture, RGBAFormat, ShaderChunk, UnsignedByteType, } from 'three';
|
|
31
31
|
/**
|
|
32
32
|
* The `varying vec3` the vertex splice publishes and the fragment body reads.
|
|
33
33
|
*
|
|
@@ -58,6 +58,20 @@ export function standardMaterialsOf(mesh) {
|
|
|
58
58
|
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
|
|
59
59
|
return materials.filter((material) => Boolean(material.isMeshStandardMaterial));
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* A black native texture whose only job is to compile Three's IBL branch.
|
|
63
|
+
*
|
|
64
|
+
* Local reflection systems can light a scene from captured probes when neither
|
|
65
|
+
* `scene.environment` nor a material `envMap` exists. Three removes both IBL
|
|
66
|
+
* entry points from that program unless one native input is present, so the
|
|
67
|
+
* caller temporarily assigns this neutral texture and restores what it found.
|
|
68
|
+
*/
|
|
69
|
+
export function createIblSentinelTexture() {
|
|
70
|
+
const texture = new DataTexture(new Uint8Array(16 * 16 * 4), 16, 16, RGBAFormat, UnsignedByteType);
|
|
71
|
+
texture.mapping = CubeUVReflectionMapping;
|
|
72
|
+
texture.needsUpdate = true;
|
|
73
|
+
return texture;
|
|
74
|
+
}
|
|
61
75
|
/**
|
|
62
76
|
* Install the override. The returned handle is the only way to reach the
|
|
63
77
|
* compiled shader or to undo the patch; the material is otherwise untouched
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
export declare function drawNeutralMatcap(size?: number): HTMLCanvasElement;
|
|
3
|
+
/** The drawn sphere as a ready-to-sample texture. Callers own disposal. */
|
|
4
|
+
export declare function createNeutralMatcapTexture(size?: number): THREE.CanvasTexture;
|
|
5
|
+
//# sourceMappingURL=matcap-texture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matcap-texture.d.ts","sourceRoot":"","sources":["../../src/render/matcap-texture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AA8B/B,wBAAgB,iBAAiB,CAAC,IAAI,SAAO,GAAG,iBAAiB,CAkDhE;AAED,2EAA2E;AAC3E,wBAAgB,0BAA0B,CAAC,IAAI,SAAO,GAAG,KAAK,CAAC,aAAa,CAQ3E"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* The neutral matcap sphere, DRAWN rather than shipped.
|
|
4
|
+
*
|
|
5
|
+
* A matcap is just a picture of a lit sphere sampled by view-space normal, so
|
|
6
|
+
* there is nothing to vendor: the same three numbers a shader would use
|
|
7
|
+
* (key, fill, rim) evaluated once per texel produce the image. Keeping it
|
|
8
|
+
* procedural means the diagnostic look has no binary asset, no license, no
|
|
9
|
+
* provenance row, and no way to go missing from a build.
|
|
10
|
+
*
|
|
11
|
+
* The look is deliberately CLAY: one warm key from the upper left, a cool
|
|
12
|
+
* fill from the lower right, a tight rim, and a broad soft highlight — the
|
|
13
|
+
* neutral sculpting material whose whole job is to let form read without
|
|
14
|
+
* colour, texture or authored lighting getting a vote.
|
|
15
|
+
*/
|
|
16
|
+
const SIZE = 256;
|
|
17
|
+
/** sRGB transfer curve — the canvas holds display-referred bytes. */
|
|
18
|
+
function encode(value) {
|
|
19
|
+
const c = Math.min(1, Math.max(0, value));
|
|
20
|
+
return c <= 0.0031308 ? c * 12.92 : 1.055 * c ** (1 / 2.4) - 0.055;
|
|
21
|
+
}
|
|
22
|
+
function normalize(x, y, z) {
|
|
23
|
+
const length = Math.hypot(x, y, z) || 1;
|
|
24
|
+
return [x / length, y / length, z / length];
|
|
25
|
+
}
|
|
26
|
+
export function drawNeutralMatcap(size = SIZE) {
|
|
27
|
+
const canvas = document.createElement('canvas');
|
|
28
|
+
canvas.width = size;
|
|
29
|
+
canvas.height = size;
|
|
30
|
+
const context = canvas.getContext('2d');
|
|
31
|
+
if (!context)
|
|
32
|
+
return canvas;
|
|
33
|
+
const image = context.createImageData(size, size);
|
|
34
|
+
const key = normalize(-0.45, 0.62, 0.64);
|
|
35
|
+
const fill = normalize(0.65, -0.35, 0.5);
|
|
36
|
+
// View direction is +Z for a matcap: the sphere is drawn facing the camera.
|
|
37
|
+
const half = normalize(key[0], key[1], key[2] + 1);
|
|
38
|
+
const base = [0.7, 0.69, 0.68];
|
|
39
|
+
const fillColor = [0.34, 0.4, 0.52];
|
|
40
|
+
const rimColor = [0.85, 0.88, 1];
|
|
41
|
+
for (let py = 0; py < size; py++) {
|
|
42
|
+
for (let px = 0; px < size; px++) {
|
|
43
|
+
const nx = (px + 0.5) / size / 0.5 - 1;
|
|
44
|
+
const ny = 1 - (py + 0.5) / size / 0.5;
|
|
45
|
+
const r2 = nx * nx + ny * ny;
|
|
46
|
+
// Outside the unit disc a matcap is never sampled by a facing surface,
|
|
47
|
+
// but bilinear filtering reaches one texel past the silhouette. Clamp
|
|
48
|
+
// to the rim normal so the edge stays the rim colour instead of
|
|
49
|
+
// bleeding whatever happened to be there.
|
|
50
|
+
const clamped = r2 > 1;
|
|
51
|
+
const scale = clamped ? 1 / Math.sqrt(r2) : 1;
|
|
52
|
+
const x = nx * scale;
|
|
53
|
+
const y = ny * scale;
|
|
54
|
+
const z = clamped ? 0 : Math.sqrt(Math.max(0, 1 - r2));
|
|
55
|
+
const diffuse = Math.max(0, x * key[0] + y * key[1] + z * key[2]);
|
|
56
|
+
const fillTerm = Math.max(0, x * fill[0] + y * fill[1] + z * fill[2]);
|
|
57
|
+
const specular = Math.max(0, x * half[0] + y * half[1] + z * half[2]) ** 42 * 0.5;
|
|
58
|
+
const rim = (1 - z) ** 3.2 * 0.4;
|
|
59
|
+
const offset = (py * size + px) * 4;
|
|
60
|
+
for (let channel = 0; channel < 3; channel++) {
|
|
61
|
+
const lit = base[channel] * (0.16 + 0.8 * diffuse) +
|
|
62
|
+
fillColor[channel] * 0.3 * fillTerm +
|
|
63
|
+
rimColor[channel] * rim +
|
|
64
|
+
specular;
|
|
65
|
+
image.data[offset + channel] = Math.round(encode(lit) * 255);
|
|
66
|
+
}
|
|
67
|
+
image.data[offset + 3] = 255;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
context.putImageData(image, 0, 0);
|
|
71
|
+
return canvas;
|
|
72
|
+
}
|
|
73
|
+
/** The drawn sphere as a ready-to-sample texture. Callers own disposal. */
|
|
74
|
+
export function createNeutralMatcapTexture(size = SIZE) {
|
|
75
|
+
const texture = new THREE.CanvasTexture(drawNeutralMatcap(size));
|
|
76
|
+
texture.colorSpace = THREE.SRGBColorSpace;
|
|
77
|
+
texture.minFilter = THREE.LinearFilter;
|
|
78
|
+
texture.magFilter = THREE.LinearFilter;
|
|
79
|
+
texture.generateMipmaps = false;
|
|
80
|
+
texture.needsUpdate = true;
|
|
81
|
+
return texture;
|
|
82
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* `
|
|
2
|
+
* Opaque scene DEPTH for native consumers, including three.quarks soft particles and translated
|
|
3
|
+
* Godot `hint_depth_texture` shader uniforms.
|
|
4
4
|
*
|
|
5
5
|
* ## What three.quarks needs, and what it does when nobody supplies it
|
|
6
6
|
*
|
|
@@ -61,12 +61,10 @@
|
|
|
61
61
|
* with the armed particle renderers and every transparent surface hidden and a
|
|
62
62
|
* colour-write-disabled override material in place.
|
|
63
63
|
*
|
|
64
|
-
* That cost is paid ONLY while something is armed.
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* world with no soft particles pays one `Set.size` read per frame and nothing
|
|
69
|
-
* else. Armed, per frame per camera it costs: one scene traverse (to find the
|
|
64
|
+
* That cost is paid ONLY while something is armed. Soft particles enter through
|
|
65
|
+
* {@link armSoftParticleDepth}; translated depth-texture shader programs enter through
|
|
66
|
+
* {@link armSceneDepthTexture}. With both registries empty {@link SoftParticleDepthPass.render}
|
|
67
|
+
* returns before it touches the scene. Armed, per frame per camera it costs: one scene traverse (to find the
|
|
70
68
|
* transparent surfaces to hide), one extra geometry-only scene draw with shadow
|
|
71
69
|
* updates suppressed, and a drawing-buffer-sized depth target
|
|
72
70
|
* (`UnsignedIntType` depth + an unread RGBA8 colour attachment ≈ 8
|
|
@@ -97,6 +95,10 @@
|
|
|
97
95
|
*/
|
|
98
96
|
import * as THREE from 'three';
|
|
99
97
|
import type { BatchedRenderer } from 'three.quarks';
|
|
98
|
+
/** Any native material/program that samples Godot's opaque-pass depth texture. */
|
|
99
|
+
export interface SceneDepthTextureConsumer {
|
|
100
|
+
setDepthTexture(texture: THREE.Texture): void;
|
|
101
|
+
}
|
|
100
102
|
/**
|
|
101
103
|
* A 1x1 texture whose red channel is 1.0 — "the depth buffer says nothing is in
|
|
102
104
|
* front of anything".
|
|
@@ -120,6 +122,10 @@ export declare function armSoftParticleDepth(renderer: BatchedRenderer): void;
|
|
|
120
122
|
* depth nobody is refreshing.
|
|
121
123
|
*/
|
|
122
124
|
export declare function disarmSoftParticleDepth(renderer: BatchedRenderer): void;
|
|
125
|
+
/** Retain one consumer of the same opaque scene-depth image Godot exposes as hint_depth_texture. */
|
|
126
|
+
export declare function armSceneDepthTexture(consumer: SceneDepthTextureConsumer): void;
|
|
127
|
+
/** Release one retained Godot depth-texture consumer without leaving a disposed target bound. */
|
|
128
|
+
export declare function disarmSceneDepthTexture(consumer: SceneDepthTextureConsumer): void;
|
|
123
129
|
/** Test/diagnostic read of the registry — how many renderers a pass would consider. */
|
|
124
130
|
export declare function armedSoftParticleRendererCount(): number;
|
|
125
131
|
/** The subset of `THREE.WebGLRenderer` this pass drives, so a host can supply its own. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"soft-particle-depth.d.ts","sourceRoot":"","sources":["../../src/render/soft-particle-depth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"soft-particle-depth.d.ts","sourceRoot":"","sources":["../../src/render/soft-particle-depth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8FG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAapD,kFAAkF;AAClF,MAAM,WAAW,yBAAyB;IACxC,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;CAC/C;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,IAAI,KAAK,CAAC,WAAW,CAOnD;AAED,8FAA8F;AAC9F,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAQvE;AAED,oGAAoG;AACpG,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,yBAAyB,GAAG,IAAI,CAG9E;AAED,iGAAiG;AACjG,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,yBAAyB,GAAG,IAAI,CAQjF;AAED,uFAAuF;AACvF,wBAAgB,8BAA8B,IAAI,MAAM,CAEvD;AAED,0FAA0F;AAC1F,MAAM,WAAW,yBAAyB;IACxC,oBAAoB,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC3D,eAAe,IAAI,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAClD,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAAC;IAC9D,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IAC1D,kGAAkG;IAClG,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,CAAC;CACpE;AAED,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,EAAE,yBAAyB,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IAC5F,OAAO,IAAI,IAAI,CAAC;CACjB;AA0CD,wBAAgB,2BAA2B,IAAI,qBAAqB,CAiHnE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* `
|
|
2
|
+
* Opaque scene DEPTH for native consumers, including three.quarks soft particles and translated
|
|
3
|
+
* Godot `hint_depth_texture` shader uniforms.
|
|
4
4
|
*
|
|
5
5
|
* ## What three.quarks needs, and what it does when nobody supplies it
|
|
6
6
|
*
|
|
@@ -61,12 +61,10 @@
|
|
|
61
61
|
* with the armed particle renderers and every transparent surface hidden and a
|
|
62
62
|
* colour-write-disabled override material in place.
|
|
63
63
|
*
|
|
64
|
-
* That cost is paid ONLY while something is armed.
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* world with no soft particles pays one `Set.size` read per frame and nothing
|
|
69
|
-
* else. Armed, per frame per camera it costs: one scene traverse (to find the
|
|
64
|
+
* That cost is paid ONLY while something is armed. Soft particles enter through
|
|
65
|
+
* {@link armSoftParticleDepth}; translated depth-texture shader programs enter through
|
|
66
|
+
* {@link armSceneDepthTexture}. With both registries empty {@link SoftParticleDepthPass.render}
|
|
67
|
+
* returns before it touches the scene. Armed, per frame per camera it costs: one scene traverse (to find the
|
|
70
68
|
* transparent surfaces to hide), one extra geometry-only scene draw with shadow
|
|
71
69
|
* updates suppressed, and a drawing-buffer-sized depth target
|
|
72
70
|
* (`UnsignedIntType` depth + an unread RGBA8 colour attachment ≈ 8
|
|
@@ -106,6 +104,7 @@ import * as THREE from 'three';
|
|
|
106
104
|
* renderers actually parented under the scene it is rendering.
|
|
107
105
|
*/
|
|
108
106
|
const armed = new Map();
|
|
107
|
+
const depthTextureConsumers = new Map();
|
|
109
108
|
let farDepth;
|
|
110
109
|
/**
|
|
111
110
|
* A 1x1 texture whose red channel is 1.0 — "the depth buffer says nothing is in
|
|
@@ -148,6 +147,22 @@ export function disarmSoftParticleDepth(renderer) {
|
|
|
148
147
|
return;
|
|
149
148
|
renderer.setDepthTexture(farDepthTexture());
|
|
150
149
|
}
|
|
150
|
+
/** Retain one consumer of the same opaque scene-depth image Godot exposes as hint_depth_texture. */
|
|
151
|
+
export function armSceneDepthTexture(consumer) {
|
|
152
|
+
depthTextureConsumers.set(consumer, (depthTextureConsumers.get(consumer) ?? 0) + 1);
|
|
153
|
+
consumer.setDepthTexture(farDepthTexture());
|
|
154
|
+
}
|
|
155
|
+
/** Release one retained Godot depth-texture consumer without leaving a disposed target bound. */
|
|
156
|
+
export function disarmSceneDepthTexture(consumer) {
|
|
157
|
+
const remaining = (depthTextureConsumers.get(consumer) ?? 0) - 1;
|
|
158
|
+
if (remaining > 0) {
|
|
159
|
+
depthTextureConsumers.set(consumer, remaining);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (!depthTextureConsumers.delete(consumer))
|
|
163
|
+
return;
|
|
164
|
+
consumer.setDepthTexture(farDepthTexture());
|
|
165
|
+
}
|
|
151
166
|
/** Test/diagnostic read of the registry — how many renderers a pass would consider. */
|
|
152
167
|
export function armedSoftParticleRendererCount() {
|
|
153
168
|
return armed.size;
|
|
@@ -210,14 +225,14 @@ export function createSoftParticleDepthPass() {
|
|
|
210
225
|
};
|
|
211
226
|
return {
|
|
212
227
|
render(renderer, scene, camera) {
|
|
213
|
-
if (armed.size === 0)
|
|
228
|
+
if (armed.size === 0 && depthTextureConsumers.size === 0)
|
|
214
229
|
return;
|
|
215
230
|
const consumers = [];
|
|
216
231
|
for (const candidate of armed.keys()) {
|
|
217
232
|
if (isUnder(candidate, scene))
|
|
218
233
|
consumers.push(candidate);
|
|
219
234
|
}
|
|
220
|
-
if (consumers.length === 0)
|
|
235
|
+
if (consumers.length === 0 && depthTextureConsumers.size === 0)
|
|
221
236
|
return;
|
|
222
237
|
// See REQUIRED_RENDERER_MEMBERS: a renderer that cannot swap render
|
|
223
238
|
// targets cannot run a prepass, and the frame is worth more than the
|
|
@@ -227,9 +242,9 @@ export function createSoftParticleDepthPass() {
|
|
|
227
242
|
if (!warnedIncapable) {
|
|
228
243
|
warnedIncapable = true;
|
|
229
244
|
// biome-ignore lint/suspicious/noConsole: deliberate loud degrade — the documented alternative to throwing out of the frame
|
|
230
|
-
console.warn(`
|
|
231
|
-
`${String(consumers.length)} particle batch(es)
|
|
232
|
-
'
|
|
245
|
+
console.warn(`opaque scene-depth prepass skipped: this renderer is missing ${missing.join(', ')}. ` +
|
|
246
|
+
`${String(consumers.length)} particle batch(es) and ${String(depthTextureConsumers.size)} ` +
|
|
247
|
+
'shader consumer(s) keep the inert far-depth default. A real ' +
|
|
233
248
|
'WebGLRenderer has these; a design-time settle stand-in does not.');
|
|
234
249
|
}
|
|
235
250
|
return;
|
|
@@ -284,14 +299,22 @@ export function createSoftParticleDepthPass() {
|
|
|
284
299
|
object.visible = true;
|
|
285
300
|
hidden.length = 0;
|
|
286
301
|
}
|
|
302
|
+
const renderedDepth = rt.depthTexture;
|
|
303
|
+
if (renderedDepth === null) {
|
|
304
|
+
throw new Error('opaque scene-depth prepass lost its authored depth texture.');
|
|
305
|
+
}
|
|
287
306
|
for (const consumer of consumers)
|
|
288
|
-
consumer.setDepthTexture(
|
|
307
|
+
consumer.setDepthTexture(renderedDepth);
|
|
308
|
+
for (const consumer of depthTextureConsumers.keys())
|
|
309
|
+
consumer.setDepthTexture(renderedDepth);
|
|
289
310
|
},
|
|
290
311
|
dispose() {
|
|
291
312
|
// Every consumer this pass fed now points at a texture that is about to
|
|
292
313
|
// go away. Hand them the inert default back rather than a disposed one.
|
|
293
314
|
for (const candidate of armed.keys())
|
|
294
315
|
candidate.setDepthTexture(farDepthTexture());
|
|
316
|
+
for (const consumer of depthTextureConsumers.keys())
|
|
317
|
+
consumer.setDepthTexture(farDepthTexture());
|
|
295
318
|
target?.dispose();
|
|
296
319
|
target = null;
|
|
297
320
|
override.dispose();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
/** Temporary developer-facing shading modes. These never become scene data. */
|
|
3
|
-
export type ViewportShadingMode = 'solid' | 'clay' | 'unlit' | 'wireframe' | 'normals' | 'overdraw';
|
|
3
|
+
export type ViewportShadingMode = 'solid' | 'clay' | 'unlit' | 'wireframe' | 'matcap' | 'normals' | 'overdraw';
|
|
4
4
|
/**
|
|
5
5
|
* Applies a render-only material view and restores every native material in a
|
|
6
6
|
* `finally` block. Gameplay and authoring therefore always observe the real
|
|
@@ -9,6 +9,16 @@ export type ViewportShadingMode = 'solid' | 'clay' | 'unlit' | 'wireframe' | 'no
|
|
|
9
9
|
export declare class ViewportShadingRenderer {
|
|
10
10
|
private readonly _derived;
|
|
11
11
|
private readonly _normals;
|
|
12
|
+
/**
|
|
13
|
+
* The clay/sculpt look. Built on FIRST USE, not at construction: the matcap
|
|
14
|
+
* sphere is drawn into a 2D canvas, and every ViewportShadingRenderer that
|
|
15
|
+
* only ever draws `solid` would otherwise pay for a texture nobody samples.
|
|
16
|
+
* `toneMapped: false` for the same reason the overdraw material sets it —
|
|
17
|
+
* a diagnostic look must read exactly as authored, not as the document's
|
|
18
|
+
* exposure and tone curve happen to grade it.
|
|
19
|
+
*/
|
|
20
|
+
private _matcap;
|
|
21
|
+
private _matcapTexture;
|
|
12
22
|
private readonly _overdraw;
|
|
13
23
|
render(scene: THREE.Scene, mode: ViewportShadingMode, draw: () => void, include?: (mesh: THREE.Mesh) => boolean): void;
|
|
14
24
|
dispose(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewport-shading.d.ts","sourceRoot":"","sources":["../../src/render/viewport-shading.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"viewport-shading.d.ts","sourceRoot":"","sources":["../../src/render/viewport-shading.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,+EAA+E;AAC/E,MAAM,MAAM,mBAAmB,GAC3B,OAAO,GACP,MAAM,GACN,OAAO,GACP,WAAW,GACX,QAAQ,GACR,SAAS,GACT,UAAU,CAAC;AAqBf;;;;GAIG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2C;IACpE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAC3D;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO,CAAyC;IACxD,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,QAAQ,CAAC,SAAS,CASvB;IAEH,MAAM,CACJ,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,IAAI,EAAE,mBAAmB,EACzB,IAAI,EAAE,MAAM,IAAI,EAChB,OAAO,GAAE,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,OAAoB,GAClD,IAAI;IA0BP,OAAO,IAAI,IAAI;IAef,OAAO,CAAC,YAAY;CAuDrB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
+
import { createNeutralMatcapTexture } from './matcap-texture';
|
|
2
3
|
function materialColor(material) {
|
|
3
4
|
const color = material.color;
|
|
4
5
|
return color?.clone() ?? new THREE.Color(0xbec7d1);
|
|
@@ -14,6 +15,16 @@ function textureOf(material, key) {
|
|
|
14
15
|
export class ViewportShadingRenderer {
|
|
15
16
|
_derived = new Map();
|
|
16
17
|
_normals = new THREE.MeshNormalMaterial();
|
|
18
|
+
/**
|
|
19
|
+
* The clay/sculpt look. Built on FIRST USE, not at construction: the matcap
|
|
20
|
+
* sphere is drawn into a 2D canvas, and every ViewportShadingRenderer that
|
|
21
|
+
* only ever draws `solid` would otherwise pay for a texture nobody samples.
|
|
22
|
+
* `toneMapped: false` for the same reason the overdraw material sets it —
|
|
23
|
+
* a diagnostic look must read exactly as authored, not as the document's
|
|
24
|
+
* exposure and tone curve happen to grade it.
|
|
25
|
+
*/
|
|
26
|
+
_matcap = null;
|
|
27
|
+
_matcapTexture = null;
|
|
17
28
|
_overdraw = new THREE.MeshBasicMaterial({
|
|
18
29
|
color: 0xffffff,
|
|
19
30
|
transparent: true,
|
|
@@ -56,12 +67,26 @@ export class ViewportShadingRenderer {
|
|
|
56
67
|
this._derived.clear();
|
|
57
68
|
this._normals.dispose();
|
|
58
69
|
this._overdraw.dispose();
|
|
70
|
+
this._matcap?.dispose();
|
|
71
|
+
this._matcapTexture?.dispose();
|
|
72
|
+
this._matcap = null;
|
|
73
|
+
this._matcapTexture = null;
|
|
59
74
|
}
|
|
60
75
|
_materialFor(material, mode) {
|
|
61
76
|
if (mode === 'normals')
|
|
62
77
|
return this._normals;
|
|
63
78
|
if (mode === 'overdraw')
|
|
64
79
|
return this._overdraw;
|
|
80
|
+
if (mode === 'matcap') {
|
|
81
|
+
if (!this._matcap) {
|
|
82
|
+
this._matcapTexture = createNeutralMatcapTexture();
|
|
83
|
+
this._matcap = new THREE.MeshMatcapMaterial({
|
|
84
|
+
matcap: this._matcapTexture,
|
|
85
|
+
toneMapped: false,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return this._matcap;
|
|
89
|
+
}
|
|
65
90
|
let pair = this._derived.get(material);
|
|
66
91
|
if (!pair) {
|
|
67
92
|
const common = {
|
|
@@ -112,14 +112,15 @@ export async function createGameRuntime(config) {
|
|
|
112
112
|
// Universal root host
|
|
113
113
|
// ---------------------------------------------------------------------------
|
|
114
114
|
/** A stand-in `THREE.WebGLRenderer` for headless (`headless:true`) three
|
|
115
|
-
* roots:
|
|
116
|
-
*
|
|
117
|
-
* this only needs to satisfy the handful of calls THIS file itself makes
|
|
115
|
+
* roots: draw submission is inert while native scene/component evaluation
|
|
116
|
+
* still runs. This satisfies Fiber's custom-renderer gate and the calls
|
|
118
117
|
* (`setPixelRatio`/`setClearColor`/`setSize` at mount, `dispose`/
|
|
119
118
|
* `forceContextLoss` at teardown) — never a real GL call. Node conformance
|
|
120
119
|
* tests only; never used when `headless` is left `false`/absent. */
|
|
121
|
-
function createHeadlessRendererStub() {
|
|
120
|
+
function createHeadlessRendererStub(canvas) {
|
|
122
121
|
return {
|
|
122
|
+
domElement: canvas,
|
|
123
|
+
render() { },
|
|
123
124
|
setPixelRatio() { },
|
|
124
125
|
setClearColor() { },
|
|
125
126
|
setSize() { },
|
|
@@ -174,7 +175,7 @@ function disposeMountedRoot(entry, container) {
|
|
|
174
175
|
async function mountOneThreeRoot(spec, ctx) {
|
|
175
176
|
const { game, canvas, w, h, dpr, isBottom, headless, assets, antialias } = ctx;
|
|
176
177
|
const renderer = headless
|
|
177
|
-
? createHeadlessRendererStub()
|
|
178
|
+
? createHeadlessRendererStub(canvas)
|
|
178
179
|
: createHostRenderer(canvas, w, h,
|
|
179
180
|
// The manifest's `rendering.antialias` reaches the WebGL context here and NOWHERE else:
|
|
180
181
|
// `createHostRenderer` passes it straight to the constructor, and the sample count is
|