@forgeax/engine-render 0.1.29 → 0.1.31

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 (350) hide show
  1. package/README.md +248 -21
  2. package/dist/assembly/atmosphere-shader-prewarm.d.ts +1 -1
  3. package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -1
  4. package/dist/assembly/device-feature-admission.d.ts +4 -3
  5. package/dist/assembly/device-feature-admission.d.ts.map +1 -1
  6. package/dist/assembly/dynamic-geometry-host.d.ts +6 -0
  7. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  8. package/dist/assembly/host-contract.d.ts +6 -0
  9. package/dist/assembly/host-contract.d.ts.map +1 -1
  10. package/dist/assembly/material/assembly.d.ts +26 -3
  11. package/dist/assembly/material/assembly.d.ts.map +1 -1
  12. package/dist/assembly/material/pipeline-helpers.d.ts +24 -0
  13. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -0
  14. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  15. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  16. package/dist/assembly/recovery/recovery-attempt.d.ts +1 -6
  17. package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -1
  18. package/dist/assembly/recovery/renderer-recover.d.ts +1 -0
  19. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  20. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  21. package/dist/assembly/shader-prewarm-policy.d.ts +1 -1
  22. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
  23. package/dist/assembly/webgpu-ready.d.ts +1 -1
  24. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  25. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  26. package/dist/capture/scene-projection.d.ts +41 -0
  27. package/dist/capture/scene-projection.d.ts.map +1 -0
  28. package/dist/{chunk-BQVQOQJH.mjs → chunk-7MQ3XBSP.mjs} +20 -14
  29. package/dist/chunk-7MQ3XBSP.mjs.map +1 -0
  30. package/dist/{chunk-S4DNKQYQ.mjs → chunk-C3DDSXYK.mjs} +86 -33
  31. package/dist/chunk-C3DDSXYK.mjs.map +1 -0
  32. package/dist/{chunk-BTWH7BP4.mjs → chunk-FUUO4UND.mjs} +73 -29
  33. package/dist/chunk-FUUO4UND.mjs.map +1 -0
  34. package/dist/{chunk-NRNXBLIJ.mjs → chunk-JRBDO2KB.mjs} +46 -6
  35. package/dist/chunk-JRBDO2KB.mjs.map +1 -0
  36. package/dist/{chunk-NICXSHAT.mjs → chunk-MDQJPY3T.mjs} +8 -6
  37. package/dist/chunk-MDQJPY3T.mjs.map +1 -0
  38. package/dist/{chunk-JQTSEI3Z.mjs → chunk-NO4WZCAH.mjs} +3 -3
  39. package/dist/chunk-NO4WZCAH.mjs.map +1 -0
  40. package/dist/{chunk-FUODTTIA.mjs → chunk-PSEQ6QPH.mjs} +621 -108
  41. package/dist/chunk-PSEQ6QPH.mjs.map +1 -0
  42. package/dist/{chunk-33XZFTQU.mjs → chunk-S5UE2T5P.mjs} +48 -6
  43. package/dist/chunk-S5UE2T5P.mjs.map +1 -0
  44. package/dist/components/directional-light.d.ts +2 -2
  45. package/dist/components/dynamic-resolution.d.ts +15 -0
  46. package/dist/components/dynamic-resolution.d.ts.map +1 -0
  47. package/dist/components/index.d.ts +1 -0
  48. package/dist/components/index.d.ts.map +1 -1
  49. package/dist/components/light-helpers.d.ts.map +1 -1
  50. package/dist/components/reflection-probe.d.ts +1 -0
  51. package/dist/components/reflection-probe.d.ts.map +1 -1
  52. package/dist/components/skylight.d.ts +4 -1
  53. package/dist/components/skylight.d.ts.map +1 -1
  54. package/dist/construct-renderer.mjs +2172 -796
  55. package/dist/construct-renderer.mjs.map +1 -1
  56. package/dist/device/device-scope.d.ts +2 -0
  57. package/dist/device/device-scope.d.ts.map +1 -1
  58. package/dist/device/gpu-residency.d.ts +2 -2
  59. package/dist/device/gpu-residency.d.ts.map +1 -1
  60. package/dist/dynamic-geometry.d.ts.map +1 -1
  61. package/dist/environment/background.d.ts +3 -2
  62. package/dist/environment/background.d.ts.map +1 -1
  63. package/dist/environment/ibl.d.ts +11 -0
  64. package/dist/environment/ibl.d.ts.map +1 -0
  65. package/dist/environment/storage.d.ts +14 -0
  66. package/dist/environment/storage.d.ts.map +1 -0
  67. package/dist/errors/gpu-driven.d.ts +2 -2
  68. package/dist/errors/gpu-driven.d.ts.map +1 -1
  69. package/dist/errors/render.d.ts +35 -1
  70. package/dist/errors/render.d.ts.map +1 -1
  71. package/dist/extract/camera.d.ts.map +1 -1
  72. package/dist/extract/contracts.d.ts +7 -0
  73. package/dist/extract/contracts.d.ts.map +1 -1
  74. package/dist/extract/gpu-driven.d.ts +18 -1
  75. package/dist/extract/gpu-driven.d.ts.map +1 -1
  76. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  77. package/dist/gpu-driven/material-artifacts.d.ts +24 -0
  78. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -0
  79. package/dist/gpu-driven/material-bindings.d.ts +7 -0
  80. package/dist/gpu-driven/material-bindings.d.ts.map +1 -0
  81. package/dist/gpu-driven/prepared-draw.d.ts +2 -0
  82. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  83. package/dist/gpu-driven/production-raster.d.ts +27 -6
  84. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  85. package/dist/gpu-resource.d.ts +5 -2
  86. package/dist/gpu-resource.d.ts.map +1 -1
  87. package/dist/gpu-scene-schema.d.ts.map +1 -1
  88. package/dist/gpu-scene.d.ts.map +1 -1
  89. package/dist/hdrp-buffers.d.ts +3 -0
  90. package/dist/hdrp-buffers.d.ts.map +1 -1
  91. package/dist/ibl/IblPipelineCache.d.ts +2 -0
  92. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  93. package/dist/ibl/skylight-bind-group.d.ts +3 -1
  94. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  95. package/dist/index.d.ts +83 -81
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.mjs +7 -5
  98. package/dist/index.mjs.map +1 -1
  99. package/dist/inspection-types.d.ts +16 -1
  100. package/dist/inspection-types.d.ts.map +1 -1
  101. package/dist/internal.mjs +6 -6
  102. package/dist/material-row.d.ts +10 -0
  103. package/dist/material-row.d.ts.map +1 -1
  104. package/dist/pbr-pipeline.d.ts +3 -1
  105. package/dist/pbr-pipeline.d.ts.map +1 -1
  106. package/dist/pipeline/render-extent.d.ts +51 -0
  107. package/dist/pipeline/render-extent.d.ts.map +1 -0
  108. package/dist/pipeline/standard-build-context.d.ts +7 -0
  109. package/dist/pipeline/standard-build-context.d.ts.map +1 -0
  110. package/dist/pipeline/standard-forward-lane.d.ts +3 -2
  111. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  112. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  113. package/dist/pipeline/standard-post.d.ts +1 -1
  114. package/dist/pipeline/standard-post.d.ts.map +1 -1
  115. package/dist/pipeline/standard-profile.d.ts +2 -1
  116. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  117. package/dist/pipeline-builder.d.ts +3 -1
  118. package/dist/pipeline-builder.d.ts.map +1 -1
  119. package/dist/plugin.d.ts.map +1 -1
  120. package/dist/post-process-errors.d.ts +9 -2
  121. package/dist/post-process-errors.d.ts.map +1 -1
  122. package/dist/prepare/extended-lighting/resources.d.ts +3 -3
  123. package/dist/record/frame-lighting.d.ts.map +1 -1
  124. package/dist/record/frame-snapshot.d.ts +3 -8
  125. package/dist/record/frame-snapshot.d.ts.map +1 -1
  126. package/dist/record/frame.d.ts +3 -2
  127. package/dist/record/frame.d.ts.map +1 -1
  128. package/dist/record/main-pass-geometry.d.ts +7 -2
  129. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  130. package/dist/record/main-pass-material.d.ts +6 -3
  131. package/dist/record/main-pass-material.d.ts.map +1 -1
  132. package/dist/record/main-pass.d.ts +2 -0
  133. package/dist/record/main-pass.d.ts.map +1 -1
  134. package/dist/record/prepared-material-bindings.d.ts.map +1 -1
  135. package/dist/record/recovery-pipeline.d.ts +9 -1
  136. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  137. package/dist/record/render-context.d.ts +34 -3
  138. package/dist/record/render-context.d.ts.map +1 -1
  139. package/dist/record/shadow-pass.d.ts +2 -2
  140. package/dist/record/shadow-pass.d.ts.map +1 -1
  141. package/dist/record/typed-frame-graph.d.ts +5 -2
  142. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  143. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  144. package/dist/reflection/background.d.ts +14 -0
  145. package/dist/reflection/background.d.ts.map +1 -0
  146. package/dist/reflection/filter.d.ts.map +1 -1
  147. package/dist/reflection/projection.d.ts +1 -0
  148. package/dist/reflection/projection.d.ts.map +1 -1
  149. package/dist/reflection/record-owner.d.ts +4 -2
  150. package/dist/reflection/record-owner.d.ts.map +1 -1
  151. package/dist/render-contract.d.ts +47 -32
  152. package/dist/render-contract.d.ts.map +1 -1
  153. package/dist/render-graph-primitives.d.ts.map +1 -1
  154. package/dist/render-pipeline.d.ts +17 -1
  155. package/dist/render-pipeline.d.ts.map +1 -1
  156. package/dist/render-system-extract-tail.d.ts +9 -2
  157. package/dist/render-system-extract-tail.d.ts.map +1 -1
  158. package/dist/render-system-extract.d.ts +29 -2
  159. package/dist/render-system-extract.d.ts.map +1 -1
  160. package/dist/render-system.d.ts.map +1 -1
  161. package/dist/scene/render-scene.d.ts +2 -0
  162. package/dist/scene/render-scene.d.ts.map +1 -1
  163. package/dist/ssao-config.d.ts +8 -6
  164. package/dist/ssao-config.d.ts.map +1 -1
  165. package/dist/ssr/graph.d.ts.map +1 -1
  166. package/dist/temporal/gpu.d.ts.map +1 -1
  167. package/dist/temporal/index.mjs +5 -5
  168. package/dist/temporal/standard-scene-data.d.ts +2 -1
  169. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  170. package/dist/temporal/target-coverage-attachment.d.ts +15 -0
  171. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -0
  172. package/dist/temporal/temporal-view.d.ts +6 -2
  173. package/dist/temporal/temporal-view.d.ts.map +1 -1
  174. package/dist/temporal/view.d.ts +6 -0
  175. package/dist/temporal/view.d.ts.map +1 -1
  176. package/dist/typed-render-graph-primitives.d.ts +6 -0
  177. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  178. package/dist/volume/component.d.ts +1 -0
  179. package/dist/volume/component.d.ts.map +1 -1
  180. package/package.json +21 -21
  181. package/src/__tests__/capture-scene-projection.unit.test.ts +24 -0
  182. package/src/__tests__/device-feature-admission.unit.test.ts +15 -24
  183. package/src/__tests__/device-loss-fanout.unit.test.ts +43 -0
  184. package/src/__tests__/dynamic-geometry-batch.unit.test.ts +157 -0
  185. package/src/__tests__/dynamic-geometry.unit.test.ts +36 -0
  186. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +81 -0
  187. package/src/__tests__/factory-contract.integration.test.ts +164 -1
  188. package/src/__tests__/frame-observation.contract.test.ts +21 -0
  189. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +1 -1
  190. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +20 -1
  191. package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +0 -3
  192. package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +0 -3
  193. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +11 -6
  194. package/src/__tests__/gpu-driven-production.integration.test.ts +13 -25
  195. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -0
  196. package/src/__tests__/gpu-pass-timing-browser-runner.ts +15 -0
  197. package/src/__tests__/gpu-pass-timing.browser.test.ts +14 -1
  198. package/src/__tests__/gpu-resource-scope.unit.test.ts +71 -0
  199. package/src/__tests__/gpu-scene.unit.test.ts +55 -1
  200. package/src/__tests__/materials-standard-contract.unit.test.ts +5 -1
  201. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +8 -0
  202. package/src/__tests__/morph-neutral-admission.unit.test.ts +19 -0
  203. package/src/__tests__/physical-clearcoat.integration.test.ts +6 -1
  204. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +6 -5
  205. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +216 -5
  206. package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +68 -1
  207. package/src/__tests__/reflection-probe-authoring.unit.test.ts +12 -10
  208. package/src/__tests__/reflection-probe-box.dawn.test.ts +71 -0
  209. package/src/__tests__/reflection-probe-filter.unit.test.ts +9 -0
  210. package/src/__tests__/reflection-probe-orientation.dawn.test.ts +294 -0
  211. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +5 -15
  212. package/src/__tests__/reflection-probe-updates.unit.test.ts +129 -0
  213. package/src/__tests__/render-error-code-owner.test-d.ts +3 -0
  214. package/src/__tests__/render-error-detail-ssot.test-d.ts +5 -1
  215. package/src/__tests__/render-extent.unit.test.ts +63 -0
  216. package/src/__tests__/render-scene-projection.unit.test.ts +3 -2
  217. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +173 -9
  218. package/src/__tests__/shader-manifest-fixture.ts +6 -0
  219. package/src/__tests__/skinned-shadow-caster.test.ts +8 -1
  220. package/src/__tests__/specular-environment-scale.dawn.test.ts +4 -2
  221. package/src/__tests__/ssao-config.unit.test.ts +7 -0
  222. package/src/__tests__/ssao-surface.dawn.test.ts +252 -0
  223. package/src/__tests__/ssr-cube-silhouette.dawn.test.ts +270 -0
  224. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +51 -43
  225. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +4 -0
  226. package/src/__tests__/ssr-gpu-dispatch.ts +10 -5
  227. package/src/__tests__/ssr-graph-topology.unit.test.ts +2 -2
  228. package/src/__tests__/ssr-hiz.browser.test.ts +1 -1
  229. package/src/__tests__/ssr-hiz.dawn.test.ts +1 -1
  230. package/src/__tests__/ssr-spatial.integration.test.ts +1 -1
  231. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +40 -0
  232. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +238 -1
  233. package/src/__tests__/standard-profile-oracle.unit.test.ts +27 -0
  234. package/src/__tests__/taa-coverage-edge.dawn.test.ts +6 -0
  235. package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +5 -1
  236. package/src/__tests__/taa-stability-feedback.ts +1 -0
  237. package/src/__tests__/temporal-reset-matrix.unit.test.ts +2 -2
  238. package/src/__tests__/temporal-view.unit.test.ts +17 -0
  239. package/src/__tests__/transmission-prewarm.unit.test.ts +57 -0
  240. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +62 -13
  241. package/src/__tests__/volumetric-fog-topology.unit.test.ts +7 -7
  242. package/src/assembly/atmosphere-shader-prewarm.ts +3 -2
  243. package/src/assembly/device-feature-admission.ts +9 -4
  244. package/src/assembly/dynamic-geometry-host.ts +236 -163
  245. package/src/assembly/host-contract.ts +9 -0
  246. package/src/assembly/material/assembly.ts +350 -6
  247. package/src/assembly/material/pipeline-helpers.ts +100 -0
  248. package/src/assembly/material-shader-policy.ts +39 -18
  249. package/src/assembly/recovery/device-loss-fanout.ts +5 -0
  250. package/src/assembly/recovery/recovery-attempt.ts +2 -29
  251. package/src/assembly/recovery/renderer-recover.ts +6 -9
  252. package/src/assembly/renderer-facade.ts +22 -1
  253. package/src/assembly/shader-prewarm-policy.ts +14 -1
  254. package/src/assembly/webgpu-ready.ts +28 -19
  255. package/src/assembly/webgpu-renderer.ts +95 -95
  256. package/src/capture/scene-projection.ts +37 -0
  257. package/src/components/__tests__/dynamic-resolution-schema.unit.test.ts +65 -0
  258. package/src/components/__tests__/light-radius.integration.test.ts +59 -0
  259. package/src/components/directional-light.ts +3 -3
  260. package/src/components/dynamic-resolution.ts +67 -0
  261. package/src/components/index.ts +1 -0
  262. package/src/components/light-helpers.ts +6 -1
  263. package/src/components/reflection-probe.ts +1 -0
  264. package/src/components/skylight.ts +4 -1
  265. package/src/device/device-scope.ts +13 -7
  266. package/src/device/gpu-residency.ts +11 -11
  267. package/src/dynamic-geometry.ts +13 -8
  268. package/src/environment/background.ts +30 -12
  269. package/src/environment/ibl.ts +211 -0
  270. package/src/environment/storage.ts +63 -0
  271. package/src/errors/gpu-driven.ts +10 -3
  272. package/src/errors/render.ts +64 -0
  273. package/src/extract/camera.ts +12 -1
  274. package/src/extract/contracts.ts +10 -0
  275. package/src/extract/gpu-driven.ts +72 -17
  276. package/src/gpu-driven/batch-topology.ts +33 -11
  277. package/src/gpu-driven/material-artifacts.ts +179 -0
  278. package/src/gpu-driven/material-bindings.ts +41 -0
  279. package/src/gpu-driven/prepared-draw.ts +13 -2
  280. package/src/gpu-driven/production-raster.ts +681 -164
  281. package/src/gpu-resource.ts +21 -2
  282. package/src/gpu-scene-schema.ts +11 -2
  283. package/src/gpu-scene.ts +14 -3
  284. package/src/hdrp-buffers.ts +69 -0
  285. package/src/ibl/IblPipelineCache.ts +5 -0
  286. package/src/ibl/skylight-bind-group.ts +27 -17
  287. package/src/index.ts +92 -81
  288. package/src/inspection-types.ts +16 -1
  289. package/src/material-row.ts +60 -11
  290. package/src/pbr-pipeline.ts +13 -2
  291. package/src/pipeline/render-extent.ts +111 -0
  292. package/src/pipeline/standard-build-context.ts +7 -0
  293. package/src/pipeline/standard-forward-lane.ts +41 -24
  294. package/src/pipeline/standard-pipeline.ts +47 -18
  295. package/src/pipeline/standard-post.ts +4 -0
  296. package/src/pipeline/standard-profile.ts +2 -1
  297. package/src/pipeline-builder.ts +12 -3
  298. package/src/plugin.ts +4 -0
  299. package/src/post-process-errors.ts +26 -18
  300. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +2 -2
  301. package/src/prepare/extended-lighting/resources.ts +3 -3
  302. package/src/record/__tests__/main-pass-geometry.unit.test.ts +68 -0
  303. package/src/record/__tests__/material-bg-cache.unit.test.ts +45 -0
  304. package/src/record/__tests__/material-slot-plan.unit.test.ts +9 -0
  305. package/src/record/__tests__/recovery-pipeline.unit.test.ts +47 -1
  306. package/src/record/__tests__/sprite-material-abi.unit.test.ts +7 -3
  307. package/src/record/__tests__/temporal-payload.unit.test.ts +2 -0
  308. package/src/record/frame-lighting.ts +3 -1
  309. package/src/record/frame-snapshot.ts +13 -11
  310. package/src/record/frame.ts +150 -74
  311. package/src/record/main-pass-geometry.ts +60 -9
  312. package/src/record/main-pass-material.ts +47 -19
  313. package/src/record/main-pass.ts +63 -4
  314. package/src/record/prepared-material-bindings.ts +4 -0
  315. package/src/record/recovery-pipeline.ts +56 -0
  316. package/src/record/render-context.ts +34 -3
  317. package/src/record/shadow-pass.ts +187 -50
  318. package/src/record/typed-frame-graph.ts +60 -3
  319. package/src/record/view-ubo.ts +1 -1
  320. package/src/recovery/render-system-candidate.ts +54 -11
  321. package/src/reflection/background.ts +151 -0
  322. package/src/reflection/filter.ts +3 -0
  323. package/src/reflection/projection.ts +16 -6
  324. package/src/reflection/record-owner.ts +282 -86
  325. package/src/render-contract.ts +50 -32
  326. package/src/render-graph-primitives.ts +28 -3
  327. package/src/render-pipeline.ts +20 -1
  328. package/src/render-system-extract-tail.ts +23 -3
  329. package/src/render-system-extract.ts +127 -42
  330. package/src/render-system.ts +35 -7
  331. package/src/scene/render-scene.ts +8 -0
  332. package/src/ssao-config.ts +25 -8
  333. package/src/ssr/graph.ts +78 -58
  334. package/src/temporal/gpu.ts +5 -0
  335. package/src/temporal/standard-scene-data.ts +7 -1
  336. package/src/temporal/target-coverage-attachment.ts +72 -0
  337. package/src/temporal/temporal-view.ts +10 -4
  338. package/src/temporal/view.ts +12 -2
  339. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +24 -9
  340. package/src/typed-render-graph-primitives.ts +38 -0
  341. package/src/volume/component.ts +1 -0
  342. package/src/volume/passes.ts +3 -3
  343. package/dist/chunk-33XZFTQU.mjs.map +0 -1
  344. package/dist/chunk-BQVQOQJH.mjs.map +0 -1
  345. package/dist/chunk-BTWH7BP4.mjs.map +0 -1
  346. package/dist/chunk-FUODTTIA.mjs.map +0 -1
  347. package/dist/chunk-JQTSEI3Z.mjs.map +0 -1
  348. package/dist/chunk-NICXSHAT.mjs.map +0 -1
  349. package/dist/chunk-NRNXBLIJ.mjs.map +0 -1
  350. package/dist/chunk-S4DNKQYQ.mjs.map +0 -1
package/src/ssr/graph.ts CHANGED
@@ -481,23 +481,22 @@ export function addSsrSpatialPasses<FrameCtx extends RenderGraphFrame>(
481
481
  );
482
482
  if (added.ok) passNames.push('ssr-hiz-seed');
483
483
  if (!added.ok) return added;
484
- for (let level = 1; level < hiz.levels.length; level += 1) {
485
- const source = hiz.levels[level - 1];
486
- const target = hiz.levels[level];
487
- if (source === undefined || target === undefined) return missingInput(`hiz.mip${level}`);
488
- const sourceExtent = hiz.plan.levels[level - 1];
489
- const targetExtent = hiz.plan.levels[level];
484
+ if (hiz.levels.length > 1) {
490
485
  added = addPass(
491
486
  graph,
492
- `ssr-hiz-reduce-${level}`,
493
- [
494
- { resource: source, usage: 'sampled-read' },
495
- { resource: target, usage: 'storage-write' },
496
- ],
487
+ 'ssr-hiz-reduce-chain',
488
+ hiz.levels.map((resource, level) => ({
489
+ resource,
490
+ usage:
491
+ level === 0
492
+ ? 'sampled-read'
493
+ : level === hiz.levels.length - 1
494
+ ? 'storage-write'
495
+ : 'sampled-storage-write',
496
+ })),
497
497
  ({ pass, frame, resources: resolver }) => {
498
498
  const shader = shaderSource(frame, 'hizReduce');
499
- if (shader === undefined || sourceExtent === undefined || targetExtent === undefined)
500
- return;
499
+ if (shader === undefined) return;
501
500
  hizReduceState ??= computeState(
502
501
  frame,
503
502
  shader,
@@ -506,28 +505,33 @@ export function addSsrSpatialPasses<FrameCtx extends RenderGraphFrame>(
506
505
  'ssr_hiz_reduce',
507
506
  );
508
507
  pass.setPipeline(hizReduceState.pipeline);
509
- pass.setBindGroup(
510
- 0,
511
- bindGroup(frame, hizReduceState, [
512
- {
513
- binding: 0,
514
- resource: { kind: 'textureView', value: resolvedView(resolver, source) },
515
- },
516
- {
517
- binding: 1,
518
- resource: { kind: 'textureView', value: resolvedView(resolver, target) },
519
- },
520
- ]),
521
- );
522
- pass.dispatchWorkgroups(
523
- Math.ceil(targetExtent.width / 8),
524
- Math.ceil(targetExtent.height / 8),
525
- 1,
526
- );
508
+ // Compute dispatches are ordered usage scopes. Each dispatch reads
509
+ // only the completed preceding mip and writes a disjoint next mip.
510
+ for (let level = 1; level < hiz.levels.length; level++) {
511
+ const source = hiz.levels[level - 1];
512
+ const target = hiz.levels[level];
513
+ const extent = hiz.plan.levels[level];
514
+ if (source === undefined || target === undefined || extent === undefined)
515
+ throw pipelineError('Hi-Z mip chain');
516
+ pass.setBindGroup(
517
+ 0,
518
+ bindGroup(frame, hizReduceState, [
519
+ {
520
+ binding: 0,
521
+ resource: { kind: 'textureView', value: resolvedView(resolver, source) },
522
+ },
523
+ {
524
+ binding: 1,
525
+ resource: { kind: 'textureView', value: resolvedView(resolver, target) },
526
+ },
527
+ ]),
528
+ );
529
+ pass.dispatchWorkgroups(Math.ceil(extent.width / 8), Math.ceil(extent.height / 8), 1);
530
+ }
527
531
  },
528
532
  );
529
533
  if (!added.ok) return added;
530
- passNames.push(`ssr-hiz-reduce-${level}`);
534
+ passNames.push('ssr-hiz-reduce-chain');
531
535
  }
532
536
  added = addPass(
533
537
  graph,
@@ -708,21 +712,21 @@ export function addSsrSpatialPasses<FrameCtx extends RenderGraphFrame>(
708
712
  if (!added.ok) return added;
709
713
  passNames.push('ssr-temporal');
710
714
  }
711
- for (let level = 1; level < reflectionLevels.length; level++) {
712
- const previous = reflectionLevels[level - 1];
713
- const target = reflectionLevels[level];
714
- if (previous === undefined || target === undefined || resolved === undefined)
715
- return missingInput('reflection-mip');
716
- const width = Math.max(1, resolved.width >> level);
717
- const height = Math.max(1, resolved.height >> level);
718
- const name = `ssr-reflection-mip-${level}`;
715
+ if (reflectionLevels.length > 1 && resolved !== undefined) {
716
+ const output = resolved;
717
+ const name = 'ssr-reflection-mip-chain';
719
718
  const added = addPass(
720
719
  graph,
721
720
  name,
722
- [
723
- { resource: previous, usage: 'sampled-read' },
724
- { resource: target, usage: 'storage-write' },
725
- ],
721
+ reflectionLevels.map((resource, level) => ({
722
+ resource,
723
+ usage:
724
+ level === 0
725
+ ? 'sampled-read'
726
+ : level === reflectionLevels.length - 1
727
+ ? 'storage-write'
728
+ : 'sampled-storage-write',
729
+ })),
726
730
  ({ pass, frame, resources: resolver }) => {
727
731
  const source = shaderSource(frame, 'temporal');
728
732
  if (source === undefined) return;
@@ -745,20 +749,36 @@ export function addSsrSpatialPasses<FrameCtx extends RenderGraphFrame>(
745
749
  'ssr_reflection_mip',
746
750
  );
747
751
  pass.setPipeline(reflectionMipState.pipeline);
748
- pass.setBindGroup(
749
- 0,
750
- bindGroup(frame, reflectionMipState, [
751
- {
752
- binding: 0,
753
- resource: { kind: 'textureView', value: resolvedView(resolver, previous) },
754
- },
755
- {
756
- binding: 7,
757
- resource: { kind: 'textureView', value: resolvedView(resolver, target) },
758
- },
759
- ]),
760
- );
761
- pass.dispatchWorkgroups(Math.ceil(width / 8), Math.ceil(height / 8), 1);
752
+ for (let level = 1; level < reflectionLevels.length; level++) {
753
+ const previous = reflectionLevels[level - 1];
754
+ const target = reflectionLevels[level];
755
+ if (previous === undefined || target === undefined)
756
+ throw pipelineError('reflection mip chain');
757
+ pass.setBindGroup(
758
+ 0,
759
+ bindGroup(frame, reflectionMipState, [
760
+ {
761
+ binding: 0,
762
+ resource: {
763
+ kind: 'textureView',
764
+ value: resolvedView(resolver, previous),
765
+ },
766
+ },
767
+ {
768
+ binding: 7,
769
+ resource: {
770
+ kind: 'textureView',
771
+ value: resolvedView(resolver, target),
772
+ },
773
+ },
774
+ ]),
775
+ );
776
+ pass.dispatchWorkgroups(
777
+ Math.ceil(Math.max(1, output.width >> level) / 8),
778
+ Math.ceil(Math.max(1, output.height >> level) / 8),
779
+ 1,
780
+ );
781
+ }
762
782
  },
763
783
  );
764
784
  if (!added.ok) return added;
@@ -251,6 +251,11 @@ export function getTemporalBindGroupResources(state: TemporalGpuState): {
251
251
  visibility: 2,
252
252
  texture: { sampleType: 'unfilterable-float', viewDimension: '2d' },
253
253
  },
254
+ {
255
+ binding: 11,
256
+ visibility: 2,
257
+ texture: { sampleType: 'unfilterable-float', viewDimension: '2d' },
258
+ },
254
259
  ],
255
260
  });
256
261
  if (!layout.ok) throw layout.error;
@@ -4,6 +4,8 @@ import type {
4
4
  RenderGraphError,
5
5
  } from '@forgeax/engine-render-graph';
6
6
  import { ok, type Result } from '@forgeax/engine-types';
7
+ import type { RenderExtent } from '../pipeline/render-extent';
8
+ import { renderExtentSize } from '../pipeline/render-extent';
7
9
  import type { RenderPipelineFrame, RenderPipelineTarget } from '../render-pipeline';
8
10
  import { createRenderPipelineTarget } from '../render-pipeline';
9
11
  import { addTypedFullscreenPass, addTypedScenePass } from '../typed-render-graph-primitives';
@@ -135,8 +137,12 @@ const TEMPORAL_TARGET: GraphTextureDescriptor = {
135
137
  /** The single Standard TAA current-frame producer target. */
136
138
  export function createStandardSceneDataTarget(
137
139
  graph: RenderGraphBuilder<RenderPipelineFrame>,
140
+ extent?: RenderExtent,
138
141
  ): Result<StandardSceneDataTargets, RenderGraphError> {
139
- const temporal = createRenderPipelineTarget(graph, 'standard-scene-temporal', TEMPORAL_TARGET);
142
+ const temporal = createRenderPipelineTarget(graph, 'standard-scene-temporal', {
143
+ ...TEMPORAL_TARGET,
144
+ size: extent === undefined ? TEMPORAL_TARGET.size : renderExtentSize(extent, 'internal'),
145
+ });
140
146
  return temporal.ok ? ok({ temporal: temporal.value }) : temporal;
141
147
  }
142
148
 
@@ -0,0 +1,72 @@
1
+ import type {
2
+ GraphTextureDescriptor,
3
+ RenderGraphBuilder,
4
+ RenderGraphError,
5
+ } from '@forgeax/engine-render-graph';
6
+ import { ok, type Result } from '@forgeax/engine-types';
7
+ import { GPU_TEXTURE_USAGE_COPY_SRC } from '../gpu-texture-usage';
8
+ import type { RenderExtent } from '../pipeline/render-extent';
9
+ import type { RenderPipelineFrame, RenderPipelineTarget } from '../render-pipeline';
10
+ import { createRenderPipelineTarget } from '../render-pipeline';
11
+ import { addTypedScenePass } from '../typed-render-graph-primitives';
12
+
13
+ export interface TargetCoverageAttachment {
14
+ readonly coverage: RenderPipelineTarget;
15
+ readonly depth: RenderPipelineTarget;
16
+ readonly outputWidth: number;
17
+ readonly outputHeight: number;
18
+ }
19
+
20
+ const COVERAGE_DESCRIPTOR: GraphTextureDescriptor = {
21
+ format: 'r8unorm',
22
+ size: 'surface',
23
+ sampleCount: 1,
24
+ usage: GPU_TEXTURE_USAGE_COPY_SRC,
25
+ };
26
+
27
+ const COVERAGE_DEPTH_DESCRIPTOR: GraphTextureDescriptor = {
28
+ format: 'depth24plus-stencil8',
29
+ size: 'surface',
30
+ sampleCount: 1,
31
+ };
32
+
33
+ /** Create the per-generation output-domain coverage/depth pair. */
34
+ export function createTargetCoverageAttachment(
35
+ graph: RenderGraphBuilder<RenderPipelineFrame>,
36
+ extent: RenderExtent,
37
+ ): Result<TargetCoverageAttachment, RenderGraphError> {
38
+ const coverage = createRenderPipelineTarget(graph, 'standard-scene-coverage', {
39
+ ...COVERAGE_DESCRIPTOR,
40
+ size: { width: extent.outputWidth, height: extent.outputHeight },
41
+ });
42
+ if (!coverage.ok) return coverage;
43
+ const depth = createRenderPipelineTarget(graph, 'standard-scene-coverage-depth', {
44
+ ...COVERAGE_DEPTH_DESCRIPTOR,
45
+ size: { width: extent.outputWidth, height: extent.outputHeight },
46
+ });
47
+ if (!depth.ok) return depth;
48
+ return ok({
49
+ coverage: coverage.value,
50
+ depth: depth.value,
51
+ outputWidth: extent.outputWidth,
52
+ outputHeight: extent.outputHeight,
53
+ });
54
+ }
55
+
56
+ /** Rasterize the real Standard draw list into binary output-domain coverage. */
57
+ export function addTargetCoveragePass(
58
+ graph: RenderGraphBuilder<RenderPipelineFrame>,
59
+ target: TargetCoverageAttachment,
60
+ ): Result<void, RenderGraphError> {
61
+ return addTypedScenePass(graph, {
62
+ name: 'standard-scene-coverage',
63
+ color: target.coverage,
64
+ colorTargets: [target.coverage],
65
+ depth: target.depth,
66
+ selector: { LightMode: ['Deferred', 'Forward'] },
67
+ passKind: 'temporal',
68
+ clearColor: [0, 0, 0, 0],
69
+ depthLoadOp: 'clear',
70
+ coverageOnly: true,
71
+ });
72
+ }
@@ -4,8 +4,8 @@ import type { CameraSnapshot } from '../render-contract';
4
4
 
5
5
  export const TEMPORAL_JITTER_SAMPLE_COUNT = 8;
6
6
 
7
- /** Current temporal view owns fixed surface dimensions; dynamic TAAU is deferred. */
8
- export const TEMPORAL_TAAU_DEPENDENCY_STATUS = 'dependency-deferred' as const;
7
+ /** TAAU shares the temporal view owner; its internal dimensions are optional. */
8
+ export const TEMPORAL_TAAU_DEPENDENCY_STATUS = 'available' as const;
9
9
 
10
10
  export type TemporalViewResetReason =
11
11
  | 'first-frame'
@@ -31,6 +31,8 @@ export interface TemporalView {
31
31
  readonly historyValid: boolean;
32
32
  readonly resetReason: TemporalViewResetReason | undefined;
33
33
  readonly currentJitterUv: readonly [number, number];
34
+ readonly internalWidth: number;
35
+ readonly internalHeight: number;
34
36
  readonly previousJitterUv: readonly [number, number];
35
37
  readonly currentJitteredViewProjection: Float32Array;
36
38
  readonly currentUnjitteredViewProjection: Float32Array;
@@ -45,6 +47,8 @@ export interface TemporalViewInput {
45
47
  readonly temporalFrameIndex: number;
46
48
  readonly surfaceWidth: number;
47
49
  readonly surfaceHeight: number;
50
+ readonly internalWidth?: number;
51
+ readonly internalHeight?: number;
48
52
  readonly lastSubmitted?: SubmittedTemporalView;
49
53
  }
50
54
 
@@ -125,8 +129,8 @@ export function projectTemporalView(input: TemporalViewInput): TemporalView {
125
129
  const viewId = temporalViewId(camera.worldId ?? 0, camera.entityKey ?? 0);
126
130
  const currentJitterUv = temporalJitterUv(
127
131
  input.temporalFrameIndex,
128
- input.surfaceWidth,
129
- input.surfaceHeight,
132
+ input.internalWidth ?? input.surfaceWidth,
133
+ input.internalHeight ?? input.surfaceHeight,
130
134
  );
131
135
  const view = mat4.invert(mat4.create(), camera.world);
132
136
  const projection = cameraProjection(camera);
@@ -145,6 +149,8 @@ export function projectTemporalView(input: TemporalViewInput): TemporalView {
145
149
  historyValid,
146
150
  resetReason: reason,
147
151
  currentJitterUv,
152
+ internalWidth: input.internalWidth ?? input.surfaceWidth,
153
+ internalHeight: input.internalHeight ?? input.surfaceHeight,
148
154
  previousJitterUv: historyValid
149
155
  ? (input.lastSubmitted?.jitterUv ?? currentJitterUv)
150
156
  : currentJitterUv,
@@ -28,6 +28,9 @@ export interface TemporalViewInput {
28
28
  readonly antialias: Antialias;
29
29
  readonly width: number;
30
30
  readonly height: number;
31
+ /** Internal scene extent used to normalize TAA jitter for TAAU. */
32
+ readonly internalWidth?: number;
33
+ readonly internalHeight?: number;
31
34
  readonly frameIndex?: number;
32
35
  readonly historyVersion?: number;
33
36
  readonly viewIdentity?: string;
@@ -47,6 +50,9 @@ interface TemporalViewSnapshot {
47
50
  readonly antialias: Antialias;
48
51
  readonly width: number;
49
52
  readonly height: number;
53
+ /** Internal scene extent used for TAAU jitter normalization. */
54
+ readonly internalWidth: number;
55
+ readonly internalHeight: number;
50
56
  readonly frameIndex: number;
51
57
  readonly historyVersion: number;
52
58
  readonly viewIdentity: string;
@@ -93,6 +99,8 @@ function validDimension(value: number, field: string): number {
93
99
  export function createTemporalView(input: TemporalViewInput): TemporalView {
94
100
  const width = validDimension(input.width, 'width');
95
101
  const height = validDimension(input.height, 'height');
102
+ const internalWidth = validDimension(input.internalWidth ?? width, 'internalWidth');
103
+ const internalHeight = validDimension(input.internalHeight ?? height, 'internalHeight');
96
104
  const historyVersion = input.historyVersion ?? 0;
97
105
  const frameIndex = input.frameIndex ?? 0;
98
106
  const deviceGeneration = input.deviceGeneration ?? 0;
@@ -109,6 +117,8 @@ export function createTemporalView(input: TemporalViewInput): TemporalView {
109
117
  ...input,
110
118
  width,
111
119
  height,
120
+ internalWidth,
121
+ internalHeight,
112
122
  frameIndex,
113
123
  historyVersion,
114
124
  viewIdentity: input.viewIdentity ?? 'camera:default',
@@ -135,11 +145,11 @@ export function createTemporalView(input: TemporalViewInput): TemporalView {
135
145
  jitterCancellationUv:
136
146
  jitter === undefined
137
147
  ? undefined
138
- : (Object.freeze([jitter[0] / width, jitter[1] / height]) as Jitter),
148
+ : (Object.freeze([jitter[0] / internalWidth, jitter[1] / internalHeight]) as Jitter),
139
149
  currentJitterUv:
140
150
  jitter === undefined
141
151
  ? undefined
142
- : (Object.freeze([jitter[0] / width, jitter[1] / height]) as Jitter),
152
+ : (Object.freeze([jitter[0] / internalWidth, jitter[1] / internalHeight]) as Jitter),
143
153
  historyValid: normalized.historyValid,
144
154
  temporalFrameIndex: frameIndex,
145
155
  currentUnjitteredViewProjection: input.currentUnjitteredViewProjection,
@@ -360,6 +360,30 @@ function luma(pixel: readonly [number, number, number, number]): number {
360
360
  }
361
361
 
362
362
  describe('Standard transmission Dawn ROI', () => {
363
+ it('completes a 300-frame transmission stream without renderer errors', async () => {
364
+ const result = await renderCase(
365
+ {
366
+ name: 'sustained-transmission',
367
+ transmission: 1,
368
+ ior: 1.5,
369
+ thickness: 0.5,
370
+ roughness: 0.3,
371
+ attenuationColor: [0.7, 0.8, 0.9],
372
+ attenuationDistance: 2,
373
+ renderPath: 'forward',
374
+ },
375
+ 300,
376
+ );
377
+ expect(result.framesObserved).toBe(300);
378
+ expect(result.errors).toEqual([]);
379
+ expect(result.observation).toBe(true);
380
+ expect(result.passNames).toContain('transmission-forward');
381
+ expect(result.pixel.every(Number.isFinite)).toBe(true);
382
+ process.stdout.write(
383
+ `[transmission-smoke-frames] ${JSON.stringify({ framesObserved: result.framesObserved })}\n`,
384
+ );
385
+ }, 120_000);
386
+
363
387
  it('uses linear HDR observation and responds to F0, Beer, texture, TIR, and fallback inputs', async () => {
364
388
  const baseline = await renderCase({
365
389
  name: 'baseline',
@@ -534,15 +558,6 @@ describe('Standard transmission Dawn ROI', () => {
534
558
  process.stdout.write(
535
559
  `[smoke] PASS - transmission stability frames=${result.framesObserved}\n`,
536
560
  );
537
- process.stdout.write(
538
- `[forgeax-smoke-receipt] ${JSON.stringify({
539
- schemaVersion: 1,
540
- gateId: 'app-learn-render-6-pbr-4-transmission-refraction/smoke',
541
- commandId: 'smoke',
542
- framesObserved: result.framesObserved,
543
- completed: true,
544
- })}\n`,
545
- );
546
561
  }, 120_000);
547
562
  }
548
563
  });
@@ -256,6 +256,7 @@ export function addTypedSkyboxPass(
256
256
  }
257
257
 
258
258
  export interface TypedScenePassOptions {
259
+ readonly environment?: import('./environment/ibl').GraphEnvironment | undefined;
259
260
  readonly name: string;
260
261
  readonly color: RenderPipelineTarget;
261
262
  readonly depth: RenderPipelineTarget;
@@ -270,6 +271,7 @@ export interface TypedScenePassOptions {
270
271
  readonly clearColor?: readonly [number, number, number, number] | undefined;
271
272
  readonly colorLoadOp?: GPULoadOp | readonly GPULoadOp[] | undefined;
272
273
  readonly depthLoadOp?: GPULoadOp | undefined;
274
+ readonly coverageOnly?: boolean | undefined;
273
275
  readonly recordMode?: 'opaque' | 'transmission' | 'transparent' | undefined;
274
276
  /** Exclude material/pass pairs consumed by an earlier graph lane. */
275
277
  readonly excludeSelector?: PassSelector | undefined;
@@ -299,6 +301,12 @@ export function addTypedScenePass(
299
301
  ...(options.transmissionBackdrop === undefined
300
302
  ? []
301
303
  : [{ resource: options.transmissionBackdrop, usage: 'sampled-read' as const }]),
304
+ ...(options.environment === undefined
305
+ ? []
306
+ : [options.environment.irradiance, options.environment.prefilter].map((resource) => ({
307
+ resource,
308
+ usage: 'sampled-read' as const,
309
+ }))),
302
310
  ...(options.extraAccesses ?? []),
303
311
  ...(options.gpuDriven?.accesses ?? []),
304
312
  ];
@@ -386,6 +394,14 @@ export function addTypedScenePass(
386
394
  const activeOcclusion = options.occlusion;
387
395
  const passContext: _InternalRenderPipelineContext = {
388
396
  ...internal,
397
+ ...(options.environment === undefined
398
+ ? {}
399
+ : {
400
+ environmentIbl: {
401
+ irradiance: resolvedView(resources, options.environment.irradiance),
402
+ prefilter: resolvedView(resources, options.environment.prefilter),
403
+ },
404
+ }),
389
405
  ...(activeOcclusion === undefined ? {} : { occlusion: activeOcclusion }),
390
406
  geometryColorView: colorViews[0] ?? null,
391
407
  geometryDepthView: depthView,
@@ -410,6 +426,7 @@ export function addTypedScenePass(
410
426
  passKind: options.passKind ?? 'forward',
411
427
  ...(options.clearColor === undefined ? {} : { clearColor: options.clearColor }),
412
428
  ...(options.recordMode === undefined ? {} : { recordMode: options.recordMode }),
429
+ ...(options.coverageOnly === undefined ? {} : { coverageOnly: options.coverageOnly }),
413
430
  ...(options.excludeSelector === undefined
414
431
  ? {}
415
432
  : { excludeSelector: options.excludeSelector }),
@@ -668,6 +685,10 @@ export interface TypedFullscreenPassOptions {
668
685
 
669
686
  export interface TypedTemporalResolveTargets {
670
687
  readonly scene: RenderPipelineTarget;
688
+ /** Output-domain coverage produced by the Standard raster witness. */
689
+ readonly coverage?: RenderPipelineTarget | undefined;
690
+ /** Paired output-domain depth used to keep the producer observable. */
691
+ readonly coverageDepth?: RenderPipelineTarget | undefined;
671
692
  /** Optional producer-owned R-channel reactivity in current screen space. */
672
693
  readonly secondaryReactivity?: GraphTextureView;
673
694
  readonly currentTemporal: RenderPipelineTarget;
@@ -688,6 +709,12 @@ export function addTypedTemporalResolvePass(
688
709
  accesses: [
689
710
  { resource: targets.scene.view, usage: 'sampled-read' },
690
711
  { resource: targets.currentTemporal.view, usage: 'sampled-read' },
712
+ ...(targets.coverage === undefined
713
+ ? []
714
+ : [{ resource: targets.coverage.view, usage: 'sampled-read' as const }]),
715
+ ...(targets.coverageDepth === undefined
716
+ ? []
717
+ : [{ resource: targets.coverageDepth.view, usage: 'sampled-read' as const }]),
691
718
  { resource: targets.historyColor.view, usage: 'sampled-read' },
692
719
  { resource: targets.historyTemporal.view, usage: 'sampled-read' },
693
720
  { resource: targets.historyStability.view, usage: 'sampled-read' },
@@ -746,6 +773,7 @@ export function addTypedTemporalResolvePass(
746
773
  words[2] = state.valid && (frame.camera.temporal?.historyValid ?? true) ? 1 : 0;
747
774
  words[3] = frame.camera.temporal?.temporalFrameIndex ?? 0;
748
775
  words[4] = Number(targets.secondaryReactivity !== undefined);
776
+ words[5] = Number(targets.coverage !== undefined);
749
777
  const written = frame.runtime.device.queue.writeBuffer(params, 0, new Uint8Array(payload));
750
778
  if (!written.ok)
751
779
  throwTemporalEncodeFailure('TAA resolve params upload succeeds', written.error);
@@ -773,6 +801,16 @@ export function addTypedTemporalResolvePass(
773
801
  : resolvedView(resources, targets.secondaryReactivity),
774
802
  },
775
803
  },
804
+ {
805
+ binding: 11,
806
+ resource: {
807
+ kind: 'textureView',
808
+ value:
809
+ targets.coverage === undefined
810
+ ? currentTemporal
811
+ : resolvedView(resources, targets.coverage.view),
812
+ },
813
+ },
776
814
  ] as never,
777
815
  });
778
816
  if (!bindGroup.ok) {
@@ -35,6 +35,7 @@ export interface VolumetricFogAuthoring {
35
35
  readonly light: EntityHandle;
36
36
  /** The optional same-World SpotLight paired with a PointLight. */
37
37
  readonly spotLight?: EntityHandle;
38
+ /** Linear scalar density over bounds; the renderer adds no noise or animation. */
38
39
  readonly density: VolumeDensityBinding;
39
40
  readonly bounds: VolumeBounds;
40
41
  readonly extinction: readonly [number, number, number];
@@ -481,9 +481,9 @@ export function addVolumetricFogPasses(
481
481
  const densitySampler = frame.runtime.device.createSampler({
482
482
  minFilter: 'linear',
483
483
  magFilter: 'linear',
484
- addressModeU: 'repeat',
485
- addressModeV: 'repeat',
486
- addressModeW: 'repeat',
484
+ addressModeU: 'clamp-to-edge',
485
+ addressModeV: 'clamp-to-edge',
486
+ addressModeW: 'clamp-to-edge',
487
487
  });
488
488
  if (!densitySampler.ok) throw densitySampler.error;
489
489
  const bindings = volumeBindGroup(frame, integrate.layout, [