@woosh/meep-engine 3.60.4 → 3.60.6

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 (419) hide show
  1. package/CHANGELOG.md +2621 -0
  2. package/CONTRIBUTING.md +7 -0
  3. package/MIGRATION_2_TO_3.md +136 -0
  4. package/SECURITY.md +4 -0
  5. package/editor/EditorCameraNavigation.d.ts +2 -1
  6. package/editor/EditorCameraNavigation.d.ts.map +1 -1
  7. package/editor/EditorCameraNavigation.js +51 -57
  8. package/package.json +6 -2
  9. package/src/engine/EngineHarness.d.ts +3 -9
  10. package/src/engine/EngineHarness.d.ts.map +1 -1
  11. package/src/engine/EngineHarness.js +6 -8
  12. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts +9 -6
  13. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts.map +1 -1
  14. package/src/engine/graphics/camera/makeOrbitalCameraController.js +44 -71
  15. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts +64 -0
  16. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts.map +1 -0
  17. package/src/engine/graphics/camera/orbital/MomentumAxis.js +187 -0
  18. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts +86 -0
  19. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts.map +1 -0
  20. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.js +319 -0
  21. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +34 -10
  22. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
  23. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +116 -30
  24. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts +1 -7
  25. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  26. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +1 -37
  27. package/src/engine/graphics/ecs/water/Water.d.ts +8 -0
  28. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  29. package/src/engine/graphics/ecs/water/Water.js +8 -0
  30. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  31. package/src/engine/graphics3/WaterSystem.js +731 -734
  32. package/src/engine/graphics3/decal/DecalTileShader.d.ts +61 -0
  33. package/src/engine/graphics3/decal/DecalTileShader.d.ts.map +1 -0
  34. package/src/engine/graphics3/decal/DecalTileShader.js +138 -0
  35. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts +10 -4
  36. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
  37. package/src/engine/graphics3/decal/GPUDecalRenderer.js +149 -44
  38. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts +25 -0
  39. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts.map +1 -0
  40. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.js +55 -0
  41. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts +22 -0
  42. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts.map +1 -0
  43. package/src/engine/graphics3/decal/graph_gather_decal_tiles.js +70 -0
  44. package/src/engine/graphics3/decal/shader_decal_composite.d.ts +7 -5
  45. package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
  46. package/src/engine/graphics3/decal/shader_decal_composite.js +48 -44
  47. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts +12 -0
  48. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts.map +1 -0
  49. package/src/engine/graphics3/decal/shader_decal_tile_copy.js +78 -0
  50. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts +11 -0
  51. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts.map +1 -0
  52. package/src/engine/graphics3/decal/shader_gather_decal_tiles.js +80 -0
  53. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts +13 -0
  54. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts.map +1 -0
  55. package/src/engine/input/devices/mouse/MouseEventButtons.js +23 -0
  56. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts +4 -0
  57. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts.map +1 -1
  58. package/src/engine/input/ecs/controllers/KeyboardCameraController.js +9 -45
  59. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  60. package/src/shade/playground/water_refraction/README.md +5 -6
  61. package/src/shade/playground/water_refraction/index.html +1 -1
  62. package/src/shade/renderer/Renderer.d.ts +11 -0
  63. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  64. package/src/shade/renderer/Renderer.js +50 -6
  65. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
  66. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  67. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
  68. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  69. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  70. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  71. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  72. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  73. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +28 -45
  74. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  75. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +111 -119
  76. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +22 -3
  77. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  78. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +84 -3
  79. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts +19 -0
  80. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts.map +1 -0
  81. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.js +25 -0
  82. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
  83. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
  84. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
  85. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +15 -0
  86. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -1
  87. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +38 -0
  88. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
  89. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
  90. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
  91. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
  92. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
  93. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +28 -59
  94. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts.map +1 -1
  95. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +84 -789
  96. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  97. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -8
  98. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +7 -6
  99. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  100. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +12 -11
  101. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -2
  102. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +2 -2
  103. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +1 -4
  104. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  105. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +1 -10
  106. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
  107. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
  108. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
  109. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  110. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
  111. package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
  112. package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
  113. package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
  114. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
  115. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
  116. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
  117. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
  118. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
  119. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
  120. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
  121. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  122. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
  123. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
  124. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
  125. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
  126. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
  127. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
  128. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
  129. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
  130. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
  131. package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
  132. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
  133. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  134. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
  135. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
  136. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
  137. package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
  138. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  139. package/src/shade/renderer/material/GPUMaterialManager.d.ts +11 -1
  140. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  141. package/src/shade/renderer/material/GPUMaterialManager.js +16 -8
  142. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
  143. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  144. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
  145. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +7 -3
  146. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
  147. package/src/shade/renderer/postprocess/gtao/GTAO.js +26 -13
  148. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts +14 -0
  149. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  150. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +196 -68
  151. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
  152. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +42 -28
  153. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
  154. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +429 -414
  155. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts +16 -0
  156. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts.map +1 -0
  157. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.js +156 -0
  158. package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -2
  159. package/src/shade/renderer/scene/GPUSceneContext.js +5 -5
  160. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  161. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
  162. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
  163. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  164. package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
  165. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
  166. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
  167. package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
  168. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  169. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  170. package/src/shade/renderer/water/shader_water.js +22 -13
  171. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  172. package/src/shade/renderer/water/shader_water_avboit.js +7 -7
  173. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
  174. package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
  175. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
  176. package/editor/REWORK_PLAN_2026_08.md +0 -692
  177. package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
  178. package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
  179. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
  180. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
  181. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
  182. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
  183. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
  184. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
  185. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
  186. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
  187. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
  188. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
  189. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
  190. package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
  191. package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
  192. package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
  193. package/src/REVIEW_2026_08_06/adv-core.md +0 -511
  194. package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
  195. package/src/REVIEW_2026_08_06/adv-view.md +0 -446
  196. package/src/REVIEW_2026_08_06/api-core.md +0 -296
  197. package/src/REVIEW_2026_08_06/api-engine.md +0 -195
  198. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
  199. package/src/REVIEW_2026_08_06/core-binary.md +0 -348
  200. package/src/REVIEW_2026_08_06/core-collection.md +0 -376
  201. package/src/REVIEW_2026_08_06/core-math.md +0 -221
  202. package/src/REVIEW_2026_08_06/core-process.md +0 -266
  203. package/src/REVIEW_2026_08_06/core-science.md +0 -223
  204. package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
  205. package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
  206. package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
  207. package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
  208. package/src/REVIEW_2026_08_06/engine-input.md +0 -197
  209. package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
  210. package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
  211. package/src/REVIEW_2026_08_06/generation.md +0 -176
  212. package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
  213. package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
  214. package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
  215. package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
  216. package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
  217. package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
  218. package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
  219. package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
  220. package/src/REVIEW_2026_08_06/view.md +0 -667
  221. package/src/REVIEW_2026_08_06.md +0 -610
  222. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
  223. package/src/core/bvh2/bvh3/NOTES.md +0 -2
  224. package/src/core/bvh8/NOTES.md +0 -63
  225. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
  226. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
  227. package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
  228. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
  229. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
  230. package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
  231. package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
  232. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
  233. package/src/core/geom/3d/gjk/NOTES.md +0 -8
  234. package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
  235. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
  236. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
  237. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
  238. package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
  239. package/src/engine/REVIEW_2026_07_03.md +0 -211
  240. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
  241. package/src/engine/control/first-person/DESIGN.md +0 -658
  242. package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
  243. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
  244. package/src/engine/control/first-person/TODO.md +0 -160
  245. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
  246. package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
  247. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
  248. package/src/engine/ecs/ik/PLAN.md +0 -179
  249. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
  250. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
  251. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
  252. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
  253. package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
  254. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
  255. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
  256. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
  257. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
  258. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
  259. package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
  260. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
  261. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
  262. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
  263. package/src/engine/network/CONGESTION_CONTROL.md +0 -87
  264. package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
  265. package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
  266. package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
  267. package/src/engine/physics/cloth/PLAN.md +0 -3056
  268. package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
  269. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
  270. package/src/engine/physics/fluid/solver/NOTES.md +0 -46
  271. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
  272. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
  273. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
  274. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
  275. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
  276. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
  277. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
  278. package/src/format/image/avif/DECISIONS.md +0 -545
  279. package/src/format/image/jpeg/NOTES.md +0 -3
  280. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
  281. package/src/generation/COORDINATES.md +0 -54
  282. package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
  283. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
  284. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
  285. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
  286. package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
  287. package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
  288. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
  289. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
  290. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
  291. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
  292. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
  293. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
  294. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
  295. package/src/shade/RENDERER_CONTRACT.md +0 -697
  296. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
  297. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
  298. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
  299. package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
  300. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
  301. package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
  302. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
  303. package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
  304. package/src/shade/renderer/NOTES.md +0 -78
  305. package/src/shade/renderer/PLAN.md +0 -8
  306. package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
  307. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
  308. package/src/shade/renderer/atmosphere/NOTES.md +0 -6
  309. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
  310. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
  311. package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
  312. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
  313. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
  314. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
  315. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
  316. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
  317. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
  318. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
  319. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
  320. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
  321. package/src/shade/renderer/camera/orbital/README.md +0 -81
  322. package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
  323. package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
  324. package/src/shade/renderer/camera/orbital/index.js +0 -9
  325. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
  326. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
  327. package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
  328. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
  329. package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
  330. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
  331. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
  332. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
  333. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
  334. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -481
  335. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
  336. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
  337. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
  338. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
  339. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
  340. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
  341. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
  342. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -529
  343. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts +0 -47
  344. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts.map +0 -1
  345. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.js +0 -80
  346. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts +0 -16
  347. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts.map +0 -1
  348. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.js +0 -67
  349. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts +0 -17
  350. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts.map +0 -1
  351. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.js +0 -145
  352. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts +0 -12
  353. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts.map +0 -1
  354. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.js +0 -105
  355. package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
  356. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4306
  357. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
  358. package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
  359. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
  360. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
  361. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
  362. package/src/shade/renderer/hiz/NOTES.md +0 -3
  363. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
  364. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
  365. package/src/shade/renderer/light/cluster/NOTES.md +0 -11
  366. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
  367. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
  368. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
  369. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
  370. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
  371. package/src/shade/renderer/particles/DESIGN.md +0 -1011
  372. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -280
  373. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
  374. package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
  375. package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
  376. package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
  377. package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
  378. package/src/shade/renderer/postprocess/nss/NOTES.md +0 -332
  379. package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
  380. package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
  381. package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
  382. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
  383. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
  384. package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
  385. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
  386. package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
  387. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
  388. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
  389. package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
  390. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
  391. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -391
  392. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -153
  393. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
  394. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
  395. package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
  396. package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
  397. package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
  398. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
  399. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
  400. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
  401. package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
  402. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -927
  403. package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
  404. package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
  405. package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
  406. package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
  407. package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
  408. package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
  409. package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
  410. package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
  411. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
  412. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
  413. package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -3
  414. package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
  415. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
  416. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
  417. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
  418. package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
  419. package/src/shade/wgsl/NOTES.md +0 -4
@@ -1,322 +0,0 @@
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
- **The paper white is 203 cd/m² since `5549db81f` (2026-10-17),** BT.2408's graphics white, not GT7's 250. Every
8
- measurement below was taken at 250, so peak ×4 was a 1000 cd/m² display; at 203 it is 812 cd/m², and a 1000 cd/m²
9
- display is ×4.93.
10
-
11
- ## 1. Recommendation
12
-
13
- The question: does each operator have one form, parameterised by the display's peak, that serves an SDR peak and an HDR
14
- peak with the same mid-tones? That is what `ShadeToneMappingMode` asks of a mode since `6ea10df28`: one mode on every
15
- output, and SDR and HDR must not look different. GT7 is the yardstick.
16
-
17
- | operator | a form that fits? | recommendation |
18
- |---|---|---|
19
- | 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** |
20
- | AgX | **No.** Both HDR forms (Chow's, Godot's) keep mid-grey and bend everything above it with the peak. | **Remove** |
21
- | 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` |
22
-
23
- GT7 stays the default.
24
-
25
- 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
26
- 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).
27
-
28
- Neutral earns a mode for a reason beyond fitting. The SDR brief named it the fallback if GT7's SDR clip reads as harsh,
29
- "at the price of SDR and HDR looking different". With a peak, that price is gone:
30
-
31
- - its forms agree exactly over a wider range than GT7's, greys to +2.0 EV against +1.5;
32
- - saturated colours just above its start differ more, a mean of 0.72 codes up to +1 EV against GT7's 0.24.
33
-
34
- **What would reverse each:**
35
-
36
- - **ACES:** a need to match an ACES 2.0 pipeline, such as grading or film interchange, accepted together with SDR and HDR
37
- looking different. It would be a new implementation, not this chunk.
38
- - **AgX:** a published AgX HDR form that holds tones fixed to about +1.5 EV over mid-grey, measured with the same
39
- script. Pestaluky lists a higher crossover as future work.
40
- - **Neutral:**
41
- - Khronos publishing its own HDR form. The HDR pass would then follow it.
42
- - Alex's session on an HDR display finding the long shoulder (0.76 to the peak) flat or too colourful.
43
- - Alex preferring one operator with no alternative. Then Neutral goes too (F3).
44
-
45
- ## 2. What the sources say
46
-
47
- ### ACES 2.0, Academy Output Transforms
48
-
49
- Sources read: `aces-aswf/aces-core` (`Lib.Academy.Tonescale.ctl`, `Lib.Academy.OutputTransform.ctl`, CHANGELOG) and
50
- `aces-aswf/aces-output`, v2.0 of 2025-04-04; the ACES 2 documentation; GT7 talk slides 116–120.
51
-
52
- - **One family for every peak.** The CHANGELOG describes the v2 tonescale's "adaptability to produce output for any peak
53
- luminance between 100-10000 nits". The output transforms are one CTL each, differing only in `peakLuminance`, the
54
- limiting primaries and the encoding.
55
- - **One of them is Shade's HDR canvas:** `Output.Academy.P3-D65_1000nit_in_P3-D65_sRGB-Piecewise`, "Extended DisplayP3
56
- (1000 nit)". It is P3 limited and sRGB-piecewise encoded, with 1.0 at 100 cd/m², clamped at peak/100.
57
- - **Mid-grey moves with the peak by design.** `init_TSParams` in `Lib.Academy.Tonescale.ctl` sets the grey target as
58
- `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
59
- "change in grey between different peak luminance". The GT7 talk says the same on slide 117: mid-grey lands at 10 to
60
- 15 cd/m² "depending on the ODT".
61
- - **The gamut stage is per peak.** `init_ODTParams` builds three 360-entry hue tables by search: the reach gamut's M, the
62
- limiting gamut's cusps and the upper hull gamma. They depend on the peak. Shade's peak is a runtime value, so every
63
- change of peak means a rebuild.
64
- - **GT7 talk, slide 120:** ACES 2.0 support for variable HDR peaks is "Additional Work Needed".
65
- - **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
66
- ACES would be a new implementation of the JMh model and its tables, not an extension of the chunk.
67
-
68
- ### AgX
69
-
70
- Sources read:
71
-
72
- - Eary Chow's `AgX` configuration and README;
73
- - his generator, `AgX_LUT_Gen`, in particular `AgXHLG.py` and `AgXBaseRec2020.py`;
74
- - Blender main's `release/datafiles/colormanagement/config.ocio`;
75
- - Pestaluky's post, cited on GT7 slide 113;
76
- - Godot master: `tonemap.glsl`, `environment_storage.cpp` and `Environment.xml`.
77
-
78
- - **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
79
- display with reference white at 100. His README says mid-grey is "set to 18% of 100 nits".
80
- - **Blender main ships the same.** There are two AgX views on Rec.2100 displays, "AgX - SDR" and "AgX - HDR 1000 nits".
81
- On sRGB, Display P3 and Rec.1886 displays, AgX is SDR only.
82
- - **The generator has one parameter, the ratio of HDR peak to SDR white.** A comment expects it to become tunable at
83
- runtime. The HDR script is the SDR Rec.2020 script plus three steps:
84
- - the shoulder exponent multiplied by ratio^log10(2);
85
- - a log-space sigmoid that pulls mid-grey down to 18% of the reference white;
86
- - a 50% "HDR purity" mix of hue and saturation.
87
-
88
- At ratio 1 the three steps change nothing: 0.0 codes over the sweep in §3, against the same script with them off.
89
- - **Pestaluky's curve, which Godot ships as its AgX.** It is parameterised by the output's maximum. The post says values
90
- below the crossover do not depend on the output's range, and the crossover is mid-grey, 0.18. Above it, the shoulder
91
- is fitted to the peak.
92
- - Godot puts the curve between AgX's inset and outset matrices, with an AgX white of 16.29 times the peak. Its
93
- matrices are `chunk_tonemap_agx`'s composed with the Rec.709/Rec.2020 conversions, to 1e-6.
94
- - This landed in Godot on 2025-12-03, "Add `agx_white`, `agx_contrast` and HDR support to the AgX tonemapper". It is
95
- in 4.7-stable and not in 4.6-stable.
96
- - **GT7 talk, slide 120:** variable HDR peaks are "No" for AgX, as of June 2025. Slide 113 calls the HDR extension work
97
- in progress.
98
- - **Neither is Shade's AgX.** `chunk_tonemap_agx` is the Filament and three.js port, with a log2 encoding, a polynomial
99
- 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
100
- 20.6 codes over −2 to +1 EV, 35.7 at worst. Adopting either HDR form changes Shade's SDR AgX as well.
101
-
102
- ### Khronos PBR Neutral
103
-
104
- Sources read: the Khronos repository (README, `pbrNeutral.glsl`, commit history to 2026-10-06) and Lalish's
105
- model-viewer write-up.
106
-
107
- - **No HDR form exists.** The README says the operator supports only sRGB output, and that expanding it is a goal for
108
- the future. Since June 2024 the repository has changed only in licensing and contribution files.
109
- - **Lalish names where to adapt it.** The single parameter, the 0.8 compression start, is "likely the most natural place
110
- to adjust the curve to HDR output". He also writes that the choice of operator should depend on the output format.
111
- - **GT7 talk, slide 120:** variable HDR peaks are "No" for Neutral.
112
- - **So the HDR form is ours.** The prototype puts the peak P where the specification has 1, and keeps the start:
113
- - p_n = P − (P − K_s)² / (p + P − 2K_s);
114
- - the desaturation term is unchanged.
115
-
116
- At P = 1 it is the specification: 0.0 codes over the sweep. Below K_s it is 1:1 at every P.
117
- - **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
118
- 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
119
- mean 0.83 against 0.72. So the prototype keeps the start.
120
-
121
- ## 3. Measured on the CPU
122
-
123
- **References, not re-derivations:**
124
-
125
- - **ACES 2.0:** OpenColorIO 2.6.0's `FIXED_FUNCTION_ACES_OUTPUT_TRANSFORM_20`, the Academy transform, with P3-D65
126
- limiting primaries.
127
- - Against OCIO's builtin `HDR-1000nit-P3-D65_2.0`, it agrees to 5e-8 in XYZ.
128
- - Against a port of the CTL tonescale, greys agree to five digits.
129
- - Input is Rec.709 → ACEScg (Bradford) → ACES2065-1.
130
- - The peak at headroom H is 100·H cd/m², since ACES puts SDR white at 100.
131
- - **AgX, Chow's:** his `AgX_Rec2100` run as written, with `HDR_max_nits` = 100·H.
132
- - **AgX, Godot's:** a port of `tonemap.glsl` with the parameters `environment_storage.cpp` computes.
133
- - **GT7:** a port of the engine's `tonemap_gt7` at a peak of 250·H. Against Polyphony's compiled sample code it agrees
134
- to 0.36 codes in the mid-tones and 14.7 in saturated highlights, which is the ICtCp blend the SDR brief reports.
135
-
136
- **Inputs:**
137
-
138
- - Eleven hues:
139
- - white, fire, blue, green, magenta, red, mint and a brake light;
140
- - the product shot's canary 231,218,63, red 203,63,63 and mint 149,218,188.
141
- - Each is scaled to luminance 0.18·2^EV, from −6 to +6 EV in quarter stops.
142
-
143
- **Outputs** are taken as an HDR canvas shows them below SDR white: linear Display P3, clipped to 1, then 8-bit
144
- sRGB-encoded. Each operator at peak ×H is compared with itself at peak ×1.
145
-
146
- **At peak ×4,** a 1000 cd/m² display under the 250 cd/m² paper white:
147
-
148
- | | mid-grey, SDR → HDR | greys equal up to | every hue equal up to | worst, at or below grey | mean, up to +1 EV |
149
- |---|---|---|---|---|---|
150
- | GT7 (engine) | 0.179 → 0.179 | +1.5 EV | −0.5 EV | 3.9 (blue) | 0.24 |
151
- | ACES 2.0 | 0.100 → 0.128 (+0.35 EV) | −4.0 EV | −5.5 EV | 24.5 (blue) | 6.98 |
152
- | AgX, Godot's | 0.180 → 0.180 | +0.25 EV | −1.5 EV | 20.9 (blue) | 2.25 |
153
- | AgX, Chow's | 0.180 → 0.180 | 0.0 EV | −1.75 EV | 36.1 (blue) | 3.64 |
154
- | **Neutral with a peak** | 0.140 → 0.140 | **+2.0 EV** | **0.0 EV** | **0.0** | 0.72 |
155
-
156
- "Equal" means within half a code. EV is the input's luminance over 0.18.
157
-
158
- - **GT7's own worst case** is a saturated blue at mid-grey luminance. Its blue channel is past the per-channel linear
159
- section, 0.444, while its luminance is at grey.
160
- - **Neutral's 1:1 region** runs on the largest channel too, but up to 0.76, so the same blue does not reach it.
161
- - **Neutral's higher mean up to +1 EV** comes from saturated colours just above the start. Its worst case is the brake
162
- 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
163
- largest channel hard, and at ×4 it barely compresses.
164
-
165
- **At ×2 and ×10 the picture is the same:**
166
-
167
- | | grey shift ×2 | ×10 | mean up to +1 EV, ×2 | ×10 |
168
- |---|---|---|---|---|
169
- | GT7 | 0 | 0 | 0.24 | 0.24 |
170
- | ACES 2.0 | +0.19 EV | +0.54 EV | 3.47 | 10.89 |
171
- | AgX, Godot's | 0 | 0 | 1.52 | 2.67 |
172
- | AgX, Chow's | 0 | 0 | 2.12 | 4.88 |
173
- | Neutral with a peak | 0 | 0 | 0.59 | 0.78 |
174
-
175
- **Grey ramps,** display-linear in units of SDR white, as SDR / peak ×4:
176
-
177
- | EV | GT7 | ACES 2.0 | AgX, Godot's | AgX, Chow's | Neutral with a peak |
178
- |---|---|---|---|---|---|
179
- | −2 | 0.031 / 0.031 | 0.013 / 0.016 | 0.037 / 0.037 | 0.037 / 0.037 | 0.013 / 0.013 |
180
- | −1 | 0.078 / 0.078 | 0.040 / 0.048 | 0.085 / 0.085 | 0.084 / 0.084 | 0.050 / 0.050 |
181
- | 0 | 0.179 / 0.179 | 0.100 / 0.128 | 0.180 / 0.180 | 0.180 / 0.180 | 0.140 / 0.140 |
182
- | +1 | 0.360 / 0.360 | 0.209 / 0.296 | 0.331 / 0.356 | 0.326 / 0.374 | 0.320 / 0.320 |
183
- | +2 | 0.674 / 0.720 | 0.370 / 0.612 | 0.511 / 0.664 | 0.484 / 0.759 | 0.680 / 0.680 |
184
- | +3 | 0.992 / 1.440 | 0.556 / 1.128 | 0.684 / 1.146 | 0.632 / 1.377 | 0.935 / 1.294 |
185
-
186
- - **GT7 and Neutral** leave greys alone until their SDR shoulders, GT7 from +1.5 EV and Neutral from +2.
187
- - **ACES** moves every grey.
188
- - **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
189
- 0.20. At +2 EV they are 0.38 and 0.65 EV brighter.
190
-
191
- **Pinning ACES's grey does not rescue it.** With `w_g` = 0 in the CTL tonescale, greys at 100 and 400 cd/m² still
192
- differ:
193
-
194
- | EV | −1 | 0 | +1 | +2 |
195
- |---|---|---|---|---|
196
- | codes | 2.8 | 0.0 | 8.0 | 25.4 |
197
-
198
- The rest of the curve still depends on the peak, and the result would no longer be the Academy's transform.
199
-
200
- ## 4. Measured on the device
201
-
202
- The playground draws operators 5–7 at a peak, clipped to SDR white (`CompareLayout.Split` shows it beside the SDR form).
203
- A one-off driver outside the repo ran it once.
204
-
205
- 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
206
- is a LUT generated per ratio. §3 measured both through their reference implementations, so a port would re-measure
207
- the same functions with a port's error added.
208
-
209
- - Headless Chrome on the RTX 4090.
210
- - The page's per-scene exposure, with bloom, TAA and SSAO off and the projection frozen.
211
- - Each scene and operator grabbed at peak ×1, ×1 again for the noise floor, then ×4 and ×10.
212
- - Compared per pixel in Display P3 codes, as the largest channel difference. Two grabs at ×1 differ by exactly 0 in
213
- every scene, so the floor is zero.
214
-
215
- **Mid-tone pixels at ×4,** those whose SDR largest channel is at most 188 (0.5 linear). Each cell gives the mean
216
- difference in codes, the share of those pixels that differ by 2 codes or more, and the largest difference.
217
-
218
- | scene | mid-tone share of the frame | GT7 | AgX, Godot's | Neutral with a peak |
219
- |---|---|---|---|---|
220
- | fire and emitters | 66–70% | 0 · 0% · 0 | 0.91 · 10.5% · 18 | 0 · 0% · 0 |
221
- | sunlit exterior | 39–40% | 0.008 · 0% · 1 | 5.22 · 87.6% · 23 | 0 · 0% · 0 |
222
- | dim interior | 83–87% | 0 · 0% · 1 | 1.43 · 20.5% · 23 | 0 · 0% · 0 |
223
- | product shot | 5–9% | 0.006 · 0% · 1 | 7.15 · 59.0% · 24 | 0 · 0% · 0 |
224
-
225
- The mid-tone share varies with the operator, because each one's own SDR frame decides which pixels count.
226
-
227
- At ×10, GT7 and Neutral are unchanged. AgX's means grow to 1.10, 6.25, 1.71 and 8.70.
228
-
229
- Between 0.5 and SDR white every form differs by design, because the HDR form has headroom there. Over all pixels below
230
- 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.
231
-
232
- ## 5. What each recommendation means for the code
233
-
234
- **Removing ACES (F1):**
235
-
236
- - `chunk_tonemap_aces.js` (`chunk_tonemap_aces`) goes.
237
- - The npm package exports `./src/*`, so the deep import breaks for any downstream user. In this repo only the playground
238
- imports it, as grid quadrant 1.
239
- - The CPU `core/color/tonemap/tonemap_aces.js` stays. It is not Shade's tone mapping, and `PathTracedRenderer`
240
- (`engine/graphics/sh3/path_tracer`) calls it.
241
-
242
- **Removing AgX (F2):**
243
-
244
- - `chunk_tonemap_agx.js` (`chunk_tonemap_agx`) goes. The same deep-import break applies. In the repo, only playground
245
- quadrant 3 imports it.
246
- - The playground's `chunk_tonemap_agx_peak.js` goes with it.
247
-
248
- **Adding Neutral (F3):**
249
-
250
- - `ShadeToneMappingMode.PBR_NEUTRAL`, with two concrete passes beside the GT7 and NONE pairs:
251
- `shader_tonemap_LDR_pbr_neutral` at peak 1, and `shader_tonemap_HDR_pbr_neutral` at the display's peak over the paper
252
- white.
253
- - `chunk_tonemap_khronos_pbr` takes the peak. Its WGSL signature changes from `tonemap_khronos_pbr(c)` to
254
- `tonemap_khronos_pbr(c, peak)`, a break for any WGSL caller outside the repo. The import path stays.
255
- - **The paper white becomes a canvas convention, not GT7's.** Neutral's HDR pass divides the display's peak by the same
256
- paper white that puts SDR white at the canvas's 1.0: 250 cd/m² then, 203 since `5549db81f`. So `chunk_GT7_PAPER_WHITE_NITS` moves out of `gt7/` under a
257
- name of its own, which is an import-path change too.
258
- - **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.
259
- Switching modes darkens mid-grey by 0.36 EV. Auto-exposure meters the scene, not the output, so it will not
260
- compensate.
261
- - **Pins:** the LDR pass equals the specification within float precision, and the HDR pass equals the LDR pass below the
262
- start. Both are plain tests in the style of `shader_tonemap_HDR.spec.js`.
263
- - **Not measured:** Neutral's HDR highlights on an HDR display. This box's headless Chrome reports an SDR display, so §4
264
- covers only what lies below SDR white.
265
-
266
- **In every case:**
267
-
268
- - **`chunk_tonemap_pbr_neutral.js` goes.** It is the Filament-derived duplicate that mixes toward 1 instead of the
269
- compressed peak (SDR brief §4.3). Nothing imports it.
270
- - **The playground's grid** loses each quadrant whose chunk goes. It either drops them or keeps copies beside the page,
271
- as it does for the GT7 sample code.
272
-
273
- ## 6. Forks for Alex, all three taken
274
-
275
- - **F1. Remove ACES.** Delete `chunk_tonemap_aces.js` and drop it from the playground. The CPU `tonemap_aces` stays.
276
- - **F2. Remove AgX.** Delete `chunk_tonemap_agx.js` and the playground's `chunk_tonemap_agx_peak.js`, and drop AgX from
277
- the playground.
278
- - **F3. Add `ShadeToneMappingMode.PBR_NEUTRAL`** with the peak form, moving the paper white out of `gt7/`. Delete
279
- `chunk_tonemap_pbr_neutral.js` either way.
280
- - If declined, Neutral goes too: delete `chunk_tonemap_khronos_pbr.js` and the playground's
281
- `chunk_tonemap_pbr_neutral_peak.js`. The folder is then GT7 alone.
282
- - If accepted, it waits on nothing else. The shader-switch proposal can later fold each mode's pair of passes into
283
- one, as it would GT7's.
284
-
285
- **Landed 2026-10-16:**
286
-
287
- - `822dbc789`: the paper white leaves `gt7/`, as `chunk_PAPER_WHITE_NITS`.
288
- - `1851d9030`, F3: `ShadeToneMappingMode.PBR_NEUTRAL` with `shader_tonemap_LDR_pbr_neutral` and
289
- `shader_tonemap_HDR_pbr_neutral`, and `tonemap_khronos_pbr(color, peak)`. The HDR pass floors the peak at the paper
290
- white, where the operator is defined. On the RTX 4090 the engine's SDR canvas equals the specification to the code,
291
- and its emulated-HDR canvas is within the SDR dither, 1 code, at or under 0.5.
292
- - `df9eb7694`, F1 and F2: the ACES, AgX and duplicate Neutral chunks are gone, along with `chunk_RRTAndODTFit`, the
293
- ACES fit only the ACES chunk used. The playground compares GT7 and PBR Neutral.
294
-
295
- ## 7. Not in scope, noticed
296
-
297
- - `chunk_tonemap_hdr_bt2390.js` and `chunk_tonemap_reinhard_luma.js` in the same folder have no importers either.
298
- - The doc comment on the playground's `chunk_tonemap_gt7_sdr_reference.js` still lists four departures of the engine's
299
- `tonemap_gt7` from the sample code. Since `6ea10df28` only the blend space differs.
300
- - The playground's environment maps are untracked under `packages/meep-engine/test_assets/`. A worktree has none until
301
- they are copied in, and the page then lights the exterior and the product shot with a flat sky.
302
-
303
- ## Sources
304
-
305
- - Academy Software Foundation, ACES 2.0 core library and output transforms:
306
- - https://github.com/aces-aswf/aces-core (`lib/Lib.Academy.Tonescale.ctl`, `lib/Lib.Academy.OutputTransform.ctl`,
307
- `CHANGELOG.md`)
308
- - https://github.com/aces-aswf/aces-output (`d65/displayP3/Output.Academy.P3-D65_1000nit_in_P3-D65_sRGB-Piecewise.ctl`)
309
- - OpenColorIO 2.6.0 (PyPI `opencolorio`), `FIXED_FUNCTION_ACES_OUTPUT_TRANSFORM_20`.
310
- - E. Chow:
311
- - AgX configuration: https://github.com/EaryChow/AgX
312
- - LUT generator: https://github.com/EaryChow/AgX_LUT_Gen (`AgXHLG.py`)
313
- - Blender, `release/datafiles/colormanagement/config.ocio`, main: https://projects.blender.org/blender/blender
314
- - A. Pestaluky, "An Adjustable Tonemapping Curve for Variable / Extended Dynamic Range", 2025-05-29:
315
- https://allenwp.com/blog/2025/05/29/allenwp-tonemapping-curve/
316
- - Godot Engine, master and 4.7-stable:
317
- - `servers/rendering/renderer_rd/shaders/effects/tonemap.glsl`
318
- - `servers/rendering/storage/environment_storage.cpp`
319
- - `doc/classes/Environment.xml`
320
- - Khronos, PBR Neutral: https://github.com/KhronosGroup/ToneMapping/tree/main/PBR_Neutral
321
- - E. Lalish, "Tone Mapping Considerations for Physically-Based Rendering": https://modelviewer.dev/examples/tone-mapping
322
- - Polyphony Digital, "Driving Toward Reality", SIGGRAPH 2025 PBS course, slides 113–120 and 154.
@@ -1,247 +0,0 @@
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
- **The paper white is 203 cd/m² since `5549db81f` (2026-10-17),** BT.2408's graphics white, where this brief chose the
9
- sample code's 250. Every measurement below was taken at 250. At 203 the SDR pass is the sample code's SDR mode with
10
- `GRAN_TURISMO_SDR_PAPER_WHITE` at 203, under the 250 its parameters were tuned on, so it is no longer the sample code
11
- exactly. The curve's toe sits at a fixed 53.8 cd/m², so the change is not a scale: an exposed 0.18 comes out 0.176
12
- (116) instead of 0.179 (117). Against the compiled sample code at 203, over the same 648 inputs, the ICtCp blend differs
13
- by up to 0.33 codes in the mid-tones and 14.7 in saturated highlights, against 0.30 and 14.4 at 250.
14
- `shader_tonemap_LDR.spec.js` pins the sample code's output at 203.
15
-
16
- ## 1. Recommendation
17
-
18
- **Make GT7's SDR mode the SDR default, exactly as Polyphony's sample code defines it.** The curve's peak is the
19
- 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.
20
-
21
- - It is the operator the HDR path already runs, and the source designs it so that SDR and HDR look alike.
22
- - It keeps the mid-tones linear: an exposed 0.18 comes out at 0.179.
23
- - Product colours come out within a few codes of their base colour.
24
-
25
- **The cost is highlight range.** GT7's SDR shoulder clips at 1.43× paper white, three stops above mid-grey. ACES
26
- reaches 6.5 stops, AgX 6.4 and Neutral 5.2. Polyphony accept the clip and lean on glare to carry what it removes;
27
- Shade's bloom, on by default, plays that part.
28
-
29
- **What would reverse it:** the clip reading as harsh in your session, in sunlit whites or skies, with bloom on. Neutral
30
- is then the default, at the price of SDR and HDR looking different.
31
-
32
- Four forks needed an answer first (§5). The first, the canvas primaries, was a defect every SDR frame showed, whichever
33
- operator was chosen.
34
-
35
- ## 2. What the sources say
36
-
37
- ### GT7: Polyphony's 2025 talk, sample code, and earlier talks
38
-
39
- Sources read:
40
-
41
- - "Driving Toward Reality", SIGGRAPH 2025 Physically Based Shading course, with speaker notes. There are no separate
42
- course notes for this talk. Four copies were read, and they agree on everything cited here:
43
- - slides v1.0 and v1.1 from the course page;
44
- - the PDF on Polyphony's publications page;
45
- - the PowerPoint there, whose hidden slides show which slides were not presented live.
46
- - `gt7_tone_mapping.cpp`, the sample code (MIT), from the course page.
47
- - The 2018 GT Sport talk notes.
48
- - Polyphony's CEDEC 2026 "Beyond HDR" deck, in Japanese.
49
-
50
- The authors do address SDR specifically:
51
-
52
- - **SDR is the same curve, with a fixed peak.** The peak is the paper white: 250 cd/m², 2.5 frame-buffer units, because
53
- 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.
54
- This is on slide 153, which is hidden in the presented deck. It is in every published PDF, and `initializeAsSDR()`
55
- in the sample code does the same.
56
-
57
- The code comment in `initializeAsSDR()` says what the scaling is for (MIT, quoted):
58
-
59
- > These adjustments ensure that the visual appearance (in terms of brightness) stays generally consistent across
60
- > both HDR and SDR outputs
61
-
62
- - **SDR is the baseline the parameters were tuned on.** `initializeAsHDR()` accepts peaks from 250 up, "because the
63
- parameters for GTToneMappingCurveV2 were determined based on an SDR paper white assumption of 250 nits" (MIT).
64
- - **One curve for every display is the design goal.** HDR is "a natural extension of SDR" (slide 27). Changing the peak
65
- lets the same curve serve SDR and HDR (slide 135). Consistency across SDR and HDR is listed as a strength (slide 137).
66
- - **The clip is deliberate.** The v2 shoulder has a sharp clipping point. Polyphony accepted it because TVs tone map
67
- as well (slide 147). A desktop sRGB monitor does not, so on one the clip is final.
68
- - **Glare compensates on SDR.** Glare is drawn wider on SDR than on HDR, which treats the peak-luminance gap as an
69
- aperture difference (slide 184).
70
- - **Their operator comparison was made in SDR**, and they say it carries over to HDR (slide 154). ACES maps 0.18 to
71
- about 10 cd/m², roughly 1/1.8 of the 18 cd/m² other operators give (slide 117, hidden in the presented deck). They
72
- scaled ACES to match exposure before comparing.
73
- - **ICtCp builds the "untwisted" colour; the final blend is in RGB.**
74
- - Steps 2 and 3 (slides 148–149) work in the UCS, ICtCp in the sample code. The untwisted colour takes its intensity
75
- from the per-channel colour and its chroma from the original, faded toward the peak.
76
- - Step 4 (slide 150, presented) lerps the per-channel and untwisted colours in linear Rec.2020 RGB. The slide says
77
- they tried blending in the UCS and found RGB looked better to them; the speaker note says the same. The code on
78
- slides 153 and 243 blends in RGB.
79
- - The hidden slide 153 adds that blending in a UCS works as well. The engine's chunk takes that route (§4.2).
80
- - **The SDR white moved between titles.** The 2018 GT Sport notes define SDR maximum brightness as 100 cd/m² (p. 66).
81
- GT7 assumes 250.
82
- - **CEDEC 2026** repeats the policy of one physically based tone mapping across SDR and HDR (p. 82). It adds nothing
83
- on SDR parameters.
84
- - **Not stated anywhere:** the auto-exposure target. Where mid-grey lands in GT7's own SDR output cannot be known from
85
- the talk. Shade's convention decides it (§3).
86
-
87
- ### Khronos PBR Neutral (Emmett Lalish)
88
-
89
- - Built for e-commerce. The Khronos repository (CC-BY 4.0) describes it as "aimed toward product photography use
90
- cases, where the scene is well-exposed and HDR color values are mostly restricted to small specular highlights".
91
- - Below 0.8, base colours are reproduced 1:1, less the 0.04 Fresnel offset. Hue is never shifted, and highlights
92
- desaturate smoothly to white.
93
- - sRGB output only, with no gamut mapping.
94
- - The model-viewer write-up proposes it as an option where tools offer several operators, and as the default where they
95
- offer one. It also says plainly that film and games want something else.
96
-
97
- ### AgX (Eary Chow's, the one Blender, Godot and three.js use)
98
-
99
- - Made to replace Blender's Filmic. It forms a closed-domain image with smooth chromatic attenuation, for wide-gamut
100
- and spectral rendering.
101
- - 16.5 stops of range. It is meant to be used with looks; "Punchy" is the contrast one.
102
- - Chow's configuration has a 1000 cd/m² HDR view. The LUT everyone ships, and the three.js port Shade's chunk comes
103
- from, are SDR only (talk slide 113).
104
-
105
- ## 3. Measured
106
-
107
- The CPU ports are line-for-line from each source. The GT7 port was checked against Polyphony's code compiled with MSVC:
108
- 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.
109
- Inputs are exposed linear Rec.709. Outputs are display-linear, with sRGB codes in brackets.
110
-
111
- | | 0.18 out | contrast at 0.18 | white reached at | 0.8 grey | canary 231,218,63 | red 203,63,63 |
112
- |---|---|---|---|---|---|---|
113
- | ACES (today) | 0.106 (91) | 1.48 | +6.5 EV | 195 | 196,187,67 | 175,29,38 |
114
- | **GT7 SDR** (reference, 1.0 = paper white) | 0.179 (117) | 1.05 | +3.0 EV | 221 | 224,212,61 | 201,58,58 |
115
- | 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 |
116
- | AgX | 0.215 (128) | 0.80 | +6.4 EV | 194 | 197,185,121 | 204,97,87 |
117
- | Neutral | 0.140 (105) | 1.29 | +5.2 EV | 226 | 227,213,34 | 198,34,34 |
118
-
119
- "Contrast" is d log out / d log in. "White reached at" is the exposure, in stops over 0.18, where output reaches 0.99.
120
-
121
- **Saturated emitters, as exposure rises:**
122
-
123
- - ACES walks fire orange from 18° to 47° by +4 EV: it turns yellow. It also takes neon blue toward cyan.
124
- - GT7 holds hue through the mid-tones, then whitens sharply. Fire is pale yellow by +2 EV and white by +4.
125
- - Neutral never moves hue. Fire whitens through a pinkish white rather than yellow.
126
- - AgX desaturates even at normal exposure: fire is at saturation 0.76 at +0 EV, where the others are at 0.95–0.97.
127
-
128
- **Mapping Shade's exposure onto GT7's frame buffer** is the one free parameter, and it is only an exposure offset of
129
- 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
130
- (×2.5) lands 0.18 at 0.179, as other operators do. It also matches the HDR path, which normalises by the paper white
131
- the same way. Reading it literally (1.0 = 100 cd/m²) darkens SDR mid-tones to 0.058.
132
-
133
- ## 4. Engine findings that bear on the choice (measured)
134
-
135
- 1. **The SDR path shows Rec.709 values as Display P3.** `Renderer` configures the canvas `colorSpace: 'display-p3'` on
136
- both paths. `shader_tonemap_HDR` converts to P3, but `shader_tonemap_LDR` writes Rec.709 values without converting.
137
-
138
- A `display-p3` canvas was cleared to known values and read back through a 2D sRGB canvas:
139
-
140
- | colour | intended | as-is |
141
- |---|---|---|
142
- | ACES red | 175,29,38 | 191,0,28 |
143
- | Neutral red | 198,34,34 | 216,0,16 |
144
- | canary yellow | 227,213,34 | 230,212,0 |
145
-
146
- Converted to P3 first, each reproduces exactly. Grey is unaffected.
147
-
148
- In the upstream repository, the commit that tagged the canvas `display-p3` (`105e8eec`, 2025-12-22, "finished HDR
149
- mapper") also switched SDR from Khronos PBR Neutral to ACES. Under this mismatch Neutral's saturated output is pushed
150
- furthest, so ACES may have been picked against a skewed picture. The commit does not say why it switched.
151
- 2. **The engine's `tonemap_gt7` is not Polyphony's.** It differs from the sample code in four ways:
152
-
153
- | | engine | sample code |
154
- |---|---|---|
155
- | weight of the per-channel colour | 0.7 | 0.4 (`blendRatio_` 0.6 weights the untwisted one) |
156
- | final blend in | ICtCp | linear Rec.2020 RGB; the talk says a UCS also works (§2) |
157
- | chroma fade | fixed PQ window 0.7–1.0 | 0.98–1.16 of the target's own intensity |
158
- | clamp at the target | no | yes |
159
-
160
- The overshoot comes from the other three differences, not the blend space. Adding them to the engine's chunk one at
161
- a time:
162
- - **The clamp alone** brings HDR white from 11.85 to 10.00, and blue at +5 EV from 15.2 to 10.5.
163
- - **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
164
- 135 with the clamp, to 186 with the fade, and to 216 with the weight.
165
- - **The blend space alone** separates 216 from the sample code's 224. For fire at +2 EV it separates 192 from 197.
166
-
167
- Mid-tones are identical: 0.18 → 0.145 in HDR at 1000/100 for both. Near and above the peak they part:
168
- - in HDR at 1000 cd/m², white reaches 11.85 against the target 10.0, 18.5% over the assumed peak;
169
- - saturated blue at +5 EV reaches 15.2 in its blue channel, against the sample code's 10.6;
170
- - at SDR settings (250/250), the canary yellow at +1.75 EV comes out 255,255,131 against the sample code's
171
- 255,255,224, a 93-code gap. It holds chroma, then clips per channel.
172
- 3. **Two Neutral chunks.** `chunk_tonemap_khronos_pbr` matches the specification. `chunk_tonemap_pbr_neutral`, taken
173
- from Filament, mixes toward 1.0 instead of the compressed peak. Grey 2.0 comes out 0.965 instead of 0.960, and grey
174
- 32 comes out 1.000 instead of 0.998. No renderer shader imports either; the playground imports the specification one.
175
- 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
176
- code does not apply. It maps 0.18 to 0.106; three.js maps it to 0.213.
177
- 5. **The HDR path's paper white is 100** (`Renderer.js`, `paper_white_nits: 100`). GT7 puts SDR white at 250. With 100,
178
- an exposed 0.18 shows at 0.145 of SDR white in HDR and at 0.179 in GT7 SDR.
179
-
180
- ## 5. Forks to answer before the default changes
181
-
182
- - **F1, the SDR primaries (§4.1).** I recommend `shader_tonemap_LDR` convert to Display P3, as the HDR shader does,
183
- rather than configuring an SDR canvas `srgb`. Then GT7's Rec.2020 output keeps its P3 gamut on wide-gamut SDR
184
- laptops.
185
-
186
- Both paths already assume the `display-p3` configure succeeds. Their shared fallback to `srgb` is untreated, and that
187
- is a separate item. F1 changes every SDR frame's saturation, so it is its own commit, pinned before any operator
188
- change.
189
- - **F2, align `tonemap_gt7` with the sample code (§4.2).** I recommend the clamp, the fade and the weight. Keeping
190
- 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
191
- highlights, over 648 inputs. It changes HDR highlights near the peak and nothing in the mid-tones.
192
-
193
- Declining means GT7 SDR would run the engine's variant, which overshoots and clips per channel at SDR. I would then
194
- reconsider GT7 as the default, or add at least the clamp.
195
- - **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
196
- 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
197
- 0.3 stops.
198
- - **F4, the selector (§6).** Superseded: Alex chose one mode for every output instead of an SDR selector.
199
-
200
- ## 6. What was built
201
-
202
- Alex decided against a per-output selector. The tone mapper is one choice for every display, which is the reason the
203
- GT7 talk gives for its operator. So there is no SDR setting, and the renderer offers two modes:
204
-
205
- ```js
206
- renderer.tone_mapping_mode = ShadeToneMappingMode.GT7; // the default
207
- renderer.tone_mapping_mode = ShadeToneMappingMode.NONE; // exposure only; SDR clips at 1.0, HDR at the display
208
- ```
209
-
210
- - **Four concrete passes.** The output's dynamic range and the mode pick the pass:
211
- - `shader_tonemap_LDR` and `shader_tonemap_HDR` for GT7;
212
- - `shader_tonemap_LDR_none` and `shader_tonemap_HDR_none` for NONE.
213
-
214
- Each module lists its own chunks, so a mode's dependencies are visible. No `override`, no runtime branch on a
215
- setting. If shader switches land, each pair can become one pass with a choice.
216
- - **The paper white is a convention, not a setting.** `chunk_GT7_PAPER_WHITE_NITS` (250; since the HDR forms brief
217
- `chunk_PAPER_WHITE_NITS`, and 203 since `5549db81f`) is the paper white on both outputs, and SDR also uses it as the
218
- peak. Below the SDR shoulder the two outputs therefore write the same colour: pinned in `shader_tonemap_HDR.spec.js`.
219
- The HDR pass's only setting is the display's peak.
220
- - **`tonemap_gt7` follows the sample code** in the curve, the relative chroma fade, the 0.6 untwisted weight and the
221
- clamp at the target, and keeps the ICtCp blend (F2). Against the compiled sample code over 648 inputs it differs by up
222
- to 0.3 sRGB codes in the mid-tones and up to 14 in saturated highlights, at 250; at 203, against the sample code at
223
- 203, by 0.33 and 14.7. An earlier draft of this brief said "at most 8", from four hand-picked cases; the full sweep
224
- says 14.
225
- - **ACES, AgX and Neutral were unwired** here, kept for a look at HDR-aware variants of each.
226
- `HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md` took that look: ACES and AgX are removed, and Neutral is
227
- `ShadeToneMappingMode.PBR_NEUTRAL`, with the display's peak in place of the specification's 1 on HDR.
228
-
229
- ## 7. Follow-ups this turned up, not done
230
-
231
- - The `srgb` fallback in `Renderer`'s canvas configure is untreated by both tonemap shaders (§5, F1).
232
- - `make_sunlight` hands `kelvin_to_rgb`'s sRGB-encoded triple to `Light.color`, which is documented as linear.
233
- Not measured.
234
- - `chunk_tonemap_pbr_neutral` duplicated the specification chunk with a difference (§4.3). Removed with the HDR forms
235
- brief's F3.
236
-
237
- ## Sources
238
-
239
- - Polyphony Digital, "Driving Toward Reality: Physically Based Tone Mapping and Perceptual Fidelity in Gran Turismo 7",
240
- SIGGRAPH 2025 PBS course: https://blog.selfshadow.com/publications/s2025-shading-course/ (slides v1.1,
241
- `pdi/supplemental/gt7_tone_mapping.cpp`).
242
- - Uchimura and Suzuki, "Practical HDR and Wide Color Techniques in Gran Turismo SPORT", SIGGRAPH Asia 2018, with notes:
243
- https://www.polyphony.co.jp/publications/sa2018/
244
- - Polyphony Digital and Sony, "Beyond HDR", CEDEC 2026: https://www.polyphony.co.jp/publications/
245
- - Khronos, PBR Neutral specification: https://github.com/KhronosGroup/ToneMapping/tree/main/PBR_Neutral
246
- - E. Lalish, "Tone Mapping Considerations for Physically-Based Rendering": https://modelviewer.dev/examples/tone-mapping
247
- - E. Chow, AgX for Blender: https://github.com/EaryChow/AgX
@@ -1,3 +0,0 @@
1
- see:
2
-
3
- * https://github.com/GPUOpen-LibrariesAndSDKs/FidelityFX-SDK
@@ -1,4 +0,0 @@
1
- Single Pass Downsample
2
-
3
- * see https://gpuopen.com/fidelityfx-spd/
4
- * see https://github.com/GPUOpen-LibrariesAndSDKs/FidelityFX-SDK/tree/main/samples/spd
@@ -1,4 +0,0 @@
1
- AMD has a SW implementation of RTX here:
2
- https://github.com/GPUOpen-Drivers/gpurt/blob/d142df384ebb5ef818e7b001a2d2523633a17cda/src/shaders/RayQuery1_1.hlsl#L128
3
-
4
- Would be useful to adopt some of their techniques, specifically APIs and tree structure