@forgeax/engine-render 0.1.32 → 0.1.34

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 (624) hide show
  1. package/README.md +1374 -142
  2. package/dist/assembly/analytic-fog-registration.d.ts +3 -0
  3. package/dist/assembly/analytic-fog-registration.d.ts.map +1 -0
  4. package/dist/assembly/backend-contract.d.ts +2 -0
  5. package/dist/assembly/backend-contract.d.ts.map +1 -1
  6. package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
  7. package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
  8. package/dist/assembly/canvas-draw-guard.d.ts +3 -0
  9. package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
  10. package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
  11. package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
  12. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  13. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  14. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  15. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  16. package/dist/assembly/factory.d.ts +1 -1
  17. package/dist/assembly/factory.d.ts.map +1 -1
  18. package/dist/assembly/fxaa-registration.d.ts +4 -0
  19. package/dist/assembly/fxaa-registration.d.ts.map +1 -0
  20. package/dist/assembly/host-contract.d.ts +3 -3
  21. package/dist/assembly/host-contract.d.ts.map +1 -1
  22. package/dist/assembly/lod-observation.d.ts +4 -0
  23. package/dist/assembly/lod-observation.d.ts.map +1 -0
  24. package/dist/assembly/material/assembly.d.ts.map +1 -1
  25. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  26. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  27. package/dist/assembly/material-shader-policy.d.ts +16 -2
  28. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  29. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  30. package/dist/assembly/motion-blur-registration.d.ts +3 -0
  31. package/dist/assembly/motion-blur-registration.d.ts.map +1 -0
  32. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  33. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  34. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  35. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  36. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  37. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  38. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  39. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  40. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  41. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  42. package/dist/assembly/renderer-inspection.d.ts +11 -0
  43. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  44. package/dist/assembly/temporal-post-process-prewarm.d.ts +13 -0
  45. package/dist/assembly/temporal-post-process-prewarm.d.ts.map +1 -0
  46. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  47. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  48. package/dist/assembly/webgpu-ready-contract.d.ts +4 -3
  49. package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -1
  50. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  51. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  52. package/dist/assembly/webgpu-ready.d.ts +2 -2
  53. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  54. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  55. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  56. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  57. package/dist/assembly/webgpu-renderer.d.ts +1 -1
  58. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  59. package/dist/authoring.mjs +1 -1
  60. package/dist/barrel-distortion.d.ts +47 -0
  61. package/dist/barrel-distortion.d.ts.map +1 -0
  62. package/dist/bloom-admission.d.ts +13 -0
  63. package/dist/bloom-admission.d.ts.map +1 -0
  64. package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
  65. package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
  66. package/dist/{chunk-JCIRYQ4V.mjs → chunk-HEB564WF.mjs} +10 -4
  67. package/dist/chunk-HEB564WF.mjs.map +1 -0
  68. package/dist/{chunk-JRIPCMYC.mjs → chunk-MKDIT2EM.mjs} +1584 -375
  69. package/dist/chunk-MKDIT2EM.mjs.map +1 -0
  70. package/dist/{chunk-S665NJNF.mjs → chunk-OCDLEI6I.mjs} +3 -3
  71. package/dist/{chunk-S665NJNF.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
  72. package/dist/chunk-ODZWR6JQ.mjs +4927 -0
  73. package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
  74. package/dist/{chunk-DRR7D3KX.mjs → chunk-SHFUFJ5N.mjs} +192 -18
  75. package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
  76. package/dist/{chunk-4NNZQCL3.mjs → chunk-UI5SFODX.mjs} +223 -277
  77. package/dist/chunk-UI5SFODX.mjs.map +1 -0
  78. package/dist/{chunk-GWCEMDVR.mjs → chunk-UINHLCZA.mjs} +787 -80
  79. package/dist/chunk-UINHLCZA.mjs.map +1 -0
  80. package/dist/{chunk-6TFBXLRJ.mjs → chunk-WEX45HKH.mjs} +222 -337
  81. package/dist/chunk-WEX45HKH.mjs.map +1 -0
  82. package/dist/cloud/density.d.ts +55 -0
  83. package/dist/cloud/density.d.ts.map +1 -0
  84. package/dist/cloud/extract.d.ts +25 -0
  85. package/dist/cloud/extract.d.ts.map +1 -0
  86. package/dist/cloud/feature.d.ts +57 -0
  87. package/dist/cloud/feature.d.ts.map +1 -0
  88. package/dist/cloud/frame-context.d.ts +8 -0
  89. package/dist/cloud/frame-context.d.ts.map +1 -0
  90. package/dist/cloud/inspection.d.ts +59 -0
  91. package/dist/cloud/inspection.d.ts.map +1 -0
  92. package/dist/cloud/optics.d.ts +56 -0
  93. package/dist/cloud/optics.d.ts.map +1 -0
  94. package/dist/cloud/parameters.d.ts +73 -0
  95. package/dist/cloud/parameters.d.ts.map +1 -0
  96. package/dist/cloud/resources.d.ts +60 -0
  97. package/dist/cloud/resources.d.ts.map +1 -0
  98. package/dist/cloud/shadow.d.ts +42 -0
  99. package/dist/cloud/shadow.d.ts.map +1 -0
  100. package/dist/cloud/temporal.d.ts +74 -0
  101. package/dist/cloud/temporal.d.ts.map +1 -0
  102. package/dist/components/atmosphere.d.ts +2 -0
  103. package/dist/components/atmosphere.d.ts.map +1 -1
  104. package/dist/components/barrel-distortion.d.ts +13 -0
  105. package/dist/components/barrel-distortion.d.ts.map +1 -0
  106. package/dist/components/camera.d.ts +20 -4
  107. package/dist/components/camera.d.ts.map +1 -1
  108. package/dist/components/cloud-layer.d.ts +29 -0
  109. package/dist/components/cloud-layer.d.ts.map +1 -0
  110. package/dist/components/index.d.ts +2 -0
  111. package/dist/components/index.d.ts.map +1 -1
  112. package/dist/components/instances.d.ts +20 -6
  113. package/dist/components/instances.d.ts.map +1 -1
  114. package/dist/components/mesh-filter.d.ts +6 -5
  115. package/dist/components/mesh-filter.d.ts.map +1 -1
  116. package/dist/components/motion-blur.d.ts +1 -0
  117. package/dist/components/motion-blur.d.ts.map +1 -1
  118. package/dist/construct-renderer.d.ts +1 -1
  119. package/dist/construct-renderer.d.ts.map +1 -1
  120. package/dist/construct-renderer.mjs +9751 -3528
  121. package/dist/construct-renderer.mjs.map +1 -1
  122. package/dist/device/gpu-residency.d.ts +6 -0
  123. package/dist/device/gpu-residency.d.ts.map +1 -1
  124. package/dist/dynamic-geometry.d.ts +5 -1
  125. package/dist/dynamic-geometry.d.ts.map +1 -1
  126. package/dist/environment/analytic-fog.d.ts +6 -0
  127. package/dist/environment/analytic-fog.d.ts.map +1 -0
  128. package/dist/errors/cloud.d.ts +59 -0
  129. package/dist/errors/cloud.d.ts.map +1 -0
  130. package/dist/errors/render.d.ts +23 -5
  131. package/dist/errors/render.d.ts.map +1 -1
  132. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  133. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  134. package/dist/extract/camera.d.ts.map +1 -1
  135. package/dist/extract/contracts.d.ts +12 -1
  136. package/dist/extract/contracts.d.ts.map +1 -1
  137. package/dist/extract/environment.d.ts +2 -0
  138. package/dist/extract/environment.d.ts.map +1 -1
  139. package/dist/features/barrel-distortion.d.ts +29 -0
  140. package/dist/features/barrel-distortion.d.ts.map +1 -0
  141. package/dist/features/error-reporting.d.ts +17 -0
  142. package/dist/features/error-reporting.d.ts.map +1 -0
  143. package/dist/features/host.d.ts +15 -0
  144. package/dist/features/host.d.ts.map +1 -1
  145. package/dist/features/motion-blur/motion-blur-feature.d.ts +20 -2
  146. package/dist/features/motion-blur/motion-blur-feature.d.ts.map +1 -1
  147. package/dist/features/motion-blur/motion-blur-params.d.ts +21 -0
  148. package/dist/features/motion-blur/motion-blur-params.d.ts.map +1 -1
  149. package/dist/features/motion-blur/motion-blur-runtime.d.ts +54 -0
  150. package/dist/features/motion-blur/motion-blur-runtime.d.ts.map +1 -0
  151. package/dist/features/plan.d.ts +15 -4
  152. package/dist/features/plan.d.ts.map +1 -1
  153. package/dist/features/prepared-gpu-work.d.ts +9 -5
  154. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  155. package/dist/features/render-graph-compute.d.ts.map +1 -1
  156. package/dist/features/render-graph-contribution.d.ts +5 -0
  157. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  158. package/dist/features/render-graph-raster.d.ts +1 -0
  159. package/dist/features/render-graph-raster.d.ts.map +1 -1
  160. package/dist/features/targets.d.ts +2 -0
  161. package/dist/features/targets.d.ts.map +1 -1
  162. package/dist/features/types.d.ts +44 -0
  163. package/dist/features/types.d.ts.map +1 -1
  164. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  165. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  166. package/dist/gpu-dirty-ranges.d.ts +11 -0
  167. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  168. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  169. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  170. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  171. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  172. package/dist/gpu-driven/prepared-draw.d.ts +7 -0
  173. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  174. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  175. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  176. package/dist/gpu-driven/production-raster.d.ts +50 -4
  177. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  178. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  179. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  180. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  181. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  182. package/dist/gpu-driven/view-gpu.d.ts +35 -2
  183. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  184. package/dist/gpu-scene.d.ts +11 -1
  185. package/dist/gpu-scene.d.ts.map +1 -1
  186. package/dist/hdrp-buffers.d.ts +2 -2
  187. package/dist/hdrp-buffers.d.ts.map +1 -1
  188. package/dist/ibl/skylight-bind-group.d.ts +10 -1
  189. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  190. package/dist/index.d.ts +31 -8
  191. package/dist/index.d.ts.map +1 -1
  192. package/dist/index.mjs +258 -8
  193. package/dist/index.mjs.map +1 -1
  194. package/dist/inspection-types.d.ts +178 -3
  195. package/dist/inspection-types.d.ts.map +1 -1
  196. package/dist/instance-buffer-cache.d.ts +4 -4
  197. package/dist/instance-buffer-cache.d.ts.map +1 -1
  198. package/dist/instances.d.ts +49 -94
  199. package/dist/instances.d.ts.map +1 -1
  200. package/dist/internal.mjs +7 -7
  201. package/dist/pbr-pipeline.d.ts +19 -1
  202. package/dist/pbr-pipeline.d.ts.map +1 -1
  203. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  204. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  205. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  206. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  207. package/dist/pipeline/standard-output/types.d.ts +4 -2
  208. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  209. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  210. package/dist/pipeline/standard-post.d.ts +28 -19
  211. package/dist/pipeline/standard-post.d.ts.map +1 -1
  212. package/dist/pipeline-builder.d.ts +1 -1
  213. package/dist/pipeline-builder.d.ts.map +1 -1
  214. package/dist/pipeline-spec.d.ts +2 -2
  215. package/dist/plugin.d.ts.map +1 -1
  216. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  217. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  218. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  219. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  220. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  221. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  222. package/dist/record/fold-buckets.d.ts +95 -0
  223. package/dist/record/fold-buckets.d.ts.map +1 -0
  224. package/dist/record/fold-instance-buffer.d.ts +6 -0
  225. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  226. package/dist/record/frame-lighting.d.ts +1 -0
  227. package/dist/record/frame-lighting.d.ts.map +1 -1
  228. package/dist/record/frame-snapshot.d.ts +40 -3
  229. package/dist/record/frame-snapshot.d.ts.map +1 -1
  230. package/dist/record/frame-targets.d.ts.map +1 -1
  231. package/dist/record/frame.d.ts +14 -62
  232. package/dist/record/frame.d.ts.map +1 -1
  233. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  234. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  235. package/dist/record/gpu-timing.d.ts +8 -0
  236. package/dist/record/gpu-timing.d.ts.map +1 -1
  237. package/dist/record/main-pass-geometry.d.ts +21 -5
  238. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  239. package/dist/record/main-pass-material.d.ts +7 -1
  240. package/dist/record/main-pass-material.d.ts.map +1 -1
  241. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  242. package/dist/record/main-pass.d.ts +13 -2
  243. package/dist/record/main-pass.d.ts.map +1 -1
  244. package/dist/record/mesh-ssbo.d.ts +6 -5
  245. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  246. package/dist/record/motion-blur-receipt.d.ts +11 -0
  247. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  248. package/dist/record/probe-blend-buffer.d.ts +16 -0
  249. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  250. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  251. package/dist/record/render-context.d.ts +34 -31
  252. package/dist/record/render-context.d.ts.map +1 -1
  253. package/dist/record/shadow-pass.d.ts +2 -0
  254. package/dist/record/shadow-pass.d.ts.map +1 -1
  255. package/dist/record/skybox-post-pass.d.ts +6 -4
  256. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  257. package/dist/record/typed-frame-graph.d.ts +22 -2
  258. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  259. package/dist/record/view-ubo.d.ts +11 -3
  260. package/dist/record/view-ubo.d.ts.map +1 -1
  261. package/dist/record/volume-params.d.ts +9 -0
  262. package/dist/record/volume-params.d.ts.map +1 -0
  263. package/dist/recovery/render-system-candidate.d.ts +10 -0
  264. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  265. package/dist/reflection/record-owner.d.ts.map +1 -1
  266. package/dist/render-contract.d.ts +66 -8
  267. package/dist/render-contract.d.ts.map +1 -1
  268. package/dist/render-graph-primitives.d.ts.map +1 -1
  269. package/dist/render-pipeline.d.ts +106 -3
  270. package/dist/render-pipeline.d.ts.map +1 -1
  271. package/dist/render-system-extract-tail.d.ts +3 -2
  272. package/dist/render-system-extract-tail.d.ts.map +1 -1
  273. package/dist/render-system-extract.d.ts +24 -10
  274. package/dist/render-system-extract.d.ts.map +1 -1
  275. package/dist/render-system-presentation.d.ts +23 -0
  276. package/dist/render-system-presentation.d.ts.map +1 -0
  277. package/dist/render-system-producer-roots.d.ts +10 -0
  278. package/dist/render-system-producer-roots.d.ts.map +1 -0
  279. package/dist/render-system-residency.d.ts +12 -0
  280. package/dist/render-system-residency.d.ts.map +1 -0
  281. package/dist/render-system.d.ts +26 -15
  282. package/dist/render-system.d.ts.map +1 -1
  283. package/dist/scene/probe-blend.d.ts +27 -0
  284. package/dist/scene/probe-blend.d.ts.map +1 -1
  285. package/dist/scene/render-scene.d.ts +14 -5
  286. package/dist/scene/render-scene.d.ts.map +1 -1
  287. package/dist/ssao-buffers.d.ts +9 -0
  288. package/dist/ssao-buffers.d.ts.map +1 -1
  289. package/dist/surface/dynamic-input.d.ts +133 -0
  290. package/dist/surface/dynamic-input.d.ts.map +1 -0
  291. package/dist/surface/gpu-driven.d.ts +41 -0
  292. package/dist/surface/gpu-driven.d.ts.map +1 -0
  293. package/dist/surface/submission-observation.d.ts +136 -0
  294. package/dist/surface/submission-observation.d.ts.map +1 -0
  295. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  296. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  297. package/dist/temporal/frame.d.ts +7 -0
  298. package/dist/temporal/frame.d.ts.map +1 -1
  299. package/dist/temporal/gpu.d.ts +13 -1
  300. package/dist/temporal/gpu.d.ts.map +1 -1
  301. package/dist/temporal/index.mjs +5 -5
  302. package/dist/temporal/inspection.d.ts.map +1 -1
  303. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  304. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  305. package/dist/temporal/view.d.ts +6 -1
  306. package/dist/temporal/view.d.ts.map +1 -1
  307. package/dist/transmission/single-layer-medium.d.ts +89 -0
  308. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  309. package/dist/typed-render-graph-primitives.d.ts +24 -9
  310. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  311. package/dist/volume/component.d.ts +9 -5
  312. package/dist/volume/component.d.ts.map +1 -1
  313. package/dist/volume/extract.d.ts +1 -1
  314. package/dist/volume/extract.d.ts.map +1 -1
  315. package/dist/volume/inspection.d.ts +2 -0
  316. package/dist/volume/inspection.d.ts.map +1 -1
  317. package/dist/volume/passes.d.ts +4 -1
  318. package/dist/volume/passes.d.ts.map +1 -1
  319. package/dist/volume/resources.d.ts.map +1 -1
  320. package/dist/volume/temporal.d.ts +3 -1
  321. package/dist/volume/temporal.d.ts.map +1 -1
  322. package/package.json +22 -21
  323. package/src/__tests__/analytic-fog-graph.unit.test.ts +199 -0
  324. package/src/__tests__/analytic-fog-optics.unit.test.ts +38 -0
  325. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  326. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  327. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  328. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  329. package/src/__tests__/bloom-exact-zero.unit.test.ts +112 -18
  330. package/src/__tests__/bloom-lifecycle.integration.test.ts +17 -4
  331. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  332. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  333. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  334. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  335. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +20 -0
  336. package/src/__tests__/environment-fog-lanes.integration.test.ts +14 -0
  337. package/src/__tests__/environment-selection.unit.test.ts +12 -0
  338. package/src/__tests__/factory-contract.integration.test.ts +626 -113
  339. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  340. package/src/__tests__/frame-camera-selection.unit.test.ts +39 -1
  341. package/src/__tests__/frame-plan-contract.unit.test.ts +2 -0
  342. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
  343. package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
  344. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
  345. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
  346. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +2 -1
  347. package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
  348. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
  349. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  350. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +7 -6
  351. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +1 -1
  352. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +103 -4
  353. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  354. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  355. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  356. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  357. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  358. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  359. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  360. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +12 -0
  361. package/src/__tests__/gpu-scene.unit.test.ts +210 -9
  362. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  363. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  364. package/src/__tests__/instances-store.unit.test.ts +105 -238
  365. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  366. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
  367. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  368. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  369. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +31 -0
  370. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  371. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  372. package/src/__tests__/motion-blur-compute.dawn.test.ts +589 -0
  373. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  374. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  375. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  376. package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
  377. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +21 -0
  378. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  379. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +86 -0
  380. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  381. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  382. package/src/__tests__/public-surface.test-d.ts +8 -0
  383. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  384. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  385. package/src/__tests__/render-error-code-owner.test-d.ts +9 -0
  386. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  387. package/src/__tests__/render-feature-error-reporting.unit.test.ts +44 -0
  388. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  389. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  390. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +23 -0
  391. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  392. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  393. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +37 -6
  394. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  395. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  396. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  397. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
  398. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  399. package/src/__tests__/renderer-frame-transaction.integration.test.ts +33 -11
  400. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  401. package/src/__tests__/shader-manifest-fixture.ts +4 -4
  402. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  403. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  404. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  405. package/src/__tests__/skinned-shadow-caster.test.ts +17 -0
  406. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  407. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  408. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  409. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  410. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  411. package/src/__tests__/standard-lighting-write.unit.test.ts +2 -1
  412. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  413. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  414. package/src/__tests__/standard-pipeline.dawn.test.ts +1 -1
  415. package/src/__tests__/standard-pipeline.integration.test.ts +200 -9
  416. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  417. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  418. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  419. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  420. package/src/__tests__/temporal-reset-matrix.unit.test.ts +10 -0
  421. package/src/__tests__/temporal-view.unit.test.ts +2 -1
  422. package/src/__tests__/typed-pipeline-topology.unit.test.ts +20 -4
  423. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  424. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  425. package/src/__tests__/volume-optics-oracle.unit.test.ts +7 -3
  426. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +189 -15
  427. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  428. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  429. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  430. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +558 -68
  431. package/src/__tests__/volumetric-fog-temporal.unit.test.ts +27 -0
  432. package/src/__tests__/volumetric-fog-topology.unit.test.ts +23 -5
  433. package/src/assembly/analytic-fog-registration.ts +14 -0
  434. package/src/assembly/backend-contract.ts +30 -0
  435. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  436. package/src/assembly/canvas-draw-guard.ts +11 -0
  437. package/src/assembly/cloud-shadow-entry.ts +22 -0
  438. package/src/assembly/dynamic-geometry-host.ts +65 -37
  439. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  440. package/src/assembly/factory.ts +2 -30
  441. package/src/assembly/fxaa-registration.ts +17 -0
  442. package/src/assembly/host-contract.ts +3 -3
  443. package/src/assembly/lod-observation.ts +12 -0
  444. package/src/assembly/material/assembly.ts +25 -13
  445. package/src/assembly/material/pipeline-helpers.ts +53 -12
  446. package/src/assembly/material-shader-policy.ts +55 -0
  447. package/src/assembly/material-shader-prewarm.ts +21 -10
  448. package/src/assembly/motion-blur-registration.ts +17 -0
  449. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  450. package/src/assembly/recovery/renderer-recover.ts +41 -18
  451. package/src/assembly/render-feature-post-processes.ts +54 -0
  452. package/src/assembly/renderer-facade.ts +6 -1
  453. package/src/assembly/renderer-feature-inspection.ts +8 -2
  454. package/src/assembly/renderer-frame-transaction.ts +23 -0
  455. package/src/assembly/renderer-inspection.ts +28 -0
  456. package/src/assembly/skin-palette-owner.ts +1 -1
  457. package/src/assembly/temporal-post-process-prewarm.ts +40 -0
  458. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  459. package/src/assembly/webgpu-ready-contract.ts +8 -3
  460. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  461. package/src/assembly/webgpu-ready.ts +296 -306
  462. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  463. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  464. package/src/assembly/webgpu-renderer.ts +228 -281
  465. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  466. package/src/barrel-distortion.ts +247 -0
  467. package/src/bloom-admission.ts +21 -0
  468. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  469. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  470. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  471. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  472. package/src/cloud/density.ts +600 -0
  473. package/src/cloud/extract.ts +110 -0
  474. package/src/cloud/feature.ts +1810 -0
  475. package/src/cloud/frame-context.ts +42 -0
  476. package/src/cloud/inspection.ts +130 -0
  477. package/src/cloud/optics.ts +285 -0
  478. package/src/cloud/parameters.ts +255 -0
  479. package/src/cloud/resources.ts +122 -0
  480. package/src/cloud/shadow.ts +167 -0
  481. package/src/cloud/temporal.ts +226 -0
  482. package/src/components/__tests__/motion-blur.unit.test.ts +1 -0
  483. package/src/components/atmosphere.ts +4 -0
  484. package/src/components/barrel-distortion.ts +46 -0
  485. package/src/components/camera.ts +66 -10
  486. package/src/components/cloud-layer.ts +47 -0
  487. package/src/components/index.ts +2 -0
  488. package/src/components/instances.ts +18 -45
  489. package/src/components/mesh-filter.ts +11 -9
  490. package/src/components/motion-blur.ts +1 -0
  491. package/src/components/sprite-instances.ts +1 -1
  492. package/src/construct-renderer.ts +1 -1
  493. package/src/device/gpu-residency.ts +56 -12
  494. package/src/dynamic-geometry.ts +12 -1
  495. package/src/environment/analytic-fog.ts +44 -0
  496. package/src/environment/background.ts +2 -2
  497. package/src/errors/cloud.ts +103 -0
  498. package/src/errors/render.ts +58 -8
  499. package/src/examples/single-layer-medium-surface.ts +59 -0
  500. package/src/extract/camera.ts +35 -8
  501. package/src/extract/contracts.ts +12 -0
  502. package/src/extract/environment.ts +4 -0
  503. package/src/features/barrel-distortion.ts +172 -0
  504. package/src/features/error-reporting.ts +98 -0
  505. package/src/features/host.ts +138 -24
  506. package/src/features/motion-blur/__tests__/motion-blur-feature.unit.test.ts +111 -1
  507. package/src/features/motion-blur/__tests__/motion-blur-params.unit.test.ts +58 -3
  508. package/src/features/motion-blur/motion-blur-feature.ts +1519 -15
  509. package/src/features/motion-blur/motion-blur-params.ts +70 -2
  510. package/src/features/motion-blur/motion-blur-runtime.ts +176 -0
  511. package/src/features/plan.ts +33 -8
  512. package/src/features/prepared-gpu-work.ts +86 -35
  513. package/src/features/render-graph-compute.ts +13 -5
  514. package/src/features/render-graph-contribution.ts +11 -0
  515. package/src/features/render-graph-raster.ts +45 -3
  516. package/src/features/targets.ts +66 -0
  517. package/src/features/types.ts +47 -0
  518. package/src/fullscreen-post-process-pass.ts +41 -9
  519. package/src/gpu-dirty-ranges.ts +48 -0
  520. package/src/gpu-driven/batch-topology.ts +53 -0
  521. package/src/gpu-driven/material-artifacts.ts +35 -32
  522. package/src/gpu-driven/prepared-draw.ts +27 -14
  523. package/src/gpu-driven/production-raster-material.ts +1894 -0
  524. package/src/gpu-driven/production-raster.ts +904 -787
  525. package/src/gpu-driven/resource-allocation.ts +142 -0
  526. package/src/gpu-driven/shadow-ownership.ts +71 -0
  527. package/src/gpu-driven/view-gpu.ts +181 -10
  528. package/src/gpu-scene.ts +259 -101
  529. package/src/hdrp-buffers.ts +4 -3
  530. package/src/ibl/skylight-bind-group.ts +49 -7
  531. package/src/index.ts +228 -9
  532. package/src/inspection-types.ts +222 -2
  533. package/src/instance-buffer-cache.ts +4 -4
  534. package/src/instances.ts +151 -492
  535. package/src/pbr-pipeline.ts +219 -13
  536. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  537. package/src/pipeline/standard-forward-lane.ts +313 -57
  538. package/src/pipeline/standard-output/graph.ts +8 -2
  539. package/src/pipeline/standard-output/types.ts +12 -1
  540. package/src/pipeline/standard-pipeline.ts +291 -18
  541. package/src/pipeline/standard-post.ts +397 -102
  542. package/src/pipeline-builder.ts +1 -1
  543. package/src/pipeline-spec.ts +5 -5
  544. package/src/plugin.ts +4 -0
  545. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  546. package/src/points-lines/__tests__/view-ubo.unit.test.ts +2 -1
  547. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  548. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  549. package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
  550. package/src/record/__tests__/temporal-payload.unit.test.ts +3 -2
  551. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  552. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  553. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  554. package/src/record/barrel-distortion-frame.ts +110 -0
  555. package/src/record/dynamic-geometry-consumption.ts +39 -9
  556. package/src/record/fold-buckets.ts +852 -0
  557. package/src/record/fold-instance-buffer.ts +51 -0
  558. package/src/record/frame-lighting.ts +36 -2
  559. package/src/record/frame-snapshot.ts +44 -4
  560. package/src/record/frame-targets.ts +10 -6
  561. package/src/record/frame.ts +373 -1099
  562. package/src/record/gpu-draw-receipts.ts +38 -0
  563. package/src/record/gpu-timing.ts +48 -5
  564. package/src/record/main-pass-geometry.ts +281 -83
  565. package/src/record/main-pass-material.ts +66 -4
  566. package/src/record/main-pass-sprite-draws.ts +13 -66
  567. package/src/record/main-pass.ts +156 -20
  568. package/src/record/mesh-ssbo.ts +43 -6
  569. package/src/record/motion-blur-receipt.ts +91 -0
  570. package/src/record/probe-blend-buffer.ts +180 -0
  571. package/src/record/recovery-pipeline.ts +35 -3
  572. package/src/record/render-context.ts +51 -31
  573. package/src/record/shadow-pass.ts +36 -2
  574. package/src/record/skybox-post-pass.ts +150 -200
  575. package/src/record/typed-frame-graph.ts +824 -44
  576. package/src/record/view-ubo.ts +26 -3
  577. package/src/record/volume-params.ts +225 -0
  578. package/src/recovery/render-system-candidate.ts +257 -52
  579. package/src/reflection/record-owner.ts +7 -3
  580. package/src/render-contract.ts +71 -8
  581. package/src/render-graph-primitives.ts +7 -1
  582. package/src/render-pipeline.ts +136 -1
  583. package/src/render-system-extract-tail.ts +72 -60
  584. package/src/render-system-extract.ts +117 -87
  585. package/src/render-system-presentation.ts +56 -0
  586. package/src/render-system-producer-roots.ts +96 -0
  587. package/src/render-system-residency.ts +159 -0
  588. package/src/render-system.ts +601 -482
  589. package/src/scene/probe-blend.ts +96 -4
  590. package/src/scene/render-scene.ts +431 -281
  591. package/src/ssao-buffers.ts +95 -2
  592. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  593. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  594. package/src/surface/dynamic-input.ts +658 -0
  595. package/src/surface/gpu-driven.ts +147 -0
  596. package/src/surface/submission-observation.ts +517 -0
  597. package/src/systems/skin-palette-allocator.ts +4 -1
  598. package/src/temporal/__tests__/temporal-frame-transaction.unit.test.ts +36 -0
  599. package/src/temporal/frame-coordinator.ts +8 -1
  600. package/src/temporal/frame.ts +20 -0
  601. package/src/temporal/gpu.ts +101 -17
  602. package/src/temporal/inspection.ts +7 -1
  603. package/src/temporal/standard-scene-data.ts +5 -0
  604. package/src/temporal/target-coverage-attachment.ts +4 -0
  605. package/src/temporal/view.ts +13 -2
  606. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  607. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  608. package/src/transmission/single-layer-medium.ts +322 -0
  609. package/src/typed-render-graph-primitives.ts +191 -50
  610. package/src/volume/component.ts +10 -10
  611. package/src/volume/extract.ts +11 -5
  612. package/src/volume/inspection.ts +3 -0
  613. package/src/volume/passes.ts +95 -8
  614. package/src/volume/resources.ts +2 -1
  615. package/src/volume/temporal.ts +11 -0
  616. package/dist/chunk-4NNZQCL3.mjs.map +0 -1
  617. package/dist/chunk-6TFBXLRJ.mjs.map +0 -1
  618. package/dist/chunk-DRR7D3KX.mjs.map +0 -1
  619. package/dist/chunk-GWCEMDVR.mjs.map +0 -1
  620. package/dist/chunk-JCIRYQ4V.mjs.map +0 -1
  621. package/dist/chunk-JRIPCMYC.mjs.map +0 -1
  622. package/dist/chunk-LULCA3OF.mjs +0 -1713
  623. package/dist/chunk-LULCA3OF.mjs.map +0 -1
  624. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
@@ -0,0 +1,322 @@
1
+ import { type Color3, fresnelReflectance, type Uv2 } from './oracle.js';
2
+
3
+ export type MediumVector3 = readonly [number, number, number];
4
+
5
+ export interface SingleLayerMediumCoefficients {
6
+ /** Linear, inverse-metre absorption coefficients. */
7
+ readonly absorption: MediumVector3;
8
+ /** Linear, inverse-metre scattering coefficients. */
9
+ readonly scattering: MediumVector3;
10
+ readonly ior: number;
11
+ /** Henyey-Greenstein phase anisotropy in [-1, 1]. */
12
+ readonly phaseG?: number;
13
+ }
14
+
15
+ export interface SingleLayerMediumOptics {
16
+ readonly sigmaT: MediumVector3;
17
+ readonly transmittance: MediumVector3;
18
+ /** Uniform-medium single-scatter integral sigmaS * (1 - T) / sigmaT. */
19
+ readonly singleScatter: MediumVector3;
20
+ readonly reflectance: number;
21
+ readonly transmissionWeight: number;
22
+ readonly phase: number;
23
+ readonly distanceMeters: number;
24
+ }
25
+
26
+ export type SingleLayerMediumBackgroundReason = 'front' | 'shore' | 'edge' | 'sky-miss';
27
+
28
+ export interface SingleLayerMediumBackgroundCandidate {
29
+ readonly color: Color3;
30
+ readonly depthMeters: number;
31
+ readonly uv: Uv2;
32
+ }
33
+
34
+ export interface SingleLayerMediumBackgroundInput {
35
+ /** No-water color and raw depth must come from the same view identity. */
36
+ readonly original: SingleLayerMediumBackgroundCandidate;
37
+ /** Refracted candidate carries color and depth as one pair. */
38
+ readonly refracted?: SingleLayerMediumBackgroundCandidate;
39
+ readonly environment?: Color3;
40
+ readonly surfaceDepthMeters: number;
41
+ readonly maxDistanceMeters: number;
42
+ readonly depthToleranceMeters?: number;
43
+ }
44
+
45
+ export interface SingleLayerMediumBackgroundResolution {
46
+ readonly source: 'refracted' | 'unrefracted' | 'environment';
47
+ readonly reason?: SingleLayerMediumBackgroundReason;
48
+ readonly candidate: SingleLayerMediumBackgroundCandidate | undefined;
49
+ readonly color: Color3;
50
+ readonly distanceMeters: number;
51
+ }
52
+
53
+ const DEFAULT_MAX_DISTANCE_METERS = 1000;
54
+ const DEFAULT_DEPTH_TOLERANCE_METERS = 0.001;
55
+ const DEFAULT_IOR = 1.333;
56
+
57
+ const finiteOr = (value: number, fallback: number): number =>
58
+ Number.isFinite(value) ? value : fallback;
59
+
60
+ function oneMinusExpNeg(value: number): number {
61
+ const x = Math.max(finiteOr(value, 0), 0);
62
+ if (x < 1e-3) {
63
+ const x2 = x * x;
64
+ return x * (1 - x * 0.5 + x2 / 6 - (x * x2) / 24);
65
+ }
66
+ return -Math.expm1(-x);
67
+ }
68
+
69
+ function singleScatterIntegral(sigmaS: number, sigmaT: number, distance: number): number {
70
+ const scattering = Math.max(finiteOr(sigmaS, 0), 0);
71
+ const extinction = Math.max(finiteOr(sigmaT, 0), 0);
72
+ const path = Math.max(finiteOr(distance, 0), 0);
73
+ if (extinction === 0) return scattering * path;
74
+ return (scattering * oneMinusExpNeg(extinction * path)) / extinction;
75
+ }
76
+
77
+ const nonNegative = (value: number): number => Math.max(finiteOr(value, 0), 0);
78
+
79
+ const clamp01 = (value: number): number => Math.min(Math.max(finiteOr(value, 0), 0), 1);
80
+
81
+ /** Test an endpoint against the undisturbed geometric water plane. */
82
+ export function isBelowSingleLayerMediumPlane(input: {
83
+ readonly surfacePosition: MediumVector3;
84
+ readonly geometricNormal: MediumVector3;
85
+ readonly endpoint: MediumVector3;
86
+ readonly epsilonMeters?: number;
87
+ }): boolean {
88
+ const [nx, ny, nz] = input.geometricNormal;
89
+ const length = Math.hypot(nx, ny, nz);
90
+ if (!Number.isFinite(length) || length <= 1e-8) return false;
91
+ const signedDistance =
92
+ ((input.endpoint[0] - input.surfacePosition[0]) * nx +
93
+ (input.endpoint[1] - input.surfacePosition[1]) * ny +
94
+ (input.endpoint[2] - input.surfacePosition[2]) * nz) /
95
+ length;
96
+ return Number.isFinite(signedDistance) && signedDistance <= (input.epsilonMeters ?? 0.001);
97
+ }
98
+
99
+ function vector3(input: MediumVector3 | undefined): MediumVector3 {
100
+ return [nonNegative(input?.[0] ?? 0), nonNegative(input?.[1] ?? 0), nonNegative(input?.[2] ?? 0)];
101
+ }
102
+
103
+ function finiteColor(input: Color3 | undefined): input is Color3 {
104
+ return input !== undefined && input.length === 3 && input.every(Number.isFinite);
105
+ }
106
+
107
+ function finiteUv(input: Uv2): boolean {
108
+ return input.length === 2 && input.every(Number.isFinite);
109
+ }
110
+
111
+ function safeDistance(value: number, maxDistance: number): number {
112
+ return Math.min(Math.max(finiteOr(value, 0), 0), maxDistance);
113
+ }
114
+
115
+ /**
116
+ * Evaluate the stable analytic portion of the Engine's single-layer model.
117
+ * Zero extinction uses the continuous limit and every returned component is
118
+ * finite, even when an authored value is NaN or infinite.
119
+ */
120
+ export function integrateSingleLayerMedium(input: {
121
+ readonly coefficients: SingleLayerMediumCoefficients;
122
+ readonly distanceMeters: number;
123
+ readonly cosTheta: number;
124
+ readonly phaseCosTheta?: number;
125
+ /** Finite authored propagation bound; defaults to the conservative 1000 m bound. */
126
+ readonly maxDistanceMeters?: number;
127
+ }): SingleLayerMediumOptics {
128
+ const absorption = vector3(input.coefficients.absorption);
129
+ const scattering = vector3(input.coefficients.scattering);
130
+ const sigmaT: MediumVector3 = [
131
+ absorption[0] + scattering[0],
132
+ absorption[1] + scattering[1],
133
+ absorption[2] + scattering[2],
134
+ ];
135
+ const maxDistanceMeters = Math.min(
136
+ Math.max(
137
+ finiteOr(input.maxDistanceMeters ?? DEFAULT_MAX_DISTANCE_METERS, DEFAULT_MAX_DISTANCE_METERS),
138
+ 0,
139
+ ),
140
+ 100000,
141
+ );
142
+ const distanceMeters = safeDistance(input.distanceMeters, maxDistanceMeters);
143
+ const transmittance: MediumVector3 = [
144
+ Number.isFinite(sigmaT[0]) && sigmaT[0] > 0 ? Math.exp(-sigmaT[0] * distanceMeters) : 1,
145
+ Number.isFinite(sigmaT[1]) && sigmaT[1] > 0 ? Math.exp(-sigmaT[1] * distanceMeters) : 1,
146
+ Number.isFinite(sigmaT[2]) && sigmaT[2] > 0 ? Math.exp(-sigmaT[2] * distanceMeters) : 1,
147
+ ];
148
+ const singleScatter: MediumVector3 = [
149
+ singleScatterIntegral(scattering[0], sigmaT[0], distanceMeters),
150
+ singleScatterIntegral(scattering[1], sigmaT[1], distanceMeters),
151
+ singleScatterIntegral(scattering[2], sigmaT[2], distanceMeters),
152
+ ];
153
+ const iorCandidate = finiteOr(input.coefficients.ior, DEFAULT_IOR);
154
+ const ior = iorCandidate >= 1 ? iorCandidate : DEFAULT_IOR;
155
+ const reflectance = fresnelReflectance(input.cosTheta, 1 / ior);
156
+ const transmissionWeight = 1 - reflectance;
157
+ const phaseG = Math.min(Math.max(finiteOr(input.coefficients.phaseG ?? 0, 0), -1), 1);
158
+ const phaseCosTheta = clamp01(input.phaseCosTheta ?? input.cosTheta);
159
+ const phaseDenominator = Math.max(1 + phaseG * phaseG - 2 * phaseG * phaseCosTheta, 1e-6);
160
+ const phase = (1 - phaseG * phaseG) / (4 * Math.PI * phaseDenominator ** 1.5);
161
+ return {
162
+ sigmaT,
163
+ transmittance,
164
+ singleScatter,
165
+ reflectance,
166
+ transmissionWeight,
167
+ phase: finiteOr(phase, 1 / (4 * Math.PI)),
168
+ distanceMeters,
169
+ };
170
+ }
171
+
172
+ /** Compose linear HDR terms after exactly one Fresnel allocation. */
173
+ export function composeSingleLayerMediumColor(input: {
174
+ readonly optics: SingleLayerMediumOptics;
175
+ readonly background: Color3;
176
+ readonly reflection: Color3;
177
+ readonly foamColor?: Color3;
178
+ readonly coverage?: number;
179
+ readonly foam?: number;
180
+ }): Color3 {
181
+ const coverage = clamp01(input.coverage ?? 1);
182
+ const foam = clamp01(input.foam ?? 0) * coverage;
183
+ const foamColor = finiteColor(input.foamColor) ? input.foamColor : [1, 1, 1];
184
+ const background = finiteColor(input.background) ? input.background : [0, 0, 0];
185
+ const reflection = finiteColor(input.reflection) ? input.reflection : [0, 0, 0];
186
+ const medium: MediumVector3 = [
187
+ background[0] * input.optics.transmittance[0] + input.optics.singleScatter[0],
188
+ background[1] * input.optics.transmittance[1] + input.optics.singleScatter[1],
189
+ background[2] * input.optics.transmittance[2] + input.optics.singleScatter[2],
190
+ ];
191
+ const waterWeight = input.optics.transmissionWeight * coverage * (1 - foam);
192
+ const reflectionWeight = input.optics.reflectance * coverage;
193
+ const foamWeight = foam;
194
+ return [
195
+ finiteOr(
196
+ reflection[0] * reflectionWeight + medium[0] * waterWeight + foamColor[0] * foamWeight,
197
+ 0,
198
+ ),
199
+ finiteOr(
200
+ reflection[1] * reflectionWeight + medium[1] * waterWeight + foamColor[1] * foamWeight,
201
+ 0,
202
+ ),
203
+ finiteOr(
204
+ reflection[2] * reflectionWeight + medium[2] * waterWeight + foamColor[2] * foamWeight,
205
+ 0,
206
+ ),
207
+ ];
208
+ }
209
+
210
+ function validCandidate(
211
+ candidate: SingleLayerMediumBackgroundCandidate | undefined,
212
+ maxDistance: number,
213
+ ): candidate is SingleLayerMediumBackgroundCandidate {
214
+ return (
215
+ candidate !== undefined &&
216
+ finiteColor(candidate.color) &&
217
+ finiteUv(candidate.uv) &&
218
+ Number.isFinite(candidate.depthMeters) &&
219
+ candidate.depthMeters >= 0 &&
220
+ candidate.depthMeters <= maxDistance
221
+ );
222
+ }
223
+
224
+ /**
225
+ * Resolve paired color/depth input with front, shore, edge, and sky-miss
226
+ * reasons. Environment is a reflection/background fallback only; it is never
227
+ * used as a riverbed transmission sample when a valid original pair exists.
228
+ */
229
+ export function resolveSingleLayerMediumBackground(
230
+ input: SingleLayerMediumBackgroundInput,
231
+ ): SingleLayerMediumBackgroundResolution {
232
+ const maxDistance = Math.max(finiteOr(input.maxDistanceMeters, DEFAULT_MAX_DISTANCE_METERS), 0);
233
+ const tolerance = Math.max(
234
+ finiteOr(
235
+ input.depthToleranceMeters ?? DEFAULT_DEPTH_TOLERANCE_METERS,
236
+ DEFAULT_DEPTH_TOLERANCE_METERS,
237
+ ),
238
+ 0,
239
+ );
240
+ const surfaceDepth = finiteOr(input.surfaceDepthMeters, 0);
241
+ if (
242
+ validCandidate(input.refracted, maxDistance) &&
243
+ input.refracted.uv.every((coordinate) => coordinate >= 0 && coordinate <= 1)
244
+ ) {
245
+ if (input.refracted.depthMeters + tolerance < surfaceDepth) {
246
+ return {
247
+ source: 'unrefracted',
248
+ reason: 'front',
249
+ candidate: validCandidate(input.original, maxDistance) ? input.original : undefined,
250
+ color: validCandidate(input.original, maxDistance) ? input.original.color : [0, 0, 0],
251
+ distanceMeters: validCandidate(input.original, maxDistance)
252
+ ? Math.max(input.original.depthMeters - surfaceDepth, 0)
253
+ : 0,
254
+ };
255
+ }
256
+ return {
257
+ source: 'refracted',
258
+ candidate: input.refracted,
259
+ color: input.refracted.color,
260
+ distanceMeters: Math.max(input.refracted.depthMeters - surfaceDepth, 0),
261
+ };
262
+ }
263
+ if (validCandidate(input.original, maxDistance)) {
264
+ const reason: SingleLayerMediumBackgroundReason =
265
+ input.refracted === undefined
266
+ ? 'shore'
267
+ : finiteUv(input.refracted.uv) &&
268
+ input.refracted.uv.some((coordinate) => coordinate < 0 || coordinate > 1)
269
+ ? 'edge'
270
+ : 'shore';
271
+ return {
272
+ source: 'unrefracted',
273
+ reason,
274
+ candidate: input.original,
275
+ color: input.original.color,
276
+ distanceMeters: Math.max(input.original.depthMeters - surfaceDepth, 0),
277
+ };
278
+ }
279
+ if (finiteColor(input.environment)) {
280
+ return {
281
+ source: 'environment',
282
+ reason: 'sky-miss',
283
+ candidate: undefined,
284
+ color: input.environment,
285
+ distanceMeters: maxDistance,
286
+ };
287
+ }
288
+ return {
289
+ source: 'environment',
290
+ reason: 'sky-miss',
291
+ candidate: undefined,
292
+ color: [0, 0, 0],
293
+ distanceMeters: maxDistance,
294
+ };
295
+ }
296
+
297
+ /** Screen-space approximation of the Euclidean endpoint path, clamped to the declared maximum. */
298
+ export function estimateSingleLayerPathLength(input: {
299
+ readonly surfacePosition: readonly [number, number, number];
300
+ readonly backgroundPosition: readonly [number, number, number] | undefined;
301
+ readonly maxDistanceMeters: number;
302
+ }): { readonly distanceMeters: number; readonly valid: boolean } {
303
+ const maxDistance = Math.max(finiteOr(input.maxDistanceMeters, DEFAULT_MAX_DISTANCE_METERS), 0);
304
+ if (
305
+ input.surfacePosition.length !== 3 ||
306
+ input.backgroundPosition === undefined ||
307
+ input.backgroundPosition.length !== 3 ||
308
+ !input.surfacePosition.every(Number.isFinite) ||
309
+ !input.backgroundPosition.every(Number.isFinite)
310
+ ) {
311
+ return { distanceMeters: maxDistance, valid: false };
312
+ }
313
+ const distance = Math.hypot(
314
+ (input.backgroundPosition[0] ?? 0) - (input.surfacePosition[0] ?? 0),
315
+ (input.backgroundPosition[1] ?? 0) - (input.surfacePosition[1] ?? 0),
316
+ (input.backgroundPosition[2] ?? 0) - (input.surfacePosition[2] ?? 0),
317
+ );
318
+ return {
319
+ distanceMeters: Math.min(Math.max(finiteOr(distance, maxDistance), 0), maxDistance),
320
+ valid: Number.isFinite(distance),
321
+ };
322
+ }
@@ -1,10 +1,10 @@
1
- import type {
2
- GraphAccess,
3
- GraphResourceResolver,
4
- GraphTextureView,
5
- RenderGraphBuilder,
1
+ import {
2
+ type GraphAccess,
3
+ type GraphResourceResolver,
4
+ type GraphTextureView,
5
+ type RenderGraphBuilder,
6
6
  RenderGraphError,
7
- ResolveContext,
7
+ type ResolveContext,
8
8
  } from '@forgeax/engine-render-graph';
9
9
  import {
10
10
  type Buffer,
@@ -13,7 +13,7 @@ import {
13
13
  type TextureFormat,
14
14
  type TextureView,
15
15
  } from '@forgeax/engine-rhi';
16
- import { ok, type PassKind, type PassSelector, type Result } from '@forgeax/engine-types';
16
+ import { err, ok, type PassKind, type PassSelector, type Result } from '@forgeax/engine-types';
17
17
  import {
18
18
  GPU_TEXTURE_USAGE_COPY_SRC,
19
19
  GPU_TEXTURE_USAGE_RENDER_ATTACHMENT,
@@ -28,10 +28,9 @@ import type {
28
28
  } from './record/render-context';
29
29
  import {
30
30
  encodeSkyboxPass,
31
- recordBloomBlurHPass,
32
- recordBloomBlurVPass,
33
- recordBloomBrightPass,
34
31
  recordBloomCompositePass,
32
+ recordBloomDownsamplePass,
33
+ recordBloomUpsamplePass,
35
34
  } from './record/skybox-post-pass';
36
35
  import { STANDARD_OUTPUT_TRANSFORM_FEATURE_ID } from './render-contract';
37
36
  import {
@@ -39,7 +38,12 @@ import {
39
38
  recordSsaoBlurPass,
40
39
  recordSsaoCalcPass,
41
40
  } from './render-graph-primitives';
42
- import type { RenderPipelineFrame, RenderPipelineGpuDrivenProjection } from './render-pipeline';
41
+ import type {
42
+ RenderPipelineFrame,
43
+ RenderPipelineGpuDrivenFilter,
44
+ RenderPipelineGpuDrivenProjection,
45
+ RenderPipelineSurfaceMediumPair,
46
+ } from './render-pipeline';
43
47
  import { createRenderPipelineTarget, type RenderPipelineTarget } from './render-pipeline';
44
48
  import type { OcclusionFrameProjection } from './scene/visibility/occlusion-runtime';
45
49
  import {
@@ -266,6 +270,8 @@ export interface TypedScenePassOptions {
266
270
  readonly sampled?: readonly RenderPipelineTarget[] | undefined;
267
271
  readonly directionalShadow?: RenderPipelineTarget | undefined;
268
272
  readonly spotShadow?: RenderPipelineTarget | undefined;
273
+ /** Stable world-space cloud shadow map sampled by direct-solar receivers. */
274
+ readonly cloudShadow?: RenderPipelineTarget | undefined;
269
275
  readonly ssao?: RenderPipelineTarget | undefined;
270
276
  readonly selector: PassSelector;
271
277
  readonly passKind?: PassKind | undefined;
@@ -273,8 +279,24 @@ export interface TypedScenePassOptions {
273
279
  readonly clearColor?: readonly [number, number, number, number] | undefined;
274
280
  readonly colorLoadOp?: GPULoadOp | readonly GPULoadOp[] | undefined;
275
281
  readonly depthLoadOp?: GPULoadOp | undefined;
282
+ /** Preserve nearest transparent fragment depth for downstream medium clipping. */
283
+ readonly transparentDepthWrite?: boolean | undefined;
276
284
  readonly coverageOnly?: boolean | undefined;
277
- readonly recordMode?: 'opaque' | 'transmission' | 'transparent' | undefined;
285
+ readonly recordMode?:
286
+ | 'opaque'
287
+ | 'transmission'
288
+ | 'transparent'
289
+ | 'single-layer-medium-nearest-layer'
290
+ | 'single-layer-medium-color'
291
+ | undefined;
292
+ /** Graph-paired Surface inputs. The raw depth status is intentionally typed. */
293
+ readonly surfacePair?: RenderPipelineSurfaceMediumPair | undefined;
294
+ /** Nearest-layer color produced by the preceding medium pass. */
295
+ readonly surfaceNearestLayer?: GraphTextureView | undefined;
296
+ /** Nearest-layer depth produced by the preceding medium pass. */
297
+ readonly surfaceNearestDepth?: GraphTextureView | undefined;
298
+ /** Restrict GPU-driven projection to the material family owned by this pass. */
299
+ readonly gpuDrivenFilter?: RenderPipelineGpuDrivenFilter | undefined;
278
300
  /** Exclude material/pass pairs consumed by an earlier graph lane. */
279
301
  readonly excludeSelector?: PassSelector | undefined;
280
302
  /** Require material membership in another lane without selecting its entries. */
@@ -300,9 +322,23 @@ export function addTypedScenePass(
300
322
  resource: target.view,
301
323
  usage: 'sampled-read' as const,
302
324
  })),
325
+ ...(options.cloudShadow === undefined
326
+ ? []
327
+ : [{ resource: options.cloudShadow.view, usage: 'sampled-read' as const }]),
303
328
  ...(options.transmissionBackdrop === undefined
304
329
  ? []
305
330
  : [{ resource: options.transmissionBackdrop, usage: 'sampled-read' as const }]),
331
+ ...(options.surfacePair?.rawDepth.status === 'available'
332
+ ? [{ resource: options.surfacePair.rawDepth.view, usage: 'sampled-read' as const }]
333
+ : []),
334
+ ...(options.recordMode === 'single-layer-medium-color' &&
335
+ options.surfaceNearestLayer !== undefined
336
+ ? [{ resource: options.surfaceNearestLayer, usage: 'sampled-read' as const }]
337
+ : []),
338
+ ...(options.recordMode === 'single-layer-medium-color' &&
339
+ options.surfaceNearestDepth !== undefined
340
+ ? [{ resource: options.surfaceNearestDepth, usage: 'sampled-read' as const }]
341
+ : []),
306
342
  ...(options.environment === undefined
307
343
  ? []
308
344
  : [options.environment.irradiance, options.environment.prefilter].map((resource) => ({
@@ -358,12 +394,28 @@ export function addTypedScenePass(
358
394
  options.spotShadow === undefined
359
395
  ? undefined
360
396
  : resolvedView(resources, options.spotShadow.view);
397
+ const cloudShadow =
398
+ options.cloudShadow === undefined
399
+ ? undefined
400
+ : resolvedView(resources, options.cloudShadow.view);
361
401
  const ssao =
362
402
  options.ssao === undefined ? undefined : resolvedView(resources, options.ssao.view);
363
403
  const transmissionBackdrop =
364
404
  options.transmissionBackdrop === undefined
365
405
  ? null
366
406
  : resolvedView(resources, options.transmissionBackdrop);
407
+ const surfaceRawDepth =
408
+ options.surfacePair?.rawDepth.status === 'available'
409
+ ? resolvedView(resources, options.surfacePair.rawDepth.view)
410
+ : null;
411
+ const surfaceNearestLayer =
412
+ options.surfaceNearestLayer === undefined
413
+ ? null
414
+ : resolvedView(resources, options.surfaceNearestLayer);
415
+ const surfaceNearestDepth =
416
+ options.surfaceNearestDepth === undefined
417
+ ? null
418
+ : resolvedView(resources, options.surfaceNearestDepth);
367
419
  internal.frameState.currentDirectionalShadowView = directionalShadow ?? null;
368
420
  internal.frameState.currentSpotShadowView = spotShadow ?? null;
369
421
  const groups = buildPerFrameBindGroups(
@@ -375,6 +427,7 @@ export function addTypedScenePass(
375
427
  {
376
428
  directionalShadow,
377
429
  spotShadow,
430
+ cloudShadow,
378
431
  projector: internal.spotLightProjector?.view ?? internal.volumetricFog?.projectorView,
379
432
  projectorSampler:
380
433
  internal.spotLightProjector?.sampler ?? internal.volumetricFog?.projectorSampler,
@@ -428,6 +481,9 @@ export function addTypedScenePass(
428
481
  passKind: options.passKind ?? 'forward',
429
482
  ...(options.clearColor === undefined ? {} : { clearColor: options.clearColor }),
430
483
  ...(options.recordMode === undefined ? {} : { recordMode: options.recordMode }),
484
+ ...(options.transparentDepthWrite === undefined
485
+ ? {}
486
+ : { transparentDepthWrite: options.transparentDepthWrite }),
431
487
  ...(options.coverageOnly === undefined ? {} : { coverageOnly: options.coverageOnly }),
432
488
  ...(options.excludeSelector === undefined
433
489
  ? {}
@@ -438,9 +494,20 @@ export function addTypedScenePass(
438
494
  ...(options.transmissionBackdrop === undefined
439
495
  ? {}
440
496
  : { transmissionBackdropView: transmissionBackdrop }),
497
+ ...(surfaceRawDepth === null ? {} : { surfaceRawDepthView: surfaceRawDepth }),
498
+ ...(surfaceNearestLayer === null ? {} : { surfaceNearestLayerView: surfaceNearestLayer }),
499
+ ...(surfaceNearestDepth === null ? {} : { surfaceNearestDepthView: surfaceNearestDepth }),
500
+ ...(options.recordMode === 'single-layer-medium-nearest-layer'
501
+ ? { fragmentEntryPoint: 'fs_nearest_layer' }
502
+ : options.recordMode === 'single-layer-medium-color'
503
+ ? { fragmentEntryPoint: 'fs_color' }
504
+ : {}),
441
505
  ...(options.gpuDriven === undefined
442
506
  ? {}
443
507
  : { gpuDriven: { projection: options.gpuDriven, resources } }),
508
+ ...(options.gpuDrivenFilter === undefined
509
+ ? {}
510
+ : { gpuDrivenFilter: options.gpuDrivenFilter }),
444
511
  });
445
512
  // encodeMainPass receives a pass-local context so attachment and
446
513
  // bind-group overrides stay isolated. Its material UBO payload cache is
@@ -502,57 +569,57 @@ export function addReflectionFallbackObservationPass(
502
569
  export interface TypedBloomTargets {
503
570
  readonly scene: RenderPipelineTarget;
504
571
  readonly composited: RenderPipelineTarget;
505
- readonly bright: RenderPipelineTarget;
506
- readonly blurH: RenderPipelineTarget;
507
- readonly blurV: RenderPipelineTarget;
572
+ readonly downsample: readonly RenderPipelineTarget[];
573
+ readonly upsample: readonly RenderPipelineTarget[];
574
+ readonly levelDimensions: readonly { readonly width: number; readonly height: number }[];
508
575
  }
509
576
 
510
577
  /** The semantic Bloom pass owner; graph inspection consumes these same identities. */
511
578
  export const TYPED_BLOOM_PASS_NAMES = {
512
- bright: 'bloom-bright',
513
- blurH: 'bloom-blur-h',
514
- blurV: 'bloom-blur-v',
579
+ downsample: 'bloom-downsample',
580
+ upsample: 'bloom-upsample',
515
581
  composite: 'bloom-composite',
516
582
  } as const;
517
583
 
584
+ export function typedBloomLevelPassName(kind: 'downsample' | 'upsample', level: number): string {
585
+ return `${TYPED_BLOOM_PASS_NAMES[kind]}-${level}`;
586
+ }
587
+
518
588
  export function addTypedBloomPasses(
519
589
  graph: RenderGraphBuilder<RenderPipelineFrame>,
520
590
  targets: TypedBloomTargets,
521
591
  ): Result<void, RenderGraphError> {
522
- const named = {
592
+ const named: Record<string, RenderPipelineTarget> = {
523
593
  hdrColor: targets.scene,
524
594
  hdrComposited: targets.composited,
525
- bloomBright: targets.bright,
526
- bloomBlurH: targets.blurH,
527
- bloomBlurV: targets.blurV,
528
595
  };
529
- const descriptors = [
530
- {
531
- name: TYPED_BLOOM_PASS_NAMES.bright,
532
- reads: [targets.scene],
533
- write: targets.bright,
534
- encode: recordBloomBrightPass,
535
- },
536
- {
537
- name: TYPED_BLOOM_PASS_NAMES.blurH,
538
- reads: [targets.bright],
539
- write: targets.blurH,
540
- encode: recordBloomBlurHPass,
541
- },
542
- {
543
- name: TYPED_BLOOM_PASS_NAMES.blurV,
544
- reads: [targets.blurH],
545
- write: targets.blurV,
546
- encode: recordBloomBlurVPass,
547
- },
548
- {
549
- name: TYPED_BLOOM_PASS_NAMES.composite,
550
- reads: [targets.scene, targets.blurV],
551
- write: targets.composited,
552
- encode: recordBloomCompositePass,
553
- },
554
- ] as const;
555
- for (const descriptor of descriptors) {
596
+ targets.downsample.forEach((target, level) => {
597
+ named[`bloomDownsample${level}`] = target;
598
+ });
599
+ targets.upsample.forEach((target, level) => {
600
+ named[`bloomUpsample${level}`] = target;
601
+ });
602
+
603
+ const add = (
604
+ name: string,
605
+ reads: readonly RenderPipelineTarget[],
606
+ write: RenderPipelineTarget,
607
+ encode: (
608
+ frame: _InternalRenderPipelineContext,
609
+ resolve: ResolveContext,
610
+ pass: import('@forgeax/engine-rhi').RhiRenderPassEncoder,
611
+ level?: number,
612
+ size?: { readonly width: number; readonly height: number },
613
+ ) => void,
614
+ level?: number,
615
+ ): Result<void, RenderGraphError> => {
616
+ const descriptor = {
617
+ name,
618
+ reads,
619
+ write,
620
+ encode,
621
+ level,
622
+ };
556
623
  const added = graph.addRasterPass(descriptor.name, {
557
624
  accesses: [
558
625
  ...descriptor.reads.map((target) => ({
@@ -574,11 +641,85 @@ export function addTypedBloomPasses(
574
641
  frame as _InternalRenderPipelineContext,
575
642
  legacyResolver(resources, named),
576
643
  pass,
644
+ descriptor.level,
645
+ descriptor.level === undefined ? undefined : targets.levelDimensions[descriptor.level],
577
646
  ),
578
647
  });
648
+ return added.ok ? ok(undefined) : added;
649
+ };
650
+
651
+ for (const [level, write] of targets.downsample.entries()) {
652
+ const source = level === 0 ? targets.scene : targets.downsample[level - 1];
653
+ if (source === undefined) {
654
+ return err(
655
+ new RenderGraphError({
656
+ code: 'resource-resolution-failed',
657
+ expected: 'Bloom downsample levels form one adjacent pyramid',
658
+ hint: 'rebuild the Standard Bloom target declaration from one level list',
659
+ detail: { resourceLabel: `bloom-level-${level}` },
660
+ }),
661
+ );
662
+ }
663
+ const added = add(
664
+ typedBloomLevelPassName('downsample', level),
665
+ [source],
666
+ write,
667
+ (frame, resolve, pass, passLevel) =>
668
+ recordBloomDownsamplePass(
669
+ frame,
670
+ resolve,
671
+ pass,
672
+ passLevel ?? level,
673
+ targets.levelDimensions[passLevel ?? level],
674
+ ),
675
+ level,
676
+ );
579
677
  if (!added.ok) return added;
580
678
  }
581
- return ok(undefined);
679
+ for (let level = targets.upsample.length - 1; level >= 0; level -= 1) {
680
+ const current = targets.downsample[level];
681
+ const coarse =
682
+ level === targets.downsample.length - 2
683
+ ? targets.downsample[level + 1]
684
+ : targets.upsample[level + 1];
685
+ const write = targets.upsample[level];
686
+ if (current === undefined || coarse === undefined || write === undefined) {
687
+ return err(
688
+ new RenderGraphError({
689
+ code: 'resource-resolution-failed',
690
+ expected: 'Bloom downsample and upsample levels form one adjacent pyramid',
691
+ hint: 'rebuild the Standard Bloom target declaration from one level list',
692
+ detail: { resourceLabel: `bloom-level-${level}` },
693
+ }),
694
+ );
695
+ }
696
+ const added = add(
697
+ typedBloomLevelPassName('upsample', level),
698
+ [current, coarse],
699
+ write,
700
+ (frame, resolve, pass, passLevel) =>
701
+ recordBloomUpsamplePass(frame, resolve, pass, passLevel ?? level),
702
+ level,
703
+ );
704
+ if (!added.ok) return added;
705
+ }
706
+ const finest = targets.upsample[0] ?? targets.downsample[0];
707
+ if (finest === undefined) {
708
+ return err(
709
+ new RenderGraphError({
710
+ code: 'resource-resolution-failed',
711
+ expected: 'Bloom has at least one downsample level',
712
+ hint: 'derive Bloom levels from a positive output extent',
713
+ detail: { resourceLabel: 'bloom-downsample-0' },
714
+ }),
715
+ );
716
+ }
717
+ return add(
718
+ TYPED_BLOOM_PASS_NAMES.composite,
719
+ [targets.scene, finest],
720
+ targets.composited,
721
+ (frame, resolve, pass) => recordBloomCompositePass(frame, resolve, pass),
722
+ );
582
723
  }
583
724
 
584
725
  export interface TypedSsaoTargets {