@forgeax/engine-render 0.1.20 → 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 (645) hide show
  1. package/README.md +365 -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 +18 -0
  5. package/dist/assembly/device-feature-admission.d.ts.map +1 -0
  6. package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
  7. package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
  8. package/dist/assembly/factory.d.ts +30 -19
  9. package/dist/assembly/factory.d.ts.map +1 -1
  10. package/dist/assembly/host-contract.d.ts +19 -0
  11. package/dist/assembly/host-contract.d.ts.map +1 -1
  12. package/dist/assembly/render-target-host.d.ts +46 -0
  13. package/dist/assembly/render-target-host.d.ts.map +1 -0
  14. package/dist/assets/render-asset-port.d.ts.map +1 -1
  15. package/dist/authoring.mjs +4 -1
  16. package/dist/authoring.mjs.map +1 -1
  17. package/dist/capture/cube-views.d.ts +21 -0
  18. package/dist/capture/cube-views.d.ts.map +1 -0
  19. package/dist/capture/scheduler.d.ts +54 -0
  20. package/dist/capture/scheduler.d.ts.map +1 -0
  21. package/dist/{chunk-PCHBPYML.mjs → chunk-4L3P6DT5.mjs} +2 -2
  22. package/dist/chunk-4L3P6DT5.mjs.map +1 -0
  23. package/dist/{chunk-VFPLTKCU.mjs → chunk-4NPUASZR.mjs} +15 -4
  24. package/dist/chunk-4NPUASZR.mjs.map +1 -0
  25. package/dist/chunk-DIYW3M5D.mjs +5085 -0
  26. package/dist/chunk-DIYW3M5D.mjs.map +1 -0
  27. package/dist/chunk-FBC4R44J.mjs +1003 -0
  28. package/dist/chunk-FBC4R44J.mjs.map +1 -0
  29. package/dist/{chunk-CDTWTHZR.mjs → chunk-FF7K3FSO.mjs} +474 -168
  30. package/dist/chunk-FF7K3FSO.mjs.map +1 -0
  31. package/dist/chunk-HZUPSYW7.mjs +1104 -0
  32. package/dist/chunk-HZUPSYW7.mjs.map +1 -0
  33. package/dist/{chunk-TBQJOK2L.mjs → chunk-QODA5UKU.mjs} +321 -269
  34. package/dist/chunk-QODA5UKU.mjs.map +1 -0
  35. package/dist/chunk-YALPS44A.mjs +296 -0
  36. package/dist/chunk-YALPS44A.mjs.map +1 -0
  37. package/dist/{chunk-4XINDLAY.mjs → chunk-ZUWKAZ2I.mjs} +1963 -2178
  38. package/dist/chunk-ZUWKAZ2I.mjs.map +1 -0
  39. package/dist/cluster-binner.d.ts +5 -0
  40. package/dist/cluster-binner.d.ts.map +1 -1
  41. package/dist/components/camera.d.ts +1 -0
  42. package/dist/components/camera.d.ts.map +1 -1
  43. package/dist/components/cube-camera.d.ts +20 -0
  44. package/dist/components/cube-camera.d.ts.map +1 -0
  45. package/dist/components/directional-light.d.ts +11 -2
  46. package/dist/components/directional-light.d.ts.map +1 -1
  47. package/dist/components/directional-shadow-filter.d.ts +25 -0
  48. package/dist/components/directional-shadow-filter.d.ts.map +1 -0
  49. package/dist/components/index.d.ts +5 -0
  50. package/dist/components/index.d.ts.map +1 -1
  51. package/dist/components/light-helpers.d.ts +4 -0
  52. package/dist/components/light-helpers.d.ts.map +1 -1
  53. package/dist/components/light-probe.d.ts +9 -0
  54. package/dist/components/light-probe.d.ts.map +1 -0
  55. package/dist/components/rect-area-light.d.ts +12 -0
  56. package/dist/components/rect-area-light.d.ts.map +1 -0
  57. package/dist/components/reflection-probe.d.ts +17 -0
  58. package/dist/components/reflection-probe.d.ts.map +1 -0
  59. package/dist/components/scene-instance.d.ts +4 -0
  60. package/dist/components/scene-instance.d.ts.map +1 -1
  61. package/dist/components/spot-light.d.ts +3 -0
  62. package/dist/components/spot-light.d.ts.map +1 -1
  63. package/dist/construct-renderer.mjs +14836 -9620
  64. package/dist/construct-renderer.mjs.map +1 -1
  65. package/dist/device/gpu-residency.d.ts +8 -1
  66. package/dist/device/gpu-residency.d.ts.map +1 -1
  67. package/dist/device/lifecycle-transaction.d.ts +2 -0
  68. package/dist/device/lifecycle-transaction.d.ts.map +1 -0
  69. package/dist/environment/frame.d.ts.map +1 -1
  70. package/dist/environment/lifecycle.d.ts +5 -0
  71. package/dist/environment/lifecycle.d.ts.map +1 -1
  72. package/dist/errors/gpu-driven.d.ts +26 -0
  73. package/dist/errors/gpu-driven.d.ts.map +1 -0
  74. package/dist/errors/index.d.ts +1 -0
  75. package/dist/errors/index.d.ts.map +1 -1
  76. package/dist/errors/recover.d.ts +9 -1
  77. package/dist/errors/recover.d.ts.map +1 -1
  78. package/dist/errors/render.d.ts +166 -93
  79. package/dist/errors/render.d.ts.map +1 -1
  80. package/dist/extract/directional-shadow-projection.d.ts +23 -0
  81. package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
  82. package/dist/extract/environment.d.ts +14 -0
  83. package/dist/extract/environment.d.ts.map +1 -1
  84. package/dist/extract/gpu-driven.d.ts +50 -0
  85. package/dist/extract/gpu-driven.d.ts.map +1 -0
  86. package/dist/extract/visibility.d.ts.map +1 -1
  87. package/dist/features/fullscreen.d.ts.map +1 -1
  88. package/dist/features/targets.d.ts.map +1 -1
  89. package/dist/features/types.d.ts +10 -0
  90. package/dist/features/types.d.ts.map +1 -1
  91. package/dist/fullscreen-post-process-pass.d.ts +13 -2
  92. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  93. package/dist/gpu-driven/batch-topology.d.ts +34 -0
  94. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  95. package/dist/gpu-driven/prepared-draw.d.ts +63 -0
  96. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -0
  97. package/dist/gpu-driven/production-raster.d.ts +97 -2
  98. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  99. package/dist/gpu-driven/view-gpu.d.ts +64 -1
  100. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  101. package/dist/gpu-scene-schema.d.ts +14 -0
  102. package/dist/gpu-scene-schema.d.ts.map +1 -1
  103. package/dist/gpu-scene.d.ts +8 -1
  104. package/dist/gpu-scene.d.ts.map +1 -1
  105. package/dist/gpu-usage.d.ts +0 -1
  106. package/dist/gpu-usage.d.ts.map +1 -1
  107. package/dist/hdrp-buffers.d.ts +21 -19
  108. package/dist/hdrp-buffers.d.ts.map +1 -1
  109. package/dist/ibl/IblPipelineCache.d.ts +4 -0
  110. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  111. package/dist/ibl/kernel-cache.d.ts +36 -0
  112. package/dist/ibl/kernel-cache.d.ts.map +1 -0
  113. package/dist/index.d.ts +39 -3
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.mjs +91 -6
  116. package/dist/index.mjs.map +1 -1
  117. package/dist/inspection-types.d.ts +214 -1
  118. package/dist/inspection-types.d.ts.map +1 -1
  119. package/dist/instances-derived-bounds.d.ts +50 -0
  120. package/dist/instances-derived-bounds.d.ts.map +1 -0
  121. package/dist/internal.d.ts +9 -0
  122. package/dist/internal.d.ts.map +1 -1
  123. package/dist/internal.mjs +23 -2
  124. package/dist/internal.mjs.map +1 -1
  125. package/dist/light-buffer-layout.d.ts +58 -140
  126. package/dist/light-buffer-layout.d.ts.map +1 -1
  127. package/dist/materials.d.ts.map +1 -1
  128. package/dist/mesh-material-bindings.d.ts +54 -0
  129. package/dist/mesh-material-bindings.d.ts.map +1 -1
  130. package/dist/pbr-pipeline.d.ts +38 -14
  131. package/dist/pbr-pipeline.d.ts.map +1 -1
  132. package/dist/pipeline/standard-forward-lane.d.ts +2 -1
  133. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  134. package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
  135. package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
  136. package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
  137. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
  138. package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
  139. package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
  140. package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
  141. package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
  142. package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
  143. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
  144. package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
  145. package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
  146. package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
  147. package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
  148. package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
  149. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
  150. package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
  151. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
  152. package/dist/pipeline/standard-pipeline.d.ts +4 -13
  153. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  154. package/dist/pipeline/standard-post.d.ts.map +1 -1
  155. package/dist/pipeline/standard-profile.d.ts +5 -26
  156. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  157. package/dist/pipeline-builder.d.ts +2 -0
  158. package/dist/pipeline-builder.d.ts.map +1 -1
  159. package/dist/pipeline-spec.d.ts +40 -7
  160. package/dist/pipeline-spec.d.ts.map +1 -1
  161. package/dist/plugin.d.ts.map +1 -1
  162. package/dist/point-shadow-inspection.d.ts +21 -0
  163. package/dist/point-shadow-inspection.d.ts.map +1 -0
  164. package/dist/prepare/extended-lighting/ltc-resources.d.ts +31 -0
  165. package/dist/prepare/extended-lighting/ltc-resources.d.ts.map +1 -0
  166. package/dist/prepare/extended-lighting/resources.d.ts +72 -0
  167. package/dist/prepare/extended-lighting/resources.d.ts.map +1 -0
  168. package/dist/prepare/extended-lighting/spot-modifiers.d.ts +42 -0
  169. package/dist/prepare/extended-lighting/spot-modifiers.d.ts.map +1 -0
  170. package/dist/prepare/extended-lighting/state.d.ts +24 -0
  171. package/dist/prepare/extended-lighting/state.d.ts.map +1 -0
  172. package/dist/record/frame-lighting.d.ts +33 -36
  173. package/dist/record/frame-lighting.d.ts.map +1 -1
  174. package/dist/record/frame-snapshot.d.ts +78 -24
  175. package/dist/record/frame-snapshot.d.ts.map +1 -1
  176. package/dist/record/frame-targets.d.ts +5 -0
  177. package/dist/record/frame-targets.d.ts.map +1 -1
  178. package/dist/record/frame.d.ts +16 -6
  179. package/dist/record/frame.d.ts.map +1 -1
  180. package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
  181. package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
  182. package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
  183. package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
  184. package/dist/record/gpu-pass-timing/index.d.ts +8 -0
  185. package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
  186. package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
  187. package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
  188. package/dist/record/gpu-pass-timing/session.d.ts +43 -0
  189. package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
  190. package/dist/record/gpu-timing.d.ts +20 -3
  191. package/dist/record/gpu-timing.d.ts.map +1 -1
  192. package/dist/record/helpers.d.ts +0 -20
  193. package/dist/record/helpers.d.ts.map +1 -1
  194. package/dist/record/main-pass-geometry.d.ts +6 -1
  195. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  196. package/dist/record/main-pass-material.d.ts +25 -2
  197. package/dist/record/main-pass-material.d.ts.map +1 -1
  198. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  199. package/dist/record/main-pass.d.ts +2 -0
  200. package/dist/record/main-pass.d.ts.map +1 -1
  201. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  202. package/dist/record/render-context.d.ts +98 -6
  203. package/dist/record/render-context.d.ts.map +1 -1
  204. package/dist/record/shadow-pass.d.ts.map +1 -1
  205. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  206. package/dist/record/typed-frame-graph.d.ts +119 -4
  207. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  208. package/dist/record/view-ubo.d.ts +7 -5
  209. package/dist/record/view-ubo.d.ts.map +1 -1
  210. package/dist/reflection/filter.d.ts +22 -0
  211. package/dist/reflection/filter.d.ts.map +1 -0
  212. package/dist/reflection/gpu-table.d.ts +25 -0
  213. package/dist/reflection/gpu-table.d.ts.map +1 -0
  214. package/dist/reflection/inspection.d.ts +10 -0
  215. package/dist/reflection/inspection.d.ts.map +1 -0
  216. package/dist/reflection/projection.d.ts +140 -0
  217. package/dist/reflection/projection.d.ts.map +1 -0
  218. package/dist/reflection/record-owner.d.ts +60 -0
  219. package/dist/reflection/record-owner.d.ts.map +1 -0
  220. package/dist/render-contract.d.ts +62 -14
  221. package/dist/render-contract.d.ts.map +1 -1
  222. package/dist/render-graph-primitives.d.ts +1 -0
  223. package/dist/render-graph-primitives.d.ts.map +1 -1
  224. package/dist/render-pipeline.d.ts +49 -2
  225. package/dist/render-pipeline.d.ts.map +1 -1
  226. package/dist/render-system-extract.d.ts +160 -31
  227. package/dist/render-system-extract.d.ts.map +1 -1
  228. package/dist/render-system.d.ts +28 -2
  229. package/dist/render-system.d.ts.map +1 -1
  230. package/dist/renderer.d.ts +43 -0
  231. package/dist/renderer.d.ts.map +1 -0
  232. package/dist/scene/probe-blend-record.d.ts +22 -0
  233. package/dist/scene/probe-blend-record.d.ts.map +1 -0
  234. package/dist/scene/probe-blend.d.ts +142 -0
  235. package/dist/scene/probe-blend.d.ts.map +1 -0
  236. package/dist/scene/render-scene-types.d.ts +0 -6
  237. package/dist/scene/render-scene-types.d.ts.map +1 -1
  238. package/dist/scene/render-scene.d.ts +117 -9
  239. package/dist/scene/render-scene.d.ts.map +1 -1
  240. package/dist/scene/visibility/bounds.d.ts +20 -0
  241. package/dist/scene/visibility/bounds.d.ts.map +1 -0
  242. package/dist/scene/visibility/budget.d.ts +16 -0
  243. package/dist/scene/visibility/budget.d.ts.map +1 -0
  244. package/dist/scene/visibility/facet.d.ts +73 -0
  245. package/dist/scene/visibility/facet.d.ts.map +1 -0
  246. package/dist/scene/visibility/gpu-frame-timing.d.ts +41 -0
  247. package/dist/scene/visibility/gpu-frame-timing.d.ts.map +1 -0
  248. package/dist/scene/visibility/gpu-lod.d.ts +46 -0
  249. package/dist/scene/visibility/gpu-lod.d.ts.map +1 -0
  250. package/dist/scene/visibility/inspection.d.ts +132 -0
  251. package/dist/scene/visibility/inspection.d.ts.map +1 -0
  252. package/dist/scene/visibility/lod-selector.d.ts +25 -0
  253. package/dist/scene/visibility/lod-selector.d.ts.map +1 -0
  254. package/dist/scene/visibility/occlusion-confidence.d.ts +81 -0
  255. package/dist/scene/visibility/occlusion-confidence.d.ts.map +1 -0
  256. package/dist/scene/visibility/occlusion-pass.d.ts +57 -0
  257. package/dist/scene/visibility/occlusion-pass.d.ts.map +1 -0
  258. package/dist/scene/visibility/occlusion-query-pool.d.ts +57 -0
  259. package/dist/scene/visibility/occlusion-query-pool.d.ts.map +1 -0
  260. package/dist/scene/visibility/occlusion-runtime.d.ts +96 -0
  261. package/dist/scene/visibility/occlusion-runtime.d.ts.map +1 -0
  262. package/dist/scene/visibility/types.d.ts +34 -0
  263. package/dist/scene/visibility/types.d.ts.map +1 -0
  264. package/dist/shadow-atlas.d.ts +3 -3
  265. package/dist/shadow-atlas.d.ts.map +1 -1
  266. package/dist/ssao-buffers.d.ts +3 -0
  267. package/dist/ssao-buffers.d.ts.map +1 -1
  268. package/dist/ssr/admission.d.ts +122 -0
  269. package/dist/ssr/admission.d.ts.map +1 -0
  270. package/dist/ssr/composition.d.ts +32 -0
  271. package/dist/ssr/composition.d.ts.map +1 -0
  272. package/dist/ssr/errors.d.ts +39 -0
  273. package/dist/ssr/errors.d.ts.map +1 -0
  274. package/dist/ssr/identity.d.ts +13 -0
  275. package/dist/ssr/identity.d.ts.map +1 -0
  276. package/dist/systems/skin-palette-allocator.d.ts +1 -1
  277. package/dist/targets/contracts.d.ts +66 -0
  278. package/dist/targets/contracts.d.ts.map +1 -0
  279. package/dist/targets/graph-projection.d.ts +29 -0
  280. package/dist/targets/graph-projection.d.ts.map +1 -0
  281. package/dist/targets/material-source.d.ts +34 -0
  282. package/dist/targets/material-source.d.ts.map +1 -0
  283. package/dist/targets/owner.d.ts +32 -0
  284. package/dist/targets/owner.d.ts.map +1 -0
  285. package/dist/targets/physical.d.ts +18 -0
  286. package/dist/targets/physical.d.ts.map +1 -0
  287. package/dist/targets/readback.d.ts +39 -0
  288. package/dist/targets/readback.d.ts.map +1 -0
  289. package/dist/temporal/frame-coordinator.d.ts +13 -0
  290. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  291. package/dist/temporal/frame.d.ts +2 -0
  292. package/dist/temporal/frame.d.ts.map +1 -1
  293. package/dist/temporal/index.mjs +6 -5
  294. package/dist/temporal/view.d.ts +7 -0
  295. package/dist/temporal/view.d.ts.map +1 -1
  296. package/dist/tilemap-chunk-extract-system.d.ts +1 -1
  297. package/dist/typed-render-graph-primitives.d.ts +5 -1
  298. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  299. package/dist/typed-shadow-passes.d.ts +1 -1
  300. package/dist/typed-shadow-passes.d.ts.map +1 -1
  301. package/dist/volume/passes.d.ts +9 -5
  302. package/dist/volume/passes.d.ts.map +1 -1
  303. package/package.json +20 -20
  304. package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
  305. package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
  306. package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
  307. package/src/__tests__/cluster-binner.unit.test.ts +35 -0
  308. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +12 -2
  309. package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
  310. package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
  311. package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
  312. package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
  313. package/src/__tests__/cube-camera.integration.test.ts +42 -0
  314. package/src/__tests__/detached-inspection.integration.test.ts +6 -0
  315. package/src/__tests__/device-feature-admission.unit.test.ts +85 -0
  316. package/src/__tests__/direct-light-snapshot.unit.test.ts +62 -6
  317. package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
  318. package/src/__tests__/environment-generation.integration.test.ts +16 -0
  319. package/src/__tests__/evidence-identity.ts +13 -0
  320. package/src/__tests__/evidence-identity.unit.test.ts +24 -0
  321. package/src/__tests__/extended-lighting-recovery.browser.test.ts +14 -0
  322. package/src/__tests__/extended-lighting-recovery.dawn.test.ts +14 -0
  323. package/src/__tests__/extended-lighting-recovery.integration.test.ts +81 -0
  324. package/src/__tests__/extended-lighting-resources.unit.test.ts +51 -0
  325. package/src/__tests__/extended-lighting-zero-feature.integration.test.ts +52 -0
  326. package/src/__tests__/factory-contract.integration.test.ts +288 -29
  327. package/src/__tests__/fog-component.unit.test.ts +67 -0
  328. package/src/__tests__/fog.integration.test.ts +86 -0
  329. package/src/__tests__/frame-observation.contract.test.ts +15 -0
  330. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
  331. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +146 -0
  332. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -8
  333. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +18 -1
  334. package/src/__tests__/gpu-driven-production.integration.test.ts +579 -17
  335. package/src/__tests__/gpu-driven-scaling.unit.test.ts +66 -2
  336. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +26 -1
  337. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +101 -6
  338. package/src/__tests__/gpu-driven-view.browser.test.ts +3 -3
  339. package/src/__tests__/gpu-driven-view.dawn.test.ts +3 -3
  340. package/src/__tests__/gpu-driven-view.unit.test.ts +50 -0
  341. package/src/__tests__/gpu-lod-evidence.ts +188 -0
  342. package/src/__tests__/gpu-lod-fallback.integration.test.ts +10 -0
  343. package/src/__tests__/gpu-lod-indirect.integration.test.ts +40 -0
  344. package/src/__tests__/gpu-lod-parity.dawn.test.ts +29 -0
  345. package/src/__tests__/gpu-lod-readiness.integration.test.ts +52 -0
  346. package/src/__tests__/gpu-lod-schema.unit.test.ts +66 -0
  347. package/src/__tests__/gpu-lod-selector.unit.test.ts +28 -0
  348. package/src/__tests__/gpu-lod-silhouette.browser.test.ts +13 -0
  349. package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
  350. package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
  351. package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
  352. package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
  353. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
  354. package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
  355. package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
  356. package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
  357. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
  358. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +66 -1
  359. package/src/__tests__/gpu-scene.dawn.test.ts +8 -1
  360. package/src/__tests__/gpu-scene.unit.test.ts +49 -3
  361. package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
  362. package/src/__tests__/instances-culling.integration.test.ts +94 -0
  363. package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
  364. package/src/__tests__/light-buffer-layout.unit.test.ts +113 -3
  365. package/src/__tests__/light-inspection.unit.test.ts +55 -0
  366. package/src/__tests__/light-resource-error.unit.test.ts +43 -0
  367. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +109 -0
  368. package/src/__tests__/lod-bounds.unit.test.ts +42 -0
  369. package/src/__tests__/lod-cpu-lane.integration.test.ts +55 -0
  370. package/src/__tests__/lod-cpu-no-change.perf.test.ts +19 -0
  371. package/src/__tests__/lod-gpu-frame-timing.unit.test.ts +49 -0
  372. package/src/__tests__/lod-multi-view.integration.test.ts +63 -0
  373. package/src/__tests__/lod-occlusion-device-loss.integration.test.ts +27 -0
  374. package/src/__tests__/lod-occlusion-final-decision.integration.test.ts +47 -0
  375. package/src/__tests__/lod-occlusion-inspection.integration.test.ts +217 -0
  376. package/src/__tests__/lod-occlusion-inspection.schema.test-d.ts +14 -0
  377. package/src/__tests__/lod-occlusion-inspection.unit.test.ts +72 -0
  378. package/src/__tests__/lod-occlusion-visual-evidence.ts +91 -0
  379. package/src/__tests__/lod-occlusion.browser.test.ts +15 -0
  380. package/src/__tests__/lod-occlusion.dawn.test.ts +20 -0
  381. package/src/__tests__/lod-selector.profile.test.ts +35 -0
  382. package/src/__tests__/lod-selector.unit.test.ts +68 -0
  383. package/src/__tests__/lod-visibility-identity.unit.test.ts +198 -0
  384. package/src/__tests__/lod-visibility-lifecycle.integration.test.ts +132 -0
  385. package/src/__tests__/ltc-resources.unit.test.ts +32 -0
  386. package/src/__tests__/material-contract-inventory.unit.test.ts +17 -0
  387. package/src/__tests__/material-observation.integration.test.ts +101 -0
  388. package/src/__tests__/occlusion-confidence.unit.test.ts +168 -0
  389. package/src/__tests__/occlusion-invalidation.integration.test.ts +37 -0
  390. package/src/__tests__/occlusion-pass-routing.unit.test.ts +16 -0
  391. package/src/__tests__/occlusion-pass.dawn.test.ts +20 -0
  392. package/src/__tests__/occlusion-pass.integration.test.ts +43 -0
  393. package/src/__tests__/occlusion-pass.rhi-null.test.ts +22 -0
  394. package/src/__tests__/occlusion-query-pool.rhi-null.test.ts +21 -0
  395. package/src/__tests__/occlusion-query-pool.unit.test.ts +95 -0
  396. package/src/__tests__/occlusion-query-ticket.integration.test.ts +47 -0
  397. package/src/__tests__/occlusion-query.dawn.test.ts +16 -0
  398. package/src/__tests__/occlusion-query.evidence.ts +178 -0
  399. package/src/__tests__/occlusion-query.rhi-null.test.ts +31 -0
  400. package/src/__tests__/occlusion-runtime.unit.test.ts +120 -0
  401. package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
  402. package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
  403. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +196 -0
  404. package/src/__tests__/probe-bindings.unit.test.ts +200 -0
  405. package/src/__tests__/probe-blend-numeric.unit.test.ts +67 -0
  406. package/src/__tests__/probe-blend-oracle.unit.test.ts +136 -0
  407. package/src/__tests__/probe-capacity.integration.test.ts +97 -0
  408. package/src/__tests__/probe-recovery.integration.test.ts +104 -0
  409. package/src/__tests__/probe-scene-dirty.integration.test.ts +211 -0
  410. package/src/__tests__/profiler-phase-catalog.test.ts +4 -1
  411. package/src/__tests__/profiler-phase-token.test.ts +1 -0
  412. package/src/__tests__/public-surface.test-d.ts +10 -0
  413. package/src/__tests__/rect-area-boundary.unit.test.ts +24 -0
  414. package/src/__tests__/reflection-fallback-graph.unit.test.ts +67 -0
  415. package/src/__tests__/reflection-fallback-inspection.unit.test.ts +77 -0
  416. package/src/__tests__/reflection-fallback-lifecycle.integration.test.ts +21 -0
  417. package/src/__tests__/reflection-fallback-projection.unit.test.ts +90 -0
  418. package/src/__tests__/reflection-fallback-source.unit.test.ts +32 -0
  419. package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
  420. package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
  421. package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
  422. package/src/__tests__/reflection-probe-owner-placement.unit.test.ts +39 -0
  423. package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
  424. package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
  425. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +120 -0
  426. package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
  427. package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
  428. package/src/__tests__/render-error-code-owner.test-d.ts +19 -3
  429. package/src/__tests__/render-feature-docs.unit.test.ts +12 -7
  430. package/src/__tests__/render-graph-fallback.integration.test.ts +24 -0
  431. package/src/__tests__/render-perf/extended-lighting.bench.test.ts +66 -0
  432. package/src/__tests__/render-scene-projection.unit.test.ts +447 -18
  433. package/src/__tests__/render-target-admission.unit.test.ts +80 -0
  434. package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
  435. package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
  436. package/src/__tests__/render-target-material-source.test-d.ts +30 -0
  437. package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
  438. package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
  439. package/src/__tests__/render-target-owner.unit.test.ts +122 -0
  440. package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
  441. package/src/__tests__/render-target-public-schema.json +107 -0
  442. package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
  443. package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
  444. package/src/__tests__/render-target-readback.integration.test.ts +90 -0
  445. package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
  446. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +124 -0
  447. package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
  448. package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
  449. package/src/__tests__/skin-motion-regression.unit.test.ts +154 -0
  450. package/src/__tests__/skinned-shadow-caster.test.ts +13 -4
  451. package/src/__tests__/spot-modifier-projection.unit.test.ts +70 -0
  452. package/src/__tests__/ssr-admission-matrix.integration.test.ts +206 -0
  453. package/src/__tests__/ssr-composition.unit.test.ts +46 -0
  454. package/src/__tests__/ssr-fallback-zero-work.bench.test.ts +94 -0
  455. package/src/__tests__/ssr-recovery-errors.unit.test.ts +58 -0
  456. package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
  457. package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
  458. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +299 -0
  459. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +15 -5
  460. package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
  461. package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
  462. package/src/__tests__/standard-lighting-write.unit.test.ts +441 -0
  463. package/src/__tests__/standard-lighting.integration.test.ts +67 -0
  464. package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
  465. package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
  466. package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
  467. package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -38
  468. package/src/__tests__/temporal-fallback-generation.integration.test.ts +16 -0
  469. package/src/__tests__/temporal-view.unit.test.ts +3 -3
  470. package/src/__tests__/transmission-prewarm.unit.test.ts +69 -0
  471. package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
  472. package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
  473. package/src/__tests__/visibility-budget.integration.test.ts +140 -0
  474. package/src/__tests__/visibility-budget.unit.test.ts +70 -0
  475. package/src/__tests__/visibility-extract.integration.test.ts +11 -6
  476. package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
  477. package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +6 -3
  478. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +31 -28
  479. package/src/assembly/backend-contract.ts +13 -0
  480. package/src/assembly/device-feature-admission.ts +80 -0
  481. package/src/assembly/directional-shadow-inspection.ts +122 -0
  482. package/src/assembly/factory.ts +1411 -366
  483. package/src/assembly/host-contract.ts +35 -0
  484. package/src/assembly/render-target-host.ts +847 -0
  485. package/src/assets/asset-decoders.ts +1 -1
  486. package/src/assets/render-asset-port.ts +7 -1
  487. package/src/capture/cube-views.ts +69 -0
  488. package/src/capture/scheduler.ts +265 -0
  489. package/src/cluster-binner.ts +31 -0
  490. package/src/components/__tests__/lighting-authoring.unit.test.ts +39 -0
  491. package/src/components/__tests__/rect-area-light.unit.test.ts +33 -0
  492. package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
  493. package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
  494. package/src/components/camera.ts +4 -0
  495. package/src/components/cube-camera.ts +52 -0
  496. package/src/components/directional-light.ts +22 -2
  497. package/src/components/directional-shadow-filter.ts +57 -0
  498. package/src/components/index.ts +5 -0
  499. package/src/components/light-helpers.ts +133 -8
  500. package/src/components/light-probe.ts +13 -0
  501. package/src/components/rect-area-light.ts +15 -0
  502. package/src/components/reflection-probe.ts +49 -0
  503. package/src/components/scene-instance.ts +6 -0
  504. package/src/components/spot-light.ts +3 -0
  505. package/src/device/__tests__/extended-lighting-recovery.unit.test.ts +24 -0
  506. package/src/device/gpu-residency.ts +140 -9
  507. package/src/device/lifecycle-transaction.ts +12 -0
  508. package/src/environment/frame.ts +6 -24
  509. package/src/environment/lifecycle.ts +20 -1
  510. package/src/errors/gpu-driven.ts +92 -0
  511. package/src/errors/index.ts +1 -0
  512. package/src/errors/recover.ts +32 -0
  513. package/src/errors/render.ts +341 -143
  514. package/src/extract/camera.ts +3 -3
  515. package/src/extract/directional-shadow-projection.ts +61 -0
  516. package/src/extract/environment.ts +57 -0
  517. package/src/extract/gpu-driven.ts +108 -0
  518. package/src/extract/visibility.ts +2 -1
  519. package/src/features/fullscreen.ts +3 -0
  520. package/src/features/targets.ts +4 -1
  521. package/src/features/types.ts +10 -0
  522. package/src/fullscreen-post-process-pass.ts +43 -2
  523. package/src/gpu-driven/batch-topology.ts +207 -28
  524. package/src/gpu-driven/prepared-draw.ts +208 -0
  525. package/src/gpu-driven/production-raster.ts +953 -43
  526. package/src/gpu-driven/view-gpu.ts +411 -29
  527. package/src/gpu-scene-schema.ts +13 -0
  528. package/src/gpu-scene.ts +140 -64
  529. package/src/gpu-usage.ts +0 -1
  530. package/src/hdrp-buffers.ts +169 -63
  531. package/src/ibl/IblPipelineCache.ts +11 -0
  532. package/src/ibl/kernel-cache.ts +88 -0
  533. package/src/index.ts +222 -0
  534. package/src/inspection-types.ts +276 -1
  535. package/src/instances-derived-bounds.ts +171 -0
  536. package/src/internal.ts +38 -0
  537. package/src/light-buffer-layout.ts +155 -310
  538. package/src/materials.ts +16 -2
  539. package/src/mesh-material-bindings.ts +132 -0
  540. package/src/pbr-pipeline.ts +255 -60
  541. package/src/pipeline/standard-forward-lane.ts +93 -16
  542. package/src/pipeline/standard-lighting/errors.ts +6 -0
  543. package/src/pipeline/standard-lighting/graph.ts +158 -0
  544. package/src/pipeline/standard-lighting/inspection.ts +88 -0
  545. package/src/pipeline/standard-lighting/layout.ts +31 -0
  546. package/src/pipeline/standard-lighting/light-frame.ts +35 -0
  547. package/src/pipeline/standard-lighting/membership.ts +43 -0
  548. package/src/pipeline/standard-lighting/prepare.ts +37 -0
  549. package/src/pipeline/standard-lighting/topology.ts +120 -0
  550. package/src/pipeline/standard-lighting/transport.ts +78 -0
  551. package/src/pipeline/standard-pipeline.ts +124 -193
  552. package/src/pipeline/standard-post.ts +26 -7
  553. package/src/pipeline/standard-profile.ts +17 -47
  554. package/src/pipeline-builder.ts +5 -2
  555. package/src/pipeline-spec.ts +95 -21
  556. package/src/plugin.ts +4 -0
  557. package/src/point-shadow-inspection.ts +55 -0
  558. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +56 -0
  559. package/src/prepare/extended-lighting/ltc-resources.ts +136 -0
  560. package/src/prepare/extended-lighting/resources.ts +389 -0
  561. package/src/prepare/extended-lighting/spot-modifiers.ts +194 -0
  562. package/src/prepare/extended-lighting/state.ts +92 -0
  563. package/src/record/__tests__/gpu-timing.unit.test.ts +177 -0
  564. package/src/record/__tests__/temporal-payload.unit.test.ts +64 -1
  565. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
  566. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +20 -1
  567. package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
  568. package/src/record/frame-lighting.ts +591 -452
  569. package/src/record/frame-snapshot.ts +92 -39
  570. package/src/record/frame-targets.ts +17 -0
  571. package/src/record/frame.ts +662 -158
  572. package/src/record/gpu-pass-timing/contract.ts +180 -0
  573. package/src/record/gpu-pass-timing/errors.ts +34 -0
  574. package/src/record/gpu-pass-timing/index.ts +37 -0
  575. package/src/record/gpu-pass-timing/parser.ts +97 -0
  576. package/src/record/gpu-pass-timing/session.ts +938 -0
  577. package/src/record/gpu-timing.ts +112 -39
  578. package/src/record/helpers.ts +0 -58
  579. package/src/record/main-pass-geometry.ts +324 -119
  580. package/src/record/main-pass-material.ts +103 -10
  581. package/src/record/main-pass-sprite-draws.ts +99 -103
  582. package/src/record/main-pass.ts +71 -15
  583. package/src/record/mesh-ssbo.ts +47 -36
  584. package/src/record/render-context.ts +136 -3
  585. package/src/record/shadow-pass.ts +83 -68
  586. package/src/record/skybox-post-pass.ts +20 -4
  587. package/src/record/typed-frame-graph.ts +1034 -43
  588. package/src/record/view-ubo.ts +72 -47
  589. package/src/reflection/filter.ts +81 -0
  590. package/src/reflection/gpu-table.ts +44 -0
  591. package/src/reflection/inspection.ts +67 -0
  592. package/src/reflection/projection.ts +476 -0
  593. package/src/reflection/record-owner.ts +1283 -0
  594. package/src/render-contract.ts +93 -10
  595. package/src/render-graph-primitives.ts +9 -4
  596. package/src/render-pipeline.ts +122 -2
  597. package/src/render-system-extract.ts +1041 -225
  598. package/src/render-system.ts +1310 -85
  599. package/src/renderer.ts +222 -0
  600. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +36 -0
  601. package/src/scene/probe-blend-record.ts +54 -0
  602. package/src/scene/probe-blend.ts +813 -0
  603. package/src/scene/render-scene-types.ts +0 -7
  604. package/src/scene/render-scene.ts +942 -171
  605. package/src/scene/visibility/bounds.ts +57 -0
  606. package/src/scene/visibility/budget.ts +40 -0
  607. package/src/scene/visibility/facet.ts +400 -0
  608. package/src/scene/visibility/gpu-frame-timing.ts +101 -0
  609. package/src/scene/visibility/gpu-lod.ts +119 -0
  610. package/src/scene/visibility/inspection.ts +313 -0
  611. package/src/scene/visibility/lod-selector.ts +84 -0
  612. package/src/scene/visibility/occlusion-confidence.ts +478 -0
  613. package/src/scene/visibility/occlusion-pass.ts +165 -0
  614. package/src/scene/visibility/occlusion-query-pool.ts +178 -0
  615. package/src/scene/visibility/occlusion-runtime.ts +672 -0
  616. package/src/scene/visibility/types.ts +50 -0
  617. package/src/shadow-atlas.ts +5 -5
  618. package/src/ssao-buffers.ts +9 -2
  619. package/src/ssr/admission.ts +451 -0
  620. package/src/ssr/composition.ts +73 -0
  621. package/src/ssr/errors.ts +76 -0
  622. package/src/ssr/identity.ts +12 -0
  623. package/src/systems/skin-palette-allocator.ts +1 -1
  624. package/src/targets/contracts.ts +182 -0
  625. package/src/targets/graph-projection.ts +169 -0
  626. package/src/targets/material-source.ts +143 -0
  627. package/src/targets/owner.ts +214 -0
  628. package/src/targets/physical.ts +18 -0
  629. package/src/targets/readback.ts +153 -0
  630. package/src/temporal/frame-coordinator.ts +26 -0
  631. package/src/temporal/frame.ts +14 -1
  632. package/src/temporal/view.ts +11 -0
  633. package/src/tilemap-chunk-extract-system.ts +4 -4
  634. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +59 -20
  635. package/src/typed-render-graph-primitives.ts +53 -3
  636. package/src/typed-shadow-passes.ts +46 -40
  637. package/src/volume/passes.ts +61 -58
  638. package/dist/.tsbuildinfo +0 -1
  639. package/dist/chunk-4XINDLAY.mjs.map +0 -1
  640. package/dist/chunk-CDTWTHZR.mjs.map +0 -1
  641. package/dist/chunk-M2MP4ZOU.mjs +0 -73
  642. package/dist/chunk-M2MP4ZOU.mjs.map +0 -1
  643. package/dist/chunk-PCHBPYML.mjs.map +0 -1
  644. package/dist/chunk-TBQJOK2L.mjs.map +0 -1
  645. package/dist/chunk-VFPLTKCU.mjs.map +0 -1
@@ -14,6 +14,7 @@ import {
14
14
  DirectionalLight,
15
15
  MeshFilter,
16
16
  MeshRenderer,
17
+ PointLight,
17
18
  TONEMAP_LINEAR,
18
19
  } from '../../components';
19
20
  import { constructRendererHost, type RhiBackendPack } from '../../construct-renderer';
@@ -57,8 +58,10 @@ interface TransmissionCase {
57
58
  readonly thicknessTexture?: number;
58
59
  readonly masked?: boolean;
59
60
  readonly overlap?: boolean;
60
- readonly lane?: 'direct' | 'clustered';
61
+ readonly renderPath?: 'forward' | 'deferred';
61
62
  readonly surfaceQuat?: readonly [number, number, number, number];
63
+ readonly directionalLight?: boolean;
64
+ readonly localLight?: boolean;
62
65
  }
63
66
 
64
67
  function textureAsset(value: number): TextureAsset {
@@ -106,6 +109,7 @@ async function renderCase(testCase: TransmissionCase): Promise<{
106
109
  readonly pixel: readonly [number, number, number, number];
107
110
  readonly passNames: readonly string[];
108
111
  readonly observation: boolean;
112
+ readonly errors: readonly string[];
109
113
  }> {
110
114
  let device: GPUDevice | undefined;
111
115
  let configuredDevice: GPUDevice | undefined;
@@ -157,7 +161,7 @@ async function renderCase(testCase: TransmissionCase): Promise<{
157
161
  {
158
162
  standardProfile: {
159
163
  ...DEFAULT_STANDARD_PROFILE,
160
- lighting: testCase.lane ?? 'direct',
164
+ renderPath: testCase.renderPath ?? DEFAULT_STANDARD_PROFILE.renderPath,
161
165
  },
162
166
  },
163
167
  { shaderManifestUrl: ENGINE_MANIFEST_URL },
@@ -172,6 +176,10 @@ async function renderCase(testCase: TransmissionCase): Promise<{
172
176
  }
173
177
 
174
178
  const { renderer } = host.value;
179
+ const errors: string[] = [];
180
+ const unsubscribe = renderer.subscribe((event) => {
181
+ if (event.kind === 'error') errors.push(event.error.code);
182
+ });
175
183
  const world = new World();
176
184
  const lease = renderer.attach(world);
177
185
  if (!lease.ok) throw lease.error;
@@ -277,12 +285,22 @@ async function renderCase(testCase: TransmissionCase): Promise<{
277
285
  );
278
286
  expect(cameraEntity.ok, `${testCase.name}: camera spawn must succeed`).toBe(true);
279
287
  if (!cameraEntity.ok) throw cameraEntity.error;
280
- const lightEntity = world.spawn({
281
- component: DirectionalLight,
282
- data: { direction: [0, 0, -1], color: [1, 1, 1], intensity: 1, castShadow: false },
283
- });
284
- expect(lightEntity.ok, `${testCase.name}: light spawn must succeed`).toBe(true);
285
- if (!lightEntity.ok) throw lightEntity.error;
288
+ if (testCase.directionalLight !== false) {
289
+ const lightEntity = world.spawn({
290
+ component: DirectionalLight,
291
+ data: { direction: [0, 0, -1], color: [1, 1, 1], intensity: 1, castShadow: false },
292
+ });
293
+ expect(lightEntity.ok, `${testCase.name}: light spawn must succeed`).toBe(true);
294
+ if (!lightEntity.ok) throw lightEntity.error;
295
+ }
296
+ if (testCase.localLight === true) {
297
+ const localLightEntity = world.spawn(
298
+ { component: Transform, data: { pos: [0, 0, 1] } },
299
+ { component: PointLight, data: { intensity: 8, range: 10 } },
300
+ );
301
+ expect(localLightEntity.ok, `${testCase.name}: local light spawn must succeed`).toBe(true);
302
+ if (!localLightEntity.ok) throw localLightEntity.error;
303
+ }
286
304
  world.update().unwrap();
287
305
  const drawn = renderer.draw({
288
306
  leases: [lease.value],
@@ -299,10 +317,12 @@ async function renderCase(testCase: TransmissionCase): Promise<{
299
317
  const renderDevice = configuredDevice ?? device;
300
318
  const passNames = renderer.inspect().perFramePassNames;
301
319
  expect(renderer.inspect().renderScene.projectionRecords).toBeGreaterThanOrEqual(1);
320
+ unsubscribe();
302
321
  return {
303
322
  pixel: await readCenter(renderDevice, target),
304
323
  passNames,
305
324
  observation: observation.ok,
325
+ errors,
306
326
  };
307
327
  }
308
328
 
@@ -403,9 +423,9 @@ describe('Standard transmission Dawn ROI', () => {
403
423
  );
404
424
  }, 120_000);
405
425
 
406
- it('exercises direct/clustered lanes and transmission-before-BLEND overlap order', async () => {
407
- const direct = await renderCase({
408
- name: 'direct',
426
+ it('exercises both Standard render paths and transmission-before-BLEND overlap order', async () => {
427
+ const forward = await renderCase({
428
+ name: 'forward',
409
429
  transmission: 1,
410
430
  ior: 1.5,
411
431
  thickness: 0.5,
@@ -413,10 +433,10 @@ describe('Standard transmission Dawn ROI', () => {
413
433
  attenuationColor: [0.7, 0.8, 0.9],
414
434
  attenuationDistance: 2,
415
435
  overlap: true,
416
- lane: 'direct',
436
+ renderPath: 'forward',
417
437
  });
418
- const clustered = await renderCase({
419
- name: 'clustered',
438
+ const deferred = await renderCase({
439
+ name: 'deferred',
420
440
  transmission: 1,
421
441
  ior: 1.5,
422
442
  thickness: 0.5,
@@ -424,14 +444,33 @@ describe('Standard transmission Dawn ROI', () => {
424
444
  attenuationColor: [0.7, 0.8, 0.9],
425
445
  attenuationDistance: 2,
426
446
  overlap: true,
427
- lane: 'clustered',
447
+ renderPath: 'deferred',
428
448
  });
429
- const transmissionIndex = direct.passNames.indexOf('transmission-forward');
430
- const transparentIndex = direct.passNames.indexOf('transparent');
449
+ const transmissionIndex = forward.passNames.indexOf('transmission-forward');
450
+ const transparentIndex = forward.passNames.indexOf('transparent');
431
451
  expect(transmissionIndex).toBeGreaterThanOrEqual(0);
432
452
  expect(transparentIndex).toBeGreaterThan(transmissionIndex);
433
- expect(clustered.pixel).not.toEqual(direct.pixel);
434
- expect(clustered.pixel.every(Number.isFinite)).toBe(true);
435
- expect(direct.pixel.every(Number.isFinite)).toBe(true);
453
+ expect(deferred.pixel.every(Number.isFinite)).toBe(true);
454
+ expect(forward.pixel.every(Number.isFinite)).toBe(true);
455
+ }, 120_000);
456
+
457
+ it('submits a real clustered local-light frame through the Standard front door', async () => {
458
+ const clustered = await renderCase({
459
+ name: 'clustered-local-light',
460
+ transmission: 0,
461
+ ior: 1.5,
462
+ thickness: 0,
463
+ roughness: 0.4,
464
+ attenuationColor: [1, 1, 1],
465
+ directionalLight: false,
466
+ localLight: true,
467
+ renderPath: 'forward',
468
+ });
469
+
470
+ expect(clustered.passNames).toEqual(
471
+ expect.arrayContaining(['cluster-membership-producer', 'main', 'output-transform']),
472
+ );
473
+ expect(clustered.observation).toBe(true);
474
+ expect(clustered.errors).toEqual([]);
436
475
  }, 120_000);
437
476
  });
@@ -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);
@@ -222,17 +225,29 @@ export function addTypedScenePass(
222
225
  projectorSampler:
223
226
  internal.spotLightProjector?.sampler ?? internal.volumetricFog?.projectorSampler,
224
227
  },
228
+ true,
229
+ internal.standardLighting,
225
230
  );
226
231
  if (groups.viewBindGroup !== null) {
227
232
  options.gpuDriven?.encode(groups.viewBindGroup, pass, resources);
228
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;
229
240
  encodeMainPass(
230
241
  {
231
242
  ...internal,
243
+ ...(activeOcclusion === undefined ? {} : { occlusion: activeOcclusion }),
232
244
  geometryColorView: colorViews[0] ?? null,
233
245
  geometryDepthView: depthView,
234
246
  geometryColorResolveView: resolveView,
235
247
  transparentColorFormat: colorTargets[0]?.format as GPUTextureFormat,
248
+ ...(colorTargets[1]?.format === 'rgba16float'
249
+ ? { reflectionFallbackColorFormat: 'rgba16float' as const }
250
+ : {}),
236
251
  msaaActive: colorTargets[0]?.sampleCount === 4,
237
252
  viewBindGroup: groups.viewBindGroup,
238
253
  meshBindGroup: groups.meshBindGroup,
@@ -254,6 +269,10 @@ export function addTypedScenePass(
254
269
  : { transmissionBackdropView: transmissionBackdrop }),
255
270
  },
256
271
  );
272
+ if (activeOcclusion !== undefined) {
273
+ const proxyResult = activeOcclusion.encodeProxyBounds(pass);
274
+ if (!proxyResult.ok) throw proxyResult.error;
275
+ }
257
276
  },
258
277
  });
259
278
  }
@@ -289,6 +308,37 @@ export function addTypedFrameObservationPass(
289
308
  });
290
309
  }
291
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
+
292
342
  export interface TypedBloomTargets {
293
343
  readonly scene: RenderPipelineTarget;
294
344
  readonly composited: RenderPipelineTarget;
@@ -696,7 +746,7 @@ export function addTypedOutputTransformPass(
696
746
  graph: RenderGraphBuilder<RenderPipelineFrame>,
697
747
  input: RenderPipelineTarget,
698
748
  output: RenderPipelineTarget,
699
- options: { readonly outputOnly?: boolean; readonly outputTransform?: boolean } = {},
749
+ options: { readonly outputOnly?: boolean; readonly dither?: boolean } = {},
700
750
  ): Result<void, RenderGraphError> {
701
751
  const outputOnly = options.outputOnly ?? false;
702
752
  return addTypedFullscreenPass(graph, {
@@ -706,7 +756,7 @@ export function addTypedOutputTransformPass(
706
756
  output,
707
757
  outputOnly,
708
758
  rawSwapchainOutput: outputOnly,
709
- ...(options.outputTransform === true
759
+ ...(options.dither !== undefined
710
760
  ? {
711
761
  paramsTransform: (params: Uint8Array | undefined): Uint8Array | undefined => {
712
762
  if (params === undefined || params.byteLength !== 16) return params;
@@ -715,7 +765,7 @@ export function addTypedOutputTransformPass(
715
765
  transformed.buffer,
716
766
  transformed.byteOffset,
717
767
  transformed.byteLength,
718
- ).setFloat32(12, 1, true);
768
+ ).setFloat32(12, options.dither === true ? 1 : 0, true);
719
769
  return transformed;
720
770
  },
721
771
  }
@@ -13,7 +13,7 @@ import { createRenderPipelineTarget, type RenderPipelineTarget } from './render-
13
13
  import { resolveDirectionalShadowAtlasGrid } from './typed-shadow-atlas';
14
14
 
15
15
  export interface TypedShadowTargets {
16
- readonly directional: RenderPipelineTarget;
16
+ readonly directional?: RenderPipelineTarget | undefined;
17
17
  readonly spot: RenderPipelineTarget;
18
18
  readonly point?: RenderPipelineTarget | undefined;
19
19
  }
@@ -44,44 +44,50 @@ export function addTypedShadowPasses(
44
44
  graph: RenderGraphBuilder<RenderPipelineFrame>,
45
45
  topology: RenderPipelineTopology,
46
46
  ): Result<TypedShadowTargets, RenderGraphError> {
47
- const atlasGrid = resolveDirectionalShadowAtlasGrid(topology.shadow.cascadeCount);
48
- const directional = createRenderPipelineTarget(graph, 'directional-shadow-depth', {
49
- format: 'depth32float',
50
- size: {
51
- width: topology.shadow.mapSize * atlasGrid.columns,
52
- height: topology.shadow.mapSize * atlasGrid.rows,
53
- },
54
- });
55
- if (!directional.ok) return directional;
56
- for (let cascade = 0; cascade < topology.shadow.cascadeCount; cascade += 1) {
57
- const col = cascade % atlasGrid.columns;
58
- const row = Math.floor(cascade / atlasGrid.columns);
59
- const added = recordShadowPass(
60
- graph,
61
- `shadowCascade${cascade}`,
62
- directional.value,
63
- cascade === 0 ? 'clear' : 'load',
64
- ({ pass, frame }) =>
65
- encodeDirectionalShadowPass(frame as never, pass, cascade, {
66
- x: col * topology.shadow.mapSize,
67
- y: row * topology.shadow.mapSize,
68
- w: topology.shadow.mapSize,
69
- h: topology.shadow.mapSize,
70
- }),
71
- (frame) => !(frame as _InternalRenderPipelineContext).directionalShadowCacheReuse,
72
- );
73
- if (!added.ok) return added;
47
+ let directional: RenderPipelineTarget | undefined;
48
+ if (topology.shadow.directional !== 'disabled') {
49
+ const { mapSize, cascadeCount } = topology.shadow.directional;
50
+ const atlasGrid = resolveDirectionalShadowAtlasGrid(cascadeCount);
51
+ const target = createRenderPipelineTarget(graph, 'directional-shadow-depth', {
52
+ format: 'depth32float',
53
+ size: {
54
+ width: mapSize * atlasGrid.columns,
55
+ height: mapSize * atlasGrid.rows,
56
+ },
57
+ });
58
+ if (!target.ok) return target;
59
+ const directionalTarget = target.value;
60
+ directional = directionalTarget;
61
+ for (let cascade = 0; cascade < cascadeCount; cascade += 1) {
62
+ const col = cascade % atlasGrid.columns;
63
+ const row = Math.floor(cascade / atlasGrid.columns);
64
+ const added = recordShadowPass(
65
+ graph,
66
+ `shadowCascade${cascade}`,
67
+ directionalTarget,
68
+ cascade === 0 ? 'clear' : 'load',
69
+ ({ pass, frame }) =>
70
+ encodeDirectionalShadowPass(frame as never, pass, cascade, {
71
+ x: col * mapSize,
72
+ y: row * mapSize,
73
+ w: mapSize,
74
+ h: mapSize,
75
+ }),
76
+ (frame) => !(frame as _InternalRenderPipelineContext).directionalShadowCacheReuse,
77
+ );
78
+ if (!added.ok) return added;
79
+ }
80
+ const observation = graph.addCopyPass('directional-shadow-observation', {
81
+ accesses: [{ resource: directionalTarget.view, usage: 'copy-src' }],
82
+ encode: ({ frame, resources }) => {
83
+ const internal = frame as _InternalRenderPipelineContext;
84
+ const texture = resources.texture(directionalTarget.texture);
85
+ if (!texture.ok) throw texture.error;
86
+ internal.pipelineState.perPassResources.shadowTexture = texture.value;
87
+ },
88
+ });
89
+ if (!observation.ok) return observation;
74
90
  }
75
- const observation = graph.addCopyPass('directional-shadow-observation', {
76
- accesses: [{ resource: directional.value.view, usage: 'copy-src' }],
77
- encode: ({ frame, resources }) => {
78
- const internal = frame as _InternalRenderPipelineContext;
79
- const texture = resources.texture(directional.value.texture);
80
- if (!texture.ok) throw texture.error;
81
- internal.pipelineState.perPassResources.shadowTexture = texture.value;
82
- },
83
- });
84
- if (!observation.ok) return observation;
85
91
 
86
92
  let point: RenderPipelineTarget | undefined;
87
93
  if (topology.shadow.pointCount > 0) {
@@ -148,7 +154,7 @@ export function addTypedShadowPasses(
148
154
 
149
155
  const spot = createRenderPipelineTarget(graph, 'spot-shadow-depth', {
150
156
  format: 'depth32float',
151
- size: { width: topology.shadow.mapSize * 2, height: topology.shadow.mapSize * 2 },
157
+ size: { width: topology.shadow.spotMapSize * 2, height: topology.shadow.spotMapSize * 2 },
152
158
  });
153
159
  if (!spot.ok) return spot;
154
160
  for (let spotIndex = 0; spotIndex < Math.max(1, topology.shadow.spotCount); spotIndex += 1) {
@@ -162,5 +168,5 @@ export function addTypedShadowPasses(
162
168
  if (!added.ok) return added;
163
169
  }
164
170
 
165
- return ok({ directional: directional.value, spot: spot.value, point });
171
+ return ok({ directional, spot: spot.value, point });
166
172
  }
@@ -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 {
@@ -89,10 +81,12 @@ export interface VolumetricFogPassInputs {
89
81
  readonly density: GraphTextureView;
90
82
  readonly params: GraphBuffer;
91
83
  readonly view: GraphBuffer;
92
- readonly directionalShadow: GraphTextureView;
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
  }
@@ -166,13 +160,29 @@ function importVolumeInputs(
166
160
  topology: RenderPipelineTopology,
167
161
  linearHdr: RenderPipelineTarget,
168
162
  sceneDepth: GraphTextureView,
169
- directionalShadow: GraphTextureView,
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(
@@ -268,10 +263,10 @@ function importVolumeInputs(
268
263
  density: density.value,
269
264
  params: params.value,
270
265
  view: view.value,
271
- directionalShadow,
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
  });
@@ -281,8 +276,9 @@ export function addAuthoredVolumetricFogPasses(
281
276
  topology: RenderPipelineTopology,
282
277
  linearHdr: RenderPipelineTarget,
283
278
  sceneDepth: GraphTextureView,
284
- directionalShadow: GraphTextureView,
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);
@@ -320,6 +317,15 @@ export function addVolumetricFogPasses(
320
317
  const packedLayers = Math.ceil(inputs.resources.extent.depth / VOLUME_PACKING_Z);
321
318
  const resolvedDispatchX = Math.ceil(inputs.resources.resolvedExtent.width / 8);
322
319
  const resolvedDispatchY = Math.ceil(inputs.resources.resolvedExtent.height / 8);
320
+ // Point-light volume injection has no cube-array shadow sampler. It keeps
321
+ // the directional cascade count at zero and therefore needs only a valid
322
+ // 2D depth binding; use the always-present spot target as the inert binding
323
+ // when directional shadows are disabled. Directional selection still uses
324
+ // its own target whenever one exists, and spot selection uses spotShadow.
325
+ const shadowResource =
326
+ inputs.selectedLightKind === 'spot'
327
+ ? inputs.spotShadow
328
+ : (inputs.directionalShadow ?? inputs.spotShadow);
323
329
  let inject: ComputeState | undefined;
324
330
  let integrate: ComputeState | undefined;
325
331
  let temporal: ComputeState | undefined;
@@ -330,12 +336,11 @@ export function addVolumetricFogPasses(
330
336
  { resource: inputs.params, usage: 'uniform-read' },
331
337
  { resource: inputs.view, usage: 'uniform-read' },
332
338
  {
333
- resource:
334
- inputs.selectedLightKind === 'spot' ? inputs.spotShadow : inputs.directionalShadow,
339
+ resource: shadowResource,
335
340
  usage: 'sampled-read',
336
341
  },
337
- { resource: inputs.spotLights, usage: 'storage-read' },
338
- { resource: inputs.pointLights, usage: 'storage-read' },
342
+ { resource: inputs.lightData, usage: 'storage-read' },
343
+ { resource: inputs.clusterUniform, usage: 'uniform-read' },
339
344
  ...(inputs.projector === undefined
340
345
  ? []
341
346
  : [{ resource: inputs.projector, usage: 'sampled-read' as const }]),
@@ -357,21 +362,19 @@ export function addVolumetricFogPasses(
357
362
  },
358
363
  },
359
364
  { binding: 7, visibility: 4, buffer: { type: 'read-only-storage' } },
360
- { binding: 8, visibility: 4, buffer: { type: 'read-only-storage' } },
365
+ { binding: 8, visibility: 4, buffer: { type: 'uniform' } },
361
366
  ]);
362
- const shadow = resources.textureView(
363
- inputs.selectedLightKind === 'spot' ? inputs.spotShadow : inputs.directionalShadow,
364
- );
367
+ const shadow = resources.textureView(shadowResource);
365
368
  const params = resources.buffer(inputs.params);
366
369
  const view = resources.buffer(inputs.view);
367
- const spotLights = resources.buffer(inputs.spotLights);
368
- const pointLights = resources.buffer(inputs.pointLights);
370
+ const lightData = resources.buffer(inputs.lightData);
371
+ const clusterUniform = resources.buffer(inputs.clusterUniform);
369
372
  const froxel = resources.textureView(inputs.resources.froxelView);
370
373
  if (!shadow.ok) throw shadow.error;
371
374
  if (!params.ok) throw params.error;
372
375
  if (!view.ok) throw view.error;
373
- if (!spotLights.ok) throw spotLights.error;
374
- if (!pointLights.ok) throw pointLights.error;
376
+ if (!lightData.ok) throw lightData.error;
377
+ if (!clusterUniform.ok) throw clusterUniform.error;
375
378
  if (!froxel.ok) throw froxel.error;
376
379
  const shadowSampler = frame.runtime.device.createSampler({ compare: 'less' });
377
380
  if (!shadowSampler.ok) throw shadowSampler.error;
@@ -381,8 +384,8 @@ export function addVolumetricFogPasses(
381
384
  { binding: 4, resource: { kind: 'sampler', value: shadowSampler.value } },
382
385
  { binding: 5, resource: { kind: 'buffer', value: { buffer: params.value } } },
383
386
  { binding: 6, resource: { kind: 'textureView', value: froxel.value as never } },
384
- { binding: 7, resource: { kind: 'buffer', value: { buffer: spotLights.value } } },
385
- { 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 } } },
386
389
  ]);
387
390
  pass.setPipeline(inject.pipeline);
388
391
  pass.setBindGroup(0, bindings);
@@ -400,8 +403,8 @@ export function addVolumetricFogPasses(
400
403
  { resource: inputs.resources.temporalView, usage: 'storage-write' },
401
404
  { resource: inputs.params, usage: 'uniform-read' },
402
405
  { resource: inputs.view, usage: 'uniform-read' },
403
- { resource: inputs.spotLights, usage: 'storage-read' },
404
- { resource: inputs.pointLights, usage: 'storage-read' },
406
+ { resource: inputs.lightData, usage: 'storage-read' },
407
+ { resource: inputs.clusterUniform, usage: 'uniform-read' },
405
408
  ...(inputs.projector === undefined
406
409
  ? []
407
410
  : [{ resource: inputs.projector, usage: 'sampled-read' as const }]),
@@ -443,7 +446,7 @@ export function addVolumetricFogPasses(
443
446
  },
444
447
  },
445
448
  { binding: 10, visibility: 4, buffer: { type: 'read-only-storage' } },
446
- { binding: 11, visibility: 4, buffer: { type: 'read-only-storage' } },
449
+ { binding: 11, visibility: 4, buffer: { type: 'uniform' } },
447
450
  { binding: 12, visibility: 4, texture: { sampleType: 'float', viewDimension: '2d' } },
448
451
  { binding: 13, visibility: 4, sampler: { type: 'filtering' } },
449
452
  ]);
@@ -455,8 +458,8 @@ export function addVolumetricFogPasses(
455
458
  const temporalSeed = resources.textureView(inputs.resources.temporalView);
456
459
  const params = resources.buffer(inputs.params);
457
460
  const view = resources.buffer(inputs.view);
458
- const spotLights = resources.buffer(inputs.spotLights);
459
- const pointLights = resources.buffer(inputs.pointLights);
461
+ const lightData = resources.buffer(inputs.lightData);
462
+ const clusterUniform = resources.buffer(inputs.clusterUniform);
460
463
  const projector =
461
464
  inputs.projector === undefined ? undefined : resources.textureView(inputs.projector);
462
465
  if (!froxel.ok) throw froxel.error;
@@ -467,8 +470,8 @@ export function addVolumetricFogPasses(
467
470
  if (!temporalSeed.ok) throw temporalSeed.error;
468
471
  if (!params.ok) throw params.error;
469
472
  if (!view.ok) throw view.error;
470
- if (!spotLights.ok) throw spotLights.error;
471
- if (!pointLights.ok) throw pointLights.error;
473
+ if (!lightData.ok) throw lightData.error;
474
+ if (!clusterUniform.ok) throw clusterUniform.error;
472
475
  if (projector !== undefined && !projector.ok) throw projector.error;
473
476
  const sampler = frame.runtime.device.createSampler({
474
477
  minFilter: 'linear',
@@ -494,8 +497,8 @@ export function addVolumetricFogPasses(
494
497
  { binding: 7, resource: { kind: 'sampler', value: densitySampler.value } },
495
498
  { binding: 8, resource: { kind: 'textureView', value: historySeed.value as never } },
496
499
  { binding: 9, resource: { kind: 'textureView', value: temporalSeed.value as never } },
497
- { binding: 10, resource: { kind: 'buffer', value: { buffer: spotLights.value } } },
498
- { 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 } } },
499
502
  {
500
503
  binding: 12,
501
504
  resource: {