@forgeax/engine-render 0.1.33 → 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 (518) hide show
  1. package/README.md +1010 -124
  2. package/dist/assembly/backend-contract.d.ts +2 -0
  3. package/dist/assembly/backend-contract.d.ts.map +1 -1
  4. package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
  5. package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
  6. package/dist/assembly/canvas-draw-guard.d.ts +3 -0
  7. package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
  8. package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
  9. package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
  10. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  11. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  12. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  13. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  14. package/dist/assembly/factory.d.ts +1 -1
  15. package/dist/assembly/factory.d.ts.map +1 -1
  16. package/dist/assembly/host-contract.d.ts +3 -3
  17. package/dist/assembly/host-contract.d.ts.map +1 -1
  18. package/dist/assembly/material/assembly.d.ts.map +1 -1
  19. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  20. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  21. package/dist/assembly/material-shader-policy.d.ts +16 -2
  22. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  23. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  24. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  25. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  26. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  27. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  28. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  29. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  30. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  31. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  32. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  33. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  34. package/dist/assembly/renderer-inspection.d.ts +11 -0
  35. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  36. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  37. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  38. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  39. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  40. package/dist/assembly/webgpu-ready.d.ts +1 -1
  41. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  42. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  43. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  44. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  45. package/dist/assembly/webgpu-renderer.d.ts +1 -1
  46. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  47. package/dist/authoring.mjs +1 -1
  48. package/dist/barrel-distortion.d.ts +47 -0
  49. package/dist/barrel-distortion.d.ts.map +1 -0
  50. package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
  51. package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
  52. package/dist/{chunk-ZDQWGQW7.mjs → chunk-HEB564WF.mjs} +4 -4
  53. package/dist/{chunk-ZDQWGQW7.mjs.map → chunk-HEB564WF.mjs.map} +1 -1
  54. package/dist/{chunk-VOZWDM3L.mjs → chunk-MKDIT2EM.mjs} +1307 -188
  55. package/dist/chunk-MKDIT2EM.mjs.map +1 -0
  56. package/dist/{chunk-LEAXOMYJ.mjs → chunk-OCDLEI6I.mjs} +3 -3
  57. package/dist/{chunk-LEAXOMYJ.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
  58. package/dist/chunk-ODZWR6JQ.mjs +4927 -0
  59. package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
  60. package/dist/{chunk-3RTCJTH4.mjs → chunk-SHFUFJ5N.mjs} +184 -13
  61. package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
  62. package/dist/{chunk-OO3DRYK7.mjs → chunk-UI5SFODX.mjs} +176 -96
  63. package/dist/chunk-UI5SFODX.mjs.map +1 -0
  64. package/dist/{chunk-PLAXOOX5.mjs → chunk-UINHLCZA.mjs} +561 -79
  65. package/dist/chunk-UINHLCZA.mjs.map +1 -0
  66. package/dist/{chunk-NB2S7ZRX.mjs → chunk-WEX45HKH.mjs} +127 -386
  67. package/dist/chunk-WEX45HKH.mjs.map +1 -0
  68. package/dist/cloud/density.d.ts +55 -0
  69. package/dist/cloud/density.d.ts.map +1 -0
  70. package/dist/cloud/extract.d.ts +25 -0
  71. package/dist/cloud/extract.d.ts.map +1 -0
  72. package/dist/cloud/feature.d.ts +57 -0
  73. package/dist/cloud/feature.d.ts.map +1 -0
  74. package/dist/cloud/frame-context.d.ts +8 -0
  75. package/dist/cloud/frame-context.d.ts.map +1 -0
  76. package/dist/cloud/inspection.d.ts +59 -0
  77. package/dist/cloud/inspection.d.ts.map +1 -0
  78. package/dist/cloud/optics.d.ts +56 -0
  79. package/dist/cloud/optics.d.ts.map +1 -0
  80. package/dist/cloud/parameters.d.ts +73 -0
  81. package/dist/cloud/parameters.d.ts.map +1 -0
  82. package/dist/cloud/resources.d.ts +60 -0
  83. package/dist/cloud/resources.d.ts.map +1 -0
  84. package/dist/cloud/shadow.d.ts +42 -0
  85. package/dist/cloud/shadow.d.ts.map +1 -0
  86. package/dist/cloud/temporal.d.ts +74 -0
  87. package/dist/cloud/temporal.d.ts.map +1 -0
  88. package/dist/components/barrel-distortion.d.ts +13 -0
  89. package/dist/components/barrel-distortion.d.ts.map +1 -0
  90. package/dist/components/cloud-layer.d.ts +29 -0
  91. package/dist/components/cloud-layer.d.ts.map +1 -0
  92. package/dist/components/index.d.ts +2 -0
  93. package/dist/components/index.d.ts.map +1 -1
  94. package/dist/components/instances.d.ts +20 -6
  95. package/dist/components/instances.d.ts.map +1 -1
  96. package/dist/construct-renderer.d.ts +1 -1
  97. package/dist/construct-renderer.d.ts.map +1 -1
  98. package/dist/construct-renderer.mjs +6759 -2875
  99. package/dist/construct-renderer.mjs.map +1 -1
  100. package/dist/dynamic-geometry.d.ts +5 -1
  101. package/dist/dynamic-geometry.d.ts.map +1 -1
  102. package/dist/errors/cloud.d.ts +59 -0
  103. package/dist/errors/cloud.d.ts.map +1 -0
  104. package/dist/errors/render.d.ts +18 -4
  105. package/dist/errors/render.d.ts.map +1 -1
  106. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  107. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  108. package/dist/extract/camera.d.ts.map +1 -1
  109. package/dist/extract/contracts.d.ts +5 -1
  110. package/dist/extract/contracts.d.ts.map +1 -1
  111. package/dist/features/barrel-distortion.d.ts +29 -0
  112. package/dist/features/barrel-distortion.d.ts.map +1 -0
  113. package/dist/features/error-reporting.d.ts +6 -2
  114. package/dist/features/error-reporting.d.ts.map +1 -1
  115. package/dist/features/host.d.ts +10 -0
  116. package/dist/features/host.d.ts.map +1 -1
  117. package/dist/features/plan.d.ts +8 -0
  118. package/dist/features/plan.d.ts.map +1 -1
  119. package/dist/features/render-graph-contribution.d.ts +5 -0
  120. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  121. package/dist/features/render-graph-raster.d.ts +1 -0
  122. package/dist/features/render-graph-raster.d.ts.map +1 -1
  123. package/dist/features/targets.d.ts +2 -0
  124. package/dist/features/targets.d.ts.map +1 -1
  125. package/dist/features/types.d.ts +44 -0
  126. package/dist/features/types.d.ts.map +1 -1
  127. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  128. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  129. package/dist/gpu-dirty-ranges.d.ts +11 -0
  130. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  131. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  132. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  133. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  134. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  135. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  136. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  137. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  138. package/dist/gpu-driven/production-raster.d.ts +47 -3
  139. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  140. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  141. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  142. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  143. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  144. package/dist/gpu-driven/view-gpu.d.ts +26 -2
  145. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  146. package/dist/gpu-scene.d.ts +5 -0
  147. package/dist/gpu-scene.d.ts.map +1 -1
  148. package/dist/hdrp-buffers.d.ts +2 -2
  149. package/dist/hdrp-buffers.d.ts.map +1 -1
  150. package/dist/ibl/skylight-bind-group.d.ts +10 -1
  151. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  152. package/dist/index.d.ts +27 -7
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.mjs +258 -8
  155. package/dist/index.mjs.map +1 -1
  156. package/dist/inspection-types.d.ts +135 -1
  157. package/dist/inspection-types.d.ts.map +1 -1
  158. package/dist/instance-buffer-cache.d.ts +4 -4
  159. package/dist/instance-buffer-cache.d.ts.map +1 -1
  160. package/dist/instances.d.ts +48 -100
  161. package/dist/instances.d.ts.map +1 -1
  162. package/dist/internal.mjs +7 -7
  163. package/dist/pbr-pipeline.d.ts +19 -1
  164. package/dist/pbr-pipeline.d.ts.map +1 -1
  165. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  166. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  167. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  168. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  169. package/dist/pipeline/standard-output/types.d.ts +4 -2
  170. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  171. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  172. package/dist/pipeline/standard-post.d.ts.map +1 -1
  173. package/dist/pipeline-builder.d.ts +1 -1
  174. package/dist/pipeline-builder.d.ts.map +1 -1
  175. package/dist/plugin.d.ts.map +1 -1
  176. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  177. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  178. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  179. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  180. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  181. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  182. package/dist/record/fold-buckets.d.ts +95 -0
  183. package/dist/record/fold-buckets.d.ts.map +1 -0
  184. package/dist/record/fold-instance-buffer.d.ts +6 -0
  185. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  186. package/dist/record/frame-lighting.d.ts +1 -0
  187. package/dist/record/frame-lighting.d.ts.map +1 -1
  188. package/dist/record/frame-snapshot.d.ts +37 -3
  189. package/dist/record/frame-snapshot.d.ts.map +1 -1
  190. package/dist/record/frame.d.ts +10 -61
  191. package/dist/record/frame.d.ts.map +1 -1
  192. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  193. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  194. package/dist/record/gpu-timing.d.ts +8 -0
  195. package/dist/record/gpu-timing.d.ts.map +1 -1
  196. package/dist/record/main-pass-geometry.d.ts +21 -5
  197. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  198. package/dist/record/main-pass-material.d.ts +7 -1
  199. package/dist/record/main-pass-material.d.ts.map +1 -1
  200. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  201. package/dist/record/main-pass.d.ts +13 -2
  202. package/dist/record/main-pass.d.ts.map +1 -1
  203. package/dist/record/motion-blur-receipt.d.ts +11 -0
  204. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  205. package/dist/record/probe-blend-buffer.d.ts +16 -0
  206. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  207. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  208. package/dist/record/render-context.d.ts +22 -3
  209. package/dist/record/render-context.d.ts.map +1 -1
  210. package/dist/record/shadow-pass.d.ts +2 -0
  211. package/dist/record/shadow-pass.d.ts.map +1 -1
  212. package/dist/record/skybox-post-pass.d.ts +1 -1
  213. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  214. package/dist/record/typed-frame-graph.d.ts +22 -2
  215. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  216. package/dist/record/view-ubo.d.ts +11 -3
  217. package/dist/record/view-ubo.d.ts.map +1 -1
  218. package/dist/record/volume-params.d.ts +9 -0
  219. package/dist/record/volume-params.d.ts.map +1 -0
  220. package/dist/recovery/render-system-candidate.d.ts +10 -0
  221. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  222. package/dist/reflection/record-owner.d.ts.map +1 -1
  223. package/dist/render-contract.d.ts +42 -4
  224. package/dist/render-contract.d.ts.map +1 -1
  225. package/dist/render-graph-primitives.d.ts.map +1 -1
  226. package/dist/render-pipeline.d.ts +103 -2
  227. package/dist/render-pipeline.d.ts.map +1 -1
  228. package/dist/render-system-extract-tail.d.ts +3 -2
  229. package/dist/render-system-extract-tail.d.ts.map +1 -1
  230. package/dist/render-system-extract.d.ts +16 -9
  231. package/dist/render-system-extract.d.ts.map +1 -1
  232. package/dist/render-system-presentation.d.ts +23 -0
  233. package/dist/render-system-presentation.d.ts.map +1 -0
  234. package/dist/render-system-producer-roots.d.ts +10 -0
  235. package/dist/render-system-producer-roots.d.ts.map +1 -0
  236. package/dist/render-system-residency.d.ts +12 -0
  237. package/dist/render-system-residency.d.ts.map +1 -0
  238. package/dist/render-system.d.ts +19 -14
  239. package/dist/render-system.d.ts.map +1 -1
  240. package/dist/scene/probe-blend.d.ts +27 -0
  241. package/dist/scene/probe-blend.d.ts.map +1 -1
  242. package/dist/scene/render-scene.d.ts +12 -5
  243. package/dist/scene/render-scene.d.ts.map +1 -1
  244. package/dist/ssao-buffers.d.ts +9 -0
  245. package/dist/ssao-buffers.d.ts.map +1 -1
  246. package/dist/surface/dynamic-input.d.ts +133 -0
  247. package/dist/surface/dynamic-input.d.ts.map +1 -0
  248. package/dist/surface/gpu-driven.d.ts +41 -0
  249. package/dist/surface/gpu-driven.d.ts.map +1 -0
  250. package/dist/surface/submission-observation.d.ts +136 -0
  251. package/dist/surface/submission-observation.d.ts.map +1 -0
  252. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  253. package/dist/temporal/gpu.d.ts +13 -1
  254. package/dist/temporal/gpu.d.ts.map +1 -1
  255. package/dist/temporal/index.mjs +5 -5
  256. package/dist/temporal/inspection.d.ts.map +1 -1
  257. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  258. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  259. package/dist/transmission/single-layer-medium.d.ts +89 -0
  260. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  261. package/dist/typed-render-graph-primitives.d.ts +14 -2
  262. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  263. package/dist/volume/component.d.ts +9 -4
  264. package/dist/volume/component.d.ts.map +1 -1
  265. package/dist/volume/extract.d.ts +1 -1
  266. package/dist/volume/extract.d.ts.map +1 -1
  267. package/dist/volume/inspection.d.ts +2 -0
  268. package/dist/volume/inspection.d.ts.map +1 -1
  269. package/dist/volume/passes.d.ts +4 -1
  270. package/dist/volume/passes.d.ts.map +1 -1
  271. package/dist/volume/resources.d.ts.map +1 -1
  272. package/package.json +22 -21
  273. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  274. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  275. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  276. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  277. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  278. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  279. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  280. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  281. package/src/__tests__/factory-contract.integration.test.ts +295 -45
  282. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  283. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
  284. package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
  285. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
  286. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
  287. package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
  288. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
  289. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  290. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +6 -5
  291. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +94 -6
  292. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  293. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  294. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  295. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  296. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  297. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  298. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  299. package/src/__tests__/gpu-scene.unit.test.ts +119 -9
  300. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  301. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  302. package/src/__tests__/instances-store.unit.test.ts +97 -305
  303. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  304. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
  305. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  306. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  307. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  308. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  309. package/src/__tests__/motion-blur-compute.dawn.test.ts +13 -7
  310. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  311. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  312. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  313. package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
  314. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  315. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  316. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  317. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  318. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  319. package/src/__tests__/render-error-code-owner.test-d.ts +7 -0
  320. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  321. package/src/__tests__/render-feature-error-reporting.unit.test.ts +21 -1
  322. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  323. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  324. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  325. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  326. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +20 -20
  327. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  328. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  329. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  330. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
  331. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  332. package/src/__tests__/renderer-frame-transaction.integration.test.ts +26 -10
  333. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  334. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  335. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  336. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  337. package/src/__tests__/skinned-shadow-caster.test.ts +15 -0
  338. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  339. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  340. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  341. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  342. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  343. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  344. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  345. package/src/__tests__/standard-pipeline.integration.test.ts +182 -1
  346. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  347. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  348. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  349. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  350. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  351. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  352. package/src/__tests__/volume-optics-oracle.unit.test.ts +4 -2
  353. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +30 -20
  354. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  355. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  356. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  357. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +113 -9
  358. package/src/__tests__/volumetric-fog-topology.unit.test.ts +5 -3
  359. package/src/assembly/backend-contract.ts +30 -0
  360. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  361. package/src/assembly/canvas-draw-guard.ts +11 -0
  362. package/src/assembly/cloud-shadow-entry.ts +22 -0
  363. package/src/assembly/dynamic-geometry-host.ts +65 -37
  364. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  365. package/src/assembly/factory.ts +2 -30
  366. package/src/assembly/host-contract.ts +3 -3
  367. package/src/assembly/material/assembly.ts +25 -13
  368. package/src/assembly/material/pipeline-helpers.ts +53 -12
  369. package/src/assembly/material-shader-policy.ts +55 -0
  370. package/src/assembly/material-shader-prewarm.ts +21 -10
  371. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  372. package/src/assembly/recovery/renderer-recover.ts +41 -18
  373. package/src/assembly/render-feature-post-processes.ts +54 -0
  374. package/src/assembly/renderer-facade.ts +4 -1
  375. package/src/assembly/renderer-feature-inspection.ts +8 -2
  376. package/src/assembly/renderer-frame-transaction.ts +23 -0
  377. package/src/assembly/renderer-inspection.ts +28 -0
  378. package/src/assembly/skin-palette-owner.ts +1 -1
  379. package/src/assembly/temporal-post-process-prewarm.ts +3 -3
  380. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  381. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  382. package/src/assembly/webgpu-ready.ts +115 -61
  383. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  384. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  385. package/src/assembly/webgpu-renderer.ts +214 -252
  386. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  387. package/src/barrel-distortion.ts +247 -0
  388. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  389. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  390. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  391. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  392. package/src/cloud/density.ts +600 -0
  393. package/src/cloud/extract.ts +110 -0
  394. package/src/cloud/feature.ts +1810 -0
  395. package/src/cloud/frame-context.ts +42 -0
  396. package/src/cloud/inspection.ts +130 -0
  397. package/src/cloud/optics.ts +285 -0
  398. package/src/cloud/parameters.ts +255 -0
  399. package/src/cloud/resources.ts +122 -0
  400. package/src/cloud/shadow.ts +167 -0
  401. package/src/cloud/temporal.ts +226 -0
  402. package/src/components/barrel-distortion.ts +46 -0
  403. package/src/components/cloud-layer.ts +47 -0
  404. package/src/components/index.ts +2 -0
  405. package/src/components/instances.ts +18 -45
  406. package/src/components/sprite-instances.ts +1 -1
  407. package/src/construct-renderer.ts +1 -1
  408. package/src/dynamic-geometry.ts +12 -1
  409. package/src/errors/cloud.ts +103 -0
  410. package/src/errors/render.ts +44 -7
  411. package/src/examples/single-layer-medium-surface.ts +59 -0
  412. package/src/extract/camera.ts +15 -1
  413. package/src/extract/contracts.ts +5 -0
  414. package/src/features/barrel-distortion.ts +172 -0
  415. package/src/features/error-reporting.ts +26 -6
  416. package/src/features/host.ts +115 -14
  417. package/src/features/plan.ts +8 -0
  418. package/src/features/render-graph-contribution.ts +9 -0
  419. package/src/features/render-graph-raster.ts +45 -3
  420. package/src/features/targets.ts +66 -0
  421. package/src/features/types.ts +47 -0
  422. package/src/fullscreen-post-process-pass.ts +41 -9
  423. package/src/gpu-dirty-ranges.ts +48 -0
  424. package/src/gpu-driven/batch-topology.ts +53 -0
  425. package/src/gpu-driven/material-artifacts.ts +33 -25
  426. package/src/gpu-driven/prepared-draw.ts +12 -4
  427. package/src/gpu-driven/production-raster-material.ts +1894 -0
  428. package/src/gpu-driven/production-raster.ts +825 -784
  429. package/src/gpu-driven/resource-allocation.ts +142 -0
  430. package/src/gpu-driven/shadow-ownership.ts +71 -0
  431. package/src/gpu-driven/view-gpu.ts +164 -10
  432. package/src/gpu-scene.ts +75 -84
  433. package/src/hdrp-buffers.ts +4 -3
  434. package/src/ibl/skylight-bind-group.ts +49 -7
  435. package/src/index.ts +196 -9
  436. package/src/inspection-types.ts +162 -0
  437. package/src/instance-buffer-cache.ts +4 -4
  438. package/src/instances.ts +149 -569
  439. package/src/pbr-pipeline.ts +219 -13
  440. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  441. package/src/pipeline/standard-forward-lane.ts +313 -57
  442. package/src/pipeline/standard-output/graph.ts +8 -2
  443. package/src/pipeline/standard-output/types.ts +12 -1
  444. package/src/pipeline/standard-pipeline.ts +291 -18
  445. package/src/pipeline/standard-post.ts +90 -24
  446. package/src/pipeline-builder.ts +1 -1
  447. package/src/plugin.ts +4 -0
  448. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  449. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  450. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  451. package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
  452. package/src/record/__tests__/temporal-payload.unit.test.ts +1 -1
  453. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  454. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  455. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  456. package/src/record/barrel-distortion-frame.ts +110 -0
  457. package/src/record/dynamic-geometry-consumption.ts +39 -9
  458. package/src/record/fold-buckets.ts +852 -0
  459. package/src/record/fold-instance-buffer.ts +51 -0
  460. package/src/record/frame-lighting.ts +36 -2
  461. package/src/record/frame-snapshot.ts +39 -3
  462. package/src/record/frame.ts +217 -1084
  463. package/src/record/gpu-draw-receipts.ts +38 -0
  464. package/src/record/gpu-timing.ts +48 -5
  465. package/src/record/main-pass-geometry.ts +251 -82
  466. package/src/record/main-pass-material.ts +66 -4
  467. package/src/record/main-pass-sprite-draws.ts +7 -65
  468. package/src/record/main-pass.ts +156 -20
  469. package/src/record/motion-blur-receipt.ts +91 -0
  470. package/src/record/probe-blend-buffer.ts +180 -0
  471. package/src/record/recovery-pipeline.ts +35 -3
  472. package/src/record/render-context.ts +39 -3
  473. package/src/record/shadow-pass.ts +30 -1
  474. package/src/record/skybox-post-pass.ts +28 -4
  475. package/src/record/typed-frame-graph.ts +770 -134
  476. package/src/record/view-ubo.ts +26 -3
  477. package/src/record/volume-params.ts +225 -0
  478. package/src/recovery/render-system-candidate.ts +235 -42
  479. package/src/reflection/record-owner.ts +7 -3
  480. package/src/render-contract.ts +48 -4
  481. package/src/render-graph-primitives.ts +7 -1
  482. package/src/render-pipeline.ts +130 -0
  483. package/src/render-system-extract-tail.ts +57 -61
  484. package/src/render-system-extract.ts +74 -76
  485. package/src/render-system-presentation.ts +56 -0
  486. package/src/render-system-producer-roots.ts +96 -0
  487. package/src/render-system-residency.ts +159 -0
  488. package/src/render-system.ts +347 -363
  489. package/src/scene/probe-blend.ts +96 -4
  490. package/src/scene/render-scene.ts +349 -280
  491. package/src/ssao-buffers.ts +95 -2
  492. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  493. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  494. package/src/surface/dynamic-input.ts +658 -0
  495. package/src/surface/gpu-driven.ts +147 -0
  496. package/src/surface/submission-observation.ts +517 -0
  497. package/src/systems/skin-palette-allocator.ts +4 -1
  498. package/src/temporal/gpu.ts +101 -17
  499. package/src/temporal/inspection.ts +7 -1
  500. package/src/temporal/standard-scene-data.ts +5 -0
  501. package/src/temporal/target-coverage-attachment.ts +4 -0
  502. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  503. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  504. package/src/transmission/single-layer-medium.ts +322 -0
  505. package/src/typed-render-graph-primitives.ts +70 -2
  506. package/src/volume/component.ts +10 -9
  507. package/src/volume/extract.ts +11 -5
  508. package/src/volume/inspection.ts +3 -0
  509. package/src/volume/passes.ts +87 -4
  510. package/src/volume/resources.ts +2 -1
  511. package/dist/chunk-3RTCJTH4.mjs.map +0 -1
  512. package/dist/chunk-NB2S7ZRX.mjs.map +0 -1
  513. package/dist/chunk-NNQL7CB3.mjs +0 -1713
  514. package/dist/chunk-NNQL7CB3.mjs.map +0 -1
  515. package/dist/chunk-OO3DRYK7.mjs.map +0 -1
  516. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
  517. package/dist/chunk-PLAXOOX5.mjs.map +0 -1
  518. package/dist/chunk-VOZWDM3L.mjs.map +0 -1
@@ -0,0 +1,42 @@
1
+ import type { World } from '@forgeax/engine-ecs';
2
+ import type { RenderFeatureFrameContext, RenderFeatureViewContext } from '../features/types';
3
+ import type { CameraSnapshot } from '../render-contract';
4
+ import type { ExtractedCloudLayer } from './extract';
5
+
6
+ /** Project the stable camera/world facts consumed by the cloud feature owner. */
7
+ export function createCloudFeatureView(
8
+ camera: CameraSnapshot | undefined,
9
+ worlds: readonly World[],
10
+ cameraOwner: number,
11
+ width: number,
12
+ height: number,
13
+ deviceGeneration: number,
14
+ cameraCut: boolean,
15
+ recovery: boolean,
16
+ ): RenderFeatureViewContext | undefined {
17
+ if (camera === undefined) return undefined;
18
+ const cameraWorld = worlds[camera.worldId ?? cameraOwner];
19
+ return {
20
+ identity: `${cameraWorld?.identity ?? 'camera-world'}:${camera.entityKey ?? 0}`,
21
+ width: Math.max(1, width),
22
+ height: Math.max(1, height),
23
+ cameraRevision: camera.historyVersion ?? 0,
24
+ deviceGeneration,
25
+ cameraPosition: [camera.position[0] ?? 0, camera.position[1] ?? 0, camera.position[2] ?? 0],
26
+ // Cloud coverage is a world-space projection. Keep the authored ground
27
+ // anchor stable until a scene-bounds owner supplies a persistent anchor.
28
+ shadowAnchor: [0, 0, 0],
29
+ cameraCut,
30
+ recovery,
31
+ };
32
+ }
33
+
34
+ export function createCloudFeatureFrameContext(
35
+ cloudLayer: ExtractedCloudLayer | undefined,
36
+ view: RenderFeatureViewContext | undefined,
37
+ ): RenderFeatureFrameContext {
38
+ return {
39
+ ...(cloudLayer === undefined ? {} : { cloudLayer }),
40
+ ...(view === undefined ? {} : { view }),
41
+ };
42
+ }
@@ -0,0 +1,130 @@
1
+ import type { RhiCaps } from '@forgeax/engine-rhi';
2
+ import type { CloudLayerResourceFacts } from './resources';
3
+ import type { CloudTemporalResetReason } from './temporal';
4
+
5
+ export type CloudLayerInspectionStatus = 'off' | 'available' | 'unavailable' | 'degraded';
6
+ export type CloudLayerResourceStage = 'none' | 'candidate' | 'accepted' | 'lkg' | 'recovering';
7
+ /** Physical-adapter evidence is explicit; RHI backend labels cannot prove it. */
8
+ export type CloudPhysicalGpuEvidence = 'unknown' | 'available' | 'unavailable';
9
+
10
+ export interface CloudLayerBudgetObservation {
11
+ readonly measured: boolean;
12
+ readonly physicalGpu: CloudPhysicalGpuEvidence;
13
+ readonly gpuTimestamp: boolean;
14
+ readonly quality: 'low' | 'medium' | 'high' | undefined;
15
+ readonly warmupFrames: number;
16
+ readonly sampleFrames: number;
17
+ readonly p50GpuMs: number | undefined;
18
+ readonly p95GpuMs: number | undefined;
19
+ readonly coldGenerationMs: number | undefined;
20
+ readonly frameBudgetMs: number | undefined;
21
+ readonly reason?: string;
22
+ }
23
+
24
+ export interface CloudLayerInspection {
25
+ readonly status: CloudLayerInspectionStatus;
26
+ readonly resourceStage: CloudLayerResourceStage;
27
+ readonly sourceKey: string | undefined;
28
+ readonly generation: number | undefined;
29
+ readonly candidateGeneration: number | undefined;
30
+ readonly lkgGeneration: number | undefined;
31
+ readonly shadowRevision: number | undefined;
32
+ readonly temporalResets: number;
33
+ readonly lastTemporalReset: CloudTemporalResetReason | undefined;
34
+ readonly resourceFacts: CloudLayerResourceFacts | undefined;
35
+ readonly capability: {
36
+ readonly compute: boolean;
37
+ readonly storageBuffer: boolean;
38
+ readonly rgba16floatRenderable: boolean;
39
+ readonly physicalGpu: CloudPhysicalGpuEvidence;
40
+ readonly timestampQuery: boolean;
41
+ };
42
+ readonly budget: CloudLayerBudgetObservation;
43
+ }
44
+
45
+ export interface CloudLayerInspectionInput {
46
+ readonly authored: boolean;
47
+ readonly sourceKey?: string;
48
+ readonly generation?: number;
49
+ readonly candidateGeneration?: number;
50
+ readonly lkgGeneration?: number;
51
+ readonly shadowRevision?: number;
52
+ readonly temporalResets?: number;
53
+ readonly lastTemporalReset?: CloudTemporalResetReason;
54
+ readonly resourceFacts?: CloudLayerResourceFacts;
55
+ readonly capability?: Partial<CloudLayerInspection['capability']>;
56
+ readonly degraded?: boolean;
57
+ readonly budget?: Partial<CloudLayerBudgetObservation>;
58
+ }
59
+
60
+ function resourceStage(input: CloudLayerInspectionInput): CloudLayerResourceStage {
61
+ if (!input.authored || input.generation === undefined) return 'none';
62
+ if (input.candidateGeneration !== undefined) return 'candidate';
63
+ if (input.degraded === true || input.lkgGeneration !== undefined) return 'lkg';
64
+ return 'accepted';
65
+ }
66
+
67
+ /** Capability and lifecycle facts are inspectable even when the lane is unavailable. */
68
+ export function inspectCloudLayer(input: CloudLayerInspectionInput): CloudLayerInspection {
69
+ const capability = {
70
+ compute: input.capability?.compute ?? false,
71
+ storageBuffer: input.capability?.storageBuffer ?? false,
72
+ rgba16floatRenderable: input.capability?.rgba16floatRenderable ?? false,
73
+ physicalGpu: input.capability?.physicalGpu ?? 'unknown',
74
+ timestampQuery: input.capability?.timestampQuery ?? false,
75
+ };
76
+ const budget: CloudLayerBudgetObservation = {
77
+ measured: input.budget?.measured ?? false,
78
+ physicalGpu: input.budget?.physicalGpu ?? capability.physicalGpu,
79
+ gpuTimestamp: input.budget?.gpuTimestamp ?? capability.timestampQuery,
80
+ quality: input.budget?.quality,
81
+ warmupFrames: input.budget?.warmupFrames ?? 0,
82
+ sampleFrames: input.budget?.sampleFrames ?? 0,
83
+ p50GpuMs: input.budget?.p50GpuMs,
84
+ p95GpuMs: input.budget?.p95GpuMs,
85
+ coldGenerationMs: input.budget?.coldGenerationMs,
86
+ frameBudgetMs: input.budget?.frameBudgetMs,
87
+ ...(input.budget?.reason === undefined ? {} : { reason: input.budget.reason }),
88
+ };
89
+ // CloudLayer's production plan allocates an HDR shadow/composite target and
90
+ // therefore requires the complete feature capability tuple. Reporting
91
+ // `available` from compute/storage alone lets inspection lie while the graph
92
+ // admission correctly disables the feature on LDR-only adapters.
93
+ const available =
94
+ capability.compute && capability.storageBuffer && capability.rgba16floatRenderable;
95
+ return Object.freeze({
96
+ status: !input.authored
97
+ ? 'off'
98
+ : !available
99
+ ? 'unavailable'
100
+ : input.degraded === true
101
+ ? 'degraded'
102
+ : 'available',
103
+ resourceStage: resourceStage(input),
104
+ sourceKey: input.sourceKey,
105
+ generation: input.generation,
106
+ candidateGeneration: input.candidateGeneration,
107
+ lkgGeneration: input.lkgGeneration,
108
+ shadowRevision: input.shadowRevision,
109
+ temporalResets: input.temporalResets ?? 0,
110
+ lastTemporalReset: input.lastTemporalReset,
111
+ resourceFacts: input.resourceFacts,
112
+ capability,
113
+ budget,
114
+ });
115
+ }
116
+
117
+ /** Convert RHI facts without letting inspection invent physical measurements. */
118
+ export function cloudCapabilitiesFromRhi(
119
+ caps: Readonly<RhiCaps>,
120
+ ): CloudLayerInspection['capability'] {
121
+ return Object.freeze({
122
+ compute: caps.compute === true,
123
+ storageBuffer: caps.storageBuffer === true,
124
+ rgba16floatRenderable: caps.rgba16floatRenderable === true,
125
+ // RHI caps intentionally do not claim a physical adapter. A browser or
126
+ // Dawn receipt must promote this fact to available/unavailable.
127
+ physicalGpu: 'unknown',
128
+ timestampQuery: caps.timestampQuery === true,
129
+ });
130
+ }
@@ -0,0 +1,285 @@
1
+ import type { CloudDensityCache } from './density';
2
+ import { evaluateCloudDensity, sampleCloudDensity } from './density';
3
+ import { CLOUD_EXTINCTION_COEFFICIENT, type ValidatedCloudLayer } from './parameters';
4
+
5
+ export type CloudOpticalPath = 'camera' | 'solar-column' | 'cloud-interior';
6
+
7
+ export interface CloudRay {
8
+ readonly origin: readonly [number, number, number];
9
+ readonly direction: readonly [number, number, number];
10
+ readonly maxDistance: number;
11
+ }
12
+
13
+ export interface CloudOpticalResult {
14
+ readonly path: CloudOpticalPath;
15
+ readonly transmittance: number;
16
+ readonly scattering: readonly [number, number, number];
17
+ readonly opticalDepth: number;
18
+ readonly representativeDepth: number;
19
+ readonly steps: number;
20
+ readonly entered: boolean;
21
+ readonly exited: boolean;
22
+ }
23
+
24
+ export interface CloudInteriorLighting {
25
+ readonly sunRadiance: readonly [number, number, number];
26
+ readonly sunDirection: readonly [number, number, number];
27
+ readonly phaseG?: number;
28
+ }
29
+
30
+ export interface CloudOpticsInput {
31
+ readonly params: ValidatedCloudLayer;
32
+ readonly ray: CloudRay;
33
+ readonly path: CloudOpticalPath;
34
+ readonly timeSeconds?: number;
35
+ readonly cache?: CloudDensityCache;
36
+ readonly steps?: number;
37
+ readonly lighting?: CloudInteriorLighting;
38
+ }
39
+
40
+ const EMPTY_SCATTERING: readonly [number, number, number] = [0, 0, 0];
41
+
42
+ function normalize(vector: ArrayLike<number>): readonly [number, number, number] {
43
+ const x = vector[0] ?? 0;
44
+ const y = vector[1] ?? 0;
45
+ const z = vector[2] ?? 0;
46
+ const length = Math.hypot(x, y, z);
47
+ return length <= 1e-8 ? [0, 1, 0] : [x / length, y / length, z / length];
48
+ }
49
+
50
+ function rayBoxInterval(
51
+ ray: CloudRay,
52
+ params: ValidatedCloudLayer,
53
+ ): { readonly start: number; readonly end: number } | undefined {
54
+ const min = [Number.NEGATIVE_INFINITY, params.baseHeight, Number.NEGATIVE_INFINITY];
55
+ const max = [
56
+ Number.POSITIVE_INFINITY,
57
+ params.baseHeight + params.thickness,
58
+ Number.POSITIVE_INFINITY,
59
+ ];
60
+ let start = 0;
61
+ let end = Math.max(0, ray.maxDistance);
62
+ for (let axis = 0; axis < 3; axis += 1) {
63
+ const origin = ray.origin[axis] ?? 0;
64
+ const direction = ray.direction[axis] ?? 0;
65
+ const lower = min[axis] ?? 0;
66
+ const upper = max[axis] ?? 0;
67
+ if (Math.abs(direction) < 1e-8) {
68
+ if (origin < lower || origin > upper) return undefined;
69
+ continue;
70
+ }
71
+ const a = (lower - origin) / direction;
72
+ const b = (upper - origin) / direction;
73
+ start = Math.max(start, Math.min(a, b));
74
+ end = Math.min(end, Math.max(a, b));
75
+ if (end <= start) return undefined;
76
+ }
77
+ return end > start ? { start, end } : undefined;
78
+ }
79
+
80
+ export function intersectCloudLayer(
81
+ ray: CloudRay,
82
+ params: ValidatedCloudLayer,
83
+ ): { readonly start: number; readonly end: number } | undefined {
84
+ return rayBoxInterval(ray, params);
85
+ }
86
+
87
+ function phaseFunction(cosTheta: number, g: number): number {
88
+ const boundedG = Math.max(-0.95, Math.min(0.95, g));
89
+ const denominator = Math.max(1e-4, 1 + boundedG * boundedG - 2 * boundedG * cosTheta);
90
+ return ((1 - boundedG * boundedG) / denominator ** 1.5) * (1 / (4 * Math.PI));
91
+ }
92
+
93
+ function cloudPhase(cosTheta: number, forwardG: number): number {
94
+ // Match the bounded dual-lobe phase used by the fullscreen WGSL path.
95
+ return phaseFunction(cosTheta, forwardG) * 0.8 + phaseFunction(cosTheta, -0.2) * 0.2;
96
+ }
97
+
98
+ function smoothstep(edge0: number, edge1: number, value: number): number {
99
+ const t = Math.max(0, Math.min(1, (value - edge0) / Math.max(1e-6, edge1 - edge0)));
100
+ return t * t * (3 - 2 * t);
101
+ }
102
+
103
+ /** Unit-sun incident light, using the same phase basis as production volumes. */
104
+ export function cloudIncidentLight(
105
+ solarT: number,
106
+ cosTheta: number,
107
+ height: number,
108
+ forwardG = 0.55,
109
+ ): readonly [number, number, number] {
110
+ const direct = solarT * cloudPhase(cosTheta, forwardG);
111
+ const multiple = (0.5 * Math.sqrt(solarT) + 0.25 * solarT ** 0.25) / (4 * Math.PI);
112
+ const energy = (direct + multiple) * (4 * Math.PI);
113
+ const skyFill = 0.025 + 0.05 * smoothstep(0.1, 0.85, height);
114
+ return [energy + 0.72 * skyFill, energy + 0.84 * skyFill, energy + skyFill];
115
+ }
116
+
117
+ function densityAt(input: CloudOpticsInput, position: readonly [number, number, number]): number {
118
+ return input.cache === undefined
119
+ ? evaluateCloudDensity(input.params, position, input.timeSeconds ?? 0).density
120
+ : sampleCloudDensity(input.cache, input.params, position, input.timeSeconds ?? 0);
121
+ }
122
+
123
+ /**
124
+ * Integrate one explicitly named optical path through the layer.
125
+ *
126
+ * Camera, solar-column and cloud-interior paths are intentionally separate
127
+ * call sites. A caller cannot accidentally use a camera interval as the
128
+ * light interval and apply the same cloud attenuation twice.
129
+ */
130
+ export function integrateCloudPath(input: CloudOpticsInput): CloudOpticalResult {
131
+ const direction = normalize(input.ray.direction);
132
+ const interval = rayBoxInterval({ ...input.ray, direction }, input.params);
133
+ if (interval === undefined || input.params.density <= 0) {
134
+ return {
135
+ path: input.path,
136
+ transmittance: 1,
137
+ scattering: EMPTY_SCATTERING,
138
+ opticalDepth: 0,
139
+ representativeDepth: input.ray.maxDistance,
140
+ steps: 0,
141
+ entered: false,
142
+ exited: false,
143
+ };
144
+ }
145
+ const steps = Math.max(1, Math.floor(input.steps ?? 32));
146
+ const length = interval.end - interval.start;
147
+ const stepLength = length / steps;
148
+ let opticalDepth = 0;
149
+ const scattering: [number, number, number] = [0, 0, 0];
150
+ let weightedDepth = 0;
151
+ let scatteringWeight = 0;
152
+ const lighting = input.lighting;
153
+ const lightDirection = lighting === undefined ? undefined : normalize(lighting.sunDirection);
154
+ const viewDirection = normalize(input.ray.direction);
155
+ for (let index = 0; index < steps; index += 1) {
156
+ const distance = interval.start + (index + 0.5) * stepLength;
157
+ const position: [number, number, number] = [
158
+ (input.ray.origin[0] ?? 0) + direction[0] * distance,
159
+ (input.ray.origin[1] ?? 0) + direction[1] * distance,
160
+ (input.ray.origin[2] ?? 0) + direction[2] * distance,
161
+ ];
162
+ const localDensity = Math.max(0, densityAt(input, position));
163
+ const extinction = localDensity * CLOUD_EXTINCTION_COEFFICIENT * stepLength;
164
+ const transmittanceBefore = Math.exp(-opticalDepth);
165
+ opticalDepth += extinction;
166
+ if (lighting !== undefined && lightDirection !== undefined && localDensity > 0) {
167
+ const localShadow = integrateCloudPath({
168
+ params: input.params,
169
+ path: 'solar-column',
170
+ ray: {
171
+ origin: position,
172
+ direction: lightDirection,
173
+ maxDistance: input.params.shadowRange,
174
+ },
175
+ steps: Math.max(4, Math.ceil((input.steps ?? 32) * 0.5)),
176
+ ...(input.timeSeconds === undefined ? {} : { timeSeconds: input.timeSeconds }),
177
+ ...(input.cache === undefined ? {} : { cache: input.cache }),
178
+ });
179
+ const cosTheta =
180
+ viewDirection[0] * lightDirection[0] +
181
+ viewDirection[1] * lightDirection[1] +
182
+ viewDirection[2] * lightDirection[2];
183
+ const segmentWeight = transmittanceBefore * (1 - Math.exp(-extinction));
184
+ const heightFraction = Math.max(
185
+ 0,
186
+ Math.min(1, ((position[1] ?? 0) - input.params.baseHeight) / input.params.thickness),
187
+ );
188
+ const incident = cloudIncidentLight(
189
+ localShadow.transmittance,
190
+ cosTheta,
191
+ heightFraction,
192
+ lighting.phaseG,
193
+ );
194
+ for (let channel = 0; channel < 3; channel++) {
195
+ scattering[channel] =
196
+ (scattering[channel] ?? 0) +
197
+ (lighting.sunRadiance[channel] ?? 0) * (incident[channel] ?? 0) * segmentWeight;
198
+ }
199
+ const weight = segmentWeight;
200
+ scatteringWeight += weight;
201
+ weightedDepth += distance * weight;
202
+ }
203
+ }
204
+ const transmittance = Math.exp(-opticalDepth);
205
+ return {
206
+ path: input.path,
207
+ transmittance,
208
+ scattering,
209
+ opticalDepth,
210
+ representativeDepth:
211
+ scatteringWeight > 1e-6 ? weightedDepth / scatteringWeight : interval.start,
212
+ steps,
213
+ entered: true,
214
+ exited: interval.end < input.ray.maxDistance,
215
+ };
216
+ }
217
+
218
+ export function integrateCloudCameraPath(
219
+ params: ValidatedCloudLayer,
220
+ ray: CloudRay,
221
+ options: Omit<CloudOpticsInput, 'params' | 'ray' | 'path'> = {},
222
+ ): CloudOpticalResult {
223
+ return integrateCloudPath({ ...options, params, ray, path: 'camera' });
224
+ }
225
+
226
+ export function integrateCloudSolarColumn(
227
+ params: ValidatedCloudLayer,
228
+ origin: readonly [number, number, number],
229
+ sunDirection: readonly [number, number, number],
230
+ options: Omit<CloudOpticsInput, 'params' | 'ray' | 'path'> & {
231
+ readonly maxDistance?: number;
232
+ } = {},
233
+ ): CloudOpticalResult {
234
+ return integrateCloudPath({
235
+ ...options,
236
+ params,
237
+ path: 'solar-column',
238
+ ray: {
239
+ origin,
240
+ direction: sunDirection,
241
+ maxDistance: options.maxDistance ?? params.shadowRange,
242
+ },
243
+ });
244
+ }
245
+
246
+ export function integrateCloudInterior(
247
+ params: ValidatedCloudLayer,
248
+ ray: CloudRay,
249
+ lighting: CloudInteriorLighting,
250
+ options: Omit<CloudOpticsInput, 'params' | 'ray' | 'path' | 'lighting'> = {},
251
+ ): CloudOpticalResult {
252
+ return integrateCloudPath({ ...options, params, ray, path: 'cloud-interior', lighting });
253
+ }
254
+
255
+ /** Standard's one selected sun term consumes this factor exactly once. */
256
+ export function applyCloudSolarTransmittance(
257
+ directSunRadiance: readonly [number, number, number],
258
+ cloudTransmittance: number,
259
+ meshVisibility = 1,
260
+ ): readonly [number, number, number] {
261
+ const factor =
262
+ Math.min(1, Math.max(0, cloudTransmittance)) * Math.min(1, Math.max(0, meshVisibility));
263
+ return [
264
+ (directSunRadiance[0] ?? 0) * factor,
265
+ (directSunRadiance[1] ?? 0) * factor,
266
+ (directSunRadiance[2] ?? 0) * factor,
267
+ ];
268
+ }
269
+
270
+ /** Scene-linear HDR composition at the cloud interval/depth boundary. */
271
+ export function compositeCloudRadiance(
272
+ sceneLinearHdr: readonly [number, number, number, number],
273
+ cloud: CloudOpticalResult,
274
+ sceneDepth: number,
275
+ cloudDepth = cloud.representativeDepth,
276
+ ): readonly [number, number, number, number] {
277
+ if (!Number.isFinite(sceneDepth) || cloudDepth > sceneDepth) return sceneLinearHdr;
278
+ const transmittance = Math.min(1, Math.max(0, cloud.transmittance));
279
+ return [
280
+ (sceneLinearHdr[0] ?? 0) * transmittance + (cloud.scattering[0] ?? 0),
281
+ (sceneLinearHdr[1] ?? 0) * transmittance + (cloud.scattering[1] ?? 0),
282
+ (sceneLinearHdr[2] ?? 0) * transmittance + (cloud.scattering[2] ?? 0),
283
+ 1,
284
+ ];
285
+ }