@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,318 @@
1
+ # HDR forms of ACES, AgX and PBR Neutral: a brief (2026-10-16)
2
+
3
+ **Status: decided and built.** Alex took all three recommendations (§6): the ACES and AgX chunks are removed, and
4
+ `ShadeToneMappingMode.PBR_NEUTRAL` runs `tonemap_khronos_pbr` with the peak form. The prototypes this brief measured
5
+ are gone from the playground `src/shade/playground/tonemap_sdr/`, which now compares GT7 and PBR Neutral.
6
+
7
+ ## 1. Recommendation
8
+
9
+ The question: does each operator have one form, parameterised by the display's peak, that serves an SDR peak and an HDR
10
+ peak with the same mid-tones? That is what `ShadeToneMappingMode` asks of a mode since `6ea10df28`: one mode on every
11
+ output, and SDR and HDR must not look different. GT7 is the yardstick.
12
+
13
+ | operator | a form that fits? | recommendation |
14
+ |---|---|---|
15
+ | ACES | **No.** ACES 2.0 is one family parameterised by peak, but it lifts mid-grey by 14% of its SDR level per stop of peak, on purpose. | **Remove** |
16
+ | AgX | **No.** Both HDR forms (Chow's, Godot's) keep mid-grey and bend everything above it with the peak. | **Remove** |
17
+ | Khronos PBR Neutral | **Yes**, with the peak in place of the specification's 1. Below the compression start it is exact at every peak. | **Add** as `ShadeToneMappingMode.PBR_NEUTRAL` |
18
+
19
+ GT7 stays the default.
20
+
21
+ On the device, in the playground's four scenes at a 1000 cd/m² peak, Neutral with a peak and GT7 leave every mid-tone
22
+ pixel as their SDR forms draw it, to within 1 code. Godot's AgX moves 10.5–87.6% of them by 2 codes or more (§4).
23
+
24
+ Neutral earns a mode for a reason beyond fitting. The SDR brief named it the fallback if GT7's SDR clip reads as harsh,
25
+ "at the price of SDR and HDR looking different". With a peak, that price is gone:
26
+
27
+ - its forms agree exactly over a wider range than GT7's, greys to +2.0 EV against +1.5;
28
+ - saturated colours just above its start differ more, a mean of 0.72 codes up to +1 EV against GT7's 0.24.
29
+
30
+ **What would reverse each:**
31
+
32
+ - **ACES:** a need to match an ACES 2.0 pipeline, such as grading or film interchange, accepted together with SDR and HDR
33
+ looking different. It would be a new implementation, not this chunk.
34
+ - **AgX:** a published AgX HDR form that holds tones fixed to about +1.5 EV over mid-grey, measured with the same
35
+ script. Pestaluky lists a higher crossover as future work.
36
+ - **Neutral:**
37
+ - Khronos publishing its own HDR form. The HDR pass would then follow it.
38
+ - Alex's session on an HDR display finding the long shoulder (0.76 to the peak) flat or too colourful.
39
+ - Alex preferring one operator with no alternative. Then Neutral goes too (F3).
40
+
41
+ ## 2. What the sources say
42
+
43
+ ### ACES 2.0, Academy Output Transforms
44
+
45
+ Sources read: `aces-aswf/aces-core` (`Lib.Academy.Tonescale.ctl`, `Lib.Academy.OutputTransform.ctl`, CHANGELOG) and
46
+ `aces-aswf/aces-output`, v2.0 of 2025-04-04; the ACES 2 documentation; GT7 talk slides 116–120.
47
+
48
+ - **One family for every peak.** The CHANGELOG describes the v2 tonescale's "adaptability to produce output for any peak
49
+ luminance between 100-10000 nits". The output transforms are one CTL each, differing only in `peakLuminance`, the
50
+ limiting primaries and the encoding.
51
+ - **One of them is Shade's HDR canvas:** `Output.Academy.P3-D65_1000nit_in_P3-D65_sRGB-Piecewise`, "Extended DisplayP3
52
+ (1000 nit)". It is P3 limited and sRGB-piecewise encoded, with 1.0 at 100 cd/m², clamped at peak/100.
53
+ - **Mid-grey moves with the peak by design.** `init_TSParams` in `Lib.Academy.Tonescale.ctl` sets the grey target as
54
+ `c_t = c_d / n_r * (1 + w_i * w_g)`, where `w_i = log2(peak / 100)` and `w_g = 0.14`. The comment on `w_g` reads
55
+ "change in grey between different peak luminance". The GT7 talk says the same on slide 117: mid-grey lands at 10 to
56
+ 15 cd/m² "depending on the ODT".
57
+ - **The gamut stage is per peak.** `init_ODTParams` builds three 360-entry hue tables by search: the reach gamut's M, the
58
+ limiting gamut's cusps and the upper hull gamma. They depend on the peak. Shade's peak is a runtime value, so every
59
+ change of peak means a rebuild.
60
+ - **GT7 talk, slide 120:** ACES 2.0 support for variable HDR peaks is "Additional Work Needed".
61
+ - **What Shade has is not ACES 2.0.** `chunk_tonemap_aces` is Hill's fit of the ACES 1.0 sRGB RRT+ODT, SDR only. An HDR
62
+ ACES would be a new implementation of the JMh model and its tables, not an extension of the chunk.
63
+
64
+ ### AgX
65
+
66
+ Sources read:
67
+
68
+ - Eary Chow's `AgX` configuration and README;
69
+ - his generator, `AgX_LUT_Gen`, in particular `AgXHLG.py` and `AgXBaseRec2020.py`;
70
+ - Blender main's `release/datafiles/colormanagement/config.ocio`;
71
+ - Pestaluky's post, cited on GT7 slide 113;
72
+ - Godot master: `tonemap.glsl`, `environment_storage.cpp` and `Environment.xml`.
73
+
74
+ - **Chow's HDR view is one baked LUT.** "AgX - HDR 1000 nits" is `AgX_Rec2100-HLG_p3_lim.cube`, for a 1000 cd/m² HLG
75
+ display with reference white at 100. His README says mid-grey is "set to 18% of 100 nits".
76
+ - **Blender main ships the same.** There are two AgX views on Rec.2100 displays, "AgX - SDR" and "AgX - HDR 1000 nits".
77
+ On sRGB, Display P3 and Rec.1886 displays, AgX is SDR only.
78
+ - **The generator has one parameter, the ratio of HDR peak to SDR white.** A comment expects it to become tunable at
79
+ runtime. The HDR script is the SDR Rec.2020 script plus three steps:
80
+ - the shoulder exponent multiplied by ratio^log10(2);
81
+ - a log-space sigmoid that pulls mid-grey down to 18% of the reference white;
82
+ - a 50% "HDR purity" mix of hue and saturation.
83
+
84
+ At ratio 1 the three steps change nothing: 0.0 codes over the sweep in §3, against the same script with them off.
85
+ - **Pestaluky's curve, which Godot ships as its AgX.** It is parameterised by the output's maximum. The post says values
86
+ below the crossover do not depend on the output's range, and the crossover is mid-grey, 0.18. Above it, the shoulder
87
+ is fitted to the peak.
88
+ - Godot puts the curve between AgX's inset and outset matrices, with an AgX white of 16.29 times the peak. Its
89
+ matrices are `chunk_tonemap_agx`'s composed with the Rec.709/Rec.2020 conversions, to 1e-6.
90
+ - This landed in Godot on 2025-12-03, "Add `agx_white`, `agx_contrast` and HDR support to the AgX tonemapper". It is
91
+ in 4.7-stable and not in 4.6-stable.
92
+ - **GT7 talk, slide 120:** variable HDR peaks are "No" for AgX, as of June 2025. Slide 113 calls the HDR extension work
93
+ in progress.
94
+ - **Neither is Shade's AgX.** `chunk_tonemap_agx` is the Filament and three.js port, with a log2 encoding, a polynomial
95
+ sigmoid and a 2.2 decode. It puts 0.18 at 0.2145. Godot's form at peak 1 puts it at 0.18, and differs from the chunk by a mean of
96
+ 20.6 codes over −2 to +1 EV, 35.7 at worst. Adopting either HDR form changes Shade's SDR AgX as well.
97
+
98
+ ### Khronos PBR Neutral
99
+
100
+ Sources read: the Khronos repository (README, `pbrNeutral.glsl`, commit history to 2026-10-06) and Lalish's
101
+ model-viewer write-up.
102
+
103
+ - **No HDR form exists.** The README says the operator supports only sRGB output, and that expanding it is a goal for
104
+ the future. Since June 2024 the repository has changed only in licensing and contribution files.
105
+ - **Lalish names where to adapt it.** The single parameter, the 0.8 compression start, is "likely the most natural place
106
+ to adjust the curve to HDR output". He also writes that the choice of operator should depend on the output format.
107
+ - **GT7 talk, slide 120:** variable HDR peaks are "No" for Neutral.
108
+ - **So the HDR form is ours.** The prototype puts the peak P where the specification has 1, and keeps the start:
109
+ - p_n = P − (P − K_s)² / (p + P − 2K_s);
110
+ - the desaturation term is unchanged.
111
+
112
+ At P = 1 it is the specification: 0.0 codes over the sweep. Below K_s it is 1:1 at every P.
113
+ - **The alternative is to move the start with the peak**, 0.8·P, a literal reading of Lalish's pointer. Below 0.76 it is
114
+ identical, and above it it strays further from SDR. Up to +1 EV the worst case is 35.0 codes against 26.6, and the
115
+ mean 0.83 against 0.72. So the prototype keeps the start.
116
+
117
+ ## 3. Measured on the CPU
118
+
119
+ **References, not re-derivations:**
120
+
121
+ - **ACES 2.0:** OpenColorIO 2.6.0's `FIXED_FUNCTION_ACES_OUTPUT_TRANSFORM_20`, the Academy transform, with P3-D65
122
+ limiting primaries.
123
+ - Against OCIO's builtin `HDR-1000nit-P3-D65_2.0`, it agrees to 5e-8 in XYZ.
124
+ - Against a port of the CTL tonescale, greys agree to five digits.
125
+ - Input is Rec.709 → ACEScg (Bradford) → ACES2065-1.
126
+ - The peak at headroom H is 100·H cd/m², since ACES puts SDR white at 100.
127
+ - **AgX, Chow's:** his `AgX_Rec2100` run as written, with `HDR_max_nits` = 100·H.
128
+ - **AgX, Godot's:** a port of `tonemap.glsl` with the parameters `environment_storage.cpp` computes.
129
+ - **GT7:** a port of the engine's `tonemap_gt7` at a peak of 250·H. Against Polyphony's compiled sample code it agrees
130
+ to 0.36 codes in the mid-tones and 14.7 in saturated highlights, which is the ICtCp blend the SDR brief reports.
131
+
132
+ **Inputs:**
133
+
134
+ - Eleven hues:
135
+ - white, fire, blue, green, magenta, red, mint and a brake light;
136
+ - the product shot's canary 231,218,63, red 203,63,63 and mint 149,218,188.
137
+ - Each is scaled to luminance 0.18·2^EV, from −6 to +6 EV in quarter stops.
138
+
139
+ **Outputs** are taken as an HDR canvas shows them below SDR white: linear Display P3, clipped to 1, then 8-bit
140
+ sRGB-encoded. Each operator at peak ×H is compared with itself at peak ×1.
141
+
142
+ **At peak ×4,** a 1000 cd/m² display under the 250 cd/m² paper white:
143
+
144
+ | | mid-grey, SDR → HDR | greys equal up to | every hue equal up to | worst, at or below grey | mean, up to +1 EV |
145
+ |---|---|---|---|---|---|
146
+ | GT7 (engine) | 0.179 → 0.179 | +1.5 EV | −0.5 EV | 3.9 (blue) | 0.24 |
147
+ | ACES 2.0 | 0.100 → 0.128 (+0.35 EV) | −4.0 EV | −5.5 EV | 24.5 (blue) | 6.98 |
148
+ | AgX, Godot's | 0.180 → 0.180 | +0.25 EV | −1.5 EV | 20.9 (blue) | 2.25 |
149
+ | AgX, Chow's | 0.180 → 0.180 | 0.0 EV | −1.75 EV | 36.1 (blue) | 3.64 |
150
+ | **Neutral with a peak** | 0.140 → 0.140 | **+2.0 EV** | **0.0 EV** | **0.0** | 0.72 |
151
+
152
+ "Equal" means within half a code. EV is the input's luminance over 0.18.
153
+
154
+ - **GT7's own worst case** is a saturated blue at mid-grey luminance. Its blue channel is past the per-channel linear
155
+ section, 0.444, while its luminance is at grey.
156
+ - **Neutral's 1:1 region** runs on the largest channel too, but up to 0.76, so the same blue does not reach it.
157
+ - **Neutral's higher mean up to +1 EV** comes from saturated colours just above the start. Its worst case is the brake
158
+ light at +0.75 EV, 26.6 codes, where GT7's worst over the same range is 7.6. Neutral's SDR shoulder compresses the
159
+ largest channel hard, and at ×4 it barely compresses.
160
+
161
+ **At ×2 and ×10 the picture is the same:**
162
+
163
+ | | grey shift ×2 | ×10 | mean up to +1 EV, ×2 | ×10 |
164
+ |---|---|---|---|---|
165
+ | GT7 | 0 | 0 | 0.24 | 0.24 |
166
+ | ACES 2.0 | +0.19 EV | +0.54 EV | 3.47 | 10.89 |
167
+ | AgX, Godot's | 0 | 0 | 1.52 | 2.67 |
168
+ | AgX, Chow's | 0 | 0 | 2.12 | 4.88 |
169
+ | Neutral with a peak | 0 | 0 | 0.59 | 0.78 |
170
+
171
+ **Grey ramps,** display-linear in units of SDR white, as SDR / peak ×4:
172
+
173
+ | EV | GT7 | ACES 2.0 | AgX, Godot's | AgX, Chow's | Neutral with a peak |
174
+ |---|---|---|---|---|---|
175
+ | −2 | 0.031 / 0.031 | 0.013 / 0.016 | 0.037 / 0.037 | 0.037 / 0.037 | 0.013 / 0.013 |
176
+ | −1 | 0.078 / 0.078 | 0.040 / 0.048 | 0.085 / 0.085 | 0.084 / 0.084 | 0.050 / 0.050 |
177
+ | 0 | 0.179 / 0.179 | 0.100 / 0.128 | 0.180 / 0.180 | 0.180 / 0.180 | 0.140 / 0.140 |
178
+ | +1 | 0.360 / 0.360 | 0.209 / 0.296 | 0.331 / 0.356 | 0.326 / 0.374 | 0.320 / 0.320 |
179
+ | +2 | 0.674 / 0.720 | 0.370 / 0.612 | 0.511 / 0.664 | 0.484 / 0.759 | 0.680 / 0.680 |
180
+ | +3 | 0.992 / 1.440 | 0.556 / 1.128 | 0.684 / 1.146 | 0.632 / 1.377 | 0.935 / 1.294 |
181
+
182
+ - **GT7 and Neutral** leave greys alone until their SDR shoulders, GT7 from +1.5 EV and Neutral from +2.
183
+ - **ACES** moves every grey.
184
+ - **AgX** keeps grey itself and lifts everything above it. At +1 EV, Godot's form is 0.11 EV brighter at ×4 and Chow's
185
+ 0.20. At +2 EV they are 0.38 and 0.65 EV brighter.
186
+
187
+ **Pinning ACES's grey does not rescue it.** With `w_g` = 0 in the CTL tonescale, greys at 100 and 400 cd/m² still
188
+ differ:
189
+
190
+ | EV | −1 | 0 | +1 | +2 |
191
+ |---|---|---|---|---|
192
+ | codes | 2.8 | 0.0 | 8.0 | 25.4 |
193
+
194
+ The rest of the curve still depends on the peak, and the result would no longer be the Academy's transform.
195
+
196
+ ## 4. Measured on the device
197
+
198
+ The playground draws operators 5–7 at a peak, clipped to SDR white (`CompareLayout.Split` shows it beside the SDR form).
199
+ A one-off driver outside the repo ran it once.
200
+
201
+ ACES 2.0 and Chow's AgX were not ported to WGSL. ACES needs the JMh model and the per-peak hue tables, and Chow's form
202
+ is a LUT generated per ratio. §3 measured both through their reference implementations, so a port would re-measure
203
+ the same functions with a port's error added.
204
+
205
+ - Headless Chrome on the RTX 4090.
206
+ - The page's per-scene exposure, with bloom, TAA and SSAO off and the projection frozen.
207
+ - Each scene and operator grabbed at peak ×1, ×1 again for the noise floor, then ×4 and ×10.
208
+ - Compared per pixel in Display P3 codes, as the largest channel difference. Two grabs at ×1 differ by exactly 0 in
209
+ every scene, so the floor is zero.
210
+
211
+ **Mid-tone pixels at ×4,** those whose SDR largest channel is at most 188 (0.5 linear). Each cell gives the mean
212
+ difference in codes, the share of those pixels that differ by 2 codes or more, and the largest difference.
213
+
214
+ | scene | mid-tone share of the frame | GT7 | AgX, Godot's | Neutral with a peak |
215
+ |---|---|---|---|---|
216
+ | fire and emitters | 66–70% | 0 · 0% · 0 | 0.91 · 10.5% · 18 | 0 · 0% · 0 |
217
+ | sunlit exterior | 39–40% | 0.008 · 0% · 1 | 5.22 · 87.6% · 23 | 0 · 0% · 0 |
218
+ | dim interior | 83–87% | 0 · 0% · 1 | 1.43 · 20.5% · 23 | 0 · 0% · 0 |
219
+ | product shot | 5–9% | 0.006 · 0% · 1 | 7.15 · 59.0% · 24 | 0 · 0% · 0 |
220
+
221
+ The mid-tone share varies with the operator, because each one's own SDR frame decides which pixels count.
222
+
223
+ At ×10, GT7 and Neutral are unchanged. AgX's means grow to 1.10, 6.25, 1.71 and 8.70.
224
+
225
+ Between 0.5 and SDR white every form differs by design, because the HDR form has headroom there. Over all pixels below
226
+ SDR white, the means at ×4 are 0.2–9.2 codes for GT7, 0.8–14.2 for Neutral and 3.4–34.3 for AgX.
227
+
228
+ ## 5. What each recommendation means for the code
229
+
230
+ **Removing ACES (F1):**
231
+
232
+ - `chunk_tonemap_aces.js` (`chunk_tonemap_aces`) goes.
233
+ - The npm package exports `./src/*`, so the deep import breaks for any downstream user. In this repo only the playground
234
+ imports it, as grid quadrant 1.
235
+ - The CPU `core/color/tonemap/tonemap_aces.js` stays. It is not Shade's tone mapping, and `PathTracedRenderer`
236
+ (`engine/graphics/sh3/path_tracer`) calls it.
237
+
238
+ **Removing AgX (F2):**
239
+
240
+ - `chunk_tonemap_agx.js` (`chunk_tonemap_agx`) goes. The same deep-import break applies. In the repo, only playground
241
+ quadrant 3 imports it.
242
+ - The playground's `chunk_tonemap_agx_peak.js` goes with it.
243
+
244
+ **Adding Neutral (F3):**
245
+
246
+ - `ShadeToneMappingMode.PBR_NEUTRAL`, with two concrete passes beside the GT7 and NONE pairs:
247
+ `shader_tonemap_LDR_pbr_neutral` at peak 1, and `shader_tonemap_HDR_pbr_neutral` at the display's peak over the paper
248
+ white.
249
+ - `chunk_tonemap_khronos_pbr` takes the peak. Its WGSL signature changes from `tonemap_khronos_pbr(c)` to
250
+ `tonemap_khronos_pbr(c, peak)`, a break for any WGSL caller outside the repo. The import path stays.
251
+ - **The paper white becomes a canvas convention, not GT7's.** Neutral's HDR pass divides the display's peak by the same
252
+ 250 cd/m² that puts SDR white at the canvas's 1.0. So `chunk_GT7_PAPER_WHITE_NITS` moves out of `gt7/` under a
253
+ name of its own, which is an import-path change too.
254
+ - **Mid-grey sits lower.** Neutral puts an exposed 0.18 at 0.140 (the 0.04 Fresnel offset), where GT7 puts it at 0.179.
255
+ Switching modes darkens mid-grey by 0.36 EV. Auto-exposure meters the scene, not the output, so it will not
256
+ compensate.
257
+ - **Pins:** the LDR pass equals the specification within float precision, and the HDR pass equals the LDR pass below the
258
+ start. Both are plain tests in the style of `shader_tonemap_HDR.spec.js`.
259
+ - **Not measured:** Neutral's HDR highlights on an HDR display. This box's headless Chrome reports an SDR display, so §4
260
+ covers only what lies below SDR white.
261
+
262
+ **In every case:**
263
+
264
+ - **`chunk_tonemap_pbr_neutral.js` goes.** It is the Filament-derived duplicate that mixes toward 1 instead of the
265
+ compressed peak (SDR brief §4.3). Nothing imports it.
266
+ - **The playground's grid** loses each quadrant whose chunk goes. It either drops them or keeps copies beside the page,
267
+ as it does for the GT7 sample code.
268
+
269
+ ## 6. Forks for Alex, all three taken
270
+
271
+ - **F1. Remove ACES.** Delete `chunk_tonemap_aces.js` and drop it from the playground. The CPU `tonemap_aces` stays.
272
+ - **F2. Remove AgX.** Delete `chunk_tonemap_agx.js` and the playground's `chunk_tonemap_agx_peak.js`, and drop AgX from
273
+ the playground.
274
+ - **F3. Add `ShadeToneMappingMode.PBR_NEUTRAL`** with the peak form, moving the paper white out of `gt7/`. Delete
275
+ `chunk_tonemap_pbr_neutral.js` either way.
276
+ - If declined, Neutral goes too: delete `chunk_tonemap_khronos_pbr.js` and the playground's
277
+ `chunk_tonemap_pbr_neutral_peak.js`. The folder is then GT7 alone.
278
+ - If accepted, it waits on nothing else. The shader-switch proposal can later fold each mode's pair of passes into
279
+ one, as it would GT7's.
280
+
281
+ **Landed 2026-10-16:**
282
+
283
+ - `822dbc789`: the paper white leaves `gt7/`, as `chunk_PAPER_WHITE_NITS`.
284
+ - `1851d9030`, F3: `ShadeToneMappingMode.PBR_NEUTRAL` with `shader_tonemap_LDR_pbr_neutral` and
285
+ `shader_tonemap_HDR_pbr_neutral`, and `tonemap_khronos_pbr(color, peak)`. The HDR pass floors the peak at the paper
286
+ white, where the operator is defined. On the RTX 4090 the engine's SDR canvas equals the specification to the code,
287
+ and its emulated-HDR canvas is within the SDR dither, 1 code, at or under 0.5.
288
+ - `df9eb7694`, F1 and F2: the ACES, AgX and duplicate Neutral chunks are gone, along with `chunk_RRTAndODTFit`, the
289
+ ACES fit only the ACES chunk used. The playground compares GT7 and PBR Neutral.
290
+
291
+ ## 7. Not in scope, noticed
292
+
293
+ - `chunk_tonemap_hdr_bt2390.js` and `chunk_tonemap_reinhard_luma.js` in the same folder have no importers either.
294
+ - The doc comment on the playground's `chunk_tonemap_gt7_sdr_reference.js` still lists four departures of the engine's
295
+ `tonemap_gt7` from the sample code. Since `6ea10df28` only the blend space differs.
296
+ - The playground's environment maps are untracked under `packages/meep-engine/test_assets/`. A worktree has none until
297
+ they are copied in, and the page then lights the exterior and the product shot with a flat sky.
298
+
299
+ ## Sources
300
+
301
+ - Academy Software Foundation, ACES 2.0 core library and output transforms:
302
+ - https://github.com/aces-aswf/aces-core (`lib/Lib.Academy.Tonescale.ctl`, `lib/Lib.Academy.OutputTransform.ctl`,
303
+ `CHANGELOG.md`)
304
+ - https://github.com/aces-aswf/aces-output (`d65/displayP3/Output.Academy.P3-D65_1000nit_in_P3-D65_sRGB-Piecewise.ctl`)
305
+ - OpenColorIO 2.6.0 (PyPI `opencolorio`), `FIXED_FUNCTION_ACES_OUTPUT_TRANSFORM_20`.
306
+ - E. Chow:
307
+ - AgX configuration: https://github.com/EaryChow/AgX
308
+ - LUT generator: https://github.com/EaryChow/AgX_LUT_Gen (`AgXHLG.py`)
309
+ - Blender, `release/datafiles/colormanagement/config.ocio`, main: https://projects.blender.org/blender/blender
310
+ - A. Pestaluky, "An Adjustable Tonemapping Curve for Variable / Extended Dynamic Range", 2025-05-29:
311
+ https://allenwp.com/blog/2025/05/29/allenwp-tonemapping-curve/
312
+ - Godot Engine, master and 4.7-stable:
313
+ - `servers/rendering/renderer_rd/shaders/effects/tonemap.glsl`
314
+ - `servers/rendering/storage/environment_storage.cpp`
315
+ - `doc/classes/Environment.xml`
316
+ - Khronos, PBR Neutral: https://github.com/KhronosGroup/ToneMapping/tree/main/PBR_Neutral
317
+ - E. Lalish, "Tone Mapping Considerations for Physically-Based Rendering": https://modelviewer.dev/examples/tone-mapping
318
+ - Polyphony Digital, "Driving Toward Reality", SIGGRAPH 2025 PBS course, slides 113–120 and 154.
@@ -0,0 +1,237 @@
1
+ # SDR tone mapping: a brief (2026-10-16)
2
+
3
+ **Status: decided and built.** Alex chose GT7 on every output, with no per-output selector (§6). F1 landed first; F2 and
4
+ F3 landed with `ShadeToneMappingMode`, whose modes were then `GT7` and `NONE`. The HDR forms brief beside this one
5
+ then added `PBR_NEUTRAL` and removed the ACES and AgX chunks. The playground `src/shade/playground/tonemap_sdr/`
6
+ compares GT7 and PBR Neutral.
7
+
8
+ ## 1. Recommendation
9
+
10
+ **Make GT7's SDR mode the SDR default, exactly as Polyphony's sample code defines it.** The curve's peak is the
11
+ 250 cd/m² SDR paper white, and the result is scaled by 1/2.5. Shade's exposed 1.0 maps to that paper white.
12
+
13
+ - It is the operator the HDR path already runs, and the source designs it so that SDR and HDR look alike.
14
+ - It keeps the mid-tones linear: an exposed 0.18 comes out at 0.179.
15
+ - Product colours come out within a few codes of their base colour.
16
+
17
+ **The cost is highlight range.** GT7's SDR shoulder clips at 1.43× paper white, three stops above mid-grey. ACES
18
+ reaches 6.5 stops, AgX 6.4 and Neutral 5.2. Polyphony accept the clip and lean on glare to carry what it removes;
19
+ Shade's bloom, on by default, plays that part.
20
+
21
+ **What would reverse it:** the clip reading as harsh in your session, in sunlit whites or skies, with bloom on. Neutral
22
+ is then the default, at the price of SDR and HDR looking different.
23
+
24
+ Four forks needed an answer first (§5). The first, the canvas primaries, was a defect every SDR frame showed, whichever
25
+ operator was chosen.
26
+
27
+ ## 2. What the sources say
28
+
29
+ ### GT7: Polyphony's 2025 talk, sample code, and earlier talks
30
+
31
+ Sources read:
32
+
33
+ - "Driving Toward Reality", SIGGRAPH 2025 Physically Based Shading course, with speaker notes. There are no separate
34
+ course notes for this talk. Four copies were read, and they agree on everything cited here:
35
+ - slides v1.0 and v1.1 from the course page;
36
+ - the PDF on Polyphony's publications page;
37
+ - the PowerPoint there, whose hidden slides show which slides were not presented live.
38
+ - `gt7_tone_mapping.cpp`, the sample code (MIT), from the course page.
39
+ - The 2018 GT Sport talk notes.
40
+ - Polyphony's CEDEC 2026 "Beyond HDR" deck, in Japanese.
41
+
42
+ The authors do address SDR specifically:
43
+
44
+ - **SDR is the same curve, with a fixed peak.** The peak is the paper white: 250 cd/m², 2.5 frame-buffer units, because
45
+ their frame buffer has 1.0 = 100 cd/m². The output is then multiplied by 1/2.5, so the paper white lands at sRGB 1.0.
46
+ This is on slide 153, which is hidden in the presented deck. It is in every published PDF, and `initializeAsSDR()`
47
+ in the sample code does the same.
48
+
49
+ The code comment in `initializeAsSDR()` says what the scaling is for (MIT, quoted):
50
+
51
+ > These adjustments ensure that the visual appearance (in terms of brightness) stays generally consistent across
52
+ > both HDR and SDR outputs
53
+
54
+ - **SDR is the baseline the parameters were tuned on.** `initializeAsHDR()` accepts peaks from 250 up, "because the
55
+ parameters for GTToneMappingCurveV2 were determined based on an SDR paper white assumption of 250 nits" (MIT).
56
+ - **One curve for every display is the design goal.** HDR is "a natural extension of SDR" (slide 27). Changing the peak
57
+ lets the same curve serve SDR and HDR (slide 135). Consistency across SDR and HDR is listed as a strength (slide 137).
58
+ - **The clip is deliberate.** The v2 shoulder has a sharp clipping point. Polyphony accepted it because TVs tone map
59
+ as well (slide 147). A desktop sRGB monitor does not, so on one the clip is final.
60
+ - **Glare compensates on SDR.** Glare is drawn wider on SDR than on HDR, which treats the peak-luminance gap as an
61
+ aperture difference (slide 184).
62
+ - **Their operator comparison was made in SDR**, and they say it carries over to HDR (slide 154). ACES maps 0.18 to
63
+ about 10 cd/m², roughly 1/1.8 of the 18 cd/m² other operators give (slide 117, hidden in the presented deck). They
64
+ scaled ACES to match exposure before comparing.
65
+ - **ICtCp builds the "untwisted" colour; the final blend is in RGB.**
66
+ - Steps 2 and 3 (slides 148–149) work in the UCS, ICtCp in the sample code. The untwisted colour takes its intensity
67
+ from the per-channel colour and its chroma from the original, faded toward the peak.
68
+ - Step 4 (slide 150, presented) lerps the per-channel and untwisted colours in linear Rec.2020 RGB. The slide says
69
+ they tried blending in the UCS and found RGB looked better to them; the speaker note says the same. The code on
70
+ slides 153 and 243 blends in RGB.
71
+ - The hidden slide 153 adds that blending in a UCS works as well. The engine's chunk takes that route (§4.2).
72
+ - **The SDR white moved between titles.** The 2018 GT Sport notes define SDR maximum brightness as 100 cd/m² (p. 66).
73
+ GT7 assumes 250.
74
+ - **CEDEC 2026** repeats the policy of one physically based tone mapping across SDR and HDR (p. 82). It adds nothing
75
+ on SDR parameters.
76
+ - **Not stated anywhere:** the auto-exposure target. Where mid-grey lands in GT7's own SDR output cannot be known from
77
+ the talk. Shade's convention decides it (§3).
78
+
79
+ ### Khronos PBR Neutral (Emmett Lalish)
80
+
81
+ - Built for e-commerce. The Khronos repository (CC-BY 4.0) describes it as "aimed toward product photography use
82
+ cases, where the scene is well-exposed and HDR color values are mostly restricted to small specular highlights".
83
+ - Below 0.8, base colours are reproduced 1:1, less the 0.04 Fresnel offset. Hue is never shifted, and highlights
84
+ desaturate smoothly to white.
85
+ - sRGB output only, with no gamut mapping.
86
+ - The model-viewer write-up proposes it as an option where tools offer several operators, and as the default where they
87
+ offer one. It also says plainly that film and games want something else.
88
+
89
+ ### AgX (Eary Chow's, the one Blender, Godot and three.js use)
90
+
91
+ - Made to replace Blender's Filmic. It forms a closed-domain image with smooth chromatic attenuation, for wide-gamut
92
+ and spectral rendering.
93
+ - 16.5 stops of range. It is meant to be used with looks; "Punchy" is the contrast one.
94
+ - Chow's configuration has a 1000 cd/m² HDR view. The LUT everyone ships, and the three.js port Shade's chunk comes
95
+ from, are SDR only (talk slide 113).
96
+
97
+ ## 3. Measured
98
+
99
+ The CPU ports are line-for-line from each source. The GT7 port was checked against Polyphony's code compiled with MSVC:
100
+ 1.8e-4 over 648 inputs. The WGSL port in the playground was checked against the same outputs on the RTX 4090: 4.4e-4.
101
+ Inputs are exposed linear Rec.709. Outputs are display-linear, with sRGB codes in brackets.
102
+
103
+ | | 0.18 out | contrast at 0.18 | white reached at | 0.8 grey | canary 231,218,63 | red 203,63,63 |
104
+ |---|---|---|---|---|---|---|
105
+ | ACES (today) | 0.106 (91) | 1.48 | +6.5 EV | 195 | 196,187,67 | 175,29,38 |
106
+ | **GT7 SDR** (reference, 1.0 = paper white) | 0.179 (117) | 1.05 | +3.0 EV | 221 | 224,212,61 | 201,58,58 |
107
+ | GT7 SDR, literal frame buffer (1.0 = 100 cd/m²) | 0.058 (68) | 1.34 | +4.3 EV | 153 | 153,144,31 | 130,28,31 |
108
+ | AgX | 0.215 (128) | 0.80 | +6.4 EV | 194 | 197,185,121 | 204,97,87 |
109
+ | Neutral | 0.140 (105) | 1.29 | +5.2 EV | 226 | 227,213,34 | 198,34,34 |
110
+
111
+ "Contrast" is d log out / d log in. "White reached at" is the exposure, in stops over 0.18, where output reaches 0.99.
112
+
113
+ **Saturated emitters, as exposure rises:**
114
+
115
+ - ACES walks fire orange from 18° to 47° by +4 EV: it turns yellow. It also takes neon blue toward cyan.
116
+ - GT7 holds hue through the mid-tones, then whitens sharply. Fire is pale yellow by +2 EV and white by +4.
117
+ - Neutral never moves hue. Fire whitens through a pinkish white rather than yellow.
118
+ - AgX desaturates even at normal exposure: fire is at saturation 0.76 at +0 EV, where the others are at 0.95–0.97.
119
+
120
+ **Mapping Shade's exposure onto GT7's frame buffer** is the one free parameter, and it is only an exposure offset of
121
+ 1.32 stops. Shade's auto-exposure puts its meter at 0.18, a fraction of paper white. Reading that as GT7's paper white
122
+ (×2.5) lands 0.18 at 0.179, as other operators do. It also matches the HDR path, which normalises by the paper white
123
+ the same way. Reading it literally (1.0 = 100 cd/m²) darkens SDR mid-tones to 0.058.
124
+
125
+ ## 4. Engine findings that bear on the choice (measured)
126
+
127
+ 1. **The SDR path shows Rec.709 values as Display P3.** `Renderer` configures the canvas `colorSpace: 'display-p3'` on
128
+ both paths. `shader_tonemap_HDR` converts to P3, but `shader_tonemap_LDR` writes Rec.709 values without converting.
129
+
130
+ A `display-p3` canvas was cleared to known values and read back through a 2D sRGB canvas:
131
+
132
+ | colour | intended | as-is |
133
+ |---|---|---|
134
+ | ACES red | 175,29,38 | 191,0,28 |
135
+ | Neutral red | 198,34,34 | 216,0,16 |
136
+ | canary yellow | 227,213,34 | 230,212,0 |
137
+
138
+ Converted to P3 first, each reproduces exactly. Grey is unaffected.
139
+
140
+ In the upstream repository, the commit that tagged the canvas `display-p3` (`105e8eec`, 2025-12-22, "finished HDR
141
+ mapper") also switched SDR from Khronos PBR Neutral to ACES. Under this mismatch Neutral's saturated output is pushed
142
+ furthest, so ACES may have been picked against a skewed picture. The commit does not say why it switched.
143
+ 2. **The engine's `tonemap_gt7` is not Polyphony's.** It differs from the sample code in four ways:
144
+
145
+ | | engine | sample code |
146
+ |---|---|---|
147
+ | weight of the per-channel colour | 0.7 | 0.4 (`blendRatio_` 0.6 weights the untwisted one) |
148
+ | final blend in | ICtCp | linear Rec.2020 RGB; the talk says a UCS also works (§2) |
149
+ | chroma fade | fixed PQ window 0.7–1.0 | 0.98–1.16 of the target's own intensity |
150
+ | clamp at the target | no | yes |
151
+
152
+ The overshoot comes from the other three differences, not the blend space. Adding them to the engine's chunk one at
153
+ a time:
154
+ - **The clamp alone** brings HDR white from 11.85 to 10.00, and blue at +5 EV from 15.2 to 10.5.
155
+ - **At SDR,** the fade and the weight carry most of the gap. The canary yellow at +1.75 EV goes from 255,255,131 to
156
+ 135 with the clamp, to 186 with the fade, and to 216 with the weight.
157
+ - **The blend space alone** separates 216 from the sample code's 224. For fire at +2 EV it separates 192 from 197.
158
+
159
+ Mid-tones are identical: 0.18 → 0.145 in HDR at 1000/100 for both. Near and above the peak they part:
160
+ - in HDR at 1000 cd/m², white reaches 11.85 against the target 10.0, 18.5% over the assumed peak;
161
+ - saturated blue at +5 EV reaches 15.2 in its blue channel, against the sample code's 10.6;
162
+ - at SDR settings (250/250), the canary yellow at +1.75 EV comes out 255,255,131 against the sample code's
163
+ 255,255,224, a 93-code gap. It holds chroma, then clips per channel.
164
+ 3. **Two Neutral chunks.** `chunk_tonemap_khronos_pbr` matches the specification. `chunk_tonemap_pbr_neutral`, taken
165
+ from Filament, mixes toward 1.0 instead of the compressed peak. Grey 2.0 comes out 0.965 instead of 0.960, and grey
166
+ 32 comes out 1.000 instead of 0.998. No renderer shader imports either; the playground imports the specification one.
167
+ 4. **The ACES chunk is the Hill fit without three.js's 1/0.6.** Its comment still describes the 1/0.6 scale, which the
168
+ code does not apply. It maps 0.18 to 0.106; three.js maps it to 0.213.
169
+ 5. **The HDR path's paper white is 100** (`Renderer.js`, `paper_white_nits: 100`). GT7 puts SDR white at 250. With 100,
170
+ an exposed 0.18 shows at 0.145 of SDR white in HDR and at 0.179 in GT7 SDR.
171
+
172
+ ## 5. Forks to answer before the default changes
173
+
174
+ - **F1, the SDR primaries (§4.1).** I recommend `shader_tonemap_LDR` convert to Display P3, as the HDR shader does,
175
+ rather than configuring an SDR canvas `srgb`. Then GT7's Rec.2020 output keeps its P3 gamut on wide-gamut SDR
176
+ laptops.
177
+
178
+ Both paths already assume the `display-p3` configure succeeds. Their shared fallback to `srgb` is untreated, and that
179
+ is a separate item. F1 changes every SDR frame's saturation, so it is its own commit, pinned before any operator
180
+ change.
181
+ - **F2, align `tonemap_gt7` with the sample code (§4.2).** I recommend the clamp, the fade and the weight. Keeping
182
+ the ICtCp blend is a choice the talk allows. It costs up to 0.3 codes in the mid-tones and up to 14 in saturated
183
+ highlights, over 648 inputs. It changes HDR highlights near the peak and nothing in the mid-tones.
184
+
185
+ Declining means GT7 SDR would run the engine's variant, which overshoots and clips per channel at SDR. I would then
186
+ reconsider GT7 as the default, or add at least the clamp.
187
+ - **F3, the paper white.** I recommend SDR at 250 with exposed 1.0 as the paper white (§3), and the HDR path at 250 as
188
+ well (§4.5), so both put an exposed 0.18 at the same fraction of SDR white. The HDR change brightens HDR mid-tones by
189
+ 0.3 stops.
190
+ - **F4, the selector (§6).** Superseded: Alex chose one mode for every output instead of an SDR selector.
191
+
192
+ ## 6. What was built
193
+
194
+ Alex decided against a per-output selector. The tone mapper is one choice for every display, which is the reason the
195
+ GT7 talk gives for its operator. So there is no SDR setting, and the renderer offers two modes:
196
+
197
+ ```js
198
+ renderer.tone_mapping_mode = ShadeToneMappingMode.GT7; // the default
199
+ renderer.tone_mapping_mode = ShadeToneMappingMode.NONE; // exposure only; SDR clips at 1.0, HDR at the display
200
+ ```
201
+
202
+ - **Four concrete passes.** The output's dynamic range and the mode pick the pass:
203
+ - `shader_tonemap_LDR` and `shader_tonemap_HDR` for GT7;
204
+ - `shader_tonemap_LDR_none` and `shader_tonemap_HDR_none` for NONE.
205
+
206
+ Each module lists its own chunks, so a mode's dependencies are visible. No `override`, no runtime branch on a
207
+ setting. If shader switches land, each pair can become one pass with a choice.
208
+ - **The paper white is a convention, not a setting.** `chunk_GT7_PAPER_WHITE_NITS` (250) is the paper white on both
209
+ outputs, and SDR also uses it as the peak. Below the SDR shoulder the two outputs therefore write the same colour:
210
+ pinned in `shader_tonemap_HDR.spec.js`. The HDR pass's only setting is the display's peak.
211
+ - **`tonemap_gt7` follows the sample code** in the curve, the relative chroma fade, the 0.6 untwisted weight and the
212
+ clamp at the target, and keeps the ICtCp blend (F2). Against the compiled sample code over 648 inputs it differs by up
213
+ to 0.3 sRGB codes in the mid-tones and up to 14 in saturated highlights. An earlier draft of this brief said "at most
214
+ 8", from four hand-picked cases; the full sweep says 14.
215
+ - **ACES, AgX and Neutral were unwired** here, kept for a look at HDR-aware variants of each.
216
+ `HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md` took that look: ACES and AgX are removed, and Neutral is
217
+ `ShadeToneMappingMode.PBR_NEUTRAL`, with the display's peak in place of the specification's 1 on HDR.
218
+
219
+ ## 7. Follow-ups this turned up, not done
220
+
221
+ - The `srgb` fallback in `Renderer`'s canvas configure is untreated by both tonemap shaders (§5, F1).
222
+ - `make_sunlight` hands `kelvin_to_rgb`'s sRGB-encoded triple to `Light.color`, which is documented as linear.
223
+ Not measured.
224
+ - `chunk_tonemap_pbr_neutral` duplicated the specification chunk with a difference (§4.3). Removed with the HDR forms
225
+ brief's F3.
226
+
227
+ ## Sources
228
+
229
+ - Polyphony Digital, "Driving Toward Reality: Physically Based Tone Mapping and Perceptual Fidelity in Gran Turismo 7",
230
+ SIGGRAPH 2025 PBS course: https://blog.selfshadow.com/publications/s2025-shading-course/ (slides v1.1,
231
+ `pdi/supplemental/gt7_tone_mapping.cpp`).
232
+ - Uchimura and Suzuki, "Practical HDR and Wide Color Techniques in Gran Turismo SPORT", SIGGRAPH Asia 2018, with notes:
233
+ https://www.polyphony.co.jp/publications/sa2018/
234
+ - Polyphony Digital and Sony, "Beyond HDR", CEDEC 2026: https://www.polyphony.co.jp/publications/
235
+ - Khronos, PBR Neutral specification: https://github.com/KhronosGroup/ToneMapping/tree/main/PBR_Neutral
236
+ - E. Lalish, "Tone Mapping Considerations for Physically-Based Rendering": https://modelviewer.dev/examples/tone-mapping
237
+ - E. Chow, AgX for Blender: https://github.com/EaryChow/AgX
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The luminance an exposed scene value of 1.0 is shown at, in cd/m², on every display and in every tone mapping mode.
3
+ * It is where the canvas puts SDR white: 1.0 on an SDR output, and 1.0 of extended Display P3 on an HDR one, so an HDR
4
+ * pass's headroom is the display's peak over this.
5
+ *
6
+ * The value is the SDR paper white of GT7's sample code, `GRAN_TURISMO_SDR_PAPER_WHITE`. Polyphony tuned the curve's
7
+ * parameters under this assumption; their sample code accepts no HDR peak below it. The GT7 passes give it to
8
+ * `tonemap_gt7` as the paper white, and the SDR pass also as the peak, which is the sample code's SDR mode.
9
+ *
10
+ * It is one constant rather than an argument for each pass, so the SDR and HDR outputs cannot drift apart.
11
+ *
12
+ * @see "Driving Toward Reality: Physically Based Tone Mapping and Perceptual Fidelity in Gran Turismo 7", slide 153
13
+ * @type {CodeChunk}
14
+ */
15
+ export const chunk_PAPER_WHITE_NITS: CodeChunk;
16
+ import { CodeChunk } from "../../../compiler/CodeChunk.js";
17
+ //# sourceMappingURL=chunk_PAPER_WHITE_NITS.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk_PAPER_WHITE_NITS.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,qCAFU,SAAS,CAOjB;0BArBwB,gCAAgC"}
@@ -0,0 +1,22 @@
1
+ import { CodeChunk } from "../../../compiler/CodeChunk.js";
2
+
3
+ /**
4
+ * The luminance an exposed scene value of 1.0 is shown at, in cd/m², on every display and in every tone mapping mode.
5
+ * It is where the canvas puts SDR white: 1.0 on an SDR output, and 1.0 of extended Display P3 on an HDR one, so an HDR
6
+ * pass's headroom is the display's peak over this.
7
+ *
8
+ * The value is the SDR paper white of GT7's sample code, `GRAN_TURISMO_SDR_PAPER_WHITE`. Polyphony tuned the curve's
9
+ * parameters under this assumption; their sample code accepts no HDR peak below it. The GT7 passes give it to
10
+ * `tonemap_gt7` as the paper white, and the SDR pass also as the peak, which is the sample code's SDR mode.
11
+ *
12
+ * It is one constant rather than an argument for each pass, so the SDR and HDR outputs cannot drift apart.
13
+ *
14
+ * @see "Driving Toward Reality: Physically Based Tone Mapping and Perceptual Fidelity in Gran Turismo 7", slide 153
15
+ * @type {CodeChunk}
16
+ */
17
+ export const chunk_PAPER_WHITE_NITS = CodeChunk.from(
18
+ //language=WGSL
19
+ `
20
+ const PAPER_WHITE_NITS: f32 = 250.0;
21
+ `
22
+ );
@@ -1,6 +1,19 @@
1
1
  /**
2
+ * Khronos PBR Neutral, with the display's peak in place of the specification's 1.
2
3
  *
3
- * @see https://www.shadertoy.com/view/lXSBzt
4
+ * - At `peak` 1 it is the specification: base colours under 0.8 come out 1:1, less the 0.04 Fresnel offset, and a
5
+ * highlight compresses toward 1 and desaturates toward white.
6
+ * - At a higher peak the compression starts at the same place, converges on the peak instead of 1, and desaturates by
7
+ * how much it compressed. Below the start every peak writes the same colour, so an SDR and an HDR display agree
8
+ * there.
9
+ *
10
+ * The specification has no HDR form. Lalish's write-up names the 0.8 start as the place to adapt it. Keeping the start
11
+ * where it is, rather than moving it with the peak, keeps SDR and HDR closest; HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md
12
+ * beside this file has the measurements.
13
+ *
14
+ * Input: non-negative linear Rec.709. Output: linear Rec.709, never above `peak`, which must be at least 1.
15
+ *
16
+ * @see https://github.com/KhronosGroup/ToneMapping/tree/main/PBR_Neutral
4
17
  * @see https://modelviewer.dev/examples/tone-mapping
5
18
  * @type {CodeChunk}
6
19
  */
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_tonemap_khronos_pbr.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_khronos_pbr.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wCAFU,SAAS,CA4BjB;0BAlCwB,gCAAgC"}
1
+ {"version":3,"file":"chunk_tonemap_khronos_pbr.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_khronos_pbr.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wCAFU,SAAS,CA4BjB;0BA/CwB,gCAAgC"}