@woosh/meep-engine 3.47.0 → 3.49.0

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 (619) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/editor/particles/effect/ParticleReferenceSimulation.d.ts +1 -2
  3. package/editor/particles/effect/ParticleReferenceSimulation.d.ts.map +1 -1
  4. package/editor/particles/effect/ParticleReferenceSimulation.js +2 -4
  5. package/editor/view/particles/effect/ParticleGraphEditorView.js +1 -1
  6. package/package.json +1 -1
  7. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +27 -11
  8. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  9. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +11 -0
  10. package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts +2 -2
  11. package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts.map +1 -1
  12. package/src/engine/graphics/ecs/particles/ParticleEffect.js +7 -7
  13. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts +8 -0
  14. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts.map +1 -1
  15. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.js +11 -3
  16. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_1_2.d.ts +26 -0
  17. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_1_2.d.ts.map +1 -0
  18. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_1_2.js +91 -0
  19. package/src/engine/graphics3/GPUParticleEmitterSystem.js +2 -2
  20. package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -1
  21. package/src/engine/graphics3/GraphicsEngine.js +8 -1
  22. package/src/engine/graphics3/ParticipatingMedia.d.ts +84 -1
  23. package/src/engine/graphics3/ParticipatingMedia.d.ts.map +1 -1
  24. package/src/engine/graphics3/ParticipatingMedia.js +139 -5
  25. package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.d.ts +6 -2
  26. package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.d.ts.map +1 -1
  27. package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.js +29 -4
  28. package/src/engine/graphics3/ParticipatingMediaSerializationUpgrader_0_1.d.ts +10 -0
  29. package/src/engine/graphics3/ParticipatingMediaSerializationUpgrader_0_1.d.ts.map +1 -0
  30. package/src/engine/graphics3/ParticipatingMediaSerializationUpgrader_0_1.js +38 -0
  31. package/src/engine/graphics3/ParticipatingMediaSystem.d.ts.map +1 -1
  32. package/src/engine/graphics3/ParticipatingMediaSystem.js +46 -3
  33. package/src/engine/network/NetworkSession.d.ts +16 -5
  34. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  35. package/src/engine/network/NetworkSession.js +104 -7
  36. package/src/engine/network/README.md +27 -1
  37. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +40 -18
  38. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
  39. package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +180 -190
  40. package/src/engine/network/replication/Replicator.d.ts +15 -4
  41. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  42. package/src/engine/network/replication/Replicator.js +50 -16
  43. package/src/engine/network/state/RecordArrivalRing.d.ts +57 -0
  44. package/src/engine/network/state/RecordArrivalRing.d.ts.map +1 -0
  45. package/src/engine/network/state/RecordArrivalRing.js +144 -0
  46. package/src/engine/physics/cloth/MEASUREMENTS.md +354 -0
  47. package/src/engine/physics/cloth/PLAN.md +85 -5
  48. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +0 -12
  49. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  50. package/src/engine/physics/cloth/ecs/ClothInstance.js +0 -13
  51. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +2 -1
  52. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  53. package/src/engine/physics/cloth/ecs/ClothSystem.js +7 -1
  54. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  55. package/src/engine/physics/cloth/ecs/ClothWorld.js +4 -15
  56. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +2 -1
  57. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
  58. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +6 -1
  59. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  60. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +20 -10
  61. package/src/engine/physics/cloth/playground/collide.html +5 -3
  62. package/src/engine/physics/cloth/playground/collide_main.js +14 -13
  63. package/src/engine/physics/cloth/solver/ClothState.d.ts +30 -2
  64. package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
  65. package/src/engine/physics/cloth/solver/ClothState.js +62 -4
  66. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +11 -3
  67. package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
  68. package/src/engine/physics/cloth/solver/cloth_self_find.js +52 -11
  69. package/src/engine/physics/cloth/solver/cloth_self_radius.d.ts +42 -0
  70. package/src/engine/physics/cloth/solver/cloth_self_radius.d.ts.map +1 -0
  71. package/src/engine/physics/cloth/solver/cloth_self_radius.js +64 -0
  72. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +99 -24
  73. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  74. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +102 -25
  75. package/src/engine/physics/cloth/solver/cloth_step.d.ts +5 -1
  76. package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
  77. package/src/engine/physics/cloth/solver/cloth_step.js +13 -3
  78. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +0 -1
  79. package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
  80. package/src/engine/physics/cloth/solver/cloth_step_instance.js +12 -14
  81. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts +23 -4
  82. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -1
  83. package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +36 -8
  84. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -1
  85. package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +4 -2
  86. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  87. package/src/shade/device/mock/SoftwareGPUDevice.d.ts +15 -0
  88. package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
  89. package/src/shade/device/mock/SoftwareGPUDevice.js +21 -0
  90. package/src/shade/device/pipeline/ComputePipelineManager.d.ts +20 -0
  91. package/src/shade/device/pipeline/ComputePipelineManager.d.ts.map +1 -1
  92. package/src/shade/device/pipeline/ComputePipelineManager.js +80 -6
  93. package/src/shade/device/pipeline/PipelineEnquiry.d.ts +52 -0
  94. package/src/shade/device/pipeline/PipelineEnquiry.d.ts.map +1 -0
  95. package/src/shade/device/pipeline/PipelineEnquiry.js +63 -0
  96. package/src/shade/device/pipeline/RenderPipelineManager.d.ts +21 -0
  97. package/src/shade/device/pipeline/RenderPipelineManager.d.ts.map +1 -1
  98. package/src/shade/device/pipeline/RenderPipelineManager.js +84 -4
  99. package/src/shade/playground/contact_shadows/ContactShadowLab.d.ts +137 -0
  100. package/src/shade/playground/contact_shadows/ContactShadowLab.d.ts.map +1 -0
  101. package/src/shade/playground/contact_shadows/ContactShadowLab.js +654 -0
  102. package/src/shade/playground/contact_shadows/README.md +126 -0
  103. package/src/shade/playground/contact_shadows/index.html +191 -0
  104. package/src/shade/playground/contact_shadows/main.d.ts +2 -0
  105. package/src/shade/playground/contact_shadows/main.d.ts.map +1 -0
  106. package/src/shade/playground/contact_shadows/main.js +888 -0
  107. package/src/shade/playground/contact_shadows/scenes.d.ts +48 -0
  108. package/src/shade/playground/contact_shadows/scenes.d.ts.map +1 -0
  109. package/src/shade/playground/contact_shadows/scenes.js +620 -0
  110. package/src/shade/playground/contact_shadows/shader_contact_lab_composite.d.ts +36 -0
  111. package/src/shade/playground/contact_shadows/shader_contact_lab_composite.d.ts.map +1 -0
  112. package/src/shade/playground/contact_shadows/shader_contact_lab_composite.js +245 -0
  113. package/src/shade/playground/contact_shadows/shader_contact_lab_reference.d.ts +15 -0
  114. package/src/shade/playground/contact_shadows/shader_contact_lab_reference.d.ts.map +1 -0
  115. package/src/shade/playground/contact_shadows/shader_contact_lab_reference.js +120 -0
  116. package/src/shade/playground/contact_shadows/shader_contact_lab_stats.d.ts +55 -0
  117. package/src/shade/playground/contact_shadows/shader_contact_lab_stats.d.ts.map +1 -0
  118. package/src/shade/playground/contact_shadows/shader_contact_lab_stats.js +216 -0
  119. package/src/shade/playground/contact_shadows/shader_contact_lab_view.d.ts +20 -0
  120. package/src/shade/playground/contact_shadows/shader_contact_lab_view.d.ts.map +1 -0
  121. package/src/shade/playground/contact_shadows/shader_contact_lab_view.js +114 -0
  122. package/src/shade/playground/contact_shadows/shader_contact_shadow_march.d.ts +11 -0
  123. package/src/shade/playground/contact_shadows/shader_contact_shadow_march.d.ts.map +1 -0
  124. package/src/shade/playground/contact_shadows/shader_contact_shadow_march.js +90 -0
  125. package/src/shade/playground/contact_shadows/textures.d.ts +16 -0
  126. package/src/shade/playground/contact_shadows/textures.d.ts.map +1 -0
  127. package/src/shade/playground/contact_shadows/textures.js +123 -0
  128. package/src/shade/playground/particle_ecs/README.md +1 -1
  129. package/src/shade/playground/particle_ecs/effects/flame.json +1932 -1881
  130. package/src/shade/playground/particle_ecs/effects/smoke.json +99 -1
  131. package/src/shade/playground/particle_ecs/effects/soot.json +152 -145
  132. package/src/shade/playground/tonemap_sdr/README.md +90 -0
  133. package/src/shade/playground/tonemap_sdr/ToneMapCompare.d.ts +105 -0
  134. package/src/shade/playground/tonemap_sdr/ToneMapCompare.d.ts.map +1 -0
  135. package/src/shade/playground/tonemap_sdr/ToneMapCompare.js +380 -0
  136. package/src/shade/playground/tonemap_sdr/chunk_tonemap_gt7_sdr_reference.d.ts +32 -0
  137. package/src/shade/playground/tonemap_sdr/chunk_tonemap_gt7_sdr_reference.d.ts.map +1 -0
  138. package/src/shade/playground/tonemap_sdr/chunk_tonemap_gt7_sdr_reference.js +104 -0
  139. package/src/shade/playground/tonemap_sdr/index.html +90 -0
  140. package/src/shade/playground/tonemap_sdr/main.d.ts +2 -0
  141. package/src/shade/playground/tonemap_sdr/main.d.ts.map +1 -0
  142. package/src/shade/playground/tonemap_sdr/main.js +306 -0
  143. package/src/shade/playground/tonemap_sdr/scenes.d.ts +26 -0
  144. package/src/shade/playground/tonemap_sdr/scenes.d.ts.map +1 -0
  145. package/src/shade/playground/tonemap_sdr/scenes.js +404 -0
  146. package/src/shade/playground/volumetrics_froxel/main.d.ts.map +1 -1
  147. package/src/shade/playground/volumetrics_froxel/main.js +85 -4
  148. package/src/shade/playground/water_refraction/README.md +26 -18
  149. package/src/shade/playground/water_refraction/index.html +1 -1
  150. package/src/shade/renderer/Renderer.d.ts +35 -3
  151. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  152. package/src/shade/renderer/Renderer.js +208 -12
  153. package/src/shade/renderer/ShadeToneMappingMode.d.ts +14 -0
  154. package/src/shade/renderer/ShadeToneMappingMode.d.ts.map +1 -0
  155. package/src/shade/renderer/ShadeToneMappingMode.js +30 -0
  156. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +9 -0
  157. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  158. package/src/shade/renderer/animation/GPUAnimationManager.js +14 -0
  159. package/src/shade/renderer/animation/skinning/shader_meshlet_apply_skinning.d.ts.map +1 -1
  160. package/src/shade/renderer/animation/skinning/shader_meshlet_apply_skinning.js +5 -3
  161. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts +7 -0
  162. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  163. package/src/shade/renderer/buffer/table/GPUDatabase.js +12 -0
  164. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts +8 -0
  165. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
  166. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +12 -0
  167. package/src/shade/renderer/camera/GPUCameraContext.d.ts.map +1 -1
  168. package/src/shade/renderer/camera/GPUCameraContext.js +19 -8
  169. package/src/shade/renderer/deferred/chunk_read_gBuffer_material.d.ts.map +1 -1
  170. package/src/shade/renderer/deferred/chunk_read_gBuffer_material.js +4 -0
  171. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.d.ts.map +1 -1
  172. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.js +4 -0
  173. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_restir.d.ts.map +1 -1
  174. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_restir.js +4 -0
  175. package/src/shade/renderer/deferred/shader_deferred_main.d.ts.map +1 -1
  176. package/src/shade/renderer/deferred/shader_deferred_main.js +3 -0
  177. package/src/shade/renderer/deferred/shader_tonemap_HDR.d.ts +6 -0
  178. package/src/shade/renderer/deferred/shader_tonemap_HDR.d.ts.map +1 -1
  179. package/src/shade/renderer/deferred/shader_tonemap_HDR.js +13 -3
  180. package/src/shade/renderer/deferred/shader_tonemap_HDR_none.d.ts +9 -0
  181. package/src/shade/renderer/deferred/shader_tonemap_HDR_none.d.ts.map +1 -0
  182. package/src/shade/renderer/deferred/shader_tonemap_HDR_none.js +63 -0
  183. package/src/shade/renderer/deferred/shader_tonemap_HDR_pbr_neutral.d.ts +10 -0
  184. package/src/shade/renderer/deferred/shader_tonemap_HDR_pbr_neutral.d.ts.map +1 -0
  185. package/src/shade/renderer/deferred/shader_tonemap_HDR_pbr_neutral.js +87 -0
  186. package/src/shade/renderer/deferred/shader_tonemap_LDR.d.ts +6 -0
  187. package/src/shade/renderer/deferred/shader_tonemap_LDR.d.ts.map +1 -1
  188. package/src/shade/renderer/deferred/shader_tonemap_LDR.js +23 -5
  189. package/src/shade/renderer/deferred/shader_tonemap_LDR_none.d.ts +9 -0
  190. package/src/shade/renderer/deferred/shader_tonemap_LDR_none.d.ts.map +1 -0
  191. package/src/shade/renderer/deferred/shader_tonemap_LDR_none.js +68 -0
  192. package/src/shade/renderer/deferred/shader_tonemap_LDR_pbr_neutral.d.ts +10 -0
  193. package/src/shade/renderer/deferred/shader_tonemap_LDR_pbr_neutral.d.ts.map +1 -0
  194. package/src/shade/renderer/deferred/shader_tonemap_LDR_pbr_neutral.js +73 -0
  195. package/src/shade/renderer/geometry/meshlet/MeshletBatch.d.ts.map +1 -1
  196. package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +58 -9
  197. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +35 -25
  198. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  199. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +97 -196
  200. package/src/shade/renderer/geometry/sdf/shader_build_sdf.d.ts.map +1 -1
  201. package/src/shade/renderer/geometry/sdf/shader_build_sdf.js +121 -129
  202. package/src/shade/renderer/global_illumination/brick4/gpu/bake/brick4_bake_basic.d.ts.map +1 -1
  203. package/src/shade/renderer/global_illumination/brick4/gpu/bake/brick4_bake_basic.js +3 -0
  204. package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_probes.d.ts.map +1 -1
  205. package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_probes.js +4 -0
  206. package/src/shade/renderer/global_illumination/brick4/gpu/draw/shader_brick4_indirect_lighting.d.ts.map +1 -1
  207. package/src/shade/renderer/global_illumination/brick4/gpu/draw/shader_brick4_indirect_lighting.js +4 -0
  208. package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.d.ts.map +1 -1
  209. package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.js +3 -0
  210. package/src/shade/renderer/global_illumination/lpv/deprecated/probe_trace_compute_shader_code.d.ts.map +1 -1
  211. package/src/shade/renderer/global_illumination/lpv/deprecated/probe_trace_compute_shader_code.js +4 -0
  212. package/src/shade/renderer/global_illumination/probe/octahedral/graph_sample_light_probes.d.ts.map +1 -1
  213. package/src/shade/renderer/global_illumination/probe/octahedral/graph_sample_light_probes.js +4 -0
  214. package/src/shade/renderer/global_illumination/shader_resolve_indirect_lighting.d.ts.map +1 -1
  215. package/src/shade/renderer/global_illumination/shader_resolve_indirect_lighting.js +4 -0
  216. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +131 -1
  217. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_delta.d.ts +7 -0
  218. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_delta.d.ts.map +1 -1
  219. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_delta.js +45 -38
  220. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_determine_range.d.ts +2 -0
  221. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_determine_range.d.ts.map +1 -1
  222. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_determine_range.js +81 -79
  223. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_find_split.d.ts +2 -0
  224. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_find_split.d.ts.map +1 -1
  225. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_find_split.js +5 -3
  226. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_internal_children.d.ts +21 -0
  227. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_internal_children.d.ts.map +1 -0
  228. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_internal_children.js +42 -0
  229. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_morton_code.d.ts +19 -0
  230. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_morton_code.d.ts.map +1 -0
  231. package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_morton_code.js +44 -0
  232. package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.d.ts +23 -5
  233. package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.d.ts.map +1 -1
  234. package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.js +139 -23
  235. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_build_single_workgroup.d.ts +25 -0
  236. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_build_single_workgroup.d.ts.map +1 -0
  237. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_build_single_workgroup.js +179 -0
  238. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.d.ts +2 -2
  239. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.d.ts.map +1 -1
  240. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.js +7 -16
  241. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.d.ts +3 -4
  242. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.d.ts.map +1 -1
  243. package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.js +6 -23
  244. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts +11 -0
  245. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts.map +1 -1
  246. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.js +14 -3
  247. package/src/shade/renderer/gpu_primitive/indirect/build_indirect_draw_command.d.ts +10 -0
  248. package/src/shade/renderer/gpu_primitive/indirect/build_indirect_draw_command.d.ts.map +1 -1
  249. package/src/shade/renderer/gpu_primitive/indirect/build_indirect_draw_command.js +13 -3
  250. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts +10 -0
  251. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts.map +1 -1
  252. package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js +14 -0
  253. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_comparator.d.ts +26 -0
  254. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_comparator.d.ts.map +1 -0
  255. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_comparator.js +52 -0
  256. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_workgroup.d.ts +32 -0
  257. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_workgroup.d.ts.map +1 -0
  258. package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_workgroup.js +89 -0
  259. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +10 -0
  260. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
  261. package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +20 -1
  262. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +10 -0
  263. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  264. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +294 -281
  265. package/src/shade/renderer/light/GPULightCollection.d.ts +8 -0
  266. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  267. package/src/shade/renderer/light/GPULightCollection.js +18 -1
  268. package/src/shade/renderer/light/cluster/cull/graph_cull_lights.d.ts +8 -0
  269. package/src/shade/renderer/light/cluster/cull/graph_cull_lights.d.ts.map +1 -1
  270. package/src/shade/renderer/light/cluster/cull/graph_cull_lights.js +234 -218
  271. package/src/shade/renderer/light/cluster/graph_assign_clsuters.d.ts +7 -0
  272. package/src/shade/renderer/light/cluster/graph_assign_clsuters.d.ts.map +1 -1
  273. package/src/shade/renderer/light/cluster/graph_assign_clsuters.js +13 -0
  274. package/src/shade/renderer/light/cluster/graph_build_light_clusters.d.ts +7 -0
  275. package/src/shade/renderer/light/cluster/graph_build_light_clusters.d.ts.map +1 -1
  276. package/src/shade/renderer/light/cluster/graph_build_light_clusters.js +16 -2
  277. package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts +10 -0
  278. package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts.map +1 -1
  279. package/src/shade/renderer/light/environment/execute_filter_environment_map.js +13 -0
  280. package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
  281. package/src/shade/renderer/lightmap/GPULightMap.js +3 -0
  282. package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_irradiance_flat.d.ts.map +1 -1
  283. package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_irradiance_flat.js +4 -0
  284. package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_sh.d.ts.map +1 -1
  285. package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_sh.js +4 -0
  286. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  287. package/src/shade/renderer/material/GPUMaterialManager.d.ts +16 -4
  288. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  289. package/src/shade/renderer/material/GPUMaterialManager.js +38 -8
  290. package/src/shade/renderer/particles/DESIGN.md +49 -7
  291. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +453 -0
  292. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts +5 -1
  293. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -1
  294. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +13 -5
  295. package/src/shade/renderer/particles/data/particle_emitter_record.js +2 -2
  296. package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.d.ts.map +1 -1
  297. package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.js +12 -0
  298. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.d.ts +60 -0
  299. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.d.ts.map +1 -1
  300. package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.js +156 -0
  301. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +2 -2
  302. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
  303. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +8 -8
  304. package/src/shade/renderer/particles/shaders/chunk_particle_billboard_vertex.d.ts.map +1 -1
  305. package/src/shade/renderer/particles/shaders/chunk_particle_billboard_vertex.js +6 -4
  306. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts +7 -6
  307. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts.map +1 -1
  308. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.js +91 -58
  309. package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.d.ts.map +1 -1
  310. package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.js +10 -0
  311. package/src/shade/renderer/path_tracer/accumulating/shader_accumulating_path_tracer.d.ts.map +1 -1
  312. package/src/shade/renderer/path_tracer/accumulating/shader_accumulating_path_tracer.js +5 -1
  313. package/src/shade/renderer/path_tracer/graph_path_trace_scene.d.ts.map +1 -1
  314. package/src/shade/renderer/path_tracer/graph_path_trace_scene.js +6 -0
  315. package/src/shade/renderer/postprocess/bloom/graph_postprocess_bloom.d.ts +7 -0
  316. package/src/shade/renderer/postprocess/bloom/graph_postprocess_bloom.d.ts.map +1 -1
  317. package/src/shade/renderer/postprocess/bloom/graph_postprocess_bloom.js +18 -0
  318. package/src/shade/renderer/postprocess/denoise/LigmaDenoiser.d.ts.map +1 -1
  319. package/src/shade/renderer/postprocess/denoise/LigmaDenoiser.js +1 -0
  320. package/src/shade/renderer/postprocess/denoise/shader_temporal_reprojection_luma.d.ts.map +1 -1
  321. package/src/shade/renderer/postprocess/denoise/shader_temporal_reprojection_luma.js +6 -4
  322. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts +11 -0
  323. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts.map +1 -1
  324. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +16 -0
  325. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +10 -0
  326. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
  327. package/src/shade/renderer/postprocess/gtao/GTAO.js +16 -0
  328. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
  329. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +32 -10
  330. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  331. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
  332. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +3 -0
  333. package/src/shade/renderer/postprocess/ssr/resolve/build_ssr_resolve_shader.d.ts.map +1 -1
  334. package/src/shade/renderer/postprocess/ssr/resolve/build_ssr_resolve_shader.js +6 -3
  335. package/src/shade/renderer/postprocess/taa/TAA.d.ts +12 -0
  336. package/src/shade/renderer/postprocess/taa/TAA.d.ts.map +1 -1
  337. package/src/shade/renderer/postprocess/taa/TAA.js +15 -0
  338. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts +7 -0
  339. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts.map +1 -1
  340. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.js +13 -0
  341. package/src/shade/renderer/rasterize/TemplatePassDescriptor.d.ts +31 -3
  342. package/src/shade/renderer/rasterize/TemplatePassDescriptor.d.ts.map +1 -1
  343. package/src/shade/renderer/rasterize/TemplatePassDescriptor.js +79 -4
  344. package/src/shade/renderer/rasterize/bucket/graph_meshlets_rasterize_by_bucket.d.ts +17 -0
  345. package/src/shade/renderer/rasterize/bucket/graph_meshlets_rasterize_by_bucket.d.ts.map +1 -1
  346. package/src/shade/renderer/rasterize/bucket/graph_meshlets_rasterize_by_bucket.js +35 -4
  347. package/src/shade/renderer/rasterize/compute/graph_mesh_frustum_cull.d.ts +7 -0
  348. package/src/shade/renderer/rasterize/compute/graph_mesh_frustum_cull.d.ts.map +1 -1
  349. package/src/shade/renderer/rasterize/compute/graph_mesh_frustum_cull.js +182 -169
  350. package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_meshes_classify_buckets.d.ts +10 -0
  351. package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_meshes_classify_buckets.d.ts.map +1 -1
  352. package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_meshes_classify_buckets.js +20 -1
  353. package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_extract_meshlets_from_bucket.d.ts +10 -0
  354. package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_extract_meshlets_from_bucket.d.ts.map +1 -1
  355. package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_extract_meshlets_from_bucket.js +18 -1
  356. package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.d.ts +10 -0
  357. package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.d.ts.map +1 -1
  358. package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.js +20 -1
  359. package/src/shade/renderer/rasterize/expand/graph_mesh_filter_one_way.d.ts +7 -0
  360. package/src/shade/renderer/rasterize/expand/graph_mesh_filter_one_way.d.ts.map +1 -1
  361. package/src/shade/renderer/rasterize/expand/graph_mesh_filter_one_way.js +187 -170
  362. package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.d.ts +10 -0
  363. package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.d.ts.map +1 -1
  364. package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.js +19 -1
  365. package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.d.ts +13 -0
  366. package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.d.ts.map +1 -1
  367. package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.js +25 -1
  368. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts +10 -0
  369. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
  370. package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +20 -0
  371. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
  372. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.js +6 -0
  373. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
  374. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.js +6 -0
  375. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +3 -2
  376. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  377. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +3 -2
  378. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts +7 -2
  379. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  380. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +12 -4
  381. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.d.ts.map +1 -1
  382. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.js +4 -3
  383. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.d.ts.map +1 -1
  384. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.js +4 -3
  385. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts +2 -1
  386. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
  387. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +11 -3
  388. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts.map +1 -1
  389. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.js +4 -3
  390. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.d.ts.map +1 -1
  391. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.js +4 -3
  392. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts +15 -0
  393. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  394. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +35 -2
  395. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts +14 -0
  396. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  397. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +32 -4
  398. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts +17 -0
  399. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
  400. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +34 -4
  401. package/src/shade/renderer/restir/di/chunk_restir_resolve.d.ts +5 -3
  402. package/src/shade/renderer/restir/di/chunk_restir_resolve.d.ts.map +1 -1
  403. package/src/shade/renderer/restir/di/chunk_restir_resolve.js +8 -3
  404. package/src/shade/renderer/restir/di/graph_restir_di.d.ts.map +1 -1
  405. package/src/shade/renderer/restir/di/graph_restir_di.js +1 -0
  406. package/src/shade/renderer/restir/di/shader_restir_di_resolve.d.ts.map +1 -1
  407. package/src/shade/renderer/restir/di/shader_restir_di_resolve.js +5 -1
  408. package/src/shade/renderer/restir/reservoir/shader.d.ts.map +1 -1
  409. package/src/shade/renderer/restir/reservoir/shader.js +7 -4
  410. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts +7 -0
  411. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts.map +1 -1
  412. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.js +13 -1
  413. package/src/shade/renderer/scene/GPUSceneContext.d.ts +10 -0
  414. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  415. package/src/shade/renderer/scene/GPUSceneContext.js +19 -0
  416. package/src/shade/renderer/scene/SceneManager.d.ts +9 -0
  417. package/src/shade/renderer/scene/SceneManager.d.ts.map +1 -1
  418. package/src/shade/renderer/scene/SceneManager.js +11 -0
  419. package/src/shade/renderer/scene/hierarchy/graph_nodes_update_transform_hierarchy.d.ts +11 -0
  420. package/src/shade/renderer/scene/hierarchy/graph_nodes_update_transform_hierarchy.d.ts.map +1 -1
  421. package/src/shade/renderer/scene/hierarchy/graph_nodes_update_transform_hierarchy.js +17 -0
  422. package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.d.ts +11 -0
  423. package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.d.ts.map +1 -1
  424. package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.js +18 -1
  425. package/src/shade/renderer/shader/ComputeShader.d.ts +12 -0
  426. package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
  427. package/src/shade/renderer/shader/ComputeShader.js +53 -0
  428. package/src/shade/renderer/shader/ImageShader.d.ts +27 -8
  429. package/src/shade/renderer/shader/ImageShader.d.ts.map +1 -1
  430. package/src/shade/renderer/shader/ImageShader.js +70 -1
  431. package/src/shade/renderer/shader/ShaderDescriptor.d.ts +21 -0
  432. package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
  433. package/src/shade/renderer/shader/ShaderDescriptor.js +71 -1
  434. package/src/shade/renderer/shader/chunk/camera/chunk_project_view_position_from_depth.d.ts +17 -0
  435. package/src/shade/renderer/shader/chunk/camera/chunk_project_view_position_from_depth.d.ts.map +1 -0
  436. package/src/shade/renderer/shader/chunk/camera/chunk_project_view_position_from_depth.js +45 -0
  437. package/src/shade/renderer/shader/chunk/camera/chunk_screen_coordinate_to_view.js +3 -3
  438. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_eotf_st2084.d.ts +1 -1
  439. package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_eotf_st2084.js +62 -62
  440. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +318 -0
  441. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +237 -0
  442. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.d.ts +17 -0
  443. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.d.ts.map +1 -0
  444. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.js +22 -0
  445. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_khronos_pbr.d.ts +14 -1
  446. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_khronos_pbr.d.ts.map +1 -1
  447. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_khronos_pbr.js +28 -15
  448. package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.d.ts +12 -0
  449. package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.d.ts.map +1 -1
  450. package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.js +128 -110
  451. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_offset_ray_from_depth.d.ts +20 -0
  452. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_offset_ray_from_depth.d.ts.map +1 -0
  453. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_offset_ray_from_depth.js +33 -0
  454. package/src/shade/renderer/shader/chunk/light/chunk_compute_multiscattering_specular.d.ts +4 -0
  455. package/src/shade/renderer/shader/chunk/light/chunk_compute_multiscattering_specular.d.ts.map +1 -1
  456. package/src/shade/renderer/shader/chunk/light/chunk_compute_multiscattering_specular.js +12 -1
  457. package/src/shade/renderer/shader/chunk/material/MATERIAL_SHADING_INFO_STRUCT.d.ts.map +1 -1
  458. package/src/shade/renderer/shader/chunk/material/MATERIAL_SHADING_INFO_STRUCT.js +7 -0
  459. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +108 -0
  460. package/src/shade/renderer/shader/chunk/material/chunk_compute_indirect_specular.d.ts.map +1 -1
  461. package/src/shade/renderer/shader/chunk/material/chunk_compute_indirect_specular.js +23 -4
  462. package/src/shade/renderer/shader/chunk/material/chunk_re_direct_multiscatter.d.ts +18 -0
  463. package/src/shade/renderer/shader/chunk/material/chunk_re_direct_multiscatter.d.ts.map +1 -0
  464. package/src/shade/renderer/shader/chunk/material/chunk_re_direct_multiscatter.js +56 -0
  465. package/src/shade/renderer/shader/chunk/material/chunk_re_indirect_specular_physical.d.ts.map +1 -1
  466. package/src/shade/renderer/shader/chunk/material/chunk_re_indirect_specular_physical.js +2 -0
  467. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_linear_ray.d.ts +43 -0
  468. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_linear_ray.d.ts.map +1 -0
  469. package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_linear_ray.js +319 -0
  470. package/src/shade/renderer/shader/compiler/CodeChunk.d.ts +33 -0
  471. package/src/shade/renderer/shader/compiler/CodeChunk.d.ts.map +1 -1
  472. package/src/shade/renderer/shader/compiler/CodeChunk.js +140 -0
  473. package/src/shade/renderer/shader/compiler/CodeChunkChoice.d.ts +74 -0
  474. package/src/shade/renderer/shader/compiler/CodeChunkChoice.d.ts.map +1 -0
  475. package/src/shade/renderer/shader/compiler/CodeChunkChoice.js +166 -0
  476. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +680 -0
  477. package/src/shade/renderer/shader/compiler/ShaderSwitch.d.ts +86 -0
  478. package/src/shade/renderer/shader/compiler/ShaderSwitch.d.ts.map +1 -0
  479. package/src/shade/renderer/shader/compiler/ShaderSwitch.js +178 -0
  480. package/src/shade/renderer/shader/compiler/ShaderSwitchSet.d.ts +67 -0
  481. package/src/shade/renderer/shader/compiler/ShaderSwitchSet.d.ts.map +1 -0
  482. package/src/shade/renderer/shader/compiler/ShaderSwitchSet.js +205 -0
  483. package/src/shade/renderer/shadow/contact/CONTACT_SHADOW_WAVE_SIZE.d.ts +14 -0
  484. package/src/shade/renderer/shadow/contact/CONTACT_SHADOW_WAVE_SIZE.d.ts.map +1 -0
  485. package/src/shade/renderer/shadow/contact/CONTACT_SHADOW_WAVE_SIZE.js +13 -0
  486. package/src/shade/renderer/shadow/contact/ContactShadowDispatchList.d.ts +65 -0
  487. package/src/shade/renderer/shadow/contact/ContactShadowDispatchList.d.ts.map +1 -0
  488. package/src/shade/renderer/shadow/contact/ContactShadowDispatchList.js +252 -0
  489. package/src/shade/renderer/shadow/contact/FINDINGS.md +413 -0
  490. package/src/shade/renderer/shadow/contact/chunk_contact_shadow_wavefront_extents.d.ts +29 -0
  491. package/src/shade/renderer/shadow/contact/chunk_contact_shadow_wavefront_extents.d.ts.map +1 -0
  492. package/src/shade/renderer/shadow/contact/chunk_contact_shadow_wavefront_extents.js +105 -0
  493. package/src/shade/renderer/shadow/contact/graph_contact_shadow_linear.d.ts +29 -0
  494. package/src/shade/renderer/shadow/contact/graph_contact_shadow_linear.d.ts.map +1 -0
  495. package/src/shade/renderer/shadow/contact/graph_contact_shadow_linear.js +39 -0
  496. package/src/shade/renderer/shadow/contact/graph_contact_shadow_wavefront.d.ts +29 -0
  497. package/src/shade/renderer/shadow/contact/graph_contact_shadow_wavefront.d.ts.map +1 -0
  498. package/src/shade/renderer/shadow/contact/graph_contact_shadow_wavefront.js +92 -0
  499. package/src/shade/renderer/shadow/contact/shader_contact_shadow_linear.d.ts +29 -0
  500. package/src/shade/renderer/shadow/contact/shader_contact_shadow_linear.d.ts.map +1 -0
  501. package/src/shade/renderer/shadow/contact/shader_contact_shadow_linear.js +128 -0
  502. package/src/shade/renderer/shadow/contact/shader_contact_shadow_wavefront.d.ts +52 -0
  503. package/src/shade/renderer/shadow/contact/shader_contact_shadow_wavefront.d.ts.map +1 -0
  504. package/src/shade/renderer/shadow/contact/shader_contact_shadow_wavefront.js +358 -0
  505. package/src/shade/renderer/shadow/map/ShadowDirectionalTechnique.d.ts +10 -0
  506. package/src/shade/renderer/shadow/map/ShadowDirectionalTechnique.d.ts.map +1 -0
  507. package/src/shade/renderer/shadow/map/ShadowDirectionalTechnique.js +12 -0
  508. package/src/shade/renderer/shadow/map/shader/SHADOW_DIRECTIONAL_TECHNIQUE.d.ts +13 -0
  509. package/src/shade/renderer/shadow/map/shader/SHADOW_DIRECTIONAL_TECHNIQUE.d.ts.map +1 -0
  510. package/src/shade/renderer/shadow/map/shader/SHADOW_DIRECTIONAL_TECHNIQUE.js +14 -0
  511. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts +14 -8
  512. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts.map +1 -1
  513. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.js +20 -86
  514. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional_cascades.d.ts +14 -0
  515. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional_cascades.d.ts.map +1 -0
  516. package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional_cascades.js +79 -0
  517. package/src/shade/renderer/shadow/ray/shader_ray_shadow_code.d.ts.map +1 -1
  518. package/src/shade/renderer/shadow/ray/shader_ray_shadow_code.js +12 -12
  519. package/src/shade/renderer/shadow/ray/staged/gen/shader_generate_rays.d.ts.map +1 -1
  520. package/src/shade/renderer/shadow/ray/staged/gen/shader_generate_rays.js +153 -151
  521. package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_directional_virtual.d.ts +13 -0
  522. package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_directional_virtual.d.ts.map +1 -0
  523. package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_directional_virtual.js +48 -0
  524. package/src/shade/renderer/texture/GPUTextureContext.d.ts +10 -0
  525. package/src/shade/renderer/texture/GPUTextureContext.d.ts.map +1 -1
  526. package/src/shade/renderer/texture/GPUTextureContext.js +24 -0
  527. package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts +219 -0
  528. package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts.map +1 -0
  529. package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.js +671 -0
  530. package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.d.ts +26 -2
  531. package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.d.ts.map +1 -1
  532. package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.js +108 -4
  533. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +5 -1
  534. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  535. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +6 -0
  536. package/src/shade/renderer/volumetrics/NOTES.md +50 -0
  537. package/src/shade/renderer/volumetrics/PARTICIPATING_MEDIA_VOLUME_STRUCT.d.ts.map +1 -1
  538. package/src/shade/renderer/volumetrics/PARTICIPATING_MEDIA_VOLUME_STRUCT.js +30 -1
  539. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts +51 -13
  540. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts.map +1 -1
  541. package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.js +98 -13
  542. package/src/shade/renderer/volumetrics/SceneVolumetrics.d.ts +9 -0
  543. package/src/shade/renderer/volumetrics/SceneVolumetrics.d.ts.map +1 -1
  544. package/src/shade/renderer/volumetrics/SceneVolumetrics.js +78 -68
  545. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +326 -0
  546. package/src/shade/renderer/volumetrics/chunk_participating_media_volume_sample.d.ts +7 -4
  547. package/src/shade/renderer/volumetrics/chunk_participating_media_volume_sample.d.ts.map +1 -1
  548. package/src/shade/renderer/volumetrics/chunk_participating_media_volume_sample.js +21 -9
  549. package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_uvw_from_clip.d.ts +19 -0
  550. package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_uvw_from_clip.d.ts.map +1 -0
  551. package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_uvw_from_clip.js +53 -0
  552. package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.d.ts +12 -3
  553. package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.d.ts.map +1 -1
  554. package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.js +85 -48
  555. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts +4 -1
  556. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts.map +1 -1
  557. package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js +4 -1
  558. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +4 -1
  559. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
  560. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +21 -1
  561. package/src/shade/renderer/volumetrics/noise/PARTICIPATING_MEDIA_NOISE.d.ts +98 -0
  562. package/src/shade/renderer/volumetrics/noise/PARTICIPATING_MEDIA_NOISE.d.ts.map +1 -0
  563. package/src/shade/renderer/volumetrics/noise/PARTICIPATING_MEDIA_NOISE.js +115 -0
  564. package/src/shade/renderer/volumetrics/noise/VOLUMETRICS_NOISE_TILE_BAKE_SETTINGS_STRUCT.d.ts +9 -0
  565. package/src/shade/renderer/volumetrics/noise/VOLUMETRICS_NOISE_TILE_BAKE_SETTINGS_STRUCT.d.ts.map +1 -0
  566. package/src/shade/renderer/volumetrics/noise/VOLUMETRICS_NOISE_TILE_BAKE_SETTINGS_STRUCT.js +24 -0
  567. package/src/shade/renderer/volumetrics/noise/bake_volumetrics_noise_tile.d.ts +27 -0
  568. package/src/shade/renderer/volumetrics/noise/bake_volumetrics_noise_tile.d.ts.map +1 -0
  569. package/src/shade/renderer/volumetrics/noise/bake_volumetrics_noise_tile.js +91 -0
  570. package/src/shade/renderer/volumetrics/noise/chunk_participating_media_noise.d.ts +35 -0
  571. package/src/shade/renderer/volumetrics/noise/chunk_participating_media_noise.d.ts.map +1 -0
  572. package/src/shade/renderer/volumetrics/noise/chunk_participating_media_noise.js +92 -0
  573. package/src/shade/renderer/volumetrics/noise/shader_volumetrics_noise_tile_bake.d.ts +10 -0
  574. package/src/shade/renderer/volumetrics/noise/shader_volumetrics_noise_tile_bake.d.ts.map +1 -0
  575. package/src/shade/renderer/volumetrics/noise/shader_volumetrics_noise_tile_bake.js +121 -0
  576. package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.d.ts.map +1 -1
  577. package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.js +38 -3
  578. package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.d.ts.map +1 -1
  579. package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.js +311 -290
  580. package/src/shade/renderer/volumetrics/volumetrics_position_world_to_froxel_uvw.d.ts.map +1 -1
  581. package/src/shade/renderer/volumetrics/volumetrics_position_world_to_froxel_uvw.js +28 -49
  582. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +3 -1
  583. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  584. package/src/shade/renderer/water/GPUWaterRenderer.js +24 -18
  585. package/src/shade/renderer/water/chunk_water_transport.d.ts +0 -1
  586. package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -1
  587. package/src/shade/renderer/water/chunk_water_transport.js +0 -17
  588. package/src/shade/renderer/water/shader_water.d.ts +4 -2
  589. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  590. package/src/shade/renderer/water/shader_water.js +27 -16
  591. package/src/shade/renderer/water/shader_water_avboit.d.ts +0 -4
  592. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  593. package/src/shade/renderer/water/shader_water_avboit.js +0 -63
  594. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  595. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +43 -9
  596. package/src/engine/network/transport/Channel.d.ts +0 -85
  597. package/src/engine/network/transport/Channel.d.ts.map +0 -1
  598. package/src/engine/network/transport/ReliableCommandPipeline.d.ts +0 -155
  599. package/src/engine/network/transport/ReliableCommandPipeline.d.ts.map +0 -1
  600. package/src/engine/network/transport/fragments/FragmentAssembler.d.ts +0 -105
  601. package/src/engine/network/transport/fragments/FragmentAssembler.d.ts.map +0 -1
  602. package/src/engine/network/transport/fragments/FragmentRetention.d.ts +0 -103
  603. package/src/engine/network/transport/fragments/FragmentRetention.d.ts.map +0 -1
  604. package/src/engine/network/transport/fragments/fragment_send.d.ts +0 -61
  605. package/src/engine/network/transport/fragments/fragment_send.d.ts.map +0 -1
  606. package/src/engine/network/transport/fragments/packet_size.d.ts +0 -99
  607. package/src/engine/network/transport/fragments/packet_size.d.ts.map +0 -1
  608. package/src/shade/renderer/shader/chunk/color/sRGB/chunk_RRTAndODTFit.d.ts +0 -6
  609. package/src/shade/renderer/shader/chunk/color/sRGB/chunk_RRTAndODTFit.d.ts.map +0 -1
  610. package/src/shade/renderer/shader/chunk/color/sRGB/chunk_RRTAndODTFit.js +0 -16
  611. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_aces.d.ts +0 -7
  612. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_aces.d.ts.map +0 -1
  613. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_aces.js +0 -46
  614. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_agx.d.ts +0 -10
  615. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_agx.d.ts.map +0 -1
  616. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_agx.js +0 -127
  617. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_pbr_neutral.d.ts +0 -7
  618. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_pbr_neutral.d.ts.map +0 -1
  619. package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_pbr_neutral.js +0 -39
@@ -0,0 +1,413 @@
1
+ # Contact shadows: what fails, and what a careful implementation fixes
2
+
3
+ Status 2026-10-16: **prototype, not wired into the renderer.** The pass here is a WGSL port of Bend
4
+ Studio's screen-space shadows; the playground `src/shade/playground/contact_shadows/` measures it, and the
5
+ engine's older per-pixel march, against a ray-traced reference, one scene per failure mode. Nothing in the
6
+ default frame changes until the forks at the end are answered.
7
+
8
+ **In short.** Of the ten ways contact shadows are known to fail:
9
+
10
+ - **Fixed**, measured:
11
+ - noise: the pass is deterministic;
12
+ - disocclusion trails: it keeps no history;
13
+ - self-shadowing where the sun grazes a receiver: 0.1% false;
14
+ - the far-field moiré where the view grazes the ground: 14,926 → 358 false px a frame with Bend's own
15
+ `IgnoreEdgePixels`.
16
+ - **A trade, no fix:**
17
+ - the thickness window: no value serves both 2 cm poles and 40 cm boxes;
18
+ - foliage: thinnest of all;
19
+ - min against multiply: multiply is closer to the sun, min keeps the cascades' softness.
20
+ - **Inherent to screen space:**
21
+ - view dependence: 11–50% of the gaps closed frame to frame round one orbit;
22
+ - off-screen casters, bounded by the 60-px reach;
23
+ - normal-map detail;
24
+ - shimmer of detail the cascades cannot resolve, under camera motion.
25
+
26
+ With the cascades, the pass closes 77–79% of the gaps at caster bases for a handful of false pixels, at
27
+ 38 µs at 1.27 Mpx on a 4090. With VSM there is a twelfth to a twentieth as much to close, and it adds about
28
+ as much false shadow as it removes.
29
+
30
+ **Later the same day, Alex chose a per-pixel march, favouring accuracy, on a generic linear trace any
31
+ screen-space feature can use (§6).** At 64 steps it matches the wavefront pass's accuracy against the sun
32
+ summed over the ten scenes, with less false shadow on fine detail, at 3.4× its cost.
33
+
34
+ ## 0. What is here
35
+
36
+ - `ContactShadowDispatchList.js`: Bend's `BuildDispatchList` (CPU). Up to 8 dispatches of 64-pixel
37
+ wavefronts converging on the light's point on screen.
38
+ - `chunk_contact_shadow_wavefront_extents.js`, `shader_contact_shadow_wavefront.js`: Bend's
39
+ `ComputeWavefrontExtents` and `WriteScreenSpaceShadow`. A 64-thread workgroup is one 64-pixel run along a
40
+ single ray to the light; each thread does 2 reads of 2 depth taps into a 128-word workgroup array and
41
+ compares 60 of its neighbours' words. **Every thread's work is fixed: 4 texture reads, 60 shared-memory
42
+ compares,** whatever the scene.
43
+ - `graph_contact_shadow_wavefront.js`: one graph pass, one dispatch per list entry, writing an `r32float`
44
+ visibility mask (1 lit). `r8unorm` storage needs `texture-formats-tier1`, which the engine takes when
45
+ offered but does not require.
46
+ - `ContactShadowDispatchList.spec.js`: the real WGSL extents function, under the emulator, against the CPU
47
+ dispatch list: every pixel of a viewport gets a thread, for lights on screen, off each edge, in a corner,
48
+ nearly perpendicular to the view, and behind the camera.
49
+
50
+ ### Two holes in Bend's released layout, found by that spec and fixed
51
+
52
+ 1. **The light's own pixel is written by no thread.** Every ring stops one pixel short of the light, so
53
+ with the light on screen one pixel kept whatever the texture held. The innermost ring's threads now
54
+ also write it (lit: a ray of no length).
55
+ 2. **A light projecting millions of pixels away loses rows to f32 spacing.** Bend clamps w only once the
56
+ light is ~1M px out; at 9e6 px the spec saw rows unwritten. The CPU now pulls the light's point in to
57
+ 2^20 px from the viewport's centre (f32 spacing 1/8 px there), turning the rays by under 0.1° at
58
+ 1600 px. An overhead sun with a level camera (w = 0, Bend's clamp) projects to 3.5e6 px and was
59
+ already whole at 1600×900.
60
+
61
+ ## 1. The failure modes, and why they happen
62
+
63
+ From the primary sources. Paths under `UE_5.4/Engine/` are Epic's installed source; Bend is
64
+ `bend_sss_gpu.h` / `bend_sss_cpu.h` (Sony, Apache 2.0) and the SIGGRAPH 2023 talk's slide text.
65
+
66
+ | # | Failure mode | Cause | What shipping code does about it |
67
+ |---|---|---|---|
68
+ | 1 | **Heightfield thickness**: thin casters smear, thick ones leak | The depth buffer holds each caster's front and nothing behind it, so every method assumes a slab thickness | Bend: 0.5% of the sample's depth to the far plane (here: in front of the ray by up to 1% of its view depth). UE desktop: ≈ L/2, set by ray length and 8 steps (`ScreenSpaceShadowRayCast.ush:26-32`, `DeferredLightingCommon.ush:63-64`). Filament ≈ 7.5 cm, three.js 1 cm, Bevy 10 cm, all world space. Nobody reconstructs back faces |
69
+ | 2 | **Self-shadowing** where the sun or the view grazes a surface, and on normal-mapped surfaces | A ray leaving a surface at a grazing angle runs along it, so the surface's own neighbouring depths sit just in front of it; depth is quantised per pixel; the shading normal and the depth disagree | Bend: an edge-aware bilinear read across the ray's minor axis, pushing the casting depth back by the step across the pixel; a start bias "suppressed legitimate detail" (talk). UE: skip samples bit-equal to the start depth. Bevy: an open draft (#25355) bends the ray toward the normal. Normal maps are invisible to all of them; Days Gone wrote a ±8 cm material displacement into depth to get that detail |
70
+ | 3 | **View dependence** | Only casters that are on screen and in front cast; the reach is counted in pixels (Bend, Godot, UE screen mode) or the screen reach shrinks with distance (world-space methods) | Bend: "they cannot replace shadow maps, only complement them" (talk). Nothing fixes it |
71
+ | 4 | **Noise and TAA instability** | Jittered starts and few steps (UE 8 steps + IGN over 8 frames, Bevy, three.js, Filament) need TAA to converge; the jittered depth buffer changes what is in it | Bend is deterministic: 4 interleaved min-reductions averaged, 4 hard near samples, an 8-sample fade. Every other source leans on the scene's TAA |
72
+ | 5 | **Disocclusion trails** | Temporal accumulation of a term that changes with the view | No source keeps contact-shadow history; trails are whatever TAA does |
73
+ | 6 | **Screen edges** | Off-screen casters are not in the depth buffer | Bend reads off-screen as the far plane (clamp-to-border); UE treats an off-screen hit as a miss; Filament fades by the ray's end. A fade only hides the pop |
74
+ | 7 | **Scale with distance** | A pixel reach means a world reach growing with depth; a world reach shrinks below a pixel | Bend 60 px fixed; UE screen mode L ∝ depth (`DeferredLightingCommon.ush:162-168`); world-space methods vanish far away |
75
+ | 8 | **Alpha-tested foliage** | Cut-outs alias per texel, cards are millimetres thick, two-sided leaves are their own receivers | Bend's `IgnoreEdgePixels` "can also thin out otherwise valid shadows, especially on foliage edges". UE attenuates subsurface/foliage receivers by 1 − exp(−density·distance) (`DeferredLightingCommon.ush:197-211`) |
76
+ | 9 | **Double darkening** against the shadow map | Multiplying two partial visibilities (a PCF penumbra and a partial contact) is darker than either | UE desktop multiplies (`DeferredLightingCommon.ush:213-216`); UE mobile and Godot take the min; Filament and Bevy multiply but skip pixels the map already shadows fully |
77
+ | 10 | **The light's point on screen** | Rays converge on it, so near it every ray is a few pixels long; Bend widens its window there | Bend: `min(sample_distance + direction, 1/thickness)` in the window scale |
78
+
79
+ ## 2. Measured
80
+
81
+ RTX 4090, headless Chrome, 1578×802, 2026-10-16. Every number is per frame, averaged over 150 frames at
82
+ 1/60 s along the scene's own camera path (the same path from the same start for every arm), classified
83
+ before TAA against a ray traced from each pixel's G-buffer position to the sun's centre ("Counters" in the
84
+ playground README). "Gaps" are pixels the reference shadows and the cascades leave lit; "closed" is the
85
+ share of those the combined term shadows; "added" is false shadow the contact term put where the reference
86
+ and the cascades are both lit. The runs are deterministic: a second campaign reproduced every count.
87
+
88
+ Arms: **Bend** is the port with Bend's starting values (surface thickness 0.005, edge threshold 0.02,
89
+ contrast 4) multiplied into the cascades' term; the next column turns on Bend's own `IgnoreEdgePixels`.
90
+ **March** is the engine's unwired per-pixel march
91
+ (`deferred/chunk_ss_trace_contact_shadow_soft.js`) given the same 60 samples and the same thickness window.
92
+
93
+ | Scene | Reference shadowed | Cascade gaps | Bend: closed / added | Bend + `IgnoreEdgePixels`: closed / added | March: closed / added |
94
+ |---|---|---|---|---|---|
95
+ | thickness | 32,686 | 2,141 | 17.1% / 155 | 17.1% / 153 | 11.2% / 186 |
96
+ | grazing | 22,286 | 7,941 | 31.9% / 23 | 28.2% / 6 | 2.8% / 1 |
97
+ | view | 22,953 | 2,523 | 28.6% / 36 | 28.1% / 26 | 20.9% / 19 |
98
+ | noise (fine detail) | 72,090 | 66,943 | 67.7% / 6,992 | 65.0% / 5,525 | 27.1% / 2,387 |
99
+ | disocclusion | 19,305 | 5,013 | 76.6% / 21 | 75.3% / 11 | 4.5% / 1 |
100
+ | screen_edge | 118,831 | 3,071 | 14.2% / 83 | 14.1% / 79 | 13.0% / 125 |
101
+ | distance | 12,296 | 3,383 | 10.2% / 49 | 10.2% / 45 | 2.7% / 5 |
102
+ | foliage | 57,767 | 26,659 | 42.6% / 3,323 | 40.8% / 3,012 | 18.6% / 1,272 |
103
+ | combine | 22,767 | 6,039 | 81.5% / 45 | 79.1% / 22 | 10.1% / 3 |
104
+ | sun_in_view | 19,868 | 2,991 | 36.2% / 14,926 | 35.3% / 358 | 33.8% / 433 |
105
+
106
+ Taking the min with the cascades instead of multiplying is item 9.
107
+
108
+ ### Verdicts, failure by failure
109
+
110
+ 1. **Heightfield thickness — inherent; the window is a trade with no safe value.** In `thickness`, Bend's
111
+ window (in front of the ray by up to 1% of its depth) closes 17.1% and smears 155 px behind the thin
112
+ poles and plank; ¼ of it closes 14.3% and adds 1 px; 4× closes 20.1% and adds 1,193 px. But the same ½
113
+ window that cleans `foliage` (3,323 → 1,302 px added) drops the movers' closure in `disocclusion` from
114
+ 76.6% to 21.6%: rays pass behind casters thicker than the window and read as lit. One depth layer cannot
115
+ tell a 2 cm pole from a 40 cm box. Bend's value is kept as the default; it is the trade every caller
116
+ would make differently.
117
+ 2. **Self-shadowing.**
118
+ - *The sun grazing a receiver* (8°, `grazing`) — **fixed by Bend's design**: 23 false px of 22,286
119
+ shadowed (0.1%), 6 with `IgnoreEdgePixels`. The edge-aware read across the ray's minor axis and the
120
+ window's one-sided offset (a sample at the ray's own depth stays lit) carry it; no start bias needed.
121
+ - *The view grazing a surface* (far ground at the horizon, sun ahead, `sun_in_view`) — **fixed by
122
+ `IgnoreEdgePixels`**: 14,926 → 358 false px a frame, all of it on ground 16–128 m away, and the
123
+ contact term's frame-to-frame change 16,957 → 5,552 (the cascades' own: 6,046), for one point of
124
+ closure. At 50 m one pixel row of ground spans ~1.7 m, past the 2% edge threshold, so the reads are
125
+ point-sampled and the row half a step nearer falls inside the window: a moiré band. Bend's notes
126
+ describe exactly this and offer the flag.
127
+ - *Normal maps* — **inherent**: depth does not carry normal-map detail, so the contact pass neither
128
+ shadows nor self-shadows from it (`grazing`'s normal-mapped slab). Days Gone wrote a ±8 cm material
129
+ displacement into depth to get it; that is a G-buffer change, not a shadow-pass one.
130
+ 3. **View dependence — inherent.** The share of `view`'s gaps closed swings from 12.7% to 42.1% frame to
131
+ frame along the orbit; casters hidden by the post cast nothing while hidden.
132
+ 4. **Noise and TAA instability — the noise is fixed; motion shimmer on sub-texel detail is inherent.**
133
+ Bend has no random term (a second campaign reproduced every count). TAA on or off changes nothing
134
+ before TAA (`noise`: 16,093 vs 15,616 flips), so the jitter is not the driver. But where the contact
135
+ term carries detail the cascades cannot resolve (`noise`: 2 cm slats, the cascades miss 93% of the
136
+ shadowed pixels), it changes frame to frame under camera motion far more than the cascades do: 15,616
137
+ pixels cross ½ a frame against the cascades' 856; summed change 18,568 against 10,788. That is the
138
+ depth buffer's own sampling of sub-pixel detail moving; only TAA can resolve it, and it costs nothing
139
+ there to try.
140
+ 5. **Disocclusion trails — fixed by construction.** The pass reads this frame's depth and nothing else;
141
+ it has no history to trail. Around the movers in `disocclusion` it closes 76.6% of the gaps with 21
142
+ false px. Any ghosting is TAA's, unchanged by the pass.
143
+ 6. **Screen edges — inherent.** See the coverage run below.
144
+ 7. **Scale with distance — mitigated.** The reach is 60 pixels, so its world length grows with depth, and
145
+ the thickness window does too. That matches both shadow maps' error, which also grows with depth (see
146
+ "The budget, derived" below). The far field's real failure was the grazing-view moiré, which
147
+ `IgnoreEdgePixels` removes (item 2).
148
+ 8. **Alpha-tested foliage — mitigated.** Contact shadows close 42.6% of the foliage gaps but add 3,323
149
+ false px (5.8% of the shadowed pixels): cards a few millimetres thick get the window's 1%-of-depth
150
+ thickness. `IgnoreEdgePixels` takes it to 3,012, a ½ window to 1,302 (closing 29.4%). It is item 1's
151
+ trade on the thinnest casters there are.
152
+ 9. **Double darkening — real, and against the sun it is the more accurate choice.** Multiplying leaves
153
+ pixels darker than both terms by over 0.1 (`combine` 978, `noise` 19,873, `foliage` 9,278, with
154
+ `IgnoreEdgePixels`); the min removes every one. But measured against the ray-traced sun, the multiply is
155
+ closer in all ten scenes (mean |error| lower or tied: `disocclusion` 0.0047 against 0.0051, `noise`
156
+ 0.0376 against 0.0393, `combine` 0.0041 against 0.0043), and the min gives up closure for it
157
+ (`disocclusion` 75.3% → 55.5%, `screen_edge` 14.1% → 9.2%) while removing some false shadow (`combine`
158
+ 22 → 14 px). The cascades' 5×5 PCF penumbra is wider than the sun's (0.37°, under a millimetre at a
159
+ contact), so darkening it toward the contact is mostly darkening toward the truth. The min only wins if
160
+ the shadow map's softness is the look to keep.
161
+ 10. **The light's point on screen.** The widened window near the sun's point did not show as a failure of
162
+ its own; the far-field moiré in `sun_in_view` (item 2) is what looking toward the sun exposed.
163
+
164
+ ### Against VSM
165
+
166
+ The same scenes with the virtual shadow map (1 cm first texel), Bend + `IgnoreEdgePixels` + min:
167
+
168
+ | Scene | Cascade gaps → closed / added | VSM gaps → closed / added |
169
+ |---|---|---|
170
+ | thickness | 2,141 → 15.8% / 142 | 197 → 7.2% / 149 |
171
+ | grazing | 7,941 → 28.0% / 5 | 3,307 → 62.1% / 12 |
172
+ | view | 2,523 → 24.0% / 8 | 336 → 1.6% / 8 |
173
+ | noise | 66,943 → 59.0% / 4,156 | 19,417 → 54.2% / 2,935 |
174
+ | disocclusion | 5,013 → 55.5% / 6 | 251 → 13.1% / 5 |
175
+ | screen_edge | 3,071 → 9.2% / 62 | 357 → 7.3% / 60 |
176
+ | distance | 3,383 → 8.7% / 27 | 166 → 4.7% / 28 |
177
+ | foliage | 26,659 → 36.1% / 2,647 | 9,557 → 16.8% / 2,201 |
178
+ | combine | 6,039 → 77.4% / 14 | 380 → 5.6% / 14 |
179
+ | sun_in_view | 2,991 → 33.2% / 224 | 284 → 23.6% / 303 |
180
+
181
+ VSM leaves a twelfth to a twentieth of the cascades' gaps at caster bases (`combine`, `disocclusion`,
182
+ `view`, `distance`, `screen_edge`, `thickness`), and there the contact term adds about as much false shadow
183
+ as it closes, or more. It still earns its place in three cases: a sun grazing the receiver (`grazing`: 62%
184
+ of VSM's 3,307 gaps closed for 12 false px), detail finer than the first page (`noise`'s 2 cm slats: 54%),
185
+ and foliage, though there it adds 2,201 false px to close 1,605. Bend's defaults without `IgnoreEdgePixels`
186
+ put the far-field moiré back under VSM too (`sun_in_view`: 14,942 false px).
187
+
188
+ ### The coverage runs
189
+
190
+ The 150-frame runs at 1/60 s cover only the first 2.5 s of each path. To traverse the pans, the orbit,
191
+ the turn and the dolly, four scenes ran 300 frames at four times the speed:
192
+
193
+ - **Screen edges — inherent, bounded by the reach.** Through the whole pan, the share of `screen_edge`'s
194
+ gaps closed swings between 9% and 20% from frame to frame, the same swing as the orbit's. A caster that
195
+ leaves the screen only takes the contact shadow within 60 px of the edge with it; off-screen reads
196
+ return the far plane (an explicit bounds check: WebGPU has no clamp-to-border), so nothing false comes
197
+ from beyond the edge.
198
+ - **View dependence.** Round the full orbit of `view`, Bend closes 11–50% of the gaps by frame and its
199
+ false shadow spikes to 2,986 px on one frame; with `IgnoreEdgePixels` (and the ½ window) the spike is
200
+ 12 px.
201
+ - **Sun in view.** Facing the sun Bend adds 12,662–25,247 false px a frame, facing away 78–345; with
202
+ `IgnoreEdgePixels` (and the ½ window) at most 67 throughout.
203
+
204
+ ### The budget, derived
205
+
206
+ Each thread's reach is its sample count in pixels. Bend's 60 is what their read formula fits in two reads
207
+ of a 64-wide wave (it over-counts: the two reads hold 64 words past each thread). What has to be reached is
208
+ the shadow map's own blur at a caster's base: the cascades filter 5×5 texels (`SHADOWMAP_FILTER_SIZE`), so
209
+ 2.5 texels either side of an edge. Measured in `combine`: cascade 0 covers the first 54 m at **4.7 cm a
210
+ texel**, so 12 cm of blur; at 1578×802 and 55° a pixel spans 1.3 mm per metre of depth, so 60 pixels reach
211
+ 12 cm at **1.5 m** and more beyond it (7.8 cm × depth in metres, for a light parallel to the image). Nearer
212
+ than 1.5 m the cascades' blur is wider than the reach; further away the reach outgrows it in step with the
213
+ cascades, whose texels also grow with distance (17 cm to 167 m, 42 cm to 400 m). For VSM's 1 cm first
214
+ texel the same 60 px covers its 2.5 cm from 0.3 m. Doubling the reach would take a third read per thread
215
+ (READ_COUNT 3) and buy the 0.75–1.5 m band for cascades only. 60 is kept.
216
+
217
+ ### Defects found on the way, outside this pass
218
+
219
+ - `shadow/ray/shader_ray_shadow_code.js`, the engine's ray-traced shadow prototype, binds five groups; a
220
+ device offers four, so it cannot be dispatched. The playground's reference is the same query in three
221
+ groups. Fixed the same day: it binds three, as the reference does.
222
+ - It also starts its rays with `offset_ray`, which offsets in proportion to |position| (meant for a ray
223
+ hit's position). On a position rebuilt from depth that leaves the far ground shadowing itself: 180,140
224
+ shadowed pixels in `combine` against 25,166 with an offset of 3e-5 of the view distance, the onset of a
225
+ plateau measured from 1e-6 to 1e-3. Fixed the same day: its rays (and the staged generator's) start at
226
+ `offset_ray_from_depth` (`shader/chunk/geometry/ray/chunk_offset_ray_from_depth.js`), that offset.
227
+ - `deferred/chunk_ss_trace_contact_shadow_soft.js`, the engine's unwired contact chunk, closes 2.7–27% of
228
+ the gaps where the wavefront pass closes 10–82%, with the same samples and window.
229
+
230
+ ## 3. Cost
231
+
232
+ GPU time per pass, RTX 4090, 1578×802 (1.27 Mpx), the three methods swapped every 4 frames in ABC CBA
233
+ order inside one profile capture, each block's first frame dropped, 90 frames per arm, camera still. Two
234
+ runs per case; their medians agree to within one timer step (~1 µs). Deferred shading read 66.6–68.6 µs in
235
+ every arm, so the clocks held.
236
+
237
+ | | Sun off screen (`combine`) | Sun on screen (`sun_in_view`, facing it) |
238
+ |---|---|---|
239
+ | Wavefront pass (Bend) | **37.9 µs** | **32.8 µs** |
240
+ | Per-pixel march (engine chunk) | 73.7 µs | 53.2 µs |
241
+ | Playground composite (scaffolding) | 48.1 µs | 31.7 µs |
242
+
243
+ About 30 µs per megapixel, so ~62 µs at 1080p and ~250 µs at 4K on this card; Bend report 0.19 ms at
244
+ 1440p on PS5. The composite is the price of applying the mask without touching deferred shading: it
245
+ re-evaluates the sun's BRDF and cascade lookup and writes the debug record. Reading the mask inside the
246
+ sun's shadow term instead is one texture load per pixel in a pass already running; it is not measured here
247
+ because it needs the deferred shader changed (fork 3).
248
+
249
+ ## 4. Reuse map
250
+
251
+ | Piece | Reuses | New |
252
+ |---|---|---|
253
+ | Depth, normals, camera | `ViewTextures`, `GBufferTextures` records; `CAMERA_UNIFORM_STRUCT`; the view's jittered `view_projection_matrix` for the light's screen point | — |
254
+ | Wavefront pass | `ComputeShader`, `CodeChunk`, immediates (`setImmediate`), `graph_prepare_bindings`, the frame graph | the Bend port: dispatch list, extents chunk, kernel |
255
+ | The mask in the sun's term (playground) | `chunk_read_gBuffer_material`, `chunk_shadowmap_get_light_visibility`, `chunk_get_directional_light_info_by_index`, `chunk_re_direct_physical`, the deferred pass's random seed — the deferred pass's own chunks | the subtractive composite (scaffolding) |
256
+ | Reference | `chunk_ray_shaded_query_occluded` (path tracer), `RESOURCE_GROUP_RTX`, resident materials, `chunk_offset_ray` | three-group reference shader |
257
+ | A/B arm | `chunk_ss_trace_pixel_occlusion` unchanged | an 8×8 dispatch of it |
258
+ | Linear trace (§6) | `chunk_v3_matrix4_project`, `chunk_ndc_to_uv`, `chunk_uv_to_ndc`, `chunk_get_view_space_depth`, `chunk_get_bilinear_filter_texel`, `chunk_interpolate_bilinear_f32`, `chunk_interleaved_gradient_noise`, `chunk_project_position_from_depth`, `graph_compute_pass` | `chunk_screen_space_linear_ray` (generic, beside the Newton ray), the contact pass on it |
259
+ | Measurement | `GPUProfileSession` (subclassed to keep spans by frame), the render-extension phases | counters shader |
260
+
261
+ Nothing in the engine builds screen-space wavefronts toward a light, so the dispatch list and kernel are
262
+ new. The unwired `deferred/chunk_ss_trace_contact_shadow_soft.js` is what the pass would supersede.
263
+
264
+ ## 5. Forks
265
+
266
+ What the measurements recommend; each is Alex's call.
267
+
268
+ 1. **The sun only, or local lights too?** Sun only. Bend's layout takes a point or spot light as
269
+ `(position, 1)` with a screen rectangle, but every light is another full pass over its rectangle (about
270
+ 30 µs per megapixel here), the local lights' shadow maps had their contact gap closed on 2026-10-04
271
+ (front faces, texel-scaled bias), and the ReSTIR DI path already traces their visibility. Not built or
272
+ measured here.
273
+ 2. **With the cascades, and with VSM.**
274
+ - Cascades: on. The pass closes 77–79% of their gaps at caster bases (`combine`, `disocclusion`) for
275
+ 12–22 false px a frame, and 41–65% of what they cannot resolve at all (foliage cards, 2 cm slats) for
276
+ 3,000–5,500 false px, at 38 µs at 1.27 Mpx.
277
+ - VSM: off. It leaves a twelfth to a twentieth of the cascades' gaps, and there the pass adds about as
278
+ much false shadow as it closes. The exceptions are a sun grazing the receiver, detail finer than the
279
+ first page, and foliage; whether those justify it is the question.
280
+ - Multiply (closer to the sun in all ten scenes) rather than min (keeps the cascades' softness, loses up
281
+ to 20 points of closure).
282
+ 3. **Where the mask is read.**
283
+ - (a) In the sun's shadow term (`chunk_shadowmap_sample_directional`, beside the CSM/VSM lookup): one
284
+ texture load per pixel. But that chunk is also linked by volumetrics, water optics and the forward
285
+ path, none of which has a screen pixel to read the mask at, so they need it without the read: a
286
+ per-pipeline choice, which waits on the shader-switches design started 2026-10-16.
287
+ - (b) A pass of its own after lighting, as the playground does: no change to deferred shading at all,
288
+ 48 µs at 1.27 Mpx (it re-evaluates the sun's BRDF and cascade lookup), more than the contact pass
289
+ itself.
290
+ - Recommendation: (a) once shader switches exist.
291
+ 4. **Default on or off.** On with the cascades, with Bend's thickness, `IgnoreEdgePixels` on, bilinear
292
+ offset mode off (it closes more in `grazing`, 38.9% against 31.9%, but adds 150 false px against 23 and
293
+ does nothing for the far-field moiré), multiplied in. Off with VSM. The thickness is the one setting no
294
+ default serves (item 1): content with thin casters (foliage, grilles) wants it smaller, chunky casters
295
+ want Bend's.
296
+
297
+ ### Follow-ups, outside this prototype
298
+
299
+ - `deferred/chunk_ss_trace_contact_shadow_soft.js` is unwired and measured worse than the wavefront pass
300
+ at twice its cost; wiring the pass should delete it.
301
+ - `shadow/ray/shader_ray_shadow_code.js` could not be dispatched (five bind groups) and self-shadowed the
302
+ far ground (`offset_ray` on depth-rebuilt positions); both fixed 2026-10-16, along with its denoiser,
303
+ which did not load. It is still unwired.
304
+
305
+ ## 6. The linear trace, per pixel
306
+
307
+ Alex's direction after reading §1–5: a per-pixel march, favouring accuracy, on a generic linear trace
308
+ with a configurable step count that the rest of the engine can reuse.
309
+
310
+ ### What it is
311
+
312
+ `shader/chunk/screen_space/chunk_screen_space_linear_ray.js`, beside the water's Newton ray. It is a port of
313
+ Tomasz Stachowiak's `raymarch.hlsl` (MIT/Apache; the march Bevy uses for contact shadows, SSR and SSGI),
314
+ built on the engine's own projection, depth and bilinear chunks:
315
+ - **Clipped first.** The segment is clipped to the view frustum in NDC, so every step lands on screen.
316
+ - **Exact depth along the ray.** It marches linearly in NDC, where device depth is affine along a projected
317
+ line.
318
+ - **Bounded.** At most one step per pixel and at most 64 steps (`SCREEN_SPACE_LINEAR_RAY_STEP_LIMIT`), plus
319
+ up to 8 bisection steps.
320
+ - **Two depth reads per step.** It takes the point-sampled and the bilinear depth from one 4-texel fetch,
321
+ and claims a hit only when the ray is behind both.
322
+ - **World-unit thickness.** Depth is compared as view distance, so `depth_thickness` is in metres; with
323
+ `march_behind_surfaces` the ray carries on past a surface it went too deep behind.
324
+ - **Hit refinement** by bisection and secant, for a trace that samples colour at the hit.
325
+
326
+ `shadow/contact/shader_contact_shadow_linear.js` is the contact pass on it. Each pixel marches from its own
327
+ NDC toward the sun:
328
+ - a world-space reach, in a configurable number of steps;
329
+ - a first step either fixed or jittered by interleaved gradient noise;
330
+ - a hit's visibility faded over the back half of the thickness, as Bevy does.
331
+
332
+ Pixels facing away from the sun are skipped.
333
+
334
+ **Pinned on the CPU** (`chunk_screen_space_linear_ray.spec.js`, emulator against analytic depth buffers):
335
+ - A ray climbing 3°, 10° or 30° off a flat ground, from near and far pixels in four headings, never finds
336
+ the ground in front of it. With point samples alone, the same rays do (the test that keeps the bilinear
337
+ read).
338
+ - A ray toward a wall stops within a pixel of the analytic crossing.
339
+ - Bisection takes a 4-step march from over 2 px off the crossing to under 1.
340
+ - A 2 m deep wall is passed behind when marching behind surfaces, and stops the ray when not.
341
+ - The sky is a miss over the whole length; the step count caps at 64 and at one per pixel.
342
+
343
+ **Found on the device only:** `filter` is a WGSL reserved word, which the CPU validator does not check; the
344
+ pipeline was invalid until it was renamed.
345
+
346
+ ### Settings, and where they come from
347
+
348
+ - **Reach** is so many texels of the shadow map serving the near field (cascade 0 as last fitted, or VSM's
349
+ first level). That way the reach follows what the shadow map cannot resolve. Cascade 0 measured 4.7 cm a
350
+ texel in `combine`: 5 texels (the 5×5 filter) is 24 cm, 10 texels 48 cm.
351
+ - **Thickness** is a multiple of reach ÷ steps. At 1 it is the least for which a march behind surfaces still
352
+ sees every surface (Tomasz's rule). Tying it to the step count makes more steps close less, because each
353
+ step's window narrows: at reach 5, 16 steps closed 58.8% in `combine`, 64 steps 39.5%.
354
+
355
+ ### Measured, against Bend with `IgnoreEdgePixels`
356
+
357
+ Same scenes, paths and counters as §2 (150 frames per arm, cascades, multiply). Gaps closed / false px added /
358
+ mean |error| against the ray-traced sun:
359
+
360
+ | Scene | Bend + `IgnoreEdgePixels` | Linear, 32 steps, reach 5, thickness ×1 | Linear, 64 steps, reach 10, thickness ×4 |
361
+ |---|---|---|---|
362
+ | thickness | 17.1% / 153 / 0.0042 | 6.2% / 0 / 0.0043 | 15.1% / 21 / 0.0042 |
363
+ | grazing | 28.2% / 6 / **0.0075** | 12.2% / 0 / 0.0086 | 11.1% / 0 / 0.0084 |
364
+ | view | 28.1% / 26 / 0.0060 | 14.3% / 0 / 0.0064 | 29.0% / 1 / **0.0058** |
365
+ | noise (fine detail) | 65.0% / 5,513 / 0.0376 | 29.7% / 175 / 0.0454 | 60.8% / 3,132 / **0.0351** |
366
+ | disocclusion | 75.3% / 12 / **0.0047** | 45.2% / 1 / 0.0052 | 57.1% / 36 / 0.0050 |
367
+ | screen_edge | 14.1% / 79 / 0.0346 | 5.3% / 1 / 0.0347 | 18.5% / 71 / **0.0342** |
368
+ | distance | 10.2% / 45 / 0.0039 | 5.6% / 0 / 0.0041 | 10.3% / 1 / 0.0039 |
369
+ | foliage | 40.8% / 3,004 / 0.0234 | 18.7% / 569 / 0.0256 | 41.0% / 1,725 / **0.0221** |
370
+ | combine | 79.1% / 22 / **0.0041** | 53.8% / 0 / 0.0052 | 41.6% / 13 / 0.0056 |
371
+ | sun_in_view | 35.3% / 358 / 0.0104 | 26.1% / 27 / 0.0110 | 48.7% / 542 / **0.0097** |
372
+ | **Σ mean \|error\|** | 0.1364 | 0.1505 | **0.1340** |
373
+
374
+ - **At the derived defaults** (reach 5, thickness ×1) the trace is the most conservative arm measured. It
375
+ adds almost no false shadow (0–1 px in seven scenes), but closes a third to three quarters of what Bend
376
+ closes, so it is the least accurate overall.
377
+ - **At 64 steps, reach 10, thickness ×4** (≈48 cm reach, 3 cm thickness) it has the lowest summed error.
378
+ - Best in five scenes, tied in two.
379
+ - Bend stays better at the bases of solid casters (`combine`, `disocclusion`) and on a grazing sun.
380
+ - It adds less false shadow than Bend in most scenes (`noise` 3,132 against 5,513, `foliage` 1,725 against
381
+ 3,004, `thickness` 21 against 153); `sun_in_view` is the exception (542 against 358).
382
+ - **With VSM** (`combine`), 32 steps at reach 10 and thickness ×4 closes 5.1% of 380 gap px with none
383
+ false. There is as little to do as in §2.
384
+ - **Jitter with TAA** changed nothing before TAA. It closed 53.0% against 53.8% in `combine` and doubled
385
+ the frame-to-frame change TAA is left to absorb (2,760 against 1,912). With at most one step per pixel
386
+ there is nothing for it to fill in. It stays off.
387
+
388
+ ### Cost
389
+
390
+ RTX 4090, 1578×802, interleaved in one capture with Bend and the old march as in §3, two runs agreeing:
391
+
392
+ | | Sun off screen | Sun on screen |
393
+ |---|---|---|
394
+ | Bend wavefront | 37.9 µs | 32.8 µs |
395
+ | Linear, 32 steps | 80.9 µs | 47.1 µs |
396
+ | Linear, 64 steps | 130.0 µs | 73.7 µs |
397
+ | Old per-pixel march (60 steps) | 73.7 µs | 53.2 µs |
398
+
399
+ Four depth reads a step, against Bend's four a pixel shared through workgroup memory. Fewer pixels march
400
+ with the sun ahead, where more of the frame is sky and rays are shorter on screen.
401
+
402
+ ### What this changes in §5
403
+
404
+ - **The method is the linear trace**, at 64 steps, reach 10 texels and thickness ×4. That setting is at
405
+ parity with Bend on accuracy against the sun and has less false shadow on fine detail, for 3.4× the cost:
406
+ ~130 µs at 1.27 Mpx, ~210 µs at 1080p on this card.
407
+ - **Forks 1, 2 and 4 stand as written.** VSM still leaves too little to close.
408
+ - **Fork 3 gets easier.** A per-pixel trace can run inline in the sun's shadow term, as Bevy does, with no
409
+ mask texture. It still needs the pixel's depth-buffer coordinate, which volumetrics and water do not
410
+ have, so it waits on shader switches all the same.
411
+ - **Reuse.** SSR and ReSTIR DI march the HZB (`ffx_sssr_hierarchical_raymarch`), and the water uses its
412
+ Newton ray. Moving any of them onto this trace is a decision of its own, not made here; ReSTIR's chunk
413
+ records why it chose the HZB over a linear march.
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Where one thread of the contact shadow pass sits: the pixel it shadows, and the ray from it to the
3
+ * light's position on screen. Port of `ComputeWavefrontExtents` from Bend Studio's `bend_sss_gpu.h`
4
+ * (Sony Interactive Entertainment, Apache 2.0).
5
+ *
6
+ * A workgroup's `workgroup_id.yz` pick a square of {@link CONTACT_SHADOW_WAVE_SIZE} pixels in one of
7
+ * the rings around the light (`wave_offset` from {@link ContactShadowDispatchList} places the
8
+ * dispatch's quadrant), and `workgroup_id.x` a point along that ring's edge. That point and the light
9
+ * define a ray; the workgroup's threads sit on it, one pixel apart along its major axis, and the
10
+ * minor axis is wherever the ray crosses — fractional, which is why the depth reads interpolate
11
+ * across it.
12
+ *
13
+ * Thread order is reversed when the light is behind the camera (`light_coordinate.w < 0`), so that a
14
+ * thread's samples are always the threads after it.
15
+ *
16
+ * - `delta_xy`: the ray's displacement over the wave's {@link CONTACT_SHADOW_WAVE_SIZE} pixels, away
17
+ * from the light; the reads step by it, times the march direction.
18
+ * - `pixel_xy`: this thread's pixel, fractional on the minor axis.
19
+ * - `pixel_distance`: this pixel's distance to the light along the major axis, in pixels.
20
+ * - `major_axis_x`: whether x is the ray's major axis.
21
+ * - `covers_light`: this thread also writes the pixel under the light's own coordinate. Bend's rings
22
+ * stop one pixel short of the light, so with the light on screen that one pixel was written by no
23
+ * thread at all and kept whatever the texture held; the threads of the innermost ring take it.
24
+ *
25
+ * @type {CodeChunk}
26
+ */
27
+ export const chunk_contact_shadow_wavefront_extents: CodeChunk;
28
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
29
+ //# sourceMappingURL=chunk_contact_shadow_wavefront_extents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_contact_shadow_wavefront_extents.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/shadow/contact/chunk_contact_shadow_wavefront_extents.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qDAFU,SAAS,CA6EhB;0BAxGuB,oCAAoC"}
@@ -0,0 +1,105 @@
1
+ import { CodeChunk } from "../../shader/compiler/CodeChunk.js";
2
+ import { CONTACT_SHADOW_WAVE_SIZE } from "./CONTACT_SHADOW_WAVE_SIZE.js";
3
+
4
+ /**
5
+ * Where one thread of the contact shadow pass sits: the pixel it shadows, and the ray from it to the
6
+ * light's position on screen. Port of `ComputeWavefrontExtents` from Bend Studio's `bend_sss_gpu.h`
7
+ * (Sony Interactive Entertainment, Apache 2.0).
8
+ *
9
+ * A workgroup's `workgroup_id.yz` pick a square of {@link CONTACT_SHADOW_WAVE_SIZE} pixels in one of
10
+ * the rings around the light (`wave_offset` from {@link ContactShadowDispatchList} places the
11
+ * dispatch's quadrant), and `workgroup_id.x` a point along that ring's edge. That point and the light
12
+ * define a ray; the workgroup's threads sit on it, one pixel apart along its major axis, and the
13
+ * minor axis is wherever the ray crosses — fractional, which is why the depth reads interpolate
14
+ * across it.
15
+ *
16
+ * Thread order is reversed when the light is behind the camera (`light_coordinate.w < 0`), so that a
17
+ * thread's samples are always the threads after it.
18
+ *
19
+ * - `delta_xy`: the ray's displacement over the wave's {@link CONTACT_SHADOW_WAVE_SIZE} pixels, away
20
+ * from the light; the reads step by it, times the march direction.
21
+ * - `pixel_xy`: this thread's pixel, fractional on the minor axis.
22
+ * - `pixel_distance`: this pixel's distance to the light along the major axis, in pixels.
23
+ * - `major_axis_x`: whether x is the ray's major axis.
24
+ * - `covers_light`: this thread also writes the pixel under the light's own coordinate. Bend's rings
25
+ * stop one pixel short of the light, so with the light on screen that one pixel was written by no
26
+ * thread at all and kept whatever the texture held; the threads of the innermost ring take it.
27
+ *
28
+ * @type {CodeChunk}
29
+ */
30
+ export const chunk_contact_shadow_wavefront_extents = CodeChunk.from(
31
+ //language=WGSL
32
+ `
33
+ struct ContactShadowWavefront {
34
+ delta_xy: vec2<f32>,
35
+ pixel_xy: vec2<f32>,
36
+ pixel_distance: f32,
37
+ major_axis_x: bool,
38
+ covers_light: bool,
39
+ }
40
+
41
+ fn contact_shadow_wavefront_extents(
42
+ light_coordinate: vec4<f32>,
43
+ wave_offset: vec2<i32>,
44
+ group_id: vec3<u32>,
45
+ thread_id: u32,
46
+ ) -> ContactShadowWavefront {
47
+ const WAVE_SIZE = ${CONTACT_SHADOW_WAVE_SIZE}i;
48
+
49
+ var xy = vec2<i32>(group_id.yz) * WAVE_SIZE + wave_offset;
50
+
51
+ // integer light position, and its fractional component
52
+ let light_xy = floor(light_coordinate.xy) + 0.5;
53
+ let light_xy_fraction = light_coordinate.xy - light_xy;
54
+ let reverse_direction = light_coordinate.w > 0.0;
55
+
56
+ let sign_xy = sign(xy);
57
+ let horizontal = abs(xy.x + sign_xy.y) < abs(xy.y - sign_xy.x);
58
+
59
+ let axis = vec2<i32>(
60
+ select(0, sign_xy.y, horizontal),
61
+ select(-sign_xy.x, 0, horizontal),
62
+ );
63
+
64
+ // step along the ring's edge
65
+ xy = axis * i32(group_id.x) + xy;
66
+ let xy_f = vec2<f32>(xy);
67
+
68
+ // only the larger axis matters for interpolating toward the light
69
+ let x_axis_major = abs(xy_f.x) > abs(xy_f.y);
70
+ let major_axis = select(xy_f.y, xy_f.x, x_axis_major);
71
+
72
+ let major_axis_start = abs(major_axis);
73
+ let major_axis_end = abs(major_axis) - f32(WAVE_SIZE);
74
+
75
+ var ma_light_frac = select(light_xy_fraction.y, light_xy_fraction.x, x_axis_major);
76
+ ma_light_frac = select(ma_light_frac, -ma_light_frac, major_axis > 0.0);
77
+
78
+ // back into screen space
79
+ let start_xy = xy_f + light_xy;
80
+
81
+ // the innermost ring ends on the light's exact coordinate, so rounding to a pixel skips none
82
+ let end_xy = mix(
83
+ light_coordinate.xy,
84
+ start_xy,
85
+ (major_axis_end + ma_light_frac) / (major_axis_start + ma_light_frac)
86
+ );
87
+
88
+ // a whole number of pixels on the major axis
89
+ let xy_delta = start_xy - end_xy;
90
+
91
+ let thread_step = f32(thread_id ^ select(u32(WAVE_SIZE - 1), 0u, reverse_direction));
92
+
93
+ var result: ContactShadowWavefront;
94
+
95
+ result.delta_xy = xy_delta;
96
+ result.pixel_xy = mix(start_xy, end_xy, thread_step / f32(WAVE_SIZE));
97
+ result.pixel_distance = major_axis_start - thread_step + ma_light_frac;
98
+ result.major_axis_x = x_axis_major;
99
+
100
+ // the innermost ring's last threads sit 1 ± ½ pixel from the light; no ring reaches distance 0
101
+ result.covers_light = result.pixel_distance < 2.5;
102
+
103
+ return result;
104
+ }
105
+ `);
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Record one light's contact shadow by the linear trace into a new visibility texture: 1 lit, 0 shadowed,
3
+ * at the depth buffer's resolution.
4
+ *
5
+ * @param {Object} options
6
+ * @param {FrameGraph} options.graph
7
+ * @param {number} options.depth the depth buffer
8
+ * @param {number} options.normal the G-buffer normals
9
+ * @param {GPUBuffer} options.camera the view's camera uniforms, whose projection drew `depth`
10
+ * @param {ArrayLike<number>} options.resolution of `depth`
11
+ * @param {{to_light: ArrayLike<number>, length: number, steps: number, thickness: number, jitter_frame: number}} options.settings
12
+ * see {@link CONTACT_SHADOW_LINEAR_SETTINGS_STRUCT}
13
+ * @returns {number} the visibility texture
14
+ */
15
+ export function graph_contact_shadow_linear({ graph, depth, normal, camera, resolution, settings }: {
16
+ graph: FrameGraph;
17
+ depth: number;
18
+ normal: number;
19
+ camera: GPUBuffer;
20
+ resolution: ArrayLike<number>;
21
+ settings: {
22
+ to_light: ArrayLike<number>;
23
+ length: number;
24
+ steps: number;
25
+ thickness: number;
26
+ jitter_frame: number;
27
+ };
28
+ }): number;
29
+ //# sourceMappingURL=graph_contact_shadow_linear.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph_contact_shadow_linear.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/shadow/contact/graph_contact_shadow_linear.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AACH;IAT+B,KAAK;IACT,KAAK,EAArB,MAAM;IACU,MAAM,EAAtB,MAAM;IACa,MAAM;IACE,UAAU,EAArC,UAAU,MAAM,CAAC;IAC8F,QAAQ,EAAvH;QAAC,QAAQ,EAAE,UAAU,MAAM,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAC;IAEnG,MAAM,CAsBlB"}
@@ -0,0 +1,39 @@
1
+ import { TextureResourceDescriptor } from "../../../device/graph/TextureResourceDescriptor.js";
2
+ import { graph_compute_pass } from "../../shader/graph/compute/graph_compute_pass.js";
3
+ import { shader_contact_shadow_linear } from "./shader_contact_shadow_linear.js";
4
+
5
+ /**
6
+ * Record one light's contact shadow by the linear trace into a new visibility texture: 1 lit, 0 shadowed,
7
+ * at the depth buffer's resolution.
8
+ *
9
+ * @param {Object} options
10
+ * @param {FrameGraph} options.graph
11
+ * @param {number} options.depth the depth buffer
12
+ * @param {number} options.normal the G-buffer normals
13
+ * @param {GPUBuffer} options.camera the view's camera uniforms, whose projection drew `depth`
14
+ * @param {ArrayLike<number>} options.resolution of `depth`
15
+ * @param {{to_light: ArrayLike<number>, length: number, steps: number, thickness: number, jitter_frame: number}} options.settings
16
+ * see {@link CONTACT_SHADOW_LINEAR_SETTINGS_STRUCT}
17
+ * @returns {number} the visibility texture
18
+ */
19
+ export function graph_contact_shadow_linear({ graph, depth, normal, camera, resolution, settings }) {
20
+ const width = resolution[0];
21
+ const height = resolution[1];
22
+
23
+ return graph_compute_pass({
24
+ graph,
25
+ shader: shader_contact_shadow_linear,
26
+ group_count: [Math.ceil(width / 8), Math.ceil(height / 8), 1],
27
+ bindings: {
28
+ settings,
29
+ gBufferDepth: depth,
30
+ gBufferNormal: normal,
31
+ camera,
32
+ tContactShadow: TextureResourceDescriptor.from({
33
+ resolution: [width, height],
34
+ format: 'r32float',
35
+ usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING,
36
+ }),
37
+ },
38
+ }).tContactShadow;
39
+ }