@forgeax/engine-render 0.1.31 → 0.1.33

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 (293) hide show
  1. package/README.md +447 -34
  2. package/dist/assembly/analytic-fog-registration.d.ts +3 -0
  3. package/dist/assembly/analytic-fog-registration.d.ts.map +1 -0
  4. package/dist/assembly/fxaa-registration.d.ts +4 -0
  5. package/dist/assembly/fxaa-registration.d.ts.map +1 -0
  6. package/dist/assembly/lod-observation.d.ts +4 -0
  7. package/dist/assembly/lod-observation.d.ts.map +1 -0
  8. package/dist/assembly/motion-blur-registration.d.ts +3 -0
  9. package/dist/assembly/motion-blur-registration.d.ts.map +1 -0
  10. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  11. package/dist/assembly/temporal-post-process-prewarm.d.ts +13 -0
  12. package/dist/assembly/temporal-post-process-prewarm.d.ts.map +1 -0
  13. package/dist/assembly/webgpu-ready-contract.d.ts +4 -3
  14. package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -1
  15. package/dist/assembly/webgpu-ready.d.ts +3 -2
  16. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  17. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  18. package/dist/bloom-admission.d.ts +13 -0
  19. package/dist/bloom-admission.d.ts.map +1 -0
  20. package/dist/{chunk-FUUO4UND.mjs → chunk-3RTCJTH4.mjs} +12 -9
  21. package/dist/chunk-3RTCJTH4.mjs.map +1 -0
  22. package/dist/{chunk-NO4WZCAH.mjs → chunk-LEAXOMYJ.mjs} +3 -3
  23. package/dist/{chunk-NO4WZCAH.mjs.map → chunk-LEAXOMYJ.mjs.map} +1 -1
  24. package/dist/{chunk-JRBDO2KB.mjs → chunk-NB2S7ZRX.mjs} +166 -10
  25. package/dist/chunk-NB2S7ZRX.mjs.map +1 -0
  26. package/dist/{chunk-7MQ3XBSP.mjs → chunk-NNQL7CB3.mjs} +4 -4
  27. package/dist/{chunk-7MQ3XBSP.mjs.map → chunk-NNQL7CB3.mjs.map} +1 -1
  28. package/dist/{chunk-C3DDSXYK.mjs → chunk-OO3DRYK7.mjs} +171 -230
  29. package/dist/chunk-OO3DRYK7.mjs.map +1 -0
  30. package/dist/{chunk-S5UE2T5P.mjs → chunk-PLAXOOX5.mjs} +608 -7
  31. package/dist/chunk-PLAXOOX5.mjs.map +1 -0
  32. package/dist/{chunk-PSEQ6QPH.mjs → chunk-VOZWDM3L.mjs} +295 -198
  33. package/dist/chunk-VOZWDM3L.mjs.map +1 -0
  34. package/dist/{chunk-MDQJPY3T.mjs → chunk-ZDQWGQW7.mjs} +10 -4
  35. package/dist/chunk-ZDQWGQW7.mjs.map +1 -0
  36. package/dist/components/atmosphere.d.ts +2 -0
  37. package/dist/components/atmosphere.d.ts.map +1 -1
  38. package/dist/components/camera.d.ts +20 -4
  39. package/dist/components/camera.d.ts.map +1 -1
  40. package/dist/components/depth-of-field.d.ts +28 -0
  41. package/dist/components/depth-of-field.d.ts.map +1 -0
  42. package/dist/components/directional-light.d.ts +2 -1
  43. package/dist/components/directional-light.d.ts.map +1 -1
  44. package/dist/components/index.d.ts +1 -0
  45. package/dist/components/index.d.ts.map +1 -1
  46. package/dist/components/mesh-filter.d.ts +6 -5
  47. package/dist/components/mesh-filter.d.ts.map +1 -1
  48. package/dist/components/motion-blur.d.ts +1 -0
  49. package/dist/components/motion-blur.d.ts.map +1 -1
  50. package/dist/construct-renderer.mjs +3746 -837
  51. package/dist/construct-renderer.mjs.map +1 -1
  52. package/dist/device/gpu-residency.d.ts +6 -0
  53. package/dist/device/gpu-residency.d.ts.map +1 -1
  54. package/dist/environment/analytic-fog.d.ts +6 -0
  55. package/dist/environment/analytic-fog.d.ts.map +1 -0
  56. package/dist/errors/render.d.ts +6 -2
  57. package/dist/errors/render.d.ts.map +1 -1
  58. package/dist/extract/camera.d.ts.map +1 -1
  59. package/dist/extract/contracts.d.ts +7 -0
  60. package/dist/extract/contracts.d.ts.map +1 -1
  61. package/dist/extract/environment.d.ts +2 -0
  62. package/dist/extract/environment.d.ts.map +1 -1
  63. package/dist/features/depth-of-field/depth-of-field-assembly.d.ts +19 -0
  64. package/dist/features/depth-of-field/depth-of-field-assembly.d.ts.map +1 -0
  65. package/dist/features/depth-of-field/depth-of-field-feature.d.ts +43 -0
  66. package/dist/features/depth-of-field/depth-of-field-feature.d.ts.map +1 -0
  67. package/dist/features/depth-of-field/depth-of-field-inspection.d.ts +34 -0
  68. package/dist/features/depth-of-field/depth-of-field-inspection.d.ts.map +1 -0
  69. package/dist/features/depth-of-field/depth-of-field-params.d.ts +83 -0
  70. package/dist/features/depth-of-field/depth-of-field-params.d.ts.map +1 -0
  71. package/dist/features/error-reporting.d.ts +13 -0
  72. package/dist/features/error-reporting.d.ts.map +1 -0
  73. package/dist/features/host.d.ts +5 -0
  74. package/dist/features/host.d.ts.map +1 -1
  75. package/dist/features/motion-blur/motion-blur-feature.d.ts +20 -2
  76. package/dist/features/motion-blur/motion-blur-feature.d.ts.map +1 -1
  77. package/dist/features/motion-blur/motion-blur-params.d.ts +21 -0
  78. package/dist/features/motion-blur/motion-blur-params.d.ts.map +1 -1
  79. package/dist/features/motion-blur/motion-blur-runtime.d.ts +54 -0
  80. package/dist/features/motion-blur/motion-blur-runtime.d.ts.map +1 -0
  81. package/dist/features/plan.d.ts +7 -4
  82. package/dist/features/plan.d.ts.map +1 -1
  83. package/dist/features/prepared-gpu-work.d.ts +9 -5
  84. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  85. package/dist/features/render-graph-compute.d.ts.map +1 -1
  86. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  87. package/dist/features/types.d.ts +19 -1
  88. package/dist/features/types.d.ts.map +1 -1
  89. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  90. package/dist/gpu-driven/prepared-draw.d.ts +7 -0
  91. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  92. package/dist/gpu-driven/production-raster.d.ts +3 -1
  93. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  94. package/dist/gpu-driven/view-gpu.d.ts +9 -0
  95. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  96. package/dist/gpu-scene.d.ts +6 -1
  97. package/dist/gpu-scene.d.ts.map +1 -1
  98. package/dist/index.d.ts +8 -3
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.mjs +6 -5
  101. package/dist/index.mjs.map +1 -1
  102. package/dist/inspection-types.d.ts +78 -2
  103. package/dist/inspection-types.d.ts.map +1 -1
  104. package/dist/instances.d.ts +15 -1
  105. package/dist/instances.d.ts.map +1 -1
  106. package/dist/internal.mjs +6 -6
  107. package/dist/mesh-material-bindings.d.ts +3 -0
  108. package/dist/mesh-material-bindings.d.ts.map +1 -1
  109. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  110. package/dist/pipeline/standard-output/types.d.ts +4 -2
  111. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  112. package/dist/pipeline/standard-post.d.ts +28 -19
  113. package/dist/pipeline/standard-post.d.ts.map +1 -1
  114. package/dist/pipeline-spec.d.ts +2 -2
  115. package/dist/plugin.d.ts.map +1 -1
  116. package/dist/record/frame-snapshot.d.ts +24 -1
  117. package/dist/record/frame-snapshot.d.ts.map +1 -1
  118. package/dist/record/frame-targets.d.ts.map +1 -1
  119. package/dist/record/frame.d.ts +5 -2
  120. package/dist/record/frame.d.ts.map +1 -1
  121. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  122. package/dist/record/main-pass.d.ts.map +1 -1
  123. package/dist/record/mesh-ssbo.d.ts +6 -5
  124. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  125. package/dist/record/render-context.d.ts +12 -28
  126. package/dist/record/render-context.d.ts.map +1 -1
  127. package/dist/record/shadow-pass.d.ts.map +1 -1
  128. package/dist/record/skybox-post-pass.d.ts +5 -3
  129. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  130. package/dist/record/typed-frame-graph.d.ts +8 -1
  131. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  132. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  133. package/dist/render-contract.d.ts +32 -5
  134. package/dist/render-contract.d.ts.map +1 -1
  135. package/dist/render-graph-primitives.d.ts +2 -0
  136. package/dist/render-graph-primitives.d.ts.map +1 -1
  137. package/dist/render-pipeline.d.ts +15 -1
  138. package/dist/render-pipeline.d.ts.map +1 -1
  139. package/dist/render-system-extract-tail.d.ts.map +1 -1
  140. package/dist/render-system-extract.d.ts +26 -5
  141. package/dist/render-system-extract.d.ts.map +1 -1
  142. package/dist/render-system.d.ts +9 -2
  143. package/dist/render-system.d.ts.map +1 -1
  144. package/dist/scene/render-scene.d.ts +2 -0
  145. package/dist/scene/render-scene.d.ts.map +1 -1
  146. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  147. package/dist/temporal/frame.d.ts +7 -0
  148. package/dist/temporal/frame.d.ts.map +1 -1
  149. package/dist/temporal/index.mjs +5 -5
  150. package/dist/temporal/view.d.ts +6 -1
  151. package/dist/temporal/view.d.ts.map +1 -1
  152. package/dist/typed-render-graph-primitives.d.ts +10 -7
  153. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  154. package/dist/volume/component.d.ts +0 -1
  155. package/dist/volume/component.d.ts.map +1 -1
  156. package/dist/volume/passes.d.ts.map +1 -1
  157. package/dist/volume/temporal.d.ts +3 -1
  158. package/dist/volume/temporal.d.ts.map +1 -1
  159. package/package.json +21 -21
  160. package/src/__tests__/analytic-fog-graph.unit.test.ts +199 -0
  161. package/src/__tests__/analytic-fog-optics.unit.test.ts +38 -0
  162. package/src/__tests__/bloom-exact-zero.unit.test.ts +112 -18
  163. package/src/__tests__/bloom-lifecycle.integration.test.ts +17 -4
  164. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +20 -0
  165. package/src/__tests__/environment-fog-lanes.integration.test.ts +14 -0
  166. package/src/__tests__/environment-selection.unit.test.ts +12 -0
  167. package/src/__tests__/factory-contract.integration.test.ts +331 -68
  168. package/src/__tests__/frame-camera-selection.unit.test.ts +39 -1
  169. package/src/__tests__/frame-plan-contract.unit.test.ts +2 -0
  170. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +12 -0
  171. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +2 -1
  172. package/src/__tests__/gpu-driven-production.integration.test.ts +27 -1
  173. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +1 -1
  174. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +1 -1
  175. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +11 -0
  176. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +12 -0
  177. package/src/__tests__/gpu-scene.unit.test.ts +91 -0
  178. package/src/__tests__/instances-store.unit.test.ts +90 -0
  179. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +31 -0
  180. package/src/__tests__/motion-blur-compute.dawn.test.ts +583 -0
  181. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +49 -0
  182. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +86 -0
  183. package/src/__tests__/public-surface.test-d.ts +8 -0
  184. package/src/__tests__/render-error-code-owner.test-d.ts +2 -0
  185. package/src/__tests__/render-feature-error-reporting.unit.test.ts +24 -0
  186. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +23 -0
  187. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +31 -0
  188. package/src/__tests__/renderer-frame-transaction.integration.test.ts +7 -1
  189. package/src/__tests__/shader-manifest-fixture.ts +4 -4
  190. package/src/__tests__/skinned-shadow-caster.test.ts +2 -0
  191. package/src/__tests__/standard-lighting-write.unit.test.ts +2 -1
  192. package/src/__tests__/standard-pipeline.dawn.test.ts +1 -1
  193. package/src/__tests__/standard-pipeline.integration.test.ts +18 -8
  194. package/src/__tests__/temporal-reset-matrix.unit.test.ts +10 -0
  195. package/src/__tests__/temporal-view.unit.test.ts +2 -1
  196. package/src/__tests__/typed-pipeline-topology.unit.test.ts +20 -4
  197. package/src/__tests__/volume-optics-oracle.unit.test.ts +3 -1
  198. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +177 -13
  199. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +447 -61
  200. package/src/__tests__/volumetric-fog-temporal.unit.test.ts +27 -0
  201. package/src/__tests__/volumetric-fog-topology.unit.test.ts +19 -3
  202. package/src/assembly/analytic-fog-registration.ts +14 -0
  203. package/src/assembly/fxaa-registration.ts +17 -0
  204. package/src/assembly/lod-observation.ts +12 -0
  205. package/src/assembly/motion-blur-registration.ts +17 -0
  206. package/src/assembly/renderer-facade.ts +2 -0
  207. package/src/assembly/temporal-post-process-prewarm.ts +40 -0
  208. package/src/assembly/webgpu-ready-contract.ts +8 -3
  209. package/src/assembly/webgpu-ready.ts +186 -250
  210. package/src/assembly/webgpu-renderer.ts +30 -45
  211. package/src/bloom-admission.ts +21 -0
  212. package/src/components/__tests__/motion-blur.unit.test.ts +1 -0
  213. package/src/components/atmosphere.ts +4 -0
  214. package/src/components/camera.ts +66 -10
  215. package/src/components/depth-of-field.ts +45 -0
  216. package/src/components/directional-light.ts +2 -1
  217. package/src/components/index.ts +1 -0
  218. package/src/components/mesh-filter.ts +11 -9
  219. package/src/components/motion-blur.ts +1 -0
  220. package/src/device/gpu-residency.ts +56 -12
  221. package/src/environment/analytic-fog.ts +44 -0
  222. package/src/environment/background.ts +2 -2
  223. package/src/errors/render.ts +14 -1
  224. package/src/extract/camera.ts +42 -9
  225. package/src/extract/contracts.ts +7 -0
  226. package/src/extract/environment.ts +4 -0
  227. package/src/features/depth-of-field/__tests__/depth-of-field-params.unit.test.ts +943 -0
  228. package/src/features/depth-of-field/depth-of-field-assembly.ts +100 -0
  229. package/src/features/depth-of-field/depth-of-field-feature.ts +295 -0
  230. package/src/features/depth-of-field/depth-of-field-inspection.ts +237 -0
  231. package/src/features/depth-of-field/depth-of-field-params.ts +556 -0
  232. package/src/features/error-reporting.ts +78 -0
  233. package/src/features/host.ts +26 -13
  234. package/src/features/motion-blur/__tests__/motion-blur-feature.unit.test.ts +111 -1
  235. package/src/features/motion-blur/__tests__/motion-blur-params.unit.test.ts +58 -3
  236. package/src/features/motion-blur/motion-blur-feature.ts +1519 -15
  237. package/src/features/motion-blur/motion-blur-params.ts +70 -2
  238. package/src/features/motion-blur/motion-blur-runtime.ts +176 -0
  239. package/src/features/plan.ts +25 -8
  240. package/src/features/prepared-gpu-work.ts +86 -35
  241. package/src/features/render-graph-compute.ts +13 -5
  242. package/src/features/render-graph-contribution.ts +2 -0
  243. package/src/features/types.ts +18 -1
  244. package/src/gpu-driven/material-artifacts.ts +2 -7
  245. package/src/gpu-driven/prepared-draw.ts +15 -10
  246. package/src/gpu-driven/production-raster.ts +83 -7
  247. package/src/gpu-driven/view-gpu.ts +17 -0
  248. package/src/gpu-scene.ts +188 -21
  249. package/src/index.ts +64 -0
  250. package/src/inspection-types.ts +98 -2
  251. package/src/instances.ts +93 -0
  252. package/src/mesh-material-bindings.ts +4 -0
  253. package/src/pipeline/standard-output/graph.ts +3 -0
  254. package/src/pipeline/standard-output/types.ts +4 -1
  255. package/src/pipeline/standard-post.ts +324 -76
  256. package/src/pipeline-spec.ts +5 -5
  257. package/src/plugin.ts +2 -0
  258. package/src/points-lines/__tests__/view-ubo.unit.test.ts +2 -1
  259. package/src/record/__tests__/temporal-payload.unit.test.ts +2 -1
  260. package/src/record/frame-snapshot.ts +31 -2
  261. package/src/record/frame-targets.ts +10 -6
  262. package/src/record/frame.ts +202 -28
  263. package/src/record/main-pass-geometry.ts +30 -1
  264. package/src/record/main-pass-sprite-draws.ts +6 -1
  265. package/src/record/main-pass.ts +1 -5
  266. package/src/record/mesh-ssbo.ts +43 -6
  267. package/src/record/render-context.ts +12 -28
  268. package/src/record/shadow-pass.ts +6 -1
  269. package/src/record/skybox-post-pass.ts +122 -196
  270. package/src/record/typed-frame-graph.ts +259 -15
  271. package/src/recovery/render-system-candidate.ts +28 -10
  272. package/src/render-contract.ts +34 -4
  273. package/src/render-graph-primitives.ts +8 -1
  274. package/src/render-pipeline.ts +22 -1
  275. package/src/render-system-extract-tail.ts +103 -13
  276. package/src/render-system-extract.ts +148 -38
  277. package/src/render-system.ts +332 -119
  278. package/src/scene/render-scene.ts +85 -4
  279. package/src/temporal/__tests__/temporal-frame-transaction.unit.test.ts +36 -0
  280. package/src/temporal/frame-coordinator.ts +8 -1
  281. package/src/temporal/frame.ts +20 -0
  282. package/src/temporal/view.ts +13 -2
  283. package/src/typed-render-graph-primitives.ts +124 -48
  284. package/src/volume/component.ts +0 -1
  285. package/src/volume/passes.ts +8 -4
  286. package/src/volume/resources.ts +1 -1
  287. package/src/volume/temporal.ts +11 -0
  288. package/dist/chunk-C3DDSXYK.mjs.map +0 -1
  289. package/dist/chunk-FUUO4UND.mjs.map +0 -1
  290. package/dist/chunk-JRBDO2KB.mjs.map +0 -1
  291. package/dist/chunk-MDQJPY3T.mjs.map +0 -1
  292. package/dist/chunk-PSEQ6QPH.mjs.map +0 -1
  293. package/dist/chunk-S5UE2T5P.mjs.map +0 -1
@@ -0,0 +1,44 @@
1
+ import { mat4 } from '@forgeax/engine-math';
2
+ import type { FogFrame } from '../extract/environment';
3
+ import { computeProjectionMatrix, computeViewMatrix } from '../record/helpers';
4
+ import type { CameraSnapshot } from '../render-contract';
5
+
6
+ /** Numerical reference for the shader's closed-form height-density integral. */
7
+ export function analyticFogOpacity(
8
+ fog: Pick<FogFrame, 'density' | 'heightFalloff' | 'maxOpacity'>,
9
+ originY: number,
10
+ endY: number,
11
+ distance: number,
12
+ ): number {
13
+ const rho = fog.density * Math.exp(Math.max(-60, Math.min(60, -fog.heightFalloff * originY)));
14
+ const t = Math.max(-60, Math.min(60, fog.heightFalloff * (endY - originY)));
15
+ const integral = Math.abs(t) < 0.001 ? 1 - t / 2 + (t * t) / 6 : -Math.expm1(-t) / t;
16
+ return fog.maxOpacity * -Math.expm1(-Math.min(80, Math.max(0, rho * distance * integral)));
17
+ }
18
+
19
+ export function encodeAnalyticFogParams(fog: FogFrame, camera: CameraSnapshot): Uint8Array {
20
+ const projection = computeProjectionMatrix(camera);
21
+ // Match the scene depth's jittered projection before temporal resolve.
22
+ const jitter = camera.temporal?.currentJitterUv;
23
+ if (jitter !== undefined) {
24
+ for (let column = 0; column < 4; column++) {
25
+ projection[column * 4] =
26
+ (projection[column * 4] ?? 0) + jitter[0] * 2 * (projection[column * 4 + 3] ?? 0);
27
+ projection[column * 4 + 1] =
28
+ (projection[column * 4 + 1] ?? 0) - jitter[1] * 2 * (projection[column * 4 + 3] ?? 0);
29
+ }
30
+ }
31
+ const inverse = mat4.invert(
32
+ mat4.create(),
33
+ mat4.multiply(mat4.create(), projection, computeViewMatrix(camera)),
34
+ );
35
+ const data = new Float32Array(28);
36
+ data.set(inverse, 0);
37
+ data.set(camera.position, 16);
38
+ data.set([...fog.color, fog.density], 20);
39
+ data.set(
40
+ [fog.heightFalloff, fog.maxOpacity, camera.near, camera.projection === 'orthographic' ? 1 : 0],
41
+ 24,
42
+ );
43
+ return new Uint8Array(data.buffer);
44
+ }
@@ -88,8 +88,8 @@ export function addAtmosphereBackground(
88
88
  settings.mieDirectionalG,
89
89
  settings.sunAngularRadius,
90
90
  settings.sunAngularRadius > 0 ? 1 : 0,
91
- 0,
92
- 0,
91
+ settings.circumsolarStrength,
92
+ settings.circumsolarWidth,
93
93
  ]);
94
94
  frame.runtime.device.queue
95
95
  .writeBuffer(resources.buffer(params.value).unwrap(), 0, values)
@@ -19,6 +19,8 @@ import type {
19
19
  SurfaceFailureKind,
20
20
  } from '@forgeax/engine-render-graph';
21
21
  import type { DeviceResourceKind, DeviceScopeReceipt } from '../device/resource-types';
22
+ import type { SunCardinalityError } from '../environment/frame';
23
+ import type { MotionBlurValidationError } from '../features/motion-blur/motion-blur-params';
22
24
  import type {
23
25
  PreparedKind,
24
26
  RenderFeatureCapabilityKey,
@@ -783,6 +785,8 @@ export interface RenderFeatureStageFailedDetail {
783
785
  readonly stage: RenderFeatureStage;
784
786
  readonly recovery: RenderFeatureRecovery;
785
787
  readonly cleanupFailures?: readonly RenderFeatureCleanupFailure[];
788
+ /** Original stage exception when the feature did not return a RenderError. */
789
+ readonly cause?: unknown;
786
790
  }
787
791
 
788
792
  export interface RenderFeatureCapabilityMissingDetail {
@@ -947,6 +951,7 @@ export class RenderFeatureStageFailedError extends Error {
947
951
  order: number,
948
952
  stage: RenderFeatureStage,
949
953
  recovery: RenderFeatureRecovery,
954
+ cause?: unknown,
950
955
  ) {
951
956
  const expected = `feature '${featureIdentity}' completes its ${stage} stage without an error`;
952
957
  const hint = renderFeatureRecoveryHintByRecovery[recovery](featureIdentity, stage);
@@ -954,7 +959,13 @@ export class RenderFeatureStageFailedError extends Error {
954
959
  this.name = 'RenderFeatureStageFailedError';
955
960
  this.expected = expected;
956
961
  this.hint = hint;
957
- this.detail = { featureIdentity, order, stage, recovery };
962
+ this.detail = {
963
+ featureIdentity,
964
+ order,
965
+ stage,
966
+ recovery,
967
+ ...(cause === undefined ? {} : { cause }),
968
+ };
958
969
  }
959
970
  }
960
971
 
@@ -1966,12 +1977,14 @@ export type RenderError =
1966
1977
  | RenderFeatureDrawRecordingFailedError
1967
1978
  | EnvironmentSourceConflictError
1968
1979
  | FogCardinalityError
1980
+ | SunCardinalityError
1969
1981
  | TaaCapsInsufficientError
1970
1982
  | EnvironmentGenerationFailedError
1971
1983
  | AtmosphereInvalidParameterError
1972
1984
  | DynamicResolutionInvalidParameterError
1973
1985
  | DynamicResolutionRequiresTaaError
1974
1986
  | DynamicResolutionTimingUnavailableError
1987
+ | MotionBlurValidationError
1975
1988
  | OwnerStageFailedError
1976
1989
  | PointsLinesInvalidStyleError
1977
1990
  | PointsLinesTopologyMismatchError
@@ -4,19 +4,25 @@ import { mat4, vec3 } from '@forgeax/engine-math';
4
4
  import { GlobalTransform } from '@forgeax/engine-scene';
5
5
  import {
6
6
  antialiasFromF32,
7
- bloomEnabledFromF32,
8
7
  Camera,
9
8
  cameraExposureFromColumns,
10
9
  cameraProjectionFromF32,
11
10
  tonemapFromF32,
11
+ validateCameraBloom,
12
12
  validateCameraColorGrading,
13
13
  } from '../components/camera';
14
+ import { DepthOfField } from '../components/depth-of-field';
14
15
  import {
15
16
  DynamicResolution,
16
17
  validateDynamicResolutionCamera,
17
18
  } from '../components/dynamic-resolution';
18
19
  import { MotionBlur } from '../components/motion-blur';
19
20
  import { ScreenSpaceReflection } from '../components/screen-space-reflection';
21
+ import {
22
+ depthOfFieldRequestFailure,
23
+ resolveDepthOfFieldParams,
24
+ } from '../features/depth-of-field/depth-of-field-params';
25
+ import { resolveMotionBlurParams } from '../features/motion-blur/motion-blur-params';
20
26
  import type { CameraSnapshot } from '../render-contract';
21
27
  import { getActiveCamera, selectActiveCameraIndex } from '../systems/active-camera';
22
28
 
@@ -32,16 +38,37 @@ export function extractCameraSnapshots(world: World): CameraSnapshot[] {
32
38
  const cameraQuery = world
33
39
  .query({
34
40
  read: [Camera],
35
- optional: [MotionBlur, DynamicResolution, ScreenSpaceReflection],
41
+ optional: [MotionBlur, DynamicResolution, ScreenSpaceReflection, DepthOfField],
36
42
  with: [GlobalTransform],
37
43
  })
38
44
  .unwrap();
39
45
  for (const row of cameraQuery) {
40
46
  const cam = row.get(Camera);
41
47
  const motionBlur = row.get(MotionBlur);
48
+ const motionBlurResult = resolveMotionBlurParams(motionBlur);
49
+ if (!motionBlurResult.ok) throw motionBlurResult.error;
50
+ const motionBlurParams = motionBlurResult.value;
51
+ const depthOfField = row.get(DepthOfField);
42
52
  validateCameraColorGrading(cam.temperature, cam.tint, cam.colorLutStrength);
43
53
  const dynamicResolution = row.get(DynamicResolution);
54
+ const projection = cameraProjectionFromF32(cam.projection);
55
+ const depthOfFieldResult = resolveDepthOfFieldParams(depthOfField, {
56
+ projection,
57
+ fov: cam.fov,
58
+ near: cam.near,
59
+ far: cam.far,
60
+ });
61
+ const depthOfFieldError = depthOfFieldResult.ok
62
+ ? undefined
63
+ : depthOfFieldRequestFailure(depthOfFieldResult.error);
44
64
  const screenSpaceReflection = row.get(ScreenSpaceReflection);
65
+ const bloom = validateCameraBloom(
66
+ cam.bloom,
67
+ cam.bloomThreshold,
68
+ cam.bloomIntensity,
69
+ cam.bloomSoftKnee,
70
+ cam.bloomScatter,
71
+ );
45
72
  const entity = row.entity as EntityHandle;
46
73
  const worldMat = readWorldMatrix(world, entity);
47
74
  if (worldMat === undefined) continue;
@@ -57,7 +84,7 @@ export function extractCameraSnapshots(world: World): CameraSnapshot[] {
57
84
  aspect: cam.aspect,
58
85
  near: cam.near,
59
86
  far: cam.far,
60
- projection: cameraProjectionFromF32(cam.projection),
87
+ projection,
61
88
  orthoLeft: cam.left,
62
89
  orthoRight: cam.right,
63
90
  orthoBottom: cam.bottom,
@@ -76,23 +103,29 @@ export function extractCameraSnapshots(world: World): CameraSnapshot[] {
76
103
  ...(dynamicResolutionResult.value === undefined
77
104
  ? {}
78
105
  : { dynamicResolution: dynamicResolutionResult.value }),
79
- bloom: bloomEnabledFromF32(cam.bloom),
106
+ bloom,
80
107
  bloomThreshold: cam.bloomThreshold,
81
108
  bloomIntensity: cam.bloomIntensity,
82
- bloomBlurRadius: cam.bloomBlurRadius,
109
+ bloomSoftKnee: cam.bloomSoftKnee,
110
+ bloomScatter: cam.bloomScatter,
83
111
  clearColor: [
84
112
  cam.clearColor[0] ?? 0,
85
113
  cam.clearColor[1] ?? 0,
86
114
  cam.clearColor[2] ?? 0,
87
115
  cam.clearColor[3] ?? 1,
88
116
  ],
89
- ...(motionBlur === undefined
117
+ ...(depthOfFieldResult.ok && depthOfFieldResult.value !== undefined
118
+ ? { depthOfField: depthOfFieldResult.value }
119
+ : {}),
120
+ ...(depthOfFieldError === undefined ? {} : { depthOfFieldError }),
121
+ ...(motionBlurParams === undefined
90
122
  ? {}
91
123
  : {
92
124
  motionBlur: {
93
- shutterAngle: motionBlur.shutterAngle,
94
- maxRadiusPixels: motionBlur.maxRadiusPixels,
95
- sampleCount: motionBlur.sampleCount,
125
+ shutterAngle: motionBlurParams.shutterAngle,
126
+ maxRadiusPixels: motionBlurParams.maxRadiusPixels,
127
+ sampleCount: motionBlurParams.sampleCount,
128
+ targetFps: motionBlurParams.targetFps,
96
129
  },
97
130
  }),
98
131
  ...(screenSpaceReflection === undefined
@@ -394,6 +394,8 @@ export interface ExtractedVolumetricFog {
394
394
  readonly generation?: number;
395
395
  readonly digest?: string;
396
396
  readonly worldId?: number;
397
+ /** Canonical simulation time projected from the owning World. */
398
+ readonly worldTimeSeconds?: number;
397
399
  readonly lightEntity?: EntityHandle;
398
400
  readonly lightKind?: 'directional' | 'point' | 'spot';
399
401
  readonly pointLightEntity?: EntityHandle;
@@ -530,6 +532,9 @@ export type RenderableReactiveReason =
530
532
  export interface RenderableTemporalSnapshot {
531
533
  readonly previousEpoch: number | undefined;
532
534
  readonly previousSource: RenderablePreviousSource;
535
+ /** True only when current and previous geometry belong to one stable source identity. */
536
+ readonly motionValid: boolean;
537
+ /** Color-history invalidation is independent from motion validity. */
533
538
  readonly reactive: boolean;
534
539
  readonly reactiveReasons: readonly RenderableReactiveReason[];
535
540
  readonly previousTransform: TransformSnapshot;
@@ -563,6 +568,8 @@ export interface GpuDrivenDrawSnapshot {
563
568
  export interface InstancesSnapshot {
564
569
  /** Packed column-major mat4 transforms (16 f32 per instance). */
565
570
  readonly transforms: Float32Array;
571
+ /** Optional unique identity generations; tokens travel with instances through reorder. */
572
+ readonly generations?: Uint32Array;
566
573
  /** Number of instances (transforms.length / 16). */
567
574
  readonly instanceCount: number;
568
575
  /** Stable per-entity GPU buffer cache key (the packed Entity u32). */
@@ -39,6 +39,8 @@ export interface AtmosphereParameters {
39
39
  readonly mieCoefficient: number;
40
40
  readonly mieDirectionalG: number;
41
41
  readonly sunAngularRadius: number;
42
+ readonly circumsolarStrength: number;
43
+ readonly circumsolarWidth: number;
42
44
  }
43
45
 
44
46
  /** Shared CPU contract for values accepted by the atmosphere shaders. */
@@ -50,6 +52,8 @@ export const ATMOSPHERE_PARAMETER_RANGES: Readonly<
50
52
  mieCoefficient: Object.freeze({ min: 0, max: Number.POSITIVE_INFINITY }),
51
53
  mieDirectionalG: Object.freeze({ min: 0, max: 0.999 }),
52
54
  sunAngularRadius: Object.freeze({ min: 0, max: Number.POSITIVE_INFINITY }),
55
+ circumsolarStrength: Object.freeze({ min: 0, max: 4 }),
56
+ circumsolarWidth: Object.freeze({ min: 0.25, max: 4 }),
53
57
  });
54
58
 
55
59
  export interface FogCandidate {