@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
@@ -0,0 +1,111 @@
1
+ /** Immutable dimensions shared by every Standard graph consumer. */
2
+ export interface RenderExtent {
3
+ readonly outputWidth: number;
4
+ readonly outputHeight: number;
5
+ readonly internalWidth: number;
6
+ readonly internalHeight: number;
7
+ readonly scale: number;
8
+ readonly generation: number;
9
+ }
10
+
11
+ export interface RenderExtentInput {
12
+ readonly outputWidth: number;
13
+ readonly outputHeight: number;
14
+ readonly requestedScale: number;
15
+ readonly generation: number;
16
+ }
17
+
18
+ export type RenderExtentDomain = 'internal' | 'output' | 'authoring';
19
+
20
+ /** Project the immutable extent into a graph texture descriptor size. */
21
+ export function renderExtentSize(
22
+ extent: RenderExtent,
23
+ domain: RenderExtentDomain,
24
+ ): { readonly width: number; readonly height: number } {
25
+ if (domain === 'internal') {
26
+ return { width: extent.internalWidth, height: extent.internalHeight };
27
+ }
28
+ return { width: extent.outputWidth, height: extent.outputHeight };
29
+ }
30
+
31
+ export type StandardLightingLane = 'direct' | 'clustered' | 'cpu-webgl2';
32
+
33
+ export interface StandardExtentDomainPlan {
34
+ readonly extent: RenderExtent;
35
+ readonly lane: StandardLightingLane;
36
+ readonly topologyKey: string;
37
+ readonly dynamicDelta: 0 | 1;
38
+ readonly domains: {
39
+ readonly internal: { readonly width: number; readonly height: number };
40
+ readonly output: { readonly width: number; readonly height: number };
41
+ readonly authoring: { readonly width: number; readonly height: number };
42
+ };
43
+ readonly resources: readonly {
44
+ readonly name: string;
45
+ readonly domain: 'internal' | 'output' | 'authoring';
46
+ }[];
47
+ }
48
+
49
+ const MIN_SCALE = 0.5;
50
+ const MAX_SCALE = 1;
51
+ const SCALE_STEPS = 32;
52
+ const AXIS_ALIGNMENT = 8;
53
+
54
+ function alignedAxis(output: number, scale: number): number {
55
+ return Math.max(AXIS_ALIGNMENT, Math.floor((output * scale) / AXIS_ALIGNMENT) * AXIS_ALIGNMENT);
56
+ }
57
+
58
+ function finiteDimension(value: number): number {
59
+ return Math.max(1, Math.floor(value));
60
+ }
61
+
62
+ /** Derive the one immutable Standard extent before graph construction. */
63
+ export function deriveRenderExtent(input: RenderExtentInput): RenderExtent {
64
+ const outputWidth = finiteDimension(input.outputWidth);
65
+ const outputHeight = finiteDimension(input.outputHeight);
66
+ const clamped = Math.min(MAX_SCALE, Math.max(MIN_SCALE, input.requestedScale));
67
+ const scale = Math.round(clamped * SCALE_STEPS) / SCALE_STEPS;
68
+ const nativeSurface = outputWidth < AXIS_ALIGNMENT || outputHeight < AXIS_ALIGNMENT;
69
+ const internalWidth = nativeSurface ? outputWidth : alignedAxis(outputWidth, scale);
70
+ const internalHeight = nativeSurface ? outputHeight : alignedAxis(outputHeight, scale);
71
+ return Object.freeze({
72
+ outputWidth,
73
+ outputHeight,
74
+ internalWidth,
75
+ internalHeight,
76
+ scale: nativeSurface ? 1 : scale,
77
+ generation: input.generation,
78
+ });
79
+ }
80
+
81
+ /** Describe Standard's shared internal/output/authoring domain assignment. */
82
+ export function standardExtentDomainPlan(
83
+ extent: RenderExtent,
84
+ lane: StandardLightingLane,
85
+ ): StandardExtentDomainPlan {
86
+ const domains = {
87
+ internal: { width: extent.internalWidth, height: extent.internalHeight },
88
+ output: { width: extent.outputWidth, height: extent.outputHeight },
89
+ authoring: { width: extent.outputWidth, height: extent.outputHeight },
90
+ } as const;
91
+ return Object.freeze({
92
+ extent,
93
+ lane,
94
+ topologyKey: `standard:${extent.internalWidth}x${extent.internalHeight}:${extent.outputWidth}x${extent.outputHeight}:g${extent.generation}`,
95
+ dynamicDelta: extent.scale === 1 ? 0 : 1,
96
+ domains,
97
+ resources: Object.freeze([
98
+ { name: 'scene', domain: 'internal' },
99
+ { name: 'depth', domain: 'internal' },
100
+ { name: 'g-buffer', domain: 'internal' },
101
+ { name: 'scene-temporal', domain: 'internal' },
102
+ { name: 'ssao', domain: 'internal' },
103
+ { name: 'taa-history', domain: 'output' },
104
+ { name: 'bloom', domain: 'output' },
105
+ { name: 'output', domain: 'output' },
106
+ { name: 'overlay', domain: 'output' },
107
+ { name: 'observation', domain: 'output' },
108
+ { name: 'shadow', domain: 'authoring' },
109
+ ] satisfies StandardExtentDomainPlan['resources']),
110
+ });
111
+ }
@@ -0,0 +1,7 @@
1
+ import type { RenderPipelineBuildContext, RenderPipelineFrame } from '../render-pipeline';
2
+ import type { TargetCoverageAttachment } from '../temporal/target-coverage-attachment';
3
+
4
+ /** Standard-only graph input; custom pipeline consumers never see coverage. */
5
+ export type StandardPipelineBuildContext = RenderPipelineBuildContext<RenderPipelineFrame> & {
6
+ readonly targetCoverage?: TargetCoverageAttachment;
7
+ };
@@ -13,7 +13,6 @@ import {
13
13
  } from '../gpu-texture-usage';
14
14
  import type {
15
15
  RenderPipeline,
16
- RenderPipelineBuildContext,
17
16
  RenderPipelineFrame,
18
17
  RenderPipelineTopology,
19
18
  } from '../render-pipeline';
@@ -28,6 +27,7 @@ import {
28
27
  createStandardSceneDataTarget,
29
28
  standardTemporalLaneAdmission,
30
29
  } from '../temporal/standard-scene-data';
30
+ import { addTargetCoveragePass } from '../temporal/target-coverage-attachment';
31
31
  import {
32
32
  addTransmissionBackdropPasses,
33
33
  addTransmissionBackdropTemporalPass,
@@ -42,6 +42,8 @@ import {
42
42
  } from '../typed-render-graph-primitives';
43
43
  import { addTypedShadowPasses } from '../typed-shadow-passes';
44
44
  import { addAuthoredVolumetricFogPasses } from '../volume/passes';
45
+ import { renderExtentSize } from './render-extent';
46
+ import type { StandardPipelineBuildContext } from './standard-build-context';
45
47
  import {
46
48
  addStandardClusterMembershipPass,
47
49
  importStandardClusterBuffers,
@@ -59,7 +61,7 @@ function target(
59
61
  }
60
62
 
61
63
  function buildUrp(
62
- context: RenderPipelineBuildContext<RenderPipelineFrame>,
64
+ context: StandardPipelineBuildContext,
63
65
  topology: RenderPipelineTopology,
64
66
  lighting: StandardTopologyInputValue,
65
67
  ): ReturnType<RenderPipeline['build']> {
@@ -67,6 +69,9 @@ function buildUrp(
67
69
  const surface = importRenderPipelineSurface(graph, topology);
68
70
  if (!surface.ok) return surface;
69
71
 
72
+ const internalSize =
73
+ topology.extent === undefined ? 'surface' : renderExtentSize(topology.extent, 'internal');
74
+
70
75
  const clearOnly = topology.clearOnly === true;
71
76
  const msaa = !clearOnly && topology.camera.antialias === 'msaa' && topology.lane.multisample;
72
77
  const hdr =
@@ -94,7 +99,7 @@ function buildUrp(
94
99
 
95
100
  const depth = target(graph, 'scene-depth', {
96
101
  format: 'depth24plus-stencil8',
97
- size: 'surface',
102
+ size: internalSize,
98
103
  sampleCount: msaa ? 4 : 1,
99
104
  });
100
105
  if (!depth.ok) return depth;
@@ -111,7 +116,7 @@ function buildUrp(
111
116
  : hdr || fxaa || linearLdr || msaa || rawOnly || needsTemporalIntermediate
112
117
  ? target(graph, 'scene-color', {
113
118
  format: sceneFormat,
114
- size: 'surface',
119
+ size: internalSize,
115
120
  sampleCount: 1,
116
121
  domain: 'linear-ldr',
117
122
  ...(sceneFormat === topology.surface.storageFormat &&
@@ -131,7 +136,7 @@ function buildUrp(
131
136
  const scene = msaa
132
137
  ? target(graph, 'scene-color-msaa', {
133
138
  format: sceneFormat,
134
- size: 'surface',
139
+ size: internalSize,
135
140
  sampleCount: 4,
136
141
  domain: 'linear-ldr',
137
142
  ...(sceneFormat === topology.surface.storageFormat &&
@@ -145,7 +150,7 @@ function buildUrp(
145
150
  const reflectionFallback = topology.reflectionFallback?.enabled
146
151
  ? target(graph, 'reflection-fallback-linear-hdr', {
147
152
  format: 'rgba16float',
148
- size: 'surface',
153
+ size: internalSize,
149
154
  sampleCount: scene.value.sampleCount,
150
155
  domain: 'linear-hdr',
151
156
  usage:
@@ -191,22 +196,22 @@ function buildUrp(
191
196
  const clusterReads =
192
197
  clusterBuffers.value === null ? [] : standardClusterReadAccesses(clusterBuffers.value);
193
198
 
194
- const skybox =
195
- topology.atmosphere === true
196
- ? addAtmosphereBackground(graph, scene.value)
197
- : addTypedSkyboxPass(graph, scene.value);
198
- if (!skybox.ok) return skybox;
199
- // The GPU-driven Standard PBR raster adapter owns one color target. A
200
- // reflection fallback adds a second attachment to this pass, so keep that
201
- // topology on the ordinary producer rather than binding a one-target
202
- // pipeline into a multi-target render pass.
203
- const gpuDriven =
204
- reflectionFallback.value === undefined
205
- ? context.projectGpuDriven({
206
- format: scene.value.format,
207
- sampleCount: scene.value.sampleCount,
208
- })
209
- : ok(undefined);
199
+ const atmosphere =
200
+ topology.atmosphere === true ? addAtmosphereBackground(graph, scene.value) : ok(undefined);
201
+ if (!atmosphere.ok) return atmosphere;
202
+ if (atmosphere.value === undefined) {
203
+ const skybox = addTypedSkyboxPass(graph, scene.value);
204
+ if (!skybox.ok) return skybox;
205
+ }
206
+ const gpuDriven = context.projectGpuDriven({
207
+ format: scene.value.format,
208
+ sampleCount: scene.value.sampleCount,
209
+ ...(reflectionFallback.value === undefined
210
+ ? {}
211
+ : {
212
+ additionalColorFormats: [reflectionFallback.value.format],
213
+ }),
214
+ });
210
215
  if (!gpuDriven.ok) return gpuDriven;
211
216
  const transmissionDemand = transmissionDemandForTopology(topology);
212
217
  const transmissionActive = resolveTransmissionBackdropTopology({
@@ -214,6 +219,7 @@ function buildUrp(
214
219
  sourceSampleCount: scene.value.sampleCount,
215
220
  }).active;
216
221
  const main = addTypedScenePass(graph, {
222
+ environment: atmosphere.value,
217
223
  name: 'main',
218
224
  color: scene.value,
219
225
  ...(reflectionFallback.value === undefined
@@ -265,12 +271,18 @@ function buildUrp(
265
271
  );
266
272
  }
267
273
  const temporal =
268
- temporalDemand.targetCount === 1 ? createStandardSceneDataTarget(graph) : ok(undefined);
274
+ temporalDemand.targetCount === 1
275
+ ? createStandardSceneDataTarget(graph, topology.extent)
276
+ : ok(undefined);
269
277
  if (!temporal.ok) return temporal;
270
278
  if (temporal.value !== undefined) {
271
279
  const producer = addStandardSceneDataPass(graph, temporal.value.temporal, depth.value);
272
280
  if (!producer.ok) return producer;
273
281
  }
282
+ if (context.targetCoverage !== undefined) {
283
+ const coverage = addTargetCoveragePass(graph, context.targetCoverage);
284
+ if (!coverage.ok) return coverage;
285
+ }
274
286
 
275
287
  const transmission = addTransmissionBackdropPasses({
276
288
  graph,
@@ -283,6 +295,7 @@ function buildUrp(
283
295
  if (!transmission.ok) return transmission;
284
296
  if (transmission.value.topology.active) {
285
297
  const transmissionPass = addTypedScenePass(graph, {
298
+ environment: atmosphere.value,
286
299
  name: 'transmission-forward',
287
300
  color: scene.value,
288
301
  depth: depth.value,
@@ -307,6 +320,7 @@ function buildUrp(
307
320
  if (!transmissionPass.ok) return transmissionPass;
308
321
 
309
322
  const transparentPass = addTypedScenePass(graph, {
323
+ environment: atmosphere.value,
310
324
  name: 'transparent',
311
325
  color: scene.value,
312
326
  depth: depth.value,
@@ -401,9 +415,12 @@ function buildUrp(
401
415
  depth.value,
402
416
  surface.value,
403
417
  temporal.value?.temporal,
418
+ undefined,
419
+ context.targetCoverage?.coverage,
420
+ context.targetCoverage?.depth,
404
421
  );
405
422
  if (!post.ok) return post;
406
- const cubeCaptures = context.contributeCubeCaptures?.();
423
+ const cubeCaptures = context.contributeCubeCaptures?.(atmosphere.value);
407
424
  if (cubeCaptures !== undefined && !cubeCaptures.ok) return cubeCaptures;
408
425
  return ok(undefined);
409
426
  }
@@ -31,6 +31,7 @@ import {
31
31
  createStandardSceneDataTarget,
32
32
  standardTemporalLaneAdmission,
33
33
  } from '../temporal/standard-scene-data';
34
+ import { addTargetCoveragePass } from '../temporal/target-coverage-attachment';
34
35
  import {
35
36
  addTransmissionBackdropPasses,
36
37
  addTransmissionBackdropTemporalPass,
@@ -46,6 +47,8 @@ import {
46
47
  } from '../typed-render-graph-primitives';
47
48
  import { addTypedShadowPasses } from '../typed-shadow-passes';
48
49
  import { addAuthoredVolumetricFogPasses } from '../volume/passes';
50
+ import { renderExtentSize } from './render-extent';
51
+ import type { StandardPipelineBuildContext } from './standard-build-context';
49
52
  import { buildStandardForwardLane } from './standard-forward-lane';
50
53
  import {
51
54
  addStandardClusterMembershipPass,
@@ -160,13 +163,15 @@ function target(
160
163
  }
161
164
 
162
165
  function buildStandardDeferredLane(
163
- context: RenderPipelineBuildContext<RenderPipelineFrame>,
166
+ context: StandardPipelineBuildContext,
164
167
  topology: RenderPipelineTopology,
165
168
  lighting: StandardTopologyInputValue,
166
169
  ): ReturnType<RenderPipeline['build']> {
167
170
  const graph = context.graph;
168
171
  const surface = importRenderPipelineSurface(graph, topology);
169
172
  if (!surface.ok) return surface;
173
+ const internalSize =
174
+ topology.extent === undefined ? 'surface' : renderExtentSize(topology.extent, 'internal');
170
175
  const buffers = importStandardClusterBuffers(graph, lighting);
171
176
  if (!buffers.ok) return buffers;
172
177
  const membership =
@@ -186,7 +191,7 @@ function buildStandardDeferredLane(
186
191
 
187
192
  const depth = target(graph, 'hdrp-depth', {
188
193
  format: 'depth24plus-stencil8',
189
- size: 'surface',
194
+ size: internalSize,
190
195
  });
191
196
  if (!depth.ok) return depth;
192
197
  const depthSample = graph.view(depth.value.texture, {
@@ -197,26 +202,26 @@ function buildStandardDeferredLane(
197
202
  if (!depthSample.ok) return depthSample;
198
203
  const gbuffer0 = target(graph, 'gbuffer-normal-roughness', {
199
204
  format: DEFERRED_COLOR_FORMATS[0] ?? 'rgba16float',
200
- size: 'surface',
205
+ size: internalSize,
201
206
  });
202
207
  if (!gbuffer0.ok) return gbuffer0;
203
208
  const gbuffer1 = target(graph, 'gbuffer-albedo-metallic', {
204
209
  format: DEFERRED_COLOR_FORMATS[1] ?? 'rgba8unorm',
205
- size: 'surface',
210
+ size: internalSize,
206
211
  });
207
212
  if (!gbuffer1.ok) return gbuffer1;
208
213
  const gbuffer2 = target(graph, 'gbuffer-specular-response-ao', {
209
214
  format: DEFERRED_COLOR_FORMATS[2] ?? 'rgba16float',
210
- size: 'surface',
215
+ size: internalSize,
211
216
  });
212
217
  if (!gbuffer2.ok) return gbuffer2;
213
- const scene = target(graph, 'hdrp-scene-color', { format: 'rgba16float', size: 'surface' });
218
+ const scene = target(graph, 'hdrp-scene-color', { format: 'rgba16float', size: internalSize });
214
219
  if (!scene.ok) return scene;
215
220
  const reflectionFallback =
216
221
  topology.reflectionFallback?.enabled === true || topology.ssr?.status === 'admitted'
217
222
  ? target(graph, 'reflection-fallback-linear-hdr', {
218
223
  format: 'rgba16float',
219
- size: 'surface',
224
+ size: internalSize,
220
225
  domain: 'linear-hdr',
221
226
  })
222
227
  : ok(undefined);
@@ -252,6 +257,11 @@ function buildStandardDeferredLane(
252
257
  const gpuDriven = context.projectGpuDriven({
253
258
  format: scene.value.format,
254
259
  sampleCount: scene.value.sampleCount,
260
+ ...(reflectionFallback.value === undefined
261
+ ? {}
262
+ : {
263
+ additionalColorFormats: [reflectionFallback.value.format],
264
+ }),
255
265
  });
256
266
  if (!gpuDriven.ok) return gpuDriven;
257
267
  const gbuffer = addTypedScenePass(graph, {
@@ -283,11 +293,13 @@ function buildStandardDeferredLane(
283
293
 
284
294
  // Initialize the background before receiver lighting. The skybox recorder
285
295
  // has no depth attachment, so placing it later would cover lit geometry.
286
- const skybox =
287
- topology.atmosphere === true
288
- ? addAtmosphereBackground(graph, scene.value)
289
- : addTypedSkyboxPass(graph, scene.value);
290
- if (!skybox.ok) return skybox;
296
+ const atmosphere =
297
+ topology.atmosphere === true ? addAtmosphereBackground(graph, scene.value) : ok(undefined);
298
+ if (!atmosphere.ok) return atmosphere;
299
+ if (atmosphere.value === undefined) {
300
+ const skybox = addTypedSkyboxPass(graph, scene.value);
301
+ if (!skybox.ok) return skybox;
302
+ }
291
303
 
292
304
  // The lighting lane is the deferred Standard receiver. It deliberately
293
305
  // selects Forward passes for the same material handles that wrote the
@@ -297,6 +309,7 @@ function buildStandardDeferredLane(
297
309
  // the later forward lane excludes these handles so SSR composition is not
298
310
  // overwritten by a second draw.
299
311
  const lightingPass = addTypedScenePass(graph, {
312
+ environment: atmosphere.value,
300
313
  name: 'lighting',
301
314
  color: scene.value,
302
315
  colorTargets: [
@@ -333,12 +346,18 @@ function buildStandardDeferredLane(
333
346
  // blur. Insert it before the spatial chain so the graph dependency order is
334
347
  // explicit and one producer serves every temporal consumer.
335
348
  const temporal =
336
- temporalDemand.targetCount === 1 ? createStandardSceneDataTarget(graph) : ok(undefined);
349
+ temporalDemand.targetCount === 1
350
+ ? createStandardSceneDataTarget(graph, topology.extent)
351
+ : ok(undefined);
337
352
  if (!temporal.ok) return temporal;
338
353
  if (temporal.value !== undefined) {
339
354
  const producer = addStandardSceneDataPass(graph, temporal.value.temporal, depth.value);
340
355
  if (!producer.ok) return producer;
341
356
  }
357
+ if (context.targetCoverage !== undefined) {
358
+ const coverage = addTargetCoveragePass(graph, context.targetCoverage);
359
+ if (!coverage.ok) return coverage;
360
+ }
342
361
 
343
362
  const sceneOutput: RenderPipelineTarget = scene.value;
344
363
  let secondaryReactivity: GraphTextureView | undefined;
@@ -409,6 +428,7 @@ function buildStandardDeferredLane(
409
428
  buffers.value === null ? [] : [...standardClusterReadAccesses(buffers.value)];
410
429
 
411
430
  const forward = addTypedScenePass(graph, {
431
+ environment: atmosphere.value,
412
432
  name: 'forward',
413
433
  color: sceneOutput,
414
434
  depth: depth.value,
@@ -449,6 +469,7 @@ function buildStandardDeferredLane(
449
469
  if (!transmission.ok) return transmission;
450
470
  if (transmission.value.topology.active) {
451
471
  const transmissionPass = addTypedScenePass(graph, {
472
+ environment: atmosphere.value,
452
473
  name: 'transmission-forward',
453
474
  color: sceneOutput,
454
475
  depth: depth.value,
@@ -478,6 +499,7 @@ function buildStandardDeferredLane(
478
499
  if (!transmissionPass.ok) return transmissionPass;
479
500
 
480
501
  const transparentPass = addTypedScenePass(graph, {
502
+ environment: atmosphere.value,
481
503
  name: 'transparent',
482
504
  color: sceneOutput,
483
505
  depth: depth.value,
@@ -570,9 +592,11 @@ function buildStandardDeferredLane(
570
592
  surface.value,
571
593
  temporal.value?.temporal,
572
594
  secondaryReactivity,
595
+ context.targetCoverage?.coverage,
596
+ context.targetCoverage?.depth,
573
597
  );
574
598
  if (!post.ok) return post;
575
- const cubeCaptures = context.contributeCubeCaptures?.();
599
+ const cubeCaptures = context.contributeCubeCaptures?.(atmosphere.value);
576
600
  if (cubeCaptures !== undefined && !cubeCaptures.ok) return cubeCaptures;
577
601
  return ok(undefined);
578
602
  }
@@ -634,7 +658,11 @@ function standardTopology(
634
658
  ): RenderPipelineTopology {
635
659
  const config = {
636
660
  ...(topology.config ?? {}),
637
- ssao: { enabled: profile.ssao },
661
+ ssao: {
662
+ ...(topology.config?.ssao ?? {}),
663
+ ...(typeof profile.ssao === 'object' ? profile.ssao : {}),
664
+ enabled: profile.ssao !== false,
665
+ },
638
666
  };
639
667
  return {
640
668
  ...topology,
@@ -653,6 +681,7 @@ function buildStandard(
653
681
  context: RenderPipelineBuildContext<RenderPipelineFrame>,
654
682
  topology: RenderPipelineTopology,
655
683
  ): ReturnType<RenderPipeline['build']> {
684
+ const standardContext = context as StandardPipelineBuildContext;
656
685
  const profile = profileFor(topology);
657
686
  if (!STANDARD_LIGHT_COUNTS.some((count) => count === profile.lightCount)) {
658
687
  return err(
@@ -675,11 +704,11 @@ function buildStandard(
675
704
  // A missing Camera is an intentional clear-only frame. Keep it on the
676
705
  // forward raster lane so clustered resources cannot introduce work.
677
706
  if (effective.clearOnly === true) {
678
- return buildStandardForwardLane(context, effective, lighting.value);
707
+ return buildStandardForwardLane(standardContext, effective, lighting.value);
679
708
  }
680
709
  return profile.renderPath === 'forward'
681
- ? buildStandardForwardLane(context, effective, lighting.value)
682
- : buildStandardDeferredLane(context, effective, lighting.value);
710
+ ? buildStandardForwardLane(standardContext, effective, lighting.value)
711
+ : buildStandardDeferredLane(standardContext, effective, lighting.value);
683
712
  }
684
713
 
685
714
  export const standardPipeline: StandardPipeline = Object.freeze({
@@ -170,6 +170,8 @@ export function addStandardPost(
170
170
  surface: StandardPostSurface,
171
171
  sceneTemporal?: RenderPipelineTarget,
172
172
  secondaryReactivity?: GraphTextureView,
173
+ coverage?: RenderPipelineTarget,
174
+ coverageDepth?: RenderPipelineTarget,
173
175
  ): Result<void, RenderPipelineBuildError> {
174
176
  const clearOnly = topology.clearOnly === true;
175
177
  const outputPlan = createStandardOutputPlan({
@@ -240,6 +242,8 @@ export function addStandardPost(
240
242
  scene,
241
243
  depth,
242
244
  currentTemporal: sceneTemporal,
245
+ ...(coverage === undefined ? {} : { coverage }),
246
+ ...(coverageDepth === undefined ? {} : { coverageDepth }),
243
247
  ...(secondaryReactivity === undefined ? {} : { secondaryReactivity }),
244
248
  historyColor: history.previousColor,
245
249
  historyTemporal: history.previousTemporal,
@@ -1,3 +1,4 @@
1
+ import type { SsaoParameterConfig } from '../ssao-config';
1
2
  export const STANDARD_PIPELINE_ID = 'forgeax::standard' as const;
2
3
  export const STANDARD_LIGHT_COUNTS = [1, 32, 256] as const;
3
4
  export {
@@ -34,7 +35,7 @@ export interface StandardProfile {
34
35
  readonly shadows: StandardShadowMode;
35
36
  readonly pbr: boolean;
36
37
  readonly ibl: boolean;
37
- readonly ssao: boolean;
38
+ readonly ssao: boolean | SsaoParameterConfig;
38
39
  /** Renderer-owned 1080p volume profile; tile width/height remain surface-derived. */
39
40
  readonly volumetricFog?: StandardVolumetricFogProfile | undefined;
40
41
  readonly postStages: typeof STANDARD_POST_STAGE_NAMES;
@@ -161,6 +161,8 @@ export interface PipelineBuilderContext {
161
161
  readonly storageBuffer: boolean;
162
162
  readonly rgba16floatRenderable: boolean;
163
163
  };
164
+ /** The output-domain binary coverage variant uses an r8unorm attachment. */
165
+ readonly coverageOnly?: boolean | undefined;
164
166
  }
165
167
 
166
168
  /**
@@ -175,7 +177,10 @@ export interface PipelineBuilderContext {
175
177
  */
176
178
  export function validateTemporalPipelineContract(
177
179
  source: string,
178
- ctx: Pick<PipelineBuilderContext, 'colorFormat' | 'depthFormat' | 'capabilities'>,
180
+ ctx: Pick<
181
+ PipelineBuilderContext,
182
+ 'colorFormat' | 'depthFormat' | 'capabilities' | 'coverageOnly'
183
+ >,
179
184
  ): Result<void, RhiError> {
180
185
  if (!source.includes('fn vs_temporal') || !source.includes('fn fs_temporal')) {
181
186
  return err(
@@ -186,12 +191,16 @@ export function validateTemporalPipelineContract(
186
191
  }),
187
192
  );
188
193
  }
189
- if (ctx.colorFormat !== 'rgba16float') {
194
+ const validCoverageTarget = ctx.coverageOnly === true && ctx.colorFormat === 'r8unorm';
195
+ if (ctx.colorFormat !== 'rgba16float' && !validCoverageTarget) {
190
196
  return err(
191
197
  new RhiError({
192
198
  code: 'shader-compile-failed',
193
199
  expected: 'temporal material target format is rgba16float',
194
- hint: `temporal producer received color format ${ctx.colorFormat}; use its physical rgba16float target`,
200
+ hint:
201
+ ctx.coverageOnly === true
202
+ ? `coverage temporal producer received unsupported color format ${ctx.colorFormat}; use r8unorm`
203
+ : `temporal producer received color format ${ctx.colorFormat}; use its physical rgba16float target`,
195
204
  }),
196
205
  );
197
206
  }
package/src/plugin.ts CHANGED
@@ -3,12 +3,14 @@ import type { Plugin } from '@forgeax/engine-plugin';
3
3
  import { Atmosphere } from './components/atmosphere';
4
4
  import { Camera } from './components/camera';
5
5
  import { DirectionalLight } from './components/directional-light';
6
+ import { DynamicResolution } from './components/dynamic-resolution';
6
7
  import { Instances } from './components/instances';
7
8
  import { Layer } from './components/layer';
8
9
  import { LightProbe } from './components/light-probe';
9
10
  import { Lines } from './components/lines';
10
11
  import { MeshFilter } from './components/mesh-filter';
11
12
  import { MeshRenderer } from './components/mesh-renderer';
13
+ import { MotionBlur } from './components/motion-blur';
12
14
  import { PointLight } from './components/point-light';
13
15
  import { PointLightShadow } from './components/point-light-shadow';
14
16
  import { Points } from './components/points';
@@ -30,11 +32,13 @@ const RENDER_COMPONENTS: readonly Component[] = [
30
32
  Atmosphere,
31
33
  Camera,
32
34
  DirectionalLight,
35
+ DynamicResolution,
33
36
  Instances,
34
37
  Layer,
35
38
  LightProbe,
36
39
  MeshFilter,
37
40
  MeshRenderer,
41
+ MotionBlur,
38
42
  PointLight,
39
43
  PointLightShadow,
40
44
  Points,
@@ -3,7 +3,7 @@
3
3
  // feat-20260609-learn-render-4-5-framebuffers-demo-offscreen-rt-an M1 / T-2
4
4
  // added 'fullscreen-input-not-found').
5
5
  //
6
- // Closed 7-member PostProcessErrorCode union + PostProcessError discriminated-union class.
6
+ // Closed PostProcessErrorCode union + PostProcessError discriminated-union class.
7
7
  // - 'post-process-already-registered' (programmer error) -> fullscreen effect registration THROWS a
8
8
  // PostProcessError, mirroring ShaderCatalog.installMaterialArtifact's Map.has -> throw
9
9
  // fail-fast (research Finding M2-4). A second register under the same id is a coding
@@ -38,7 +38,7 @@
38
38
  /**
39
39
  * Closed union of fullscreen post-process error codes.
40
40
  *
41
- * Exactly 7 members; AI users perform exhaustive `switch (err.code)` without a default
41
+ * AI users perform exhaustive `switch (err.code)` without a default
42
42
  * and TS guards completeness (AC-08).
43
43
  *
44
44
  * | code | channel | trigger |
@@ -134,21 +134,23 @@ export interface PostProcessParamsUpdateSizeMismatchDetail {
134
134
  * `detail` parameter to the variant payload at compile time.
135
135
  */
136
136
  export type PostProcessErrorDetailFor<C extends PostProcessErrorCode> =
137
- C extends 'post-process-already-registered'
138
- ? PostProcessPreviouslyRegisteredDetail
139
- : C extends 'post-process-not-found'
140
- ? PostProcessNotFoundDetail
141
- : C extends 'fullscreen-input-not-found'
142
- ? FullscreenInputNotFoundDetail
143
- : C extends 'ssao-radius-non-positive'
144
- ? SsaoRadiusNonPositiveDetail
145
- : C extends 'ssao-bias-negative'
146
- ? SsaoBiasNegativeDetail
147
- : C extends 'params-size-mismatch'
148
- ? PostProcessParamsSizeMismatchDetail
149
- : C extends 'params-update-size-mismatch'
150
- ? PostProcessParamsUpdateSizeMismatchDetail
151
- : never;
137
+ C extends 'ssao-parameter-invalid'
138
+ ? { readonly paramName: string; readonly value: unknown }
139
+ : C extends 'post-process-already-registered'
140
+ ? PostProcessPreviouslyRegisteredDetail
141
+ : C extends 'post-process-not-found'
142
+ ? PostProcessNotFoundDetail
143
+ : C extends 'fullscreen-input-not-found'
144
+ ? FullscreenInputNotFoundDetail
145
+ : C extends 'ssao-radius-non-positive'
146
+ ? SsaoRadiusNonPositiveDetail
147
+ : C extends 'ssao-bias-negative'
148
+ ? SsaoBiasNegativeDetail
149
+ : C extends 'params-size-mismatch'
150
+ ? PostProcessParamsSizeMismatchDetail
151
+ : C extends 'params-update-size-mismatch'
152
+ ? PostProcessParamsUpdateSizeMismatchDetail
153
+ : never;
152
154
 
153
155
  /**
154
156
  * Tagged union of `.detail` payloads. The variants are unique by structural fields
@@ -170,7 +172,8 @@ const POST_PROCESS_POLICY = {
170
172
  expected: 'typed fullscreen plan references a registered post-process id',
171
173
  hint: (detail) =>
172
174
  `no post-process is registered for id '${(detail as PostProcessNotFoundDetail).id}'. ` +
173
- `Register '${(detail as PostProcessNotFoundDetail).id}' with the feature host ({source, reads?}), ` +
175
+ 'For Engine-owned effects, rebuild the shader manifest with that Engine entry enabled. ' +
176
+ `For custom effects, register '${(detail as PostProcessNotFoundDetail).id}' with the feature host ({source, reads?}), ` +
174
177
  'then reference it from a typed fullscreen RenderFeaturePlan.',
175
178
  },
176
179
  'fullscreen-input-not-found': {
@@ -187,6 +190,11 @@ const POST_PROCESS_POLICY = {
187
190
  );
188
191
  },
189
192
  },
193
+ 'ssao-parameter-invalid': {
194
+ expected: 'finite non-negative SSAO intensity and low, medium, or high quality',
195
+ hint: () =>
196
+ 'Set ssao.intensity to a finite non-negative value and ssao.quality to low, medium, or high.',
197
+ },
190
198
  'ssao-radius-non-positive': {
191
199
  expected: 'SSAO radius must be > 0',
192
200
  hint: (detail) => {