@forgeax/engine-render 0.1.19 → 0.1.21

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 (452) hide show
  1. package/README.md +215 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/assembly/device-feature-admission.d.ts +18 -0
  4. package/dist/assembly/device-feature-admission.d.ts.map +1 -0
  5. package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
  6. package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
  7. package/dist/assembly/factory.d.ts +34 -20
  8. package/dist/assembly/factory.d.ts.map +1 -1
  9. package/dist/assembly/host-contract.d.ts +9 -0
  10. package/dist/assembly/host-contract.d.ts.map +1 -1
  11. package/dist/assembly/render-target-host.d.ts +46 -0
  12. package/dist/assembly/render-target-host.d.ts.map +1 -0
  13. package/dist/assets/render-asset-port.d.ts.map +1 -1
  14. package/dist/authoring.mjs +3 -0
  15. package/dist/authoring.mjs.map +1 -1
  16. package/dist/capture/cube-views.d.ts +21 -0
  17. package/dist/capture/cube-views.d.ts.map +1 -0
  18. package/dist/capture/scheduler.d.ts +54 -0
  19. package/dist/capture/scheduler.d.ts.map +1 -0
  20. package/dist/{chunk-RJRUS55L.mjs → chunk-5YADUCA7.mjs} +1896 -1624
  21. package/dist/chunk-5YADUCA7.mjs.map +1 -0
  22. package/dist/{chunk-LOSO4CTV.mjs → chunk-6OPXDQ2E.mjs} +423 -46
  23. package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
  24. package/dist/{chunk-IPXCABEP.mjs → chunk-BXBQQKFQ.mjs} +3 -9
  25. package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
  26. package/dist/chunk-FS2KNUQH.mjs +1294 -0
  27. package/dist/chunk-FS2KNUQH.mjs.map +1 -0
  28. package/dist/components/camera.d.ts +1 -0
  29. package/dist/components/camera.d.ts.map +1 -1
  30. package/dist/components/cube-camera.d.ts +20 -0
  31. package/dist/components/cube-camera.d.ts.map +1 -0
  32. package/dist/components/directional-light.d.ts +11 -2
  33. package/dist/components/directional-light.d.ts.map +1 -1
  34. package/dist/components/directional-shadow-filter.d.ts +25 -0
  35. package/dist/components/directional-shadow-filter.d.ts.map +1 -0
  36. package/dist/components/index.d.ts +2 -0
  37. package/dist/components/index.d.ts.map +1 -1
  38. package/dist/components/light-helpers.d.ts.map +1 -1
  39. package/dist/components/reflection-probe.d.ts +17 -0
  40. package/dist/components/reflection-probe.d.ts.map +1 -0
  41. package/dist/components/spot-light.d.ts +12 -0
  42. package/dist/components/spot-light.d.ts.map +1 -1
  43. package/dist/construct-renderer.mjs +8552 -1612
  44. package/dist/construct-renderer.mjs.map +1 -1
  45. package/dist/device/gpu-residency.d.ts +19 -2
  46. package/dist/device/gpu-residency.d.ts.map +1 -1
  47. package/dist/environment/frame.d.ts.map +1 -1
  48. package/dist/environment/lifecycle.d.ts +5 -0
  49. package/dist/environment/lifecycle.d.ts.map +1 -1
  50. package/dist/errors/render.d.ts +209 -93
  51. package/dist/errors/render.d.ts.map +1 -1
  52. package/dist/extract/directional-shadow-projection.d.ts +23 -0
  53. package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
  54. package/dist/extract/environment.d.ts +14 -0
  55. package/dist/extract/environment.d.ts.map +1 -1
  56. package/dist/extract/visibility.d.ts.map +1 -1
  57. package/dist/features/fullscreen.d.ts.map +1 -1
  58. package/dist/features/targets.d.ts.map +1 -1
  59. package/dist/features/types.d.ts +10 -0
  60. package/dist/features/types.d.ts.map +1 -1
  61. package/dist/fullscreen-post-process-pass.d.ts +13 -2
  62. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  63. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  64. package/dist/gpu-driven/production-raster.d.ts +0 -1
  65. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  66. package/dist/gpu-scene.d.ts.map +1 -1
  67. package/dist/gpu-usage.d.ts +2 -0
  68. package/dist/gpu-usage.d.ts.map +1 -1
  69. package/dist/hdrp-buffers.d.ts +19 -17
  70. package/dist/hdrp-buffers.d.ts.map +1 -1
  71. package/dist/ibl/IblPipelineCache.d.ts +4 -0
  72. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  73. package/dist/ibl/kernel-cache.d.ts +36 -0
  74. package/dist/ibl/kernel-cache.d.ts.map +1 -0
  75. package/dist/index.d.ts +35 -4
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.mjs +4 -4
  78. package/dist/index.mjs.map +1 -1
  79. package/dist/inspection-types.d.ts +51 -0
  80. package/dist/inspection-types.d.ts.map +1 -1
  81. package/dist/instances-derived-bounds.d.ts +50 -0
  82. package/dist/instances-derived-bounds.d.ts.map +1 -0
  83. package/dist/internal.mjs +1 -1
  84. package/dist/light-buffer-layout.d.ts +30 -13
  85. package/dist/light-buffer-layout.d.ts.map +1 -1
  86. package/dist/mesh-material-bindings.d.ts +54 -0
  87. package/dist/mesh-material-bindings.d.ts.map +1 -1
  88. package/dist/pbr-pipeline.d.ts +20 -7
  89. package/dist/pbr-pipeline.d.ts.map +1 -1
  90. package/dist/pipeline/standard-forward-lane.d.ts +2 -1
  91. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  92. package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
  93. package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
  94. package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
  95. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
  96. package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
  97. package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
  98. package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
  99. package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
  100. package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
  101. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
  102. package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
  103. package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
  104. package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
  105. package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
  106. package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
  107. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
  108. package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
  109. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
  110. package/dist/pipeline/standard-pipeline.d.ts +4 -13
  111. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  112. package/dist/pipeline/standard-post.d.ts.map +1 -1
  113. package/dist/pipeline/standard-profile.d.ts +12 -20
  114. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  115. package/dist/pipeline-spec.d.ts +40 -7
  116. package/dist/pipeline-spec.d.ts.map +1 -1
  117. package/dist/point-shadow-inspection.d.ts +21 -0
  118. package/dist/point-shadow-inspection.d.ts.map +1 -0
  119. package/dist/record/frame-lighting.d.ts +29 -32
  120. package/dist/record/frame-lighting.d.ts.map +1 -1
  121. package/dist/record/frame-snapshot.d.ts +65 -15
  122. package/dist/record/frame-snapshot.d.ts.map +1 -1
  123. package/dist/record/frame-targets.d.ts +5 -0
  124. package/dist/record/frame-targets.d.ts.map +1 -1
  125. package/dist/record/frame.d.ts +12 -5
  126. package/dist/record/frame.d.ts.map +1 -1
  127. package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
  128. package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
  129. package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
  130. package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
  131. package/dist/record/gpu-pass-timing/index.d.ts +8 -0
  132. package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
  133. package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
  134. package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
  135. package/dist/record/gpu-pass-timing/session.d.ts +43 -0
  136. package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
  137. package/dist/record/gpu-timing.d.ts +37 -0
  138. package/dist/record/gpu-timing.d.ts.map +1 -0
  139. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  140. package/dist/record/main-pass-material.d.ts +23 -2
  141. package/dist/record/main-pass-material.d.ts.map +1 -1
  142. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  143. package/dist/record/main-pass.d.ts +2 -0
  144. package/dist/record/main-pass.d.ts.map +1 -1
  145. package/dist/record/render-context.d.ts +48 -3
  146. package/dist/record/render-context.d.ts.map +1 -1
  147. package/dist/record/shadow-pass.d.ts.map +1 -1
  148. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  149. package/dist/record/typed-frame-graph.d.ts +81 -5
  150. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  151. package/dist/record/view-ubo.d.ts +7 -4
  152. package/dist/record/view-ubo.d.ts.map +1 -1
  153. package/dist/reflection/filter.d.ts +22 -0
  154. package/dist/reflection/filter.d.ts.map +1 -0
  155. package/dist/reflection/gpu-table.d.ts +25 -0
  156. package/dist/reflection/gpu-table.d.ts.map +1 -0
  157. package/dist/reflection/projection.d.ts +91 -0
  158. package/dist/reflection/projection.d.ts.map +1 -0
  159. package/dist/render-contract.d.ts +114 -7
  160. package/dist/render-contract.d.ts.map +1 -1
  161. package/dist/render-data.d.ts +10 -6
  162. package/dist/render-data.d.ts.map +1 -1
  163. package/dist/render-graph-primitives.d.ts +1 -0
  164. package/dist/render-graph-primitives.d.ts.map +1 -1
  165. package/dist/render-pipeline.d.ts +78 -2
  166. package/dist/render-pipeline.d.ts.map +1 -1
  167. package/dist/render-system-extract.d.ts +113 -20
  168. package/dist/render-system-extract.d.ts.map +1 -1
  169. package/dist/render-system.d.ts +24 -3
  170. package/dist/render-system.d.ts.map +1 -1
  171. package/dist/renderer-inspect.d.ts +29 -0
  172. package/dist/renderer-inspect.d.ts.map +1 -0
  173. package/dist/renderer.d.ts +43 -0
  174. package/dist/renderer.d.ts.map +1 -0
  175. package/dist/scene/render-scene.d.ts +14 -0
  176. package/dist/scene/render-scene.d.ts.map +1 -1
  177. package/dist/shadow-atlas.d.ts +3 -3
  178. package/dist/shadow-atlas.d.ts.map +1 -1
  179. package/dist/ssao-buffers.d.ts +3 -0
  180. package/dist/ssao-buffers.d.ts.map +1 -1
  181. package/dist/targets/contracts.d.ts +66 -0
  182. package/dist/targets/contracts.d.ts.map +1 -0
  183. package/dist/targets/graph-projection.d.ts +29 -0
  184. package/dist/targets/graph-projection.d.ts.map +1 -0
  185. package/dist/targets/material-source.d.ts +34 -0
  186. package/dist/targets/material-source.d.ts.map +1 -0
  187. package/dist/targets/owner.d.ts +32 -0
  188. package/dist/targets/owner.d.ts.map +1 -0
  189. package/dist/targets/physical.d.ts +18 -0
  190. package/dist/targets/physical.d.ts.map +1 -0
  191. package/dist/targets/readback.d.ts +39 -0
  192. package/dist/targets/readback.d.ts.map +1 -0
  193. package/dist/temporal/frame.d.ts +44 -0
  194. package/dist/temporal/frame.d.ts.map +1 -0
  195. package/dist/temporal/index.mjs +3 -3
  196. package/dist/typed-render-graph-primitives.d.ts +6 -1
  197. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  198. package/dist/typed-shadow-atlas.d.ts +10 -0
  199. package/dist/typed-shadow-atlas.d.ts.map +1 -0
  200. package/dist/typed-shadow-passes.d.ts +1 -1
  201. package/dist/typed-shadow-passes.d.ts.map +1 -1
  202. package/dist/volume/capability.d.ts +57 -0
  203. package/dist/volume/capability.d.ts.map +1 -0
  204. package/dist/volume/component.d.ts +61 -0
  205. package/dist/volume/component.d.ts.map +1 -0
  206. package/dist/volume/extract.d.ts +11 -0
  207. package/dist/volume/extract.d.ts.map +1 -0
  208. package/dist/volume/inspection.d.ts +38 -0
  209. package/dist/volume/inspection.d.ts.map +1 -0
  210. package/dist/volume/passes.d.ts +38 -0
  211. package/dist/volume/passes.d.ts.map +1 -0
  212. package/dist/volume/recovery.d.ts +38 -0
  213. package/dist/volume/recovery.d.ts.map +1 -0
  214. package/dist/volume/resources.d.ts +57 -0
  215. package/dist/volume/resources.d.ts.map +1 -0
  216. package/dist/volume/temporal.d.ts +35 -0
  217. package/dist/volume/temporal.d.ts.map +1 -0
  218. package/package.json +20 -20
  219. package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
  220. package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
  221. package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
  222. package/src/__tests__/cluster-binner.unit.test.ts +35 -0
  223. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -2
  224. package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
  225. package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
  226. package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
  227. package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
  228. package/src/__tests__/cube-camera.integration.test.ts +42 -0
  229. package/src/__tests__/device-feature-admission.unit.test.ts +73 -0
  230. package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -3
  231. package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
  232. package/src/__tests__/factory-contract.integration.test.ts +255 -29
  233. package/src/__tests__/fog-component.unit.test.ts +67 -0
  234. package/src/__tests__/fog.integration.test.ts +86 -0
  235. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
  236. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -9
  237. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +17 -1
  238. package/src/__tests__/gpu-driven-production.integration.test.ts +16 -17
  239. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +12 -4
  240. package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
  241. package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
  242. package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
  243. package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
  244. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
  245. package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
  246. package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
  247. package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
  248. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
  249. package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
  250. package/src/__tests__/instances-culling.integration.test.ts +94 -0
  251. package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
  252. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -14
  253. package/src/__tests__/material-observation.integration.test.ts +101 -0
  254. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
  255. package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
  256. package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
  257. package/src/__tests__/public-surface.test-d.ts +10 -0
  258. package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
  259. package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
  260. package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
  261. package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
  262. package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
  263. package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
  264. package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
  265. package/src/__tests__/render-error-code-owner.test-d.ts +23 -3
  266. package/src/__tests__/render-feature-docs.unit.test.ts +1 -1
  267. package/src/__tests__/render-target-admission.unit.test.ts +80 -0
  268. package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
  269. package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
  270. package/src/__tests__/render-target-material-source.test-d.ts +30 -0
  271. package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
  272. package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
  273. package/src/__tests__/render-target-owner.unit.test.ts +122 -0
  274. package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
  275. package/src/__tests__/render-target-public-schema.json +107 -0
  276. package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
  277. package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
  278. package/src/__tests__/render-target-readback.integration.test.ts +90 -0
  279. package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
  280. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
  281. package/src/__tests__/renderer-frame-transaction.integration.test.ts +1 -1
  282. package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
  283. package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
  284. package/src/__tests__/skin-motion-regression.unit.test.ts +132 -0
  285. package/src/__tests__/skinned-shadow-caster.test.ts +32 -2
  286. package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
  287. package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
  288. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +232 -0
  289. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +8 -5
  290. package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
  291. package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
  292. package/src/__tests__/standard-lighting-write.unit.test.ts +377 -0
  293. package/src/__tests__/standard-lighting.integration.test.ts +67 -0
  294. package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
  295. package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
  296. package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
  297. package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -36
  298. package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
  299. package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
  300. package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
  301. package/src/__tests__/volume-optics-oracle.unit.test.ts +85 -0
  302. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +655 -0
  303. package/src/__tests__/volumetric-fog-component.unit.test.ts +71 -0
  304. package/src/__tests__/volumetric-fog-composite-stage-readback.dawn.test.ts +376 -0
  305. package/src/__tests__/volumetric-fog-errors.unit.test.ts +51 -0
  306. package/src/__tests__/volumetric-fog-inspection.unit.test.ts +77 -0
  307. package/src/__tests__/volumetric-fog-light-capability.unit.test.ts +19 -0
  308. package/src/__tests__/volumetric-fog-light-consumers.integration.test.ts +18 -0
  309. package/src/__tests__/volumetric-fog-light-errors.unit.test.ts +17 -0
  310. package/src/__tests__/volumetric-fog-light-topology.unit.test.ts +21 -0
  311. package/src/__tests__/volumetric-fog-light-transaction.integration.test.ts +53 -0
  312. package/src/__tests__/volumetric-fog-m9-watcher.integration.test.ts +27 -0
  313. package/src/__tests__/volumetric-fog-point-light-owner.integration.test.ts +44 -0
  314. package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +49 -0
  315. package/src/__tests__/volumetric-fog-point-spot-contract.unit.test.ts +28 -0
  316. package/src/__tests__/volumetric-fog-point-spot-lkg.integration.test.ts +65 -0
  317. package/src/__tests__/volumetric-fog-point-spot-selection.integration.test.ts +49 -0
  318. package/src/__tests__/volumetric-fog-point-spot-temporal.unit.test.ts +55 -0
  319. package/src/__tests__/volumetric-fog-projector-contract.unit.test.ts +22 -0
  320. package/src/__tests__/volumetric-fog-projector-inspection.unit.test.ts +12 -0
  321. package/src/__tests__/volumetric-fog-projector-surface-volume.integration.test.ts +11 -0
  322. package/src/__tests__/volumetric-fog-projector-transaction.integration.test.ts +26 -0
  323. package/src/__tests__/volumetric-fog-recovery.integration.test.ts +47 -0
  324. package/src/__tests__/volumetric-fog-selected-light-resolution.integration.test.ts +63 -0
  325. package/src/__tests__/volumetric-fog-spot-closure.integration.test.ts +26 -0
  326. package/src/__tests__/volumetric-fog-spot-contract.test-d.ts +21 -0
  327. package/src/__tests__/volumetric-fog-spot-contract.unit.test.ts +27 -0
  328. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +14 -0
  329. package/src/__tests__/volumetric-fog-spot-optics.integration.test.ts +29 -0
  330. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +550 -0
  331. package/src/__tests__/volumetric-fog-temporal-selected-light.unit.test.ts +33 -0
  332. package/src/__tests__/volumetric-fog-temporal.unit.test.ts +45 -0
  333. package/src/__tests__/volumetric-fog-topology.unit.test.ts +237 -0
  334. package/src/__tests__/volumetric-fog-transparent.integration.test.ts +27 -0
  335. package/src/assembly/device-feature-admission.ts +73 -0
  336. package/src/assembly/directional-shadow-inspection.ts +122 -0
  337. package/src/assembly/factory.ts +1093 -246
  338. package/src/assembly/host-contract.ts +25 -0
  339. package/src/assembly/render-target-host.ts +847 -0
  340. package/src/assets/asset-decoders.ts +1 -1
  341. package/src/assets/render-asset-port.ts +7 -1
  342. package/src/capture/cube-views.ts +69 -0
  343. package/src/capture/scheduler.ts +265 -0
  344. package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
  345. package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
  346. package/src/components/camera.ts +4 -0
  347. package/src/components/cube-camera.ts +52 -0
  348. package/src/components/directional-light.ts +22 -2
  349. package/src/components/directional-shadow-filter.ts +57 -0
  350. package/src/components/index.ts +2 -0
  351. package/src/components/light-helpers.ts +85 -7
  352. package/src/components/reflection-probe.ts +49 -0
  353. package/src/components/spot-light.ts +22 -3
  354. package/src/device/gpu-residency.ts +168 -58
  355. package/src/environment/frame.ts +6 -24
  356. package/src/environment/lifecycle.ts +12 -0
  357. package/src/errors/render.ts +405 -143
  358. package/src/extract/directional-shadow-projection.ts +61 -0
  359. package/src/extract/environment.ts +57 -0
  360. package/src/extract/visibility.ts +25 -1
  361. package/src/features/fullscreen.ts +3 -0
  362. package/src/features/targets.ts +4 -1
  363. package/src/features/types.ts +10 -0
  364. package/src/fullscreen-post-process-pass.ts +43 -2
  365. package/src/gpu-driven/batch-topology.ts +1 -0
  366. package/src/gpu-driven/production-raster.ts +1 -3
  367. package/src/gpu-scene.ts +8 -1
  368. package/src/gpu-usage.ts +2 -0
  369. package/src/hdrp-buffers.ts +165 -59
  370. package/src/ibl/IblPipelineCache.ts +11 -0
  371. package/src/ibl/kernel-cache.ts +88 -0
  372. package/src/index.ts +186 -1
  373. package/src/inspection-types.ts +56 -0
  374. package/src/instances-derived-bounds.ts +171 -0
  375. package/src/light-buffer-layout.ts +74 -26
  376. package/src/mesh-material-bindings.ts +132 -0
  377. package/src/pbr-pipeline.ts +139 -27
  378. package/src/pipeline/standard-forward-lane.ts +65 -15
  379. package/src/pipeline/standard-lighting/errors.ts +6 -0
  380. package/src/pipeline/standard-lighting/graph.ts +157 -0
  381. package/src/pipeline/standard-lighting/inspection.ts +88 -0
  382. package/src/pipeline/standard-lighting/layout.ts +31 -0
  383. package/src/pipeline/standard-lighting/light-frame.ts +34 -0
  384. package/src/pipeline/standard-lighting/membership.ts +43 -0
  385. package/src/pipeline/standard-lighting/prepare.ts +37 -0
  386. package/src/pipeline/standard-lighting/topology.ts +120 -0
  387. package/src/pipeline/standard-lighting/transport.ts +77 -0
  388. package/src/pipeline/standard-pipeline.ts +141 -192
  389. package/src/pipeline/standard-post.ts +26 -7
  390. package/src/pipeline/standard-profile.ts +23 -30
  391. package/src/pipeline-spec.ts +84 -21
  392. package/src/point-shadow-inspection.ts +55 -0
  393. package/src/record/__tests__/temporal-payload.unit.test.ts +42 -1
  394. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
  395. package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
  396. package/src/record/frame-lighting.ts +470 -516
  397. package/src/record/frame-snapshot.ts +76 -28
  398. package/src/record/frame-targets.ts +23 -2
  399. package/src/record/frame.ts +1169 -79
  400. package/src/record/gpu-pass-timing/contract.ts +180 -0
  401. package/src/record/gpu-pass-timing/errors.ts +34 -0
  402. package/src/record/gpu-pass-timing/index.ts +37 -0
  403. package/src/record/gpu-pass-timing/parser.ts +97 -0
  404. package/src/record/gpu-pass-timing/session.ts +938 -0
  405. package/src/record/gpu-timing.ts +233 -0
  406. package/src/record/main-pass-geometry.ts +120 -80
  407. package/src/record/main-pass-material.ts +101 -11
  408. package/src/record/main-pass-sprite-draws.ts +54 -25
  409. package/src/record/main-pass.ts +71 -15
  410. package/src/record/render-context.ts +77 -0
  411. package/src/record/shadow-pass.ts +104 -66
  412. package/src/record/skybox-post-pass.ts +20 -4
  413. package/src/record/typed-frame-graph.ts +1016 -32
  414. package/src/record/view-ubo.ts +63 -28
  415. package/src/reflection/filter.ts +81 -0
  416. package/src/reflection/gpu-table.ts +44 -0
  417. package/src/reflection/projection.ts +281 -0
  418. package/src/render-contract.ts +147 -4
  419. package/src/render-data.ts +50 -22
  420. package/src/render-graph-primitives.ts +9 -4
  421. package/src/render-pipeline.ts +161 -2
  422. package/src/render-system-extract.ts +886 -103
  423. package/src/render-system.ts +1174 -66
  424. package/src/renderer-inspect.ts +66 -0
  425. package/src/renderer.ts +222 -0
  426. package/src/scene/render-scene.ts +117 -9
  427. package/src/shadow-atlas.ts +5 -5
  428. package/src/ssao-buffers.ts +9 -2
  429. package/src/targets/contracts.ts +182 -0
  430. package/src/targets/graph-projection.ts +169 -0
  431. package/src/targets/material-source.ts +143 -0
  432. package/src/targets/owner.ts +214 -0
  433. package/src/targets/physical.ts +18 -0
  434. package/src/targets/readback.ts +153 -0
  435. package/src/temporal/frame.ts +128 -0
  436. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +61 -23
  437. package/src/typed-render-graph-primitives.ts +34 -2
  438. package/src/typed-shadow-atlas.ts +17 -0
  439. package/src/typed-shadow-passes.ts +47 -40
  440. package/src/volume/capability.ts +173 -0
  441. package/src/volume/component.ts +110 -0
  442. package/src/volume/extract.ts +21 -0
  443. package/src/volume/inspection.ts +78 -0
  444. package/src/volume/passes.ts +686 -0
  445. package/src/volume/recovery.ts +86 -0
  446. package/src/volume/resources.ts +236 -0
  447. package/src/volume/temporal.ts +89 -0
  448. package/dist/chunk-IPXCABEP.mjs.map +0 -1
  449. package/dist/chunk-LOSO4CTV.mjs.map +0 -1
  450. package/dist/chunk-RJRUS55L.mjs.map +0 -1
  451. package/dist/chunk-YTQ5C7YQ.mjs +0 -584
  452. package/dist/chunk-YTQ5C7YQ.mjs.map +0 -1
@@ -0,0 +1,686 @@
1
+ import type {
2
+ GraphBuffer,
3
+ GraphTextureView,
4
+ RenderGraphBuilder,
5
+ RenderGraphError,
6
+ } from '@forgeax/engine-render-graph';
7
+ import type {
8
+ BindGroup,
9
+ BindGroupLayout,
10
+ Buffer,
11
+ ComputePipeline,
12
+ RenderPipeline,
13
+ Sampler,
14
+ TextureView,
15
+ } from '@forgeax/engine-rhi';
16
+ import { RhiError } from '@forgeax/engine-rhi';
17
+ import { ok, type Result } from '@forgeax/engine-types';
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';
29
+ import { VIEW_UNIFORM_BYTES } from '../record/view-ubo';
30
+ import type { VolumetricFogFrameContext, VolumetricFogShaderSources } from '../render-contract';
31
+ import type {
32
+ RenderPipelineFrame,
33
+ RenderPipelineTarget,
34
+ RenderPipelineTopology,
35
+ } from '../render-pipeline';
36
+ import type { VolumetricFogResources } from './resources';
37
+ import {
38
+ createVolumetricFogResources,
39
+ VOLUME_FROXEL_FORMAT,
40
+ VOLUME_HISTORY_FORMAT,
41
+ VOLUME_PACKING_Z,
42
+ VOLUME_RESOLVED_FORMAT,
43
+ } from './resources';
44
+ import type { VolumeProjectorTuple } from './temporal';
45
+
46
+ export const VOLUMETRIC_FOG_PASS_ORDER = [
47
+ 'volume-inject',
48
+ 'volume-integrate',
49
+ 'volume-temporal',
50
+ 'volume-composite',
51
+ ] as const;
52
+ export interface VolumetricFogTopology {
53
+ readonly passes: readonly string[];
54
+ readonly resources: readonly string[];
55
+ readonly colorInput: 'linear-hdr';
56
+ readonly depthInput: 'scene-depth';
57
+ readonly lightKind?: 'directional' | 'point' | 'spot';
58
+ readonly lightEntity?: number;
59
+ readonly lightRevision?: number;
60
+ readonly projector?: Pick<VolumeProjectorTuple, 'guid' | 'generation' | 'revision'>;
61
+ }
62
+ export function volumetricFogTopology(
63
+ enabled: boolean,
64
+ selectedLight?: {
65
+ readonly lightKind: 'directional' | 'point' | 'spot';
66
+ readonly lightEntity: number;
67
+ readonly lightRevision: number;
68
+ },
69
+ ): VolumetricFogTopology {
70
+ return enabled
71
+ ? {
72
+ passes: [...VOLUMETRIC_FOG_PASS_ORDER],
73
+ resources: [
74
+ 'volume-froxel',
75
+ 'volume-resolved-current',
76
+ 'volume-history',
77
+ 'volume-temporal',
78
+ ],
79
+ colorInput: 'linear-hdr',
80
+ depthInput: 'scene-depth',
81
+ ...(selectedLight ?? {}),
82
+ }
83
+ : { passes: [], resources: [], colorInput: 'linear-hdr', depthInput: 'scene-depth' };
84
+ }
85
+ export interface VolumetricFogPassInputs {
86
+ readonly resources: VolumetricFogResources;
87
+ readonly linearHdr: RenderPipelineTarget;
88
+ readonly sceneDepth: GraphTextureView;
89
+ readonly density: GraphTextureView;
90
+ readonly params: GraphBuffer;
91
+ readonly view: GraphBuffer;
92
+ readonly directionalShadow?: GraphTextureView;
93
+ readonly spotShadow: GraphTextureView;
94
+ readonly pointLights: GraphBuffer;
95
+ readonly spotLights: GraphBuffer;
96
+ readonly selectedLightKind: 'directional' | 'point' | 'spot';
97
+ readonly projector?: GraphTextureView;
98
+ }
99
+ function pipelineError(stage: string): RhiError {
100
+ return new RhiError({
101
+ code: 'rhi-not-available',
102
+ expected: `volumetric fog ${stage} pipeline to be available`,
103
+ hint: 'construct the renderer through a backend pack with shader module support',
104
+ });
105
+ }
106
+ function shaderSource(frame: RenderPipelineFrame, stage: keyof VolumetricFogShaderSources): string {
107
+ const source = frame.volumetricFogShaders?.[stage];
108
+ if (source === undefined) throw pipelineError(`${stage} shader source`);
109
+ return source;
110
+ }
111
+ interface ComputeState {
112
+ readonly pipeline: ComputePipeline;
113
+ readonly layout: BindGroupLayout;
114
+ }
115
+ function computeState(
116
+ frame: RenderPipelineFrame,
117
+ source: string,
118
+ label: string,
119
+ entries: readonly unknown[],
120
+ entryPoint = label,
121
+ ): ComputeState {
122
+ const factory = frame.runtime.shaderModuleFactory;
123
+ if (factory === undefined) throw pipelineError(label);
124
+ const module = factory.createShaderModule({ code: source, label });
125
+ if (!module.ok) throw module.error;
126
+ const layout = frame.runtime.device.createBindGroupLayout({ entries: entries as never });
127
+ if (!layout.ok) throw layout.error;
128
+ const pipelineLayout = frame.runtime.device.createPipelineLayout({
129
+ label: `${label}.layout`,
130
+ bindGroupLayouts: [layout.value],
131
+ });
132
+ if (!pipelineLayout.ok) throw pipelineLayout.error;
133
+ const pipeline = frame.runtime.device.createComputePipeline({
134
+ label,
135
+ layout: pipelineLayout.value,
136
+ compute: { module: module.value, entryPoint },
137
+ });
138
+ if (!pipeline.ok) throw pipeline.error;
139
+ return { pipeline: pipeline.value, layout: layout.value };
140
+ }
141
+ type VolumeBinding =
142
+ | {
143
+ readonly binding: number;
144
+ readonly resource: { readonly kind: 'textureView'; readonly value: TextureView };
145
+ }
146
+ | {
147
+ readonly binding: number;
148
+ readonly resource: { readonly kind: 'sampler'; readonly value: Sampler };
149
+ }
150
+ | {
151
+ readonly binding: number;
152
+ readonly resource: { readonly kind: 'buffer'; readonly value: { readonly buffer: Buffer } };
153
+ };
154
+ function volumeBindGroup(
155
+ frame: RenderPipelineFrame,
156
+ layout: BindGroupLayout,
157
+ entries: readonly VolumeBinding[],
158
+ ): BindGroup {
159
+ const group = frame.runtime.device.createBindGroup({ layout, entries });
160
+ if (!group.ok) throw group.error;
161
+ return group.value;
162
+ }
163
+ type ImportedVolumeInputs = Omit<VolumetricFogPassInputs, 'resources'>;
164
+ function importVolumeInputs(
165
+ graph: RenderGraphBuilder<RenderPipelineFrame>,
166
+ topology: RenderPipelineTopology,
167
+ linearHdr: RenderPipelineTarget,
168
+ sceneDepth: GraphTextureView,
169
+ directionalShadow: GraphTextureView | undefined,
170
+ spotShadow: GraphTextureView,
171
+ selectedLightKind: 'directional' | 'point' | 'spot' | undefined,
172
+ ): Result<ImportedVolumeInputs | undefined, RenderGraphError> {
173
+ const volume = topology.volumetricFog;
174
+ if (volume?.enabled !== true || volume.format === undefined || volume.extent === undefined)
175
+ return ok(undefined);
176
+ const texture = graph.importTexture(
177
+ 'volume-density',
178
+ {
179
+ format: volume.format,
180
+ size: {
181
+ width: volume.extent.width,
182
+ height: volume.extent.height,
183
+ depthOrArrayLayers: volume.extent.depth,
184
+ },
185
+ dimension: '3d',
186
+ usage: GPU_TEXTURE_USAGE_TEXTURE_BINDING,
187
+ },
188
+ (frame) => {
189
+ const context = frame.volumetricFog as VolumetricFogFrameContext | undefined;
190
+ if (context === undefined) throw pipelineError('density residency');
191
+ return context.densityTexture;
192
+ },
193
+ );
194
+ if (!texture.ok) return texture;
195
+ const density = graph.importView(
196
+ texture.value,
197
+ { label: 'volume-density.view', dimension: '3d' },
198
+ (frame) => {
199
+ const context = frame.volumetricFog as VolumetricFogFrameContext | undefined;
200
+ if (context === undefined) throw pipelineError('density view residency');
201
+ return context.densityView;
202
+ },
203
+ );
204
+ if (!density.ok) return density;
205
+ const params = graph.importBuffer(
206
+ 'volume-params',
207
+ { size: 128, usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST },
208
+ (frame) => {
209
+ const context = frame.volumetricFog as VolumetricFogFrameContext | undefined;
210
+ if (context === undefined) throw pipelineError('parameter residency');
211
+ return context.paramsBuffer;
212
+ },
213
+ );
214
+ if (!params.ok) return params;
215
+ const view = graph.importBuffer(
216
+ 'volume-view',
217
+ { size: VIEW_UNIFORM_BYTES, usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST },
218
+ (frame) => frame.pipelineState.viewUniformBuffer,
219
+ );
220
+ 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
+ let projector: GraphTextureView | undefined;
237
+ if (volume.projector !== undefined) {
238
+ const projectorTexture = graph.importTexture(
239
+ 'spot-projector',
240
+ {
241
+ format: 'rgba8unorm-srgb',
242
+ size: { width: 128, height: 128, depthOrArrayLayers: 1 },
243
+ dimension: '2d',
244
+ usage: GPU_TEXTURE_USAGE_TEXTURE_BINDING,
245
+ },
246
+ (frame) => {
247
+ const context = frame.volumetricFog as VolumetricFogFrameContext | undefined;
248
+ if (context?.projectorTexture === undefined) throw pipelineError('projector residency');
249
+ return context.projectorTexture;
250
+ },
251
+ );
252
+ if (!projectorTexture.ok) return projectorTexture;
253
+ const projectorView = graph.importView(
254
+ projectorTexture.value,
255
+ { label: 'spot-projector.view', dimension: '2d' },
256
+ (frame) => {
257
+ const context = frame.volumetricFog as VolumetricFogFrameContext | undefined;
258
+ if (context?.projectorView === undefined) throw pipelineError('projector view residency');
259
+ return context.projectorView;
260
+ },
261
+ );
262
+ if (!projectorView.ok) return projectorView;
263
+ projector = projectorView.value;
264
+ }
265
+ return ok({
266
+ linearHdr,
267
+ sceneDepth,
268
+ density: density.value,
269
+ params: params.value,
270
+ view: view.value,
271
+ ...(directionalShadow === undefined ? {} : { directionalShadow }),
272
+ spotShadow,
273
+ pointLights: pointLights.value,
274
+ spotLights: spotLights.value,
275
+ selectedLightKind: selectedLightKind ?? 'directional',
276
+ ...(projector === undefined ? {} : { projector }),
277
+ });
278
+ }
279
+ export function addAuthoredVolumetricFogPasses(
280
+ graph: RenderGraphBuilder<RenderPipelineFrame>,
281
+ topology: RenderPipelineTopology,
282
+ linearHdr: RenderPipelineTarget,
283
+ sceneDepth: GraphTextureView,
284
+ directionalShadow: GraphTextureView | undefined,
285
+ spotShadow: GraphTextureView,
286
+ ): Result<void, RenderGraphError> {
287
+ // A paired Point+Spot volume stores the Spot shadow lane as well. The
288
+ // topology's primary light remains PointLight for radiance selection, but
289
+ // injection must import the spot atlas so the packed visibility can be
290
+ // applied only to the spot term during integration.
291
+ const shadowLightKind =
292
+ topology.volumetricFog?.spotLightEntity === undefined
293
+ ? topology.volumetricFog?.lightKind
294
+ : 'spot';
295
+ const imported = importVolumeInputs(
296
+ graph,
297
+ topology,
298
+ linearHdr,
299
+ sceneDepth,
300
+ directionalShadow,
301
+ spotShadow,
302
+ shadowLightKind,
303
+ );
304
+ if (!imported.ok) return imported;
305
+ if (imported.value === undefined) return ok(undefined);
306
+ const resources = createVolumetricFogResources(
307
+ graph,
308
+ topology.volumetricFog?.froxelExtent ?? { width: 64, height: 64, depth: 64 },
309
+ topology.volumetricFog?.resolvedExtent,
310
+ );
311
+ if (!resources.ok) return resources;
312
+ return addVolumetricFogPasses(graph, { ...imported.value, resources: resources.value });
313
+ }
314
+ export function addVolumetricFogPasses(
315
+ graph: RenderGraphBuilder<RenderPipelineFrame>,
316
+ inputs: VolumetricFogPassInputs,
317
+ ): Result<void, RenderGraphError> {
318
+ const dispatchX = Math.ceil(inputs.resources.extent.width / 8);
319
+ const dispatchY = Math.ceil(inputs.resources.extent.height / 8);
320
+ const packedLayers = Math.ceil(inputs.resources.extent.depth / VOLUME_PACKING_Z);
321
+ const resolvedDispatchX = Math.ceil(inputs.resources.resolvedExtent.width / 8);
322
+ const resolvedDispatchY = Math.ceil(inputs.resources.resolvedExtent.height / 8);
323
+ // Point-light volume injection has no cube-array shadow sampler. It keeps
324
+ // the directional cascade count at zero and therefore needs only a valid
325
+ // 2D depth binding; use the always-present spot target as the inert binding
326
+ // when directional shadows are disabled. Directional selection still uses
327
+ // its own target whenever one exists, and spot selection uses spotShadow.
328
+ const shadowResource =
329
+ inputs.selectedLightKind === 'spot'
330
+ ? inputs.spotShadow
331
+ : (inputs.directionalShadow ?? inputs.spotShadow);
332
+ let inject: ComputeState | undefined;
333
+ let integrate: ComputeState | undefined;
334
+ let temporal: ComputeState | undefined;
335
+ let composite: RenderPipeline | undefined;
336
+ let compositeLayout: BindGroupLayout | undefined;
337
+ const injected = graph.addComputePass('volume-inject', {
338
+ accesses: [
339
+ { resource: inputs.params, usage: 'uniform-read' },
340
+ { resource: inputs.view, usage: 'uniform-read' },
341
+ {
342
+ resource: shadowResource,
343
+ usage: 'sampled-read',
344
+ },
345
+ { resource: inputs.spotLights, usage: 'storage-read' },
346
+ { resource: inputs.pointLights, usage: 'storage-read' },
347
+ ...(inputs.projector === undefined
348
+ ? []
349
+ : [{ resource: inputs.projector, usage: 'sampled-read' as const }]),
350
+ { resource: inputs.resources.froxelView, usage: 'storage-write' },
351
+ ],
352
+ encode: ({ pass, frame, resources }) => {
353
+ inject ??= computeState(frame, shaderSource(frame, 'inject'), 'volume_inject', [
354
+ { binding: 0, visibility: 4, buffer: { type: 'uniform' } },
355
+ { binding: 3, visibility: 4, texture: { sampleType: 'depth', viewDimension: '2d' } },
356
+ { binding: 4, visibility: 4, sampler: { type: 'comparison' } },
357
+ { binding: 5, visibility: 4, buffer: { type: 'uniform' } },
358
+ {
359
+ binding: 6,
360
+ visibility: 4,
361
+ storageTexture: {
362
+ access: 'write-only',
363
+ format: VOLUME_FROXEL_FORMAT,
364
+ viewDimension: '2d-array',
365
+ },
366
+ },
367
+ { binding: 7, visibility: 4, buffer: { type: 'read-only-storage' } },
368
+ { binding: 8, visibility: 4, buffer: { type: 'read-only-storage' } },
369
+ ]);
370
+ const shadow = resources.textureView(shadowResource);
371
+ const params = resources.buffer(inputs.params);
372
+ const view = resources.buffer(inputs.view);
373
+ const spotLights = resources.buffer(inputs.spotLights);
374
+ const pointLights = resources.buffer(inputs.pointLights);
375
+ const froxel = resources.textureView(inputs.resources.froxelView);
376
+ if (!shadow.ok) throw shadow.error;
377
+ if (!params.ok) throw params.error;
378
+ if (!view.ok) throw view.error;
379
+ if (!spotLights.ok) throw spotLights.error;
380
+ if (!pointLights.ok) throw pointLights.error;
381
+ if (!froxel.ok) throw froxel.error;
382
+ const shadowSampler = frame.runtime.device.createSampler({ compare: 'less' });
383
+ if (!shadowSampler.ok) throw shadowSampler.error;
384
+ const bindings = volumeBindGroup(frame, inject.layout, [
385
+ { binding: 0, resource: { kind: 'buffer', value: { buffer: view.value } } },
386
+ { binding: 3, resource: { kind: 'textureView', value: shadow.value as never } },
387
+ { binding: 4, resource: { kind: 'sampler', value: shadowSampler.value } },
388
+ { binding: 5, resource: { kind: 'buffer', value: { buffer: params.value } } },
389
+ { 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 } } },
392
+ ]);
393
+ pass.setPipeline(inject.pipeline);
394
+ pass.setBindGroup(0, bindings);
395
+ pass.dispatchWorkgroups(dispatchX, dispatchY, packedLayers);
396
+ },
397
+ });
398
+ if (!injected.ok) return injected;
399
+ const integratePass = graph.addComputePass('volume-integrate', {
400
+ accesses: [
401
+ { resource: inputs.resources.froxelView, usage: 'sampled-read' },
402
+ { resource: inputs.sceneDepth, usage: 'sampled-read' },
403
+ { resource: inputs.density, usage: 'sampled-read' },
404
+ { resource: inputs.resources.resolvedView, usage: 'storage-write' },
405
+ { resource: inputs.resources.historyView, usage: 'storage-write' },
406
+ { resource: inputs.resources.temporalView, usage: 'storage-write' },
407
+ { resource: inputs.params, usage: 'uniform-read' },
408
+ { resource: inputs.view, usage: 'uniform-read' },
409
+ { resource: inputs.spotLights, usage: 'storage-read' },
410
+ { resource: inputs.pointLights, usage: 'storage-read' },
411
+ ...(inputs.projector === undefined
412
+ ? []
413
+ : [{ resource: inputs.projector, usage: 'sampled-read' as const }]),
414
+ ],
415
+ encode: ({ pass, frame, resources }) => {
416
+ integrate ??= computeState(frame, shaderSource(frame, 'integrate'), 'volume_integrate', [
417
+ { binding: 0, visibility: 4, texture: { sampleType: 'float', viewDimension: '2d-array' } },
418
+ { binding: 1, visibility: 4, texture: { sampleType: 'depth', viewDimension: '2d' } },
419
+ {
420
+ binding: 2,
421
+ visibility: 4,
422
+ storageTexture: {
423
+ access: 'write-only',
424
+ format: VOLUME_RESOLVED_FORMAT,
425
+ viewDimension: '2d',
426
+ },
427
+ },
428
+ { binding: 3, visibility: 4, buffer: { type: 'uniform' } },
429
+ { binding: 4, visibility: 4, buffer: { type: 'uniform' } },
430
+ { binding: 5, visibility: 4, sampler: { type: 'filtering' } },
431
+ { binding: 6, visibility: 4, texture: { sampleType: 'float', viewDimension: '3d' } },
432
+ { binding: 7, visibility: 4, sampler: { type: 'filtering' } },
433
+ {
434
+ binding: 8,
435
+ visibility: 4,
436
+ storageTexture: {
437
+ access: 'write-only',
438
+ format: VOLUME_HISTORY_FORMAT,
439
+ viewDimension: '2d',
440
+ },
441
+ },
442
+ {
443
+ binding: 9,
444
+ visibility: 4,
445
+ storageTexture: {
446
+ access: 'write-only',
447
+ format: VOLUME_HISTORY_FORMAT,
448
+ viewDimension: '2d',
449
+ },
450
+ },
451
+ { binding: 10, visibility: 4, buffer: { type: 'read-only-storage' } },
452
+ { binding: 11, visibility: 4, buffer: { type: 'read-only-storage' } },
453
+ { binding: 12, visibility: 4, texture: { sampleType: 'float', viewDimension: '2d' } },
454
+ { binding: 13, visibility: 4, sampler: { type: 'filtering' } },
455
+ ]);
456
+ const froxel = resources.textureView(inputs.resources.froxelView);
457
+ const depth = resources.textureView(inputs.sceneDepth);
458
+ const density = resources.textureView(inputs.density);
459
+ const resolved = resources.textureView(inputs.resources.resolvedView);
460
+ const historySeed = resources.textureView(inputs.resources.historyView);
461
+ const temporalSeed = resources.textureView(inputs.resources.temporalView);
462
+ const params = resources.buffer(inputs.params);
463
+ const view = resources.buffer(inputs.view);
464
+ const spotLights = resources.buffer(inputs.spotLights);
465
+ const pointLights = resources.buffer(inputs.pointLights);
466
+ const projector =
467
+ inputs.projector === undefined ? undefined : resources.textureView(inputs.projector);
468
+ if (!froxel.ok) throw froxel.error;
469
+ if (!depth.ok) throw depth.error;
470
+ if (!density.ok) throw density.error;
471
+ if (!resolved.ok) throw resolved.error;
472
+ if (!historySeed.ok) throw historySeed.error;
473
+ if (!temporalSeed.ok) throw temporalSeed.error;
474
+ if (!params.ok) throw params.error;
475
+ if (!view.ok) throw view.error;
476
+ if (!spotLights.ok) throw spotLights.error;
477
+ if (!pointLights.ok) throw pointLights.error;
478
+ if (projector !== undefined && !projector.ok) throw projector.error;
479
+ const sampler = frame.runtime.device.createSampler({
480
+ minFilter: 'linear',
481
+ magFilter: 'linear',
482
+ });
483
+ if (!sampler.ok) throw sampler.error;
484
+ const densitySampler = frame.runtime.device.createSampler({
485
+ minFilter: 'linear',
486
+ magFilter: 'linear',
487
+ addressModeU: 'repeat',
488
+ addressModeV: 'repeat',
489
+ addressModeW: 'repeat',
490
+ });
491
+ if (!densitySampler.ok) throw densitySampler.error;
492
+ const bindings = volumeBindGroup(frame, integrate.layout, [
493
+ { binding: 0, resource: { kind: 'textureView', value: froxel.value as never } },
494
+ { binding: 1, resource: { kind: 'textureView', value: depth.value as never } },
495
+ { binding: 2, resource: { kind: 'textureView', value: resolved.value as never } },
496
+ { binding: 3, resource: { kind: 'buffer', value: { buffer: params.value } } },
497
+ { binding: 4, resource: { kind: 'buffer', value: { buffer: view.value } } },
498
+ { binding: 5, resource: { kind: 'sampler', value: sampler.value } },
499
+ { binding: 6, resource: { kind: 'textureView', value: density.value as never } },
500
+ { binding: 7, resource: { kind: 'sampler', value: densitySampler.value } },
501
+ { binding: 8, resource: { kind: 'textureView', value: historySeed.value as never } },
502
+ { 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 } } },
505
+ {
506
+ binding: 12,
507
+ resource: {
508
+ kind: 'textureView',
509
+ value:
510
+ projector === undefined
511
+ ? frame.pipelineState.defaultWhiteTextureView
512
+ : (projector.value as never),
513
+ },
514
+ },
515
+ {
516
+ binding: 13,
517
+ resource: {
518
+ kind: 'sampler',
519
+ value: frame.volumetricFog?.projectorSampler ?? frame.pipelineState.defaultSampler,
520
+ },
521
+ },
522
+ ]);
523
+ pass.setPipeline(integrate.pipeline);
524
+ pass.setBindGroup(0, bindings);
525
+ pass.dispatchWorkgroups(resolvedDispatchX, resolvedDispatchY, 1);
526
+ },
527
+ });
528
+ if (!integratePass.ok) return integratePass;
529
+ const temporalPass = graph.addComputePass('volume-temporal', {
530
+ accesses: [
531
+ { resource: inputs.resources.resolvedView, usage: 'sampled-read' },
532
+ { resource: inputs.resources.historyView, usage: 'sampled-storage-read-write' },
533
+ { resource: inputs.resources.temporalView, usage: 'sampled-storage-read-write' },
534
+ { resource: inputs.params, usage: 'uniform-read' },
535
+ { resource: inputs.view, usage: 'uniform-read' },
536
+ ],
537
+ encode: ({ pass, frame, resources }) => {
538
+ temporal ??= computeState(frame, shaderSource(frame, 'temporal'), 'volume_temporal', [
539
+ { binding: 0, visibility: 4, texture: { sampleType: 'float', viewDimension: '2d' } },
540
+ { binding: 1, visibility: 4, texture: { sampleType: 'float', viewDimension: '2d' } },
541
+ {
542
+ binding: 2,
543
+ visibility: 4,
544
+ storageTexture: {
545
+ access: 'write-only',
546
+ format: VOLUME_HISTORY_FORMAT,
547
+ viewDimension: '2d',
548
+ },
549
+ },
550
+ { binding: 3, visibility: 4, buffer: { type: 'uniform' } },
551
+ { binding: 4, visibility: 4, buffer: { type: 'uniform' } },
552
+ ]);
553
+ const current = resources.textureView(inputs.resources.resolvedView);
554
+ const history = resources.textureView(
555
+ frame.volumetricFog?.historyReadSlot === 0
556
+ ? inputs.resources.historyView
557
+ : inputs.resources.temporalView,
558
+ );
559
+ const pending = resources.textureView(
560
+ frame.volumetricFog?.historyWriteSlot === 0
561
+ ? inputs.resources.historyView
562
+ : inputs.resources.temporalView,
563
+ );
564
+ const params = resources.buffer(inputs.params);
565
+ const view = resources.buffer(inputs.view);
566
+ if (!current.ok) throw current.error;
567
+ if (!history.ok) throw history.error;
568
+ if (!pending.ok) throw pending.error;
569
+ if (!params.ok) throw params.error;
570
+ if (!view.ok) throw view.error;
571
+ const bindings = volumeBindGroup(frame, temporal.layout, [
572
+ { binding: 0, resource: { kind: 'textureView', value: current.value as never } },
573
+ { binding: 1, resource: { kind: 'textureView', value: history.value as never } },
574
+ { binding: 2, resource: { kind: 'textureView', value: pending.value as never } },
575
+ { binding: 3, resource: { kind: 'buffer', value: { buffer: params.value } } },
576
+ { binding: 4, resource: { kind: 'buffer', value: { buffer: view.value } } },
577
+ ]);
578
+ pass.setPipeline(temporal.pipeline);
579
+ pass.setBindGroup(0, bindings);
580
+ pass.dispatchWorkgroups(resolvedDispatchX, resolvedDispatchY, 1);
581
+ },
582
+ });
583
+ if (!temporalPass.ok) return temporalPass;
584
+ return graph.addRasterPass('volume-composite', {
585
+ accesses: [
586
+ { resource: inputs.resources.historyView, usage: 'sampled-read' },
587
+ { resource: inputs.resources.temporalView, usage: 'sampled-read' },
588
+ { resource: inputs.sceneDepth, usage: 'sampled-read' },
589
+ { resource: inputs.view, usage: 'uniform-read' },
590
+ { resource: inputs.linearHdr.view, usage: 'color-attachment' },
591
+ ],
592
+ colorAttachments: [
593
+ {
594
+ view: inputs.linearHdr.view,
595
+ loadOp: 'load',
596
+ storeOp: 'store',
597
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
598
+ },
599
+ ],
600
+ encode: ({ pass, frame, resources }) => {
601
+ composite ??= (() => {
602
+ const factory = frame.runtime.shaderModuleFactory;
603
+ if (factory === undefined) throw pipelineError('volume_composite');
604
+ const module = factory.createShaderModule({
605
+ code: shaderSource(frame, 'composite'),
606
+ label: 'volume_composite',
607
+ });
608
+ if (!module.ok) throw module.error;
609
+ const layout = frame.runtime.device.createBindGroupLayout({
610
+ label: 'volume_composite.bind-group-layout',
611
+ entries: [
612
+ {
613
+ binding: 0,
614
+ visibility: 2 | 1,
615
+ texture: { sampleType: 'float', viewDimension: '2d' },
616
+ },
617
+ { binding: 1, visibility: 2 | 1, sampler: { type: 'filtering' } },
618
+ {
619
+ binding: 2,
620
+ visibility: 2 | 1,
621
+ texture: { sampleType: 'depth', viewDimension: '2d' },
622
+ },
623
+ { binding: 3, visibility: 2 | 1, buffer: { type: 'uniform' } },
624
+ ],
625
+ });
626
+ if (!layout.ok) throw layout.error;
627
+ const pipelineLayout = frame.runtime.device.createPipelineLayout({
628
+ label: 'volume_composite.layout',
629
+ bindGroupLayouts: [layout.value],
630
+ });
631
+ if (!pipelineLayout.ok) throw pipelineLayout.error;
632
+ const created = frame.runtime.device.createRenderPipeline({
633
+ label: 'volume_composite',
634
+ layout: pipelineLayout.value,
635
+ vertex: { module: module.value, entryPoint: 'volume_vs', buffers: [] },
636
+ fragment: {
637
+ module: module.value,
638
+ entryPoint: 'volume_fs',
639
+ targets: [
640
+ {
641
+ format: inputs.linearHdr.format,
642
+ blend: {
643
+ color: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
644
+ alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
645
+ },
646
+ },
647
+ ],
648
+ },
649
+ primitive: { topology: 'triangle-list' },
650
+ });
651
+ if (!created.ok) throw created.error;
652
+ compositeLayout = layout.value;
653
+ return created.value;
654
+ })();
655
+ const resolved = resources.textureView(
656
+ frame.volumetricFog?.historyWriteSlot === 0
657
+ ? inputs.resources.historyView
658
+ : inputs.resources.temporalView,
659
+ );
660
+ const depth = resources.textureView(inputs.sceneDepth);
661
+ const view = resources.buffer(inputs.view);
662
+ if (!resolved.ok) throw resolved.error;
663
+ if (!depth.ok) throw depth.error;
664
+ if (!view.ok) throw view.error;
665
+ const sampler = frame.runtime.device.createSampler({
666
+ label: 'volume_composite.sampler',
667
+ minFilter: 'linear',
668
+ magFilter: 'linear',
669
+ });
670
+ if (!sampler.ok) throw sampler.error;
671
+ const bindings = frame.runtime.device.createBindGroup({
672
+ layout: compositeLayout as BindGroupLayout,
673
+ entries: [
674
+ { binding: 0, resource: { kind: 'textureView', value: resolved.value as never } },
675
+ { binding: 1, resource: { kind: 'sampler', value: sampler.value } },
676
+ { binding: 2, resource: { kind: 'textureView', value: depth.value as never } },
677
+ { binding: 3, resource: { kind: 'buffer', value: { buffer: view.value } } },
678
+ ],
679
+ });
680
+ if (!bindings.ok) throw bindings.error;
681
+ pass.setPipeline(composite);
682
+ pass.setBindGroup(0, bindings.value);
683
+ pass.draw(3);
684
+ },
685
+ });
686
+ }