@forgeax/engine-render 0.1.21 → 0.1.23

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.
Files changed (426) hide show
  1. package/README.md +150 -29
  2. package/dist/assembly/backend-contract.d.ts +13 -0
  3. package/dist/assembly/backend-contract.d.ts.map +1 -1
  4. package/dist/assembly/device-feature-admission.d.ts.map +1 -1
  5. package/dist/assembly/factory.d.ts +14 -6
  6. package/dist/assembly/factory.d.ts.map +1 -1
  7. package/dist/assembly/host-contract.d.ts +10 -0
  8. package/dist/assembly/host-contract.d.ts.map +1 -1
  9. package/dist/authoring.mjs +1 -1
  10. package/dist/{chunk-PCHBPYML.mjs → chunk-4L3P6DT5.mjs} +2 -2
  11. package/dist/chunk-4L3P6DT5.mjs.map +1 -0
  12. package/dist/{chunk-VFPLTKCU.mjs → chunk-4NPUASZR.mjs} +15 -4
  13. package/dist/chunk-4NPUASZR.mjs.map +1 -0
  14. package/dist/chunk-DIYW3M5D.mjs +5085 -0
  15. package/dist/chunk-DIYW3M5D.mjs.map +1 -0
  16. package/dist/chunk-FBC4R44J.mjs +1003 -0
  17. package/dist/chunk-FBC4R44J.mjs.map +1 -0
  18. package/dist/{chunk-FS2KNUQH.mjs → chunk-FF7K3FSO.mjs} +253 -489
  19. package/dist/chunk-FF7K3FSO.mjs.map +1 -0
  20. package/dist/chunk-HZUPSYW7.mjs +1104 -0
  21. package/dist/chunk-HZUPSYW7.mjs.map +1 -0
  22. package/dist/{chunk-6OPXDQ2E.mjs → chunk-QODA5UKU.mjs} +33 -294
  23. package/dist/chunk-QODA5UKU.mjs.map +1 -0
  24. package/dist/chunk-YALPS44A.mjs +296 -0
  25. package/dist/chunk-YALPS44A.mjs.map +1 -0
  26. package/dist/{chunk-5YADUCA7.mjs → chunk-ZUWKAZ2I.mjs} +585 -991
  27. package/dist/chunk-ZUWKAZ2I.mjs.map +1 -0
  28. package/dist/cluster-binner.d.ts +5 -0
  29. package/dist/cluster-binner.d.ts.map +1 -1
  30. package/dist/components/index.d.ts +3 -0
  31. package/dist/components/index.d.ts.map +1 -1
  32. package/dist/components/light-helpers.d.ts +4 -0
  33. package/dist/components/light-helpers.d.ts.map +1 -1
  34. package/dist/components/light-probe.d.ts +9 -0
  35. package/dist/components/light-probe.d.ts.map +1 -0
  36. package/dist/components/rect-area-light.d.ts +12 -0
  37. package/dist/components/rect-area-light.d.ts.map +1 -0
  38. package/dist/components/scene-instance.d.ts +4 -0
  39. package/dist/components/scene-instance.d.ts.map +1 -1
  40. package/dist/components/spot-light.d.ts +3 -0
  41. package/dist/components/spot-light.d.ts.map +1 -1
  42. package/dist/construct-renderer.mjs +10437 -10044
  43. package/dist/construct-renderer.mjs.map +1 -1
  44. package/dist/device/gpu-residency.d.ts +8 -1
  45. package/dist/device/gpu-residency.d.ts.map +1 -1
  46. package/dist/device/lifecycle-transaction.d.ts +2 -0
  47. package/dist/device/lifecycle-transaction.d.ts.map +1 -0
  48. package/dist/environment/lifecycle.d.ts.map +1 -1
  49. package/dist/errors/gpu-driven.d.ts +26 -0
  50. package/dist/errors/gpu-driven.d.ts.map +1 -0
  51. package/dist/errors/index.d.ts +1 -0
  52. package/dist/errors/index.d.ts.map +1 -1
  53. package/dist/errors/recover.d.ts +9 -1
  54. package/dist/errors/recover.d.ts.map +1 -1
  55. package/dist/errors/render.d.ts +26 -1
  56. package/dist/errors/render.d.ts.map +1 -1
  57. package/dist/extract/gpu-driven.d.ts +50 -0
  58. package/dist/extract/gpu-driven.d.ts.map +1 -0
  59. package/dist/extract/visibility.d.ts.map +1 -1
  60. package/dist/gpu-driven/batch-topology.d.ts +34 -0
  61. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  62. package/dist/gpu-driven/prepared-draw.d.ts +63 -0
  63. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -0
  64. package/dist/gpu-driven/production-raster.d.ts +98 -2
  65. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  66. package/dist/gpu-driven/view-gpu.d.ts +64 -1
  67. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  68. package/dist/gpu-scene-schema.d.ts +14 -0
  69. package/dist/gpu-scene-schema.d.ts.map +1 -1
  70. package/dist/gpu-scene.d.ts +8 -1
  71. package/dist/gpu-scene.d.ts.map +1 -1
  72. package/dist/gpu-usage.d.ts +0 -1
  73. package/dist/gpu-usage.d.ts.map +1 -1
  74. package/dist/hdrp-buffers.d.ts +3 -3
  75. package/dist/hdrp-buffers.d.ts.map +1 -1
  76. package/dist/index.d.ts +12 -1
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.mjs +90 -5
  79. package/dist/index.mjs.map +1 -1
  80. package/dist/inspection-types.d.ts +163 -1
  81. package/dist/inspection-types.d.ts.map +1 -1
  82. package/dist/internal.d.ts +9 -0
  83. package/dist/internal.d.ts.map +1 -1
  84. package/dist/internal.mjs +23 -2
  85. package/dist/internal.mjs.map +1 -1
  86. package/dist/light-buffer-layout.d.ts +58 -149
  87. package/dist/light-buffer-layout.d.ts.map +1 -1
  88. package/dist/materials.d.ts.map +1 -1
  89. package/dist/pbr-pipeline.d.ts +26 -12
  90. package/dist/pbr-pipeline.d.ts.map +1 -1
  91. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  92. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -1
  93. package/dist/pipeline/standard-lighting/light-frame.d.ts +3 -3
  94. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -1
  95. package/dist/pipeline/standard-lighting/topology.d.ts +1 -1
  96. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -1
  97. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -1
  98. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  99. package/dist/pipeline-builder.d.ts +2 -0
  100. package/dist/pipeline-builder.d.ts.map +1 -1
  101. package/dist/pipeline-spec.d.ts +1 -1
  102. package/dist/pipeline-spec.d.ts.map +1 -1
  103. package/dist/plugin.d.ts.map +1 -1
  104. package/dist/prepare/extended-lighting/ltc-resources.d.ts +31 -0
  105. package/dist/prepare/extended-lighting/ltc-resources.d.ts.map +1 -0
  106. package/dist/prepare/extended-lighting/resources.d.ts +72 -0
  107. package/dist/prepare/extended-lighting/resources.d.ts.map +1 -0
  108. package/dist/prepare/extended-lighting/spot-modifiers.d.ts +42 -0
  109. package/dist/prepare/extended-lighting/spot-modifiers.d.ts.map +1 -0
  110. package/dist/prepare/extended-lighting/state.d.ts +24 -0
  111. package/dist/prepare/extended-lighting/state.d.ts.map +1 -0
  112. package/dist/record/frame-lighting.d.ts +8 -6
  113. package/dist/record/frame-lighting.d.ts.map +1 -1
  114. package/dist/record/frame-snapshot.d.ts +50 -10
  115. package/dist/record/frame-snapshot.d.ts.map +1 -1
  116. package/dist/record/frame.d.ts +7 -3
  117. package/dist/record/frame.d.ts.map +1 -1
  118. package/dist/record/gpu-timing.d.ts +19 -7
  119. package/dist/record/gpu-timing.d.ts.map +1 -1
  120. package/dist/record/helpers.d.ts +0 -20
  121. package/dist/record/helpers.d.ts.map +1 -1
  122. package/dist/record/main-pass-geometry.d.ts +6 -1
  123. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  124. package/dist/record/main-pass-material.d.ts +3 -1
  125. package/dist/record/main-pass-material.d.ts.map +1 -1
  126. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  127. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  128. package/dist/record/render-context.d.ts +57 -6
  129. package/dist/record/render-context.d.ts.map +1 -1
  130. package/dist/record/shadow-pass.d.ts.map +1 -1
  131. package/dist/record/typed-frame-graph.d.ts +49 -2
  132. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  133. package/dist/record/view-ubo.d.ts +1 -2
  134. package/dist/record/view-ubo.d.ts.map +1 -1
  135. package/dist/reflection/inspection.d.ts +10 -0
  136. package/dist/reflection/inspection.d.ts.map +1 -0
  137. package/dist/reflection/projection.d.ts +49 -0
  138. package/dist/reflection/projection.d.ts.map +1 -1
  139. package/dist/reflection/record-owner.d.ts +60 -0
  140. package/dist/reflection/record-owner.d.ts.map +1 -0
  141. package/dist/render-contract.d.ts +14 -8
  142. package/dist/render-contract.d.ts.map +1 -1
  143. package/dist/render-pipeline.d.ts +7 -0
  144. package/dist/render-pipeline.d.ts.map +1 -1
  145. package/dist/render-system-extract.d.ts +104 -16
  146. package/dist/render-system-extract.d.ts.map +1 -1
  147. package/dist/render-system.d.ts +12 -1
  148. package/dist/render-system.d.ts.map +1 -1
  149. package/dist/scene/probe-blend-record.d.ts +22 -0
  150. package/dist/scene/probe-blend-record.d.ts.map +1 -0
  151. package/dist/scene/probe-blend.d.ts +142 -0
  152. package/dist/scene/probe-blend.d.ts.map +1 -0
  153. package/dist/scene/render-scene-types.d.ts +0 -6
  154. package/dist/scene/render-scene-types.d.ts.map +1 -1
  155. package/dist/scene/render-scene.d.ts +103 -9
  156. package/dist/scene/render-scene.d.ts.map +1 -1
  157. package/dist/scene/visibility/bounds.d.ts +20 -0
  158. package/dist/scene/visibility/bounds.d.ts.map +1 -0
  159. package/dist/scene/visibility/budget.d.ts +16 -0
  160. package/dist/scene/visibility/budget.d.ts.map +1 -0
  161. package/dist/scene/visibility/facet.d.ts +73 -0
  162. package/dist/scene/visibility/facet.d.ts.map +1 -0
  163. package/dist/scene/visibility/gpu-frame-timing.d.ts +41 -0
  164. package/dist/scene/visibility/gpu-frame-timing.d.ts.map +1 -0
  165. package/dist/scene/visibility/gpu-lod.d.ts +46 -0
  166. package/dist/scene/visibility/gpu-lod.d.ts.map +1 -0
  167. package/dist/scene/visibility/inspection.d.ts +132 -0
  168. package/dist/scene/visibility/inspection.d.ts.map +1 -0
  169. package/dist/scene/visibility/lod-selector.d.ts +25 -0
  170. package/dist/scene/visibility/lod-selector.d.ts.map +1 -0
  171. package/dist/scene/visibility/occlusion-confidence.d.ts +81 -0
  172. package/dist/scene/visibility/occlusion-confidence.d.ts.map +1 -0
  173. package/dist/scene/visibility/occlusion-pass.d.ts +57 -0
  174. package/dist/scene/visibility/occlusion-pass.d.ts.map +1 -0
  175. package/dist/scene/visibility/occlusion-query-pool.d.ts +57 -0
  176. package/dist/scene/visibility/occlusion-query-pool.d.ts.map +1 -0
  177. package/dist/scene/visibility/occlusion-runtime.d.ts +96 -0
  178. package/dist/scene/visibility/occlusion-runtime.d.ts.map +1 -0
  179. package/dist/scene/visibility/types.d.ts +34 -0
  180. package/dist/scene/visibility/types.d.ts.map +1 -0
  181. package/dist/ssr/admission.d.ts +122 -0
  182. package/dist/ssr/admission.d.ts.map +1 -0
  183. package/dist/ssr/composition.d.ts +32 -0
  184. package/dist/ssr/composition.d.ts.map +1 -0
  185. package/dist/ssr/errors.d.ts +39 -0
  186. package/dist/ssr/errors.d.ts.map +1 -0
  187. package/dist/ssr/identity.d.ts +13 -0
  188. package/dist/ssr/identity.d.ts.map +1 -0
  189. package/dist/systems/skin-palette-allocator.d.ts +1 -1
  190. package/dist/temporal/frame-coordinator.d.ts +13 -0
  191. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  192. package/dist/temporal/frame.d.ts +2 -0
  193. package/dist/temporal/frame.d.ts.map +1 -1
  194. package/dist/temporal/index.mjs +6 -5
  195. package/dist/temporal/view.d.ts +7 -0
  196. package/dist/temporal/view.d.ts.map +1 -1
  197. package/dist/tilemap-chunk-extract-system.d.ts +1 -1
  198. package/dist/typed-render-graph-primitives.d.ts +4 -0
  199. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  200. package/dist/volume/passes.d.ts +8 -4
  201. package/dist/volume/passes.d.ts.map +1 -1
  202. package/package.json +20 -20
  203. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +5 -0
  204. package/src/__tests__/detached-inspection.integration.test.ts +6 -0
  205. package/src/__tests__/device-feature-admission.unit.test.ts +13 -1
  206. package/src/__tests__/direct-light-snapshot.unit.test.ts +59 -3
  207. package/src/__tests__/environment-generation.integration.test.ts +16 -0
  208. package/src/__tests__/evidence-identity.ts +13 -0
  209. package/src/__tests__/evidence-identity.unit.test.ts +24 -0
  210. package/src/__tests__/extended-lighting-recovery.browser.test.ts +14 -0
  211. package/src/__tests__/extended-lighting-recovery.dawn.test.ts +14 -0
  212. package/src/__tests__/extended-lighting-recovery.integration.test.ts +81 -0
  213. package/src/__tests__/extended-lighting-resources.unit.test.ts +51 -0
  214. package/src/__tests__/extended-lighting-zero-feature.integration.test.ts +52 -0
  215. package/src/__tests__/factory-contract.integration.test.ts +33 -0
  216. package/src/__tests__/frame-observation.contract.test.ts +15 -0
  217. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +146 -0
  218. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +1 -0
  219. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +1 -0
  220. package/src/__tests__/gpu-driven-production.integration.test.ts +572 -9
  221. package/src/__tests__/gpu-driven-scaling.unit.test.ts +66 -2
  222. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +26 -1
  223. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +89 -2
  224. package/src/__tests__/gpu-driven-view.browser.test.ts +3 -3
  225. package/src/__tests__/gpu-driven-view.dawn.test.ts +3 -3
  226. package/src/__tests__/gpu-driven-view.unit.test.ts +50 -0
  227. package/src/__tests__/gpu-lod-evidence.ts +188 -0
  228. package/src/__tests__/gpu-lod-fallback.integration.test.ts +10 -0
  229. package/src/__tests__/gpu-lod-indirect.integration.test.ts +40 -0
  230. package/src/__tests__/gpu-lod-parity.dawn.test.ts +29 -0
  231. package/src/__tests__/gpu-lod-readiness.integration.test.ts +52 -0
  232. package/src/__tests__/gpu-lod-schema.unit.test.ts +66 -0
  233. package/src/__tests__/gpu-lod-selector.unit.test.ts +28 -0
  234. package/src/__tests__/gpu-lod-silhouette.browser.test.ts +13 -0
  235. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +66 -1
  236. package/src/__tests__/gpu-scene.dawn.test.ts +8 -1
  237. package/src/__tests__/gpu-scene.unit.test.ts +49 -3
  238. package/src/__tests__/light-buffer-layout.unit.test.ts +113 -3
  239. package/src/__tests__/light-inspection.unit.test.ts +55 -0
  240. package/src/__tests__/light-resource-error.unit.test.ts +43 -0
  241. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +109 -0
  242. package/src/__tests__/lod-bounds.unit.test.ts +42 -0
  243. package/src/__tests__/lod-cpu-lane.integration.test.ts +55 -0
  244. package/src/__tests__/lod-cpu-no-change.perf.test.ts +19 -0
  245. package/src/__tests__/lod-gpu-frame-timing.unit.test.ts +49 -0
  246. package/src/__tests__/lod-multi-view.integration.test.ts +63 -0
  247. package/src/__tests__/lod-occlusion-device-loss.integration.test.ts +27 -0
  248. package/src/__tests__/lod-occlusion-final-decision.integration.test.ts +47 -0
  249. package/src/__tests__/lod-occlusion-inspection.integration.test.ts +217 -0
  250. package/src/__tests__/lod-occlusion-inspection.schema.test-d.ts +14 -0
  251. package/src/__tests__/lod-occlusion-inspection.unit.test.ts +72 -0
  252. package/src/__tests__/lod-occlusion-visual-evidence.ts +91 -0
  253. package/src/__tests__/lod-occlusion.browser.test.ts +15 -0
  254. package/src/__tests__/lod-occlusion.dawn.test.ts +20 -0
  255. package/src/__tests__/lod-selector.profile.test.ts +35 -0
  256. package/src/__tests__/lod-selector.unit.test.ts +68 -0
  257. package/src/__tests__/lod-visibility-identity.unit.test.ts +198 -0
  258. package/src/__tests__/lod-visibility-lifecycle.integration.test.ts +132 -0
  259. package/src/__tests__/ltc-resources.unit.test.ts +32 -0
  260. package/src/__tests__/material-contract-inventory.unit.test.ts +17 -0
  261. package/src/__tests__/occlusion-confidence.unit.test.ts +168 -0
  262. package/src/__tests__/occlusion-invalidation.integration.test.ts +37 -0
  263. package/src/__tests__/occlusion-pass-routing.unit.test.ts +16 -0
  264. package/src/__tests__/occlusion-pass.dawn.test.ts +20 -0
  265. package/src/__tests__/occlusion-pass.integration.test.ts +43 -0
  266. package/src/__tests__/occlusion-pass.rhi-null.test.ts +22 -0
  267. package/src/__tests__/occlusion-query-pool.rhi-null.test.ts +21 -0
  268. package/src/__tests__/occlusion-query-pool.unit.test.ts +95 -0
  269. package/src/__tests__/occlusion-query-ticket.integration.test.ts +47 -0
  270. package/src/__tests__/occlusion-query.dawn.test.ts +16 -0
  271. package/src/__tests__/occlusion-query.evidence.ts +178 -0
  272. package/src/__tests__/occlusion-query.rhi-null.test.ts +31 -0
  273. package/src/__tests__/occlusion-runtime.unit.test.ts +120 -0
  274. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +196 -0
  275. package/src/__tests__/probe-bindings.unit.test.ts +200 -0
  276. package/src/__tests__/probe-blend-numeric.unit.test.ts +67 -0
  277. package/src/__tests__/probe-blend-oracle.unit.test.ts +136 -0
  278. package/src/__tests__/probe-capacity.integration.test.ts +97 -0
  279. package/src/__tests__/probe-recovery.integration.test.ts +104 -0
  280. package/src/__tests__/probe-scene-dirty.integration.test.ts +211 -0
  281. package/src/__tests__/profiler-phase-catalog.test.ts +4 -1
  282. package/src/__tests__/profiler-phase-token.test.ts +1 -0
  283. package/src/__tests__/rect-area-boundary.unit.test.ts +24 -0
  284. package/src/__tests__/reflection-fallback-graph.unit.test.ts +67 -0
  285. package/src/__tests__/reflection-fallback-inspection.unit.test.ts +77 -0
  286. package/src/__tests__/reflection-fallback-lifecycle.integration.test.ts +21 -0
  287. package/src/__tests__/reflection-fallback-projection.unit.test.ts +90 -0
  288. package/src/__tests__/reflection-fallback-source.unit.test.ts +32 -0
  289. package/src/__tests__/reflection-probe-owner-placement.unit.test.ts +39 -0
  290. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +120 -0
  291. package/src/__tests__/render-error-code-owner.test-d.ts +1 -0
  292. package/src/__tests__/render-feature-docs.unit.test.ts +12 -7
  293. package/src/__tests__/render-graph-fallback.integration.test.ts +24 -0
  294. package/src/__tests__/render-perf/extended-lighting.bench.test.ts +66 -0
  295. package/src/__tests__/render-scene-projection.unit.test.ts +447 -18
  296. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
  297. package/src/__tests__/skin-motion-regression.unit.test.ts +22 -0
  298. package/src/__tests__/skinned-shadow-caster.test.ts +2 -2
  299. package/src/__tests__/spot-modifier-projection.unit.test.ts +70 -0
  300. package/src/__tests__/ssr-admission-matrix.integration.test.ts +206 -0
  301. package/src/__tests__/ssr-composition.unit.test.ts +46 -0
  302. package/src/__tests__/ssr-fallback-zero-work.bench.test.ts +94 -0
  303. package/src/__tests__/ssr-recovery-errors.unit.test.ts +58 -0
  304. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +67 -0
  305. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +7 -0
  306. package/src/__tests__/standard-lighting-inspection.integration.test.ts +1 -1
  307. package/src/__tests__/standard-lighting-write.unit.test.ts +66 -2
  308. package/src/__tests__/temporal-fallback-generation.integration.test.ts +16 -0
  309. package/src/__tests__/temporal-view.unit.test.ts +3 -3
  310. package/src/__tests__/transmission-prewarm.unit.test.ts +69 -0
  311. package/src/__tests__/visibility-budget.integration.test.ts +140 -0
  312. package/src/__tests__/visibility-budget.unit.test.ts +70 -0
  313. package/src/__tests__/visibility-extract.integration.test.ts +11 -6
  314. package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +6 -3
  315. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +31 -28
  316. package/src/assembly/backend-contract.ts +13 -0
  317. package/src/assembly/device-feature-admission.ts +16 -9
  318. package/src/assembly/factory.ts +547 -93
  319. package/src/assembly/host-contract.ts +10 -0
  320. package/src/cluster-binner.ts +31 -0
  321. package/src/components/__tests__/lighting-authoring.unit.test.ts +39 -0
  322. package/src/components/__tests__/rect-area-light.unit.test.ts +33 -0
  323. package/src/components/index.ts +3 -0
  324. package/src/components/light-helpers.ts +52 -1
  325. package/src/components/light-probe.ts +13 -0
  326. package/src/components/rect-area-light.ts +15 -0
  327. package/src/components/scene-instance.ts +6 -0
  328. package/src/components/spot-light.ts +3 -0
  329. package/src/device/__tests__/extended-lighting-recovery.unit.test.ts +24 -0
  330. package/src/device/gpu-residency.ts +140 -9
  331. package/src/device/lifecycle-transaction.ts +12 -0
  332. package/src/environment/lifecycle.ts +8 -1
  333. package/src/errors/gpu-driven.ts +92 -0
  334. package/src/errors/index.ts +1 -0
  335. package/src/errors/recover.ts +32 -0
  336. package/src/errors/render.ts +55 -1
  337. package/src/extract/camera.ts +3 -3
  338. package/src/extract/gpu-driven.ts +108 -0
  339. package/src/extract/visibility.ts +0 -23
  340. package/src/gpu-driven/batch-topology.ts +206 -28
  341. package/src/gpu-driven/prepared-draw.ts +208 -0
  342. package/src/gpu-driven/production-raster.ts +953 -41
  343. package/src/gpu-driven/view-gpu.ts +411 -29
  344. package/src/gpu-scene-schema.ts +13 -0
  345. package/src/gpu-scene.ts +134 -65
  346. package/src/gpu-usage.ts +0 -1
  347. package/src/hdrp-buffers.ts +6 -6
  348. package/src/index.ts +74 -0
  349. package/src/inspection-types.ts +220 -1
  350. package/src/internal.ts +38 -0
  351. package/src/light-buffer-layout.ts +154 -324
  352. package/src/materials.ts +16 -2
  353. package/src/pbr-pipeline.ts +151 -45
  354. package/src/pipeline/standard-forward-lane.ts +47 -0
  355. package/src/pipeline/standard-lighting/graph.ts +2 -1
  356. package/src/pipeline/standard-lighting/light-frame.ts +3 -2
  357. package/src/pipeline/standard-lighting/topology.ts +1 -1
  358. package/src/pipeline/standard-lighting/transport.ts +2 -1
  359. package/src/pipeline/standard-pipeline.ts +2 -0
  360. package/src/pipeline-builder.ts +5 -2
  361. package/src/pipeline-spec.ts +12 -1
  362. package/src/plugin.ts +4 -0
  363. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +56 -0
  364. package/src/prepare/extended-lighting/ltc-resources.ts +136 -0
  365. package/src/prepare/extended-lighting/resources.ts +389 -0
  366. package/src/prepare/extended-lighting/spot-modifiers.ts +194 -0
  367. package/src/prepare/extended-lighting/state.ts +92 -0
  368. package/src/record/__tests__/gpu-timing.unit.test.ts +177 -0
  369. package/src/record/__tests__/temporal-payload.unit.test.ts +23 -1
  370. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +20 -1
  371. package/src/record/frame-lighting.ts +252 -53
  372. package/src/record/frame-snapshot.ts +57 -12
  373. package/src/record/frame.ts +410 -93
  374. package/src/record/gpu-timing.ts +108 -44
  375. package/src/record/helpers.ts +0 -58
  376. package/src/record/main-pass-geometry.ts +204 -39
  377. package/src/record/main-pass-material.ts +8 -1
  378. package/src/record/main-pass-sprite-draws.ts +52 -85
  379. package/src/record/mesh-ssbo.ts +47 -36
  380. package/src/record/render-context.ts +65 -4
  381. package/src/record/shadow-pass.ts +66 -40
  382. package/src/record/typed-frame-graph.ts +225 -83
  383. package/src/record/view-ubo.ts +14 -24
  384. package/src/reflection/inspection.ts +67 -0
  385. package/src/reflection/projection.ts +196 -1
  386. package/src/reflection/record-owner.ts +1283 -0
  387. package/src/render-contract.ts +17 -5
  388. package/src/render-pipeline.ts +5 -0
  389. package/src/render-system-extract.ts +493 -134
  390. package/src/render-system.ts +811 -615
  391. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +36 -0
  392. package/src/scene/probe-blend-record.ts +54 -0
  393. package/src/scene/probe-blend.ts +813 -0
  394. package/src/scene/render-scene-types.ts +0 -7
  395. package/src/scene/render-scene.ts +848 -183
  396. package/src/scene/visibility/bounds.ts +57 -0
  397. package/src/scene/visibility/budget.ts +40 -0
  398. package/src/scene/visibility/facet.ts +400 -0
  399. package/src/scene/visibility/gpu-frame-timing.ts +101 -0
  400. package/src/scene/visibility/gpu-lod.ts +119 -0
  401. package/src/scene/visibility/inspection.ts +313 -0
  402. package/src/scene/visibility/lod-selector.ts +84 -0
  403. package/src/scene/visibility/occlusion-confidence.ts +478 -0
  404. package/src/scene/visibility/occlusion-pass.ts +165 -0
  405. package/src/scene/visibility/occlusion-query-pool.ts +178 -0
  406. package/src/scene/visibility/occlusion-runtime.ts +672 -0
  407. package/src/scene/visibility/types.ts +50 -0
  408. package/src/ssr/admission.ts +451 -0
  409. package/src/ssr/composition.ts +73 -0
  410. package/src/ssr/errors.ts +76 -0
  411. package/src/ssr/identity.ts +12 -0
  412. package/src/systems/skin-palette-allocator.ts +1 -1
  413. package/src/temporal/frame-coordinator.ts +26 -0
  414. package/src/temporal/frame.ts +14 -1
  415. package/src/temporal/view.ts +11 -0
  416. package/src/tilemap-chunk-extract-system.ts +4 -4
  417. package/src/typed-render-graph-primitives.ts +48 -0
  418. package/src/volume/passes.ts +46 -49
  419. package/dist/.tsbuildinfo +0 -1
  420. package/dist/chunk-5YADUCA7.mjs.map +0 -1
  421. package/dist/chunk-6OPXDQ2E.mjs.map +0 -1
  422. package/dist/chunk-BXBQQKFQ.mjs +0 -67
  423. package/dist/chunk-BXBQQKFQ.mjs.map +0 -1
  424. package/dist/chunk-FS2KNUQH.mjs.map +0 -1
  425. package/dist/chunk-PCHBPYML.mjs.map +0 -1
  426. package/dist/chunk-VFPLTKCU.mjs.map +0 -1
@@ -70,6 +70,32 @@ export interface TemporalFrameReceipt<T = unknown> {
70
70
  readonly historyDirection: 'a-to-b' | 'b-to-a';
71
71
  }
72
72
 
73
+ export type ReflectionFallbackTemporalReset =
74
+ | { readonly reset: false }
75
+ | { readonly reset: true; readonly reason: 'reflection-fallback-generation' };
76
+
77
+ /** Maps committed producer generations into the existing temporal reset seam. */
78
+ export function resolveReflectionFallbackTemporalReset(
79
+ previousGeneration: number | undefined,
80
+ nextGeneration: number | undefined,
81
+ ): ReflectionFallbackTemporalReset {
82
+ if (previousGeneration === undefined || nextGeneration === undefined) return { reset: false };
83
+ return previousGeneration === nextGeneration
84
+ ? { reset: false }
85
+ : { reset: true, reason: 'reflection-fallback-generation' };
86
+ }
87
+
88
+ /**
89
+ * Keeps SSR admission on the existing producer-generation reset seam. The
90
+ * admission path never allocates or resolves temporal history itself.
91
+ */
92
+ export function resolveSsrAdmissionTemporalReset(
93
+ previousGeneration: number | undefined,
94
+ nextGeneration: number | undefined,
95
+ ): ReflectionFallbackTemporalReset {
96
+ return resolveReflectionFallbackTemporalReset(previousGeneration, nextGeneration);
97
+ }
98
+
73
99
  function failure(code: TemporalFrameErrorCode, hint: string): TemporalFrameError {
74
100
  return {
75
101
  code,
@@ -44,6 +44,8 @@ export interface TemporalFrameTransaction {
44
44
  stage(input: TemporalFrameInput): void;
45
45
  commit(submit: TemporalSubmitResult): Result<TemporalFrame, TemporalFrameSubmitError>;
46
46
  snapshot(): TemporalFrame;
47
+ /** Drop accepted/staged history after a producer or device generation cut. */
48
+ reset(reason?: Extract<TemporalResetReason, 'signature-change' | 'device-recovery'>): void;
47
49
  }
48
50
 
49
51
  function copyInput(input: TemporalFrameInput): TemporalFrameInput {
@@ -82,6 +84,7 @@ export function createTemporalFrameTransaction(options: {
82
84
  let accepted: TemporalFrame | undefined;
83
85
  let staged: TemporalFrameInput | undefined;
84
86
  let historyEpoch = 0;
87
+ let pendingResetReason: Exclude<TemporalResetReason, 'none' | 'queue-submit-failed'> | undefined;
85
88
 
86
89
  return {
87
90
  stage(input) {
@@ -96,7 +99,7 @@ export function createTemporalFrameTransaction(options: {
96
99
  return err(new TemporalFrameSubmitError('queue-submit-failed'));
97
100
  }
98
101
 
99
- const resetReason = submit.resetReason ?? staged.resetReason ?? 'none';
102
+ const resetReason = submit.resetReason ?? staged.resetReason ?? pendingResetReason ?? 'none';
100
103
  const shouldReset = resetReason !== 'none';
101
104
  if (shouldReset) historyEpoch += 1;
102
105
  const next: TemporalFrame = {
@@ -117,6 +120,7 @@ export function createTemporalFrameTransaction(options: {
117
120
  };
118
121
  accepted = next;
119
122
  staged = undefined;
123
+ pendingResetReason = undefined;
120
124
  return ok(copyFrame(next));
121
125
  },
122
126
  snapshot() {
@@ -124,5 +128,14 @@ export function createTemporalFrameTransaction(options: {
124
128
  throw new Error('TemporalFrame snapshot is unavailable before commit');
125
129
  return copyFrame(accepted);
126
130
  },
131
+ reset(reason = 'signature-change') {
132
+ accepted = undefined;
133
+ staged = undefined;
134
+ historyEpoch += 1;
135
+ // The reason is carried into the next accepted frame while clearing the
136
+ // committed frame prevents stale motion vectors from crossing the
137
+ // producer/device boundary.
138
+ pendingResetReason = reason;
139
+ },
127
140
  };
128
141
  }
@@ -38,6 +38,8 @@ export interface TemporalViewInput {
38
38
  readonly historyValid?: boolean;
39
39
  readonly currentUnjitteredViewProjection?: ArrayLike<number> | undefined;
40
40
  readonly previousUnjitteredViewProjection?: ArrayLike<number> | undefined;
41
+ readonly currentCameraPosition?: readonly [number, number, number] | undefined;
42
+ readonly previousCameraPosition?: readonly [number, number, number] | undefined;
41
43
  readonly resetReason?: TemporalResetReason | undefined;
42
44
  }
43
45
 
@@ -55,6 +57,8 @@ interface TemporalViewSnapshot {
55
57
  readonly historyValid: boolean;
56
58
  readonly currentUnjitteredViewProjection: ArrayLike<number> | undefined;
57
59
  readonly previousUnjitteredViewProjection: ArrayLike<number> | undefined;
60
+ readonly currentCameraPosition: readonly [number, number, number] | undefined;
61
+ readonly previousCameraPosition: readonly [number, number, number] | undefined;
58
62
  readonly resetReason: TemporalResetReason | undefined;
59
63
  }
60
64
 
@@ -70,6 +74,9 @@ export interface TemporalView {
70
74
  /** Unjittered matrices are supplied by the renderer projection owner. */
71
75
  readonly currentUnjitteredViewProjection: ArrayLike<number> | undefined;
72
76
  readonly previousUnjitteredViewProjection: ArrayLike<number> | undefined;
77
+ /** Camera origins follow the same accepted-submit boundary as the matrices. */
78
+ readonly currentCameraPosition: readonly [number, number, number] | undefined;
79
+ readonly previousCameraPosition: readonly [number, number, number] | undefined;
73
80
  readonly currentProjection: 'jittered' | 'unjittered';
74
81
  readonly previousProjection: 'unjittered';
75
82
  readonly historyRequired: boolean;
@@ -112,6 +119,8 @@ export function createTemporalView(input: TemporalViewInput): TemporalView {
112
119
  historyValid: input.historyValid ?? false,
113
120
  currentUnjitteredViewProjection: input.currentUnjitteredViewProjection,
114
121
  previousUnjitteredViewProjection: input.previousUnjitteredViewProjection,
122
+ currentCameraPosition: input.currentCameraPosition,
123
+ previousCameraPosition: input.previousCameraPosition,
115
124
  resetReason: input.resetReason,
116
125
  });
117
126
  const taa = input.antialias === 'taa';
@@ -135,6 +144,8 @@ export function createTemporalView(input: TemporalViewInput): TemporalView {
135
144
  temporalFrameIndex: frameIndex,
136
145
  currentUnjitteredViewProjection: input.currentUnjitteredViewProjection,
137
146
  previousUnjitteredViewProjection: input.previousUnjitteredViewProjection,
147
+ currentCameraPosition: input.currentCameraPosition,
148
+ previousCameraPosition: input.previousCameraPosition,
138
149
  currentProjection: taa ? 'jittered' : 'unjittered',
139
150
  previousProjection: 'unjittered',
140
151
  historyRequired: taa,
@@ -57,7 +57,7 @@ import {
57
57
  import type { EntityHandle, World } from '@forgeax/engine-ecs';
58
58
  import { decodeTileBits } from '@forgeax/engine-graphics-extras';
59
59
  import { type box3, frustum, mat4 } from '@forgeax/engine-math';
60
- import { ChildOf, Children, Transform } from '@forgeax/engine-scene';
60
+ import { ChildOf, Children, GlobalTransform, Transform } from '@forgeax/engine-scene';
61
61
  import {
62
62
  type Handle,
63
63
  type MaterialAsset,
@@ -874,13 +874,13 @@ function bucketTileLayer(
874
874
  * cull paths use byte-identical planes (charter P4 consistent abstraction).
875
875
  */
876
876
  function buildCameraFrustumPlanes(world: World): frustum.Frustum | null {
877
- const query = world.query({ with: [Camera, Transform] }).unwrap();
877
+ const query = world.query({ with: [Camera, Transform, GlobalTransform] }).unwrap();
878
878
  let result: frustum.Frustum | null = null;
879
879
  for (const row of query) {
880
880
  const camEntity = row.entity;
881
881
 
882
882
  const camRes = world.get(camEntity, Camera);
883
- const trRes = world.get(camEntity, Transform);
883
+ const trRes = world.get(camEntity, GlobalTransform);
884
884
  if (!camRes.ok || !trRes.ok) continue;
885
885
 
886
886
  const cam = camRes.value;
@@ -1081,7 +1081,7 @@ function evictDeadPerCellStreamingCaches(work: readonly LayerWork[], world: Worl
1081
1081
  /**
1082
1082
  * Walk every TileLayer ChildOf-ing a Tilemap, extract its non-zero cells
1083
1083
  * into derived render entities. A Renderer attaches this system to FrameEnd;
1084
- * World's final publication then resolves newly-created Transform.world values before the
1084
+ * World's final publication then resolves newly-created GlobalTransform.world values before the
1085
1085
  * read-only render walk begins.
1086
1086
  *
1087
1087
  * Two paths based on `TileLayer.sortScope`:
@@ -34,6 +34,7 @@ import {
34
34
  } from './render-graph-primitives';
35
35
  import type { RenderPipelineFrame, RenderPipelineGpuDrivenProjection } from './render-pipeline';
36
36
  import { createRenderPipelineTarget, type RenderPipelineTarget } from './render-pipeline';
37
+ import type { OcclusionFrameProjection } from './scene/visibility/occlusion-runtime';
37
38
  import {
38
39
  getTemporalBindGroupResources,
39
40
  getTemporalGpuState,
@@ -136,6 +137,7 @@ export interface TypedScenePassOptions {
136
137
  readonly transmissionBackdrop?: GraphTextureView | undefined;
137
138
  readonly extraAccesses?: readonly GraphAccess[] | undefined;
138
139
  readonly gpuDriven?: RenderPipelineGpuDrivenProjection | undefined;
140
+ readonly occlusion?: OcclusionFrameProjection | undefined;
139
141
  }
140
142
 
141
143
  export function addTypedScenePass(
@@ -187,6 +189,7 @@ export function addTypedScenePass(
187
189
  stencilLoadOp: options.depthLoadOp ?? 'clear',
188
190
  stencilStoreOp: 'store',
189
191
  },
192
+ occlusionQuerySet: options.occlusion?.querySet,
190
193
  encode: ({ pass, frame, resources }) => {
191
194
  const colorViews = colorTargets.map((target) => resolvedView(resources, target.view));
192
195
  const depthView = resolvedView(resources, options.depth.view);
@@ -228,13 +231,23 @@ export function addTypedScenePass(
228
231
  if (groups.viewBindGroup !== null) {
229
232
  options.gpuDriven?.encode(groups.viewBindGroup, pass, resources);
230
233
  }
234
+ // The context carries the frame's primary occlusion projection for
235
+ // pipeline construction, but only the pass that owns that projection
236
+ // may begin its query. Forwarding it to deferred/temporal scene passes
237
+ // leaves their descriptors without an occlusionQuerySet and makes Dawn
238
+ // reject beginOcclusionQuery in those passes.
239
+ const activeOcclusion = options.occlusion;
231
240
  encodeMainPass(
232
241
  {
233
242
  ...internal,
243
+ ...(activeOcclusion === undefined ? {} : { occlusion: activeOcclusion }),
234
244
  geometryColorView: colorViews[0] ?? null,
235
245
  geometryDepthView: depthView,
236
246
  geometryColorResolveView: resolveView,
237
247
  transparentColorFormat: colorTargets[0]?.format as GPUTextureFormat,
248
+ ...(colorTargets[1]?.format === 'rgba16float'
249
+ ? { reflectionFallbackColorFormat: 'rgba16float' as const }
250
+ : {}),
238
251
  msaaActive: colorTargets[0]?.sampleCount === 4,
239
252
  viewBindGroup: groups.viewBindGroup,
240
253
  meshBindGroup: groups.meshBindGroup,
@@ -256,6 +269,10 @@ export function addTypedScenePass(
256
269
  : { transmissionBackdropView: transmissionBackdrop }),
257
270
  },
258
271
  );
272
+ if (activeOcclusion !== undefined) {
273
+ const proxyResult = activeOcclusion.encodeProxyBounds(pass);
274
+ if (!proxyResult.ok) throw proxyResult.error;
275
+ }
259
276
  },
260
277
  });
261
278
  }
@@ -291,6 +308,37 @@ export function addTypedFrameObservationPass(
291
308
  });
292
309
  }
293
310
 
311
+ /** Publish the same-frame fallback MRT as a detached, copy-readable source. */
312
+ export function addReflectionFallbackObservationPass(
313
+ graph: RenderGraphBuilder<RenderPipelineFrame>,
314
+ target: RenderPipelineTarget,
315
+ ): Result<void, RenderGraphError> {
316
+ return graph.addCopyPass('reflection-fallback-observation', {
317
+ accesses: [{ resource: target.view, usage: 'copy-src' }],
318
+ encode: ({ frame, resources }) => {
319
+ const internal = frame as _InternalRenderPipelineContext;
320
+ const texture = resources.texture(target.texture);
321
+ if (!texture.ok) throw texture.error;
322
+ internal.frameState.reflectionFallbackObservationSource = {
323
+ texture: texture.value,
324
+ descriptor: {
325
+ texture: texture.value,
326
+ format: target.format,
327
+ size: { width: frame.targetW, height: frame.targetH },
328
+ usage:
329
+ GPU_TEXTURE_USAGE_COPY_SRC |
330
+ GPU_TEXTURE_USAGE_RENDER_ATTACHMENT |
331
+ GPU_TEXTURE_USAGE_TEXTURE_BINDING,
332
+ sample: target.sampleCount,
333
+ },
334
+ frameId: internal.frameState.frameNumber,
335
+ pipelineId: 'forgeax::standard',
336
+ backendId: internal.runtime.device.caps.backendKind,
337
+ };
338
+ },
339
+ });
340
+ }
341
+
294
342
  export interface TypedBloomTargets {
295
343
  readonly scene: RenderPipelineTarget;
296
344
  readonly composited: RenderPipelineTarget;
@@ -2,8 +2,8 @@ import type {
2
2
  GraphBuffer,
3
3
  GraphTextureView,
4
4
  RenderGraphBuilder,
5
- RenderGraphError,
6
5
  } from '@forgeax/engine-render-graph';
6
+ import { RenderGraphError } from '@forgeax/engine-render-graph';
7
7
  import type {
8
8
  BindGroup,
9
9
  BindGroupLayout,
@@ -14,18 +14,10 @@ import type {
14
14
  TextureView,
15
15
  } from '@forgeax/engine-rhi';
16
16
  import { RhiError } from '@forgeax/engine-rhi';
17
- import { ok, type Result } from '@forgeax/engine-types';
17
+ import { err, ok, type Result } from '@forgeax/engine-types';
18
18
  import { GPU_TEXTURE_USAGE_TEXTURE_BINDING } from '../gpu-texture-usage';
19
- import {
20
- GPU_BUFFER_USAGE_COPY_DST,
21
- GPU_BUFFER_USAGE_STORAGE,
22
- GPU_BUFFER_USAGE_UNIFORM,
23
- } from '../gpu-usage';
24
- import {
25
- LIGHT_ARRAY_HEADER_BYTES,
26
- LIGHT_ARRAY_MAX_SLOTS,
27
- SPOT_LIGHT_STD430_BYTES,
28
- } from '../light-buffer-layout';
19
+ import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from '../gpu-usage';
20
+ import type { StandardClusterGraphBuffers } from '../pipeline/standard-lighting/graph';
29
21
  import { VIEW_UNIFORM_BYTES } from '../record/view-ubo';
30
22
  import type { VolumetricFogFrameContext, VolumetricFogShaderSources } from '../render-contract';
31
23
  import type {
@@ -91,8 +83,10 @@ export interface VolumetricFogPassInputs {
91
83
  readonly view: GraphBuffer;
92
84
  readonly directionalShadow?: GraphTextureView;
93
85
  readonly spotShadow: GraphTextureView;
94
- readonly pointLights: GraphBuffer;
95
- readonly spotLights: GraphBuffer;
86
+ /** The single Standard Cluster light payload consumed by all volume stages. */
87
+ readonly lightData: GraphBuffer;
88
+ /** The Cluster uniform carries the admitted light count for slot guards. */
89
+ readonly clusterUniform: GraphBuffer;
96
90
  readonly selectedLightKind: 'directional' | 'point' | 'spot';
97
91
  readonly projector?: GraphTextureView;
98
92
  }
@@ -169,10 +163,26 @@ function importVolumeInputs(
169
163
  directionalShadow: GraphTextureView | undefined,
170
164
  spotShadow: GraphTextureView,
171
165
  selectedLightKind: 'directional' | 'point' | 'spot' | undefined,
166
+ clusterBuffers: StandardClusterGraphBuffers | null,
172
167
  ): Result<ImportedVolumeInputs | undefined, RenderGraphError> {
173
168
  const volume = topology.volumetricFog;
174
169
  if (volume?.enabled !== true || volume.format === undefined || volume.extent === undefined)
175
170
  return ok(undefined);
171
+ if (clusterBuffers === null) {
172
+ return err(
173
+ new RenderGraphError({
174
+ code: 'resource-descriptor-invalid',
175
+ expected: 'volumetric fog consumes the Standard Cluster light buffers',
176
+ hint: 'enable the storage-backed Standard Cluster transport before enabling volumetric fog',
177
+ detail: {
178
+ resourceLabel: 'volumetric-fog',
179
+ field: 'clusterBuffers',
180
+ expected: 'StandardClusterGraphBuffers',
181
+ actual: 'missing',
182
+ },
183
+ }),
184
+ );
185
+ }
176
186
  const texture = graph.importTexture(
177
187
  'volume-density',
178
188
  {
@@ -218,21 +228,6 @@ function importVolumeInputs(
218
228
  (frame) => frame.pipelineState.viewUniformBuffer,
219
229
  );
220
230
  if (!view.ok) return view;
221
- const spotLights = graph.importBuffer(
222
- 'volume-spot-lights',
223
- {
224
- size: LIGHT_ARRAY_HEADER_BYTES + LIGHT_ARRAY_MAX_SLOTS * SPOT_LIGHT_STD430_BYTES,
225
- usage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,
226
- },
227
- (frame) => frame.pipelineState.spotLightsBuffer,
228
- );
229
- if (!spotLights.ok) return spotLights;
230
- const pointLights = graph.importBuffer(
231
- 'volume-point-lights',
232
- { size: 16 + 4 * 32, usage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST },
233
- (frame) => frame.pipelineState.pointLightsBuffer,
234
- );
235
- if (!pointLights.ok) return pointLights;
236
231
  let projector: GraphTextureView | undefined;
237
232
  if (volume.projector !== undefined) {
238
233
  const projectorTexture = graph.importTexture(
@@ -270,8 +265,8 @@ function importVolumeInputs(
270
265
  view: view.value,
271
266
  ...(directionalShadow === undefined ? {} : { directionalShadow }),
272
267
  spotShadow,
273
- pointLights: pointLights.value,
274
- spotLights: spotLights.value,
268
+ lightData: clusterBuffers.lightData,
269
+ clusterUniform: clusterBuffers.clusterUniform,
275
270
  selectedLightKind: selectedLightKind ?? 'directional',
276
271
  ...(projector === undefined ? {} : { projector }),
277
272
  });
@@ -283,6 +278,7 @@ export function addAuthoredVolumetricFogPasses(
283
278
  sceneDepth: GraphTextureView,
284
279
  directionalShadow: GraphTextureView | undefined,
285
280
  spotShadow: GraphTextureView,
281
+ clusterBuffers: StandardClusterGraphBuffers | null,
286
282
  ): Result<void, RenderGraphError> {
287
283
  // A paired Point+Spot volume stores the Spot shadow lane as well. The
288
284
  // topology's primary light remains PointLight for radiance selection, but
@@ -300,6 +296,7 @@ export function addAuthoredVolumetricFogPasses(
300
296
  directionalShadow,
301
297
  spotShadow,
302
298
  shadowLightKind,
299
+ clusterBuffers,
303
300
  );
304
301
  if (!imported.ok) return imported;
305
302
  if (imported.value === undefined) return ok(undefined);
@@ -342,8 +339,8 @@ export function addVolumetricFogPasses(
342
339
  resource: shadowResource,
343
340
  usage: 'sampled-read',
344
341
  },
345
- { resource: inputs.spotLights, usage: 'storage-read' },
346
- { resource: inputs.pointLights, usage: 'storage-read' },
342
+ { resource: inputs.lightData, usage: 'storage-read' },
343
+ { resource: inputs.clusterUniform, usage: 'uniform-read' },
347
344
  ...(inputs.projector === undefined
348
345
  ? []
349
346
  : [{ resource: inputs.projector, usage: 'sampled-read' as const }]),
@@ -365,19 +362,19 @@ export function addVolumetricFogPasses(
365
362
  },
366
363
  },
367
364
  { binding: 7, visibility: 4, buffer: { type: 'read-only-storage' } },
368
- { binding: 8, visibility: 4, buffer: { type: 'read-only-storage' } },
365
+ { binding: 8, visibility: 4, buffer: { type: 'uniform' } },
369
366
  ]);
370
367
  const shadow = resources.textureView(shadowResource);
371
368
  const params = resources.buffer(inputs.params);
372
369
  const view = resources.buffer(inputs.view);
373
- const spotLights = resources.buffer(inputs.spotLights);
374
- const pointLights = resources.buffer(inputs.pointLights);
370
+ const lightData = resources.buffer(inputs.lightData);
371
+ const clusterUniform = resources.buffer(inputs.clusterUniform);
375
372
  const froxel = resources.textureView(inputs.resources.froxelView);
376
373
  if (!shadow.ok) throw shadow.error;
377
374
  if (!params.ok) throw params.error;
378
375
  if (!view.ok) throw view.error;
379
- if (!spotLights.ok) throw spotLights.error;
380
- if (!pointLights.ok) throw pointLights.error;
376
+ if (!lightData.ok) throw lightData.error;
377
+ if (!clusterUniform.ok) throw clusterUniform.error;
381
378
  if (!froxel.ok) throw froxel.error;
382
379
  const shadowSampler = frame.runtime.device.createSampler({ compare: 'less' });
383
380
  if (!shadowSampler.ok) throw shadowSampler.error;
@@ -387,8 +384,8 @@ export function addVolumetricFogPasses(
387
384
  { binding: 4, resource: { kind: 'sampler', value: shadowSampler.value } },
388
385
  { binding: 5, resource: { kind: 'buffer', value: { buffer: params.value } } },
389
386
  { binding: 6, resource: { kind: 'textureView', value: froxel.value as never } },
390
- { binding: 7, resource: { kind: 'buffer', value: { buffer: spotLights.value } } },
391
- { binding: 8, resource: { kind: 'buffer', value: { buffer: pointLights.value } } },
387
+ { binding: 7, resource: { kind: 'buffer', value: { buffer: lightData.value } } },
388
+ { binding: 8, resource: { kind: 'buffer', value: { buffer: clusterUniform.value } } },
392
389
  ]);
393
390
  pass.setPipeline(inject.pipeline);
394
391
  pass.setBindGroup(0, bindings);
@@ -406,8 +403,8 @@ export function addVolumetricFogPasses(
406
403
  { resource: inputs.resources.temporalView, usage: 'storage-write' },
407
404
  { resource: inputs.params, usage: 'uniform-read' },
408
405
  { resource: inputs.view, usage: 'uniform-read' },
409
- { resource: inputs.spotLights, usage: 'storage-read' },
410
- { resource: inputs.pointLights, usage: 'storage-read' },
406
+ { resource: inputs.lightData, usage: 'storage-read' },
407
+ { resource: inputs.clusterUniform, usage: 'uniform-read' },
411
408
  ...(inputs.projector === undefined
412
409
  ? []
413
410
  : [{ resource: inputs.projector, usage: 'sampled-read' as const }]),
@@ -449,7 +446,7 @@ export function addVolumetricFogPasses(
449
446
  },
450
447
  },
451
448
  { binding: 10, visibility: 4, buffer: { type: 'read-only-storage' } },
452
- { binding: 11, visibility: 4, buffer: { type: 'read-only-storage' } },
449
+ { binding: 11, visibility: 4, buffer: { type: 'uniform' } },
453
450
  { binding: 12, visibility: 4, texture: { sampleType: 'float', viewDimension: '2d' } },
454
451
  { binding: 13, visibility: 4, sampler: { type: 'filtering' } },
455
452
  ]);
@@ -461,8 +458,8 @@ export function addVolumetricFogPasses(
461
458
  const temporalSeed = resources.textureView(inputs.resources.temporalView);
462
459
  const params = resources.buffer(inputs.params);
463
460
  const view = resources.buffer(inputs.view);
464
- const spotLights = resources.buffer(inputs.spotLights);
465
- const pointLights = resources.buffer(inputs.pointLights);
461
+ const lightData = resources.buffer(inputs.lightData);
462
+ const clusterUniform = resources.buffer(inputs.clusterUniform);
466
463
  const projector =
467
464
  inputs.projector === undefined ? undefined : resources.textureView(inputs.projector);
468
465
  if (!froxel.ok) throw froxel.error;
@@ -473,8 +470,8 @@ export function addVolumetricFogPasses(
473
470
  if (!temporalSeed.ok) throw temporalSeed.error;
474
471
  if (!params.ok) throw params.error;
475
472
  if (!view.ok) throw view.error;
476
- if (!spotLights.ok) throw spotLights.error;
477
- if (!pointLights.ok) throw pointLights.error;
473
+ if (!lightData.ok) throw lightData.error;
474
+ if (!clusterUniform.ok) throw clusterUniform.error;
478
475
  if (projector !== undefined && !projector.ok) throw projector.error;
479
476
  const sampler = frame.runtime.device.createSampler({
480
477
  minFilter: 'linear',
@@ -500,8 +497,8 @@ export function addVolumetricFogPasses(
500
497
  { binding: 7, resource: { kind: 'sampler', value: densitySampler.value } },
501
498
  { binding: 8, resource: { kind: 'textureView', value: historySeed.value as never } },
502
499
  { binding: 9, resource: { kind: 'textureView', value: temporalSeed.value as never } },
503
- { binding: 10, resource: { kind: 'buffer', value: { buffer: spotLights.value } } },
504
- { binding: 11, resource: { kind: 'buffer', value: { buffer: pointLights.value } } },
500
+ { binding: 10, resource: { kind: 'buffer', value: { buffer: lightData.value } } },
501
+ { binding: 11, resource: { kind: 'buffer', value: { buffer: clusterUniform.value } } },
505
502
  {
506
503
  binding: 12,
507
504
  resource: {