@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,453 @@
1
+ # Particle orientation — scope (2026-10-15, revision 2)
2
+
3
+ Arbitrary rotation for GPU particles, with every projection mode kept, BILLBOARD included.
4
+
5
+ **Revision 2** follows Alex's review of revision 1.
6
+
7
+ - **Roll goes through the quaternion.** The scalar `rotation` channel is deleted rather than kept
8
+ beside the new one.
9
+ - **The u32 quaternion is placed by measurement.** The codec is measured (below), and it belongs on
10
+ the render side, not in the particle record.
11
+ - **The pre-pass is answered.** Writing back into the record is out. A per-view pass with an output of
12
+ its own is the right shape, and it is gated on a measurement.
13
+ - **The stretch moves inside the quad's own axes.** That turns every projection mode into one
14
+ function that produces a world rotation.
15
+
16
+ ## Outcome (2026-10-16)
17
+
18
+ Landed as revision 2 describes, in four commits: the frame fix, the channel, the library, and this
19
+ document with DESIGN.md and the bonfire. The departures from the plan:
20
+
21
+ - **`randomRotation` is `sampleRotation`**, named like the sphere samplers it sits beside.
22
+ - **The demonstrator is the soot, not an `ash` behind `?ash`.**
23
+ - The README already described the soot as "dark tumbling flakes", and a roll in the camera plane
24
+ was its stand-in.
25
+ - It is now FACING_WORLD: a `sampleRotation` at birth, a `tumble` axis at the speed its roll used to
26
+ spin at, and `quatIntegrate` every frame.
27
+ - That adds no new effect, flag or entity.
28
+ - **Group costs are measured**, as the graph compiler lowers them (instructions / registers):
29
+ `quatMultiply` 22/15, `quatIntegrate` 39/17, `sampleRotation` 29/7, `emitterRotation` 105/28. The
30
+ estimates below (~9, ~17) were the hand count of an optimised body. These are pinned in
31
+ `particle_group_library.spec.js`.
32
+
33
+ **Device results.** RTX 4090, headless Chrome, `?debug` stepping, this branch against its base
34
+ `59861de99`.
35
+
36
+ - **The draw does not move.** p10 over 240 profiled frames per launch, ABBA:
37
+
38
+ | pass | base | branch |
39
+ |---|---|---|
40
+ | Particle AVBOIT Draw | 239.6, 214.0 µs | 221.2, 219.1 µs |
41
+ | Particle AVBOIT Splat | 22.5, 27.6 µs | 23.6, 21.5 µs |
42
+ | Particle Simulate | 218.1, 218.1 µs | 218.1, 218.1 µs |
43
+
44
+ The same-tree spread of the draw is wider than any base-to-branch difference.
45
+ - **With the soot running.** The soot's longer INIT read Emit at 54.3 against 46.1 µs, from one launch
46
+ each. That is a single pair and not a finding.
47
+ - **Flame, smoke and embers look as they did.** Spawn order is not deterministic, so the same tree
48
+ differs from itself run to run: the base against itself is a mean |d| of 3.70 (and 3.58 for the
49
+ branch against itself). The base against the branch is 3.62 and 3.36, inside that floor. The soot is
50
+ removed for this comparison.
51
+ - **The soot reads as flakes.** Same camera on the plume: the base draws round camera-facing dots, the
52
+ branch ellipses, slivers edge-on, and flakes face-on.
53
+ - **A pre-existing console error.** "Worker error: ErrorEvent" logs in both trees. Vite names it: the
54
+ page's image-decoder worker, `build/bundle-worker-image-decoder.js`, is a build artifact a fresh
55
+ tree does not have.
56
+ - **The shaders compile on Tint.** Draw, splat and bounds-accumulate compile with no messages on
57
+ swiftshader, and a control with a broken call is reported.
58
+
59
+ ### Pre-pass gate (2026-10-16): not built
60
+
61
+ **Verdict: the per-view pass does not pay.** The whole vertex stage is worth about 2 µs at 121k
62
+ particles. The cheapest pass that could replace it costs 9 µs. So the u32 rotation has no render-side
63
+ home either, and stays unused.
64
+
65
+ **The setup.** RTX 4090, headless Chrome, the bonfire page with `?debug`.
66
+
67
+ - **The load.** The four effects are removed, and in their place one spark emitter of tiny additive
68
+ BILLBOARD quads: size 0.005, about 1.5 px, uniform in a 4 × 2 × 4 m box, about one second of life.
69
+ - **Two counts.** About 121k live particles, and about 1.3k (the bonfire's count).
70
+ - **The order.** Arms ABBAAB per load. p10 over 240 profiled frames per launch, after 240 frames of
71
+ warm-up. The timestamp tick is about 1 µs.
72
+
73
+ **The three arms:**
74
+
75
+ - **A — the vertex chunk as built.** It decodes the emitter row, reads the channels through the
76
+ bindings, and builds `particle_basis`.
77
+ - **B — a floor no real consumer reaches.**
78
+ - It does no storage read at all: the instance index hashes to a position in the same box.
79
+ - Size, colour, flags and the white texel's UV are constants.
80
+ - The quad sits on the camera's axes, with no basis.
81
+ - It draws the same cloud as A.
82
+ - A − B is therefore an upper bound on what any view pass could take off the vertex.
83
+ - **C — a floor no real pass gets under.** A standalone compute pass, one thread per live particle,
84
+ timed with timestamp queries in the same page. It reads a record's header and 8 words at a shuffled
85
+ slot and writes 8 words. It does no emitter decode and builds no basis.
86
+
87
+ **The numbers** (µs):
88
+
89
+ | load | pass | A | B | A − B | C |
90
+ |---|---|---|---|---|---|
91
+ | 121k | draw | 201.7, 202.8, 202.8 | 200.7, 201.7, 201.7 | ≈ 1.0 | 9.2–10.2 |
92
+ | 121k | splat | 68.6 ×3 | 67.6 ×3 | 1.0 | |
93
+ | 1.3k | draw | 7.2, 7.2, 8.2 | 7.2 ×3 | ≈ 0.3 | 3.1 |
94
+ | 1.3k | splat | 4.1 ×3 | 3.1 ×3 | 1.0 | |
95
+
96
+ The rule was to build only if A − B clears C. At 121k it is about 2 µs against at least 9.2. At 1.3k
97
+ it is about 1.3 µs against 3.1.
98
+
99
+ **Where the draw's time does go.** The draw does scale with the particle count: 7 µs at 1.3k, 202 µs at
100
+ 121k, about 1.6 ns a particle. Two findings bound it:
101
+
102
+ - **Not the vertex stage.** The table above shows that.
103
+ - **Not the shading after the extinct test** (one launch). A B whose every fragment was discarded at
104
+ the empty-colour test read the same 200.7 / 67.6 µs. Its UV pointed at an empty texel by mistake, so
105
+ those fragments skipped the volumetrics, the contribution and all four accumulator writes.
106
+
107
+ What remains is rasterising a quarter-million one-pixel triangles plus the fragment's first two
108
+ samples (transmittance and atlas). That attribution is not measured.
109
+
110
+ Bench, driver and arms: session scratchpad `gate/`; none of it is committed.
111
+
112
+ ## Where it stands
113
+
114
+ - **One vertex chunk draws every particle.** `chunk_particle_billboard_vertex` reads a record through
115
+ the emitter's render bindings. Both AVBOIT passes call it: the splat and the draw.
116
+ - **How a corner is placed.** `particle_billboard_offset` rolls the corner by the scalar `rotation`,
117
+ then lays it on two axes the projection mode picks. `particle_billboard_normal` picks the face in a
118
+ second, separate per-mode switch.
119
+ - **The VM is view-independent.** There is no camera builtin. One simulation serves every view and
120
+ the warm-up, so "face the camera" cannot be a program. It has to stay something the renderer applies
121
+ per view.
122
+ - **FACING_WORLD was meant for this.** Its comment says "oriented by the particle's own rotation
123
+ attribute in world space", but it only ever got a roll about world Z.
124
+ - **Bounds are already orientation-free.** `particle_billboard_radius` is √2·size, times (1 + |v|)
125
+ under STRETCHED, and a rotation keeps every corner inside that sphere.
126
+ - **The quaternion pieces exist on both sides.**
127
+ - Graph library: `quatFromAxisAngle`, `quatLookRotation` (maps +Z to `forward` and +Y to `up`) and
128
+ `quatRotate`, all x, y, z, w with w last.
129
+ - Shaders: `quat_rotate_v3`, `quat_from_m3`, and `quat_encode_u32` / `quat_decode_u32`, which have
130
+ JS twins held to the WGSL by `quat_encode_u32_parity.spec`.
131
+ - **Room in the record.** Records are a fixed 32-word stride, and the bonfire's layouts use 16 of the
132
+ 31 user words.
133
+
134
+ ### Found while scoping: three of five frames draw the mirror image (measured)
135
+
136
+ Measured on the emulator with the real `particle_billboard_offset`, corners (1, 0) and (0, 1). The
137
+ camera is at +Z looking −Z unless the row says otherwise.
138
+
139
+ | mode | local +X lands | local +Y lands | front (x × y) |
140
+ |---|---|---|---|
141
+ | BILLBOARD | screen right | screen up | toward the eye |
142
+ | FACING_WORLD | world +X | world +Y | world +Z |
143
+ | STRETCHED, v = 0 | screen **left** | screen up | **away** |
144
+ | STRETCHED, v along screen right | screen up | screen right (×3) | **away** |
145
+ | VERTICAL | screen **left** | screen up | **away** |
146
+ | HORIZONTAL, seen from above | screen right | screen **down** | **world −Y** |
147
+
148
+ - **What it means.** STRETCHED, VERTICAL and HORIZONTAL (seen from above) draw the mirror image of
149
+ BILLBOARD, and roll turns the opposite way in them.
150
+ - **Why nothing caught it.** The offset spec checks STRETCHED's cross axis with `Math.abs` and has no
151
+ VERTICAL case. `particle_billboard_normal` turns every face toward the eye afterwards, which hides
152
+ HORIZONTAL's.
153
+ - **Why it blocks this work.** A rotation composed inside a mirrored frame turns the wrong way about
154
+ every axis.
155
+ - **The three causes:**
156
+ - STRETCHED's `perp = (-dir.y, dir.x)` wants `(dir.y, -dir.x)`.
157
+ - VERTICAL's `cross(up, cam_forward)` wants `cross(cam_forward, up)`.
158
+ - HORIZONTAL's up `(0, 0, 1)` wants `(0, 0, -1)`.
159
+ - **What changes on screen.** No effect in the tree uses VERTICAL or HORIZONTAL. The STRETCHED sparks
160
+ are round and bind no roll.
161
+
162
+ ## The design
163
+
164
+ **The record says how a particle is turned. The projection mode says how a view sees it. One
165
+ function composes the two.**
166
+
167
+ W = F(mode, camera, velocity) · Q
168
+ offset = W · (corner.x · size, corner.y · size · k, 0)
169
+ normal = W · ẑ, turned toward the eye, bent toward the corner as now
170
+
171
+ The parts:
172
+
173
+ - **`Q`, the `orientation` channel**, the only rotation a particle has.
174
+ - A 4-component attribute holding a unit quaternion (x, y, z, w), in the mode's frame.
175
+ - Normalised at the draw; unbound reads as the identity.
176
+ - A zero quaternion is also the identity, with no branch: `q * inverseSqrt(max(dot(q,q), tiny))`
177
+ stays zero, and `quat_rotate_v3(0, v) == v`.
178
+ - A roll is `quatFromAxisAngle(+Z, θ)`, and nothing else.
179
+ - **`F`, the mode's frame.** A proper rotation whose +Z is the side the mode shows (table below). It
180
+ is the mirror fix and the only thing a mode contributes besides `k`.
181
+ - **`k`, STRETCHED's elongation**, `1 + |v_screen|`, and 1 in every other mode.
182
+ - It now stretches the sprite along **its own** +Y.
183
+ - With `Q` the identity, that is the same quad as today.
184
+ - With `Q` turned, the streak turns with the sprite rather than being sheared inside a
185
+ screen-aligned envelope. That fits better: the mode aims the sprite, and the elongation belongs to
186
+ the sprite.
187
+ - It also makes the normal exactly `W · ẑ`, with no inverse-transpose.
188
+ - **`corner`, the canonical quad.** Local +X is the edge BILLBOARD draws on the right, +Y the edge it
189
+ draws at the top, +Z the side it shows the eye.
190
+
191
+ | mode | F.x | F.y | F.z (front) |
192
+ |---|---|---|---|
193
+ | BILLBOARD | camera right | camera up | toward the eye |
194
+ | STRETCHED | screen velocity turned −90° in the camera plane (camera right at rest) | screen velocity (camera up at rest) | toward the eye |
195
+ | VERTICAL | `normalize(cam_forward × +Y)`, world +X looking straight down | world +Y | horizontal, toward the eye |
196
+ | HORIZONTAL | world +X | world −Z | world +Y |
197
+ | FACING_WORLD | world +X | world +Y | world +Z |
198
+
199
+ **The modes are now one function**, `particle_view_rotation(mode, camera, velocity, q) → {W, k}`.
200
+ The vertex calls it once, and neither offset nor normal has a switch of its own. That is the shape a
201
+ pre-pass would host, and it does not change if one is built (see below).
202
+
203
+ **What an orientation means in each mode:**
204
+
205
+ - **FACING_WORLD + orientation is the feature**: a quad turned any way in the world.
206
+ - **BILLBOARD + orientation is a rotation relative to the view.** A roll is the case every existing
207
+ effect uses. A tilt is a card that flips toward the eye. Unity's VFX Graph composes its element
208
+ matrix the same way, `[axisX|axisY|axisZ] · R(angles) · S`, with angleX/Y tilting relative to the
209
+ camera under FaceCameraPlane (`VFXCommon.hlsl`, `GetElementToVFXMatrix`).
210
+ - **STRETCHED, VERTICAL and HORIZONTAL + orientation**: a rotation inside those frames. Nothing needs
211
+ a rule for them.
212
+
213
+ **Bounds do not change.**
214
+
215
+ |W · (c.x·size, c.y·size·k, 0)| ≤ √2 · |size| · k
216
+
217
+ That is `particle_billboard_radius` as it stands, because `k ≤ 1 + |v|`. The bounds pass never reads
218
+ the channel.
219
+
220
+ **The VM does not change.** No opcode, no builtin, no mode ([[particle-vm-isa-stays-primitive]]).
221
+
222
+ **AVBOIT needs nothing new.** Turned quads run through depth across a voxel as HORIZONTAL and
223
+ FACING_WORLD quads already do, and the draw has applied `avboit_footprint_bias` to them since
224
+ ledger 26.
225
+
226
+ ### Why roll goes (Alex's point, and he is right)
227
+
228
+ Revision 1 kept `rotation` beside `orientation` on a cost argument: one word and one MAD a frame
229
+ where a quaternion is four words and a sine and a cosine. That cost is about four VM instructions per
230
+ particle, next to effects that spend hundreds on noise.
231
+
232
+ - **The program keeps its angle.** Spin stays a scalar state attribute (`spin += rate · dt`), and the
233
+ program writes `quatFromAxisAngle(+Z, spin)` to the channel.
234
+ - **What it costs the bonfire.** Flame, smoke and soot go from 16 to 20 words of 31.
235
+ - **What it buys.** Two rotation channels composed in a fixed order is two ways of saying one thing,
236
+ plus an ordering rule. One channel is one rotation.
237
+
238
+ ### The u32 quaternion: on the render side, not in the record (measured)
239
+
240
+ The engine's codec is Bungie's smallest-three: a 2-bit index and three 10-bit components.
241
+
242
+ **As a render format it is invisible.** Over 200,000 uniform random rotations, the round-trip error is
243
+ median 0.085°, p99 0.150° and max 0.244°. At the corner of a 1 m quad, that is at most 3 mm.
244
+
245
+ **As state a program integrates, it fails.** The test re-encodes every frame for 10 s with an exact
246
+ axis-angle step, over 200 random starts and axes:
247
+
248
+ | spin | fps | frames that did not move | turned / asked (median) | final error (median, p90) |
249
+ |---|---|---|---|---|
250
+ | 0.1 rad/s | 60 | 84.5 % | 0.001 | 57°, 57° |
251
+ | 0.3 rad/s | 60 | 0 % | 0.963 | 22°, 33° |
252
+ | 1 rad/s | 60 | 0 % | 1.000 | 7.5°, 12.7° |
253
+ | 0.1 rad/s | 144 | 100 % | 0.000 | 57°, 57° |
254
+ | 0.3 rad/s | 144 | 71.5 % | 0.294 | 124°, 172° |
255
+ | 1 rad/s | 144 | 0 % | 0.974 | 30°, 52° |
256
+ | 10 rad/s | 144 | 0 % | 1.000 | 5.9°, 10.3° |
257
+
258
+ A falling leaf's tumble is exactly that slow range. It freezes, and how badly depends on the
259
+ player's frame rate.
260
+
261
+ **The VM also cannot carry the word.** Its registers are `f32` and it has no bit operations.
262
+
263
+ - **Where a codec word goes wrong.** The identity rotation encodes to a word that reads as NaN as an
264
+ `f32`, and so does a 90° roll. About 0.46 % of uniform random rotations read as NaN or subnormal.
265
+ - **Why that matters.** WGSL does not promise to preserve those bits through arithmetic or moves
266
+ (subnormals may be flushed). I have not measured a failure, but an f32 register is not a safe
267
+ carrier for them.
268
+ - **What it would take.** An encode-at-store opcode: domain-specific, in the switch of the two passes
269
+ whose register pressure sets occupancy.
270
+ - **What it would save.** Words of a fixed stride, so no memory: two words for a roll-only effect, and
271
+ for a tumbling one nothing, since it still needs its `f32` state.
272
+
273
+ So the record carries `f32 × 4`, and the u32 lives wherever the world rotation is written down for a
274
+ view, which is the next section.
275
+
276
+ ### The pre-pass
277
+
278
+ Alex's suggestion: a pass that writes the quaternion under the camera-dependent modes and leaves it
279
+ alone under the others, so the vertex only ever reads a quaternion. It splits in two.
280
+
281
+ **Writing into the particle's own attribute: no.**
282
+
283
+ - **The attribute is the program's state.** Next frame's UPDATE reads it back. A spin integrated on
284
+ top of the camera's rotation is garbage. The roll the program wrote is exactly what would be
285
+ overwritten, so roll could not go through the quaternion at all.
286
+ - **Its owner would depend on the mode.** The renderer would own it under BILLBOARD and the program
287
+ under FACING_WORLD. That is a channel whose meaning depends on a flag, the same smell as a
288
+ parameter whose meaning depends on its type.
289
+ - **One value cannot serve two views.** One view today. Not once shadows, reflections or a second
290
+ viewport draw particles.
291
+
292
+ **A per-view pass with its own output: yes in shape, not yet in fact.**
293
+
294
+ - **What it does.** One thread per alive particle per view, indirect over the alive count, calls
295
+ `particle_view_rotation`, encodes `W` with `quat_encode_u32` and writes it beside `k`. The vertex
296
+ then decodes and rotates.
297
+ - **Why u32 belongs there.** The pass encodes once from the exact rotation, nothing integrates
298
+ through it, and the word never touches an `f32` register.
299
+ - **Where the doubt is.** If it writes only the rotation, it removes about 30 ALU ops of frame math
300
+ per vertex. It still leaves the vertex decoding the emitter record and reading five channels through
301
+ the bindings. The price is a dispatch (5–8 µs floor on the 4090) and a write plus read per particle.
302
+ - **Where it could earn its keep.** By resolving the whole draw input: position, size × k, rotation as
303
+ u32, colour, atlas rect for the current frame, and flags. Then the twelve vertex invocations a
304
+ particle costs each frame (six in the splat, six in the draw) read one compact record and never see
305
+ an emitter or a binding.
306
+ - **What decides it.** The vertex stage's share of splat + draw at a vertex-heavy load, which nobody
307
+ has measured.
308
+
309
+ **Decision:** land the channel with `particle_view_rotation` called from the vertex. Then measure:
310
+
311
+ - **Load.** One page, paired, a vertex-heavy scene (about 200k small additive sparks).
312
+ - **Arms.** Splat + draw as built, against a vertex whose record and emitter reads are replaced by
313
+ constants. That second arm is the floor of what any view pass can give the vertex.
314
+ - **Plus.** A compute pass that touches alive × 8 words, which is the pass's own cost.
315
+ - **Rule.** If the difference does not clear the pass's cost, the pass is not built.
316
+
317
+ Nothing in the first step is thrown away either way. The record contract is the same, and the pass
318
+ would move one call out of the vertex.
319
+
320
+ ### Library: graph groups, not opcodes
321
+
322
+ The library already has `quatFromAxisAngle`, `quatLookRotation` and `quatRotate`, and gains four:
323
+
324
+ - **`quatMultiply(a, b)`.** Turn by b, then by a, the same order as `Quaternion.multiplyQuaternions`.
325
+ About 9 instructions.
326
+ - **`quatIntegrate(quat, omega, dt)`.** `quatFromAxisAngle(ω, |ω|·dt) ⊗ q`, renormalised, about 17
327
+ instructions, exact at any `dt`.
328
+ - **Rejected alternative:** first-order (`core/geom/3d/quaternion/quat3_integrate.js`, Catto),
329
+ which turns by `2·atan(|ω|dt/2)`.
330
+ - **Why it loses.** The warm-up's ticks reach 156 ms for a 5 s pre-warm (32 ticks at most), where
331
+ 10 rad/s comes out 15 % short. DESIGN.md's warm-up rests on programs not caring what `DELTA_TIME`
332
+ they get.
333
+ - **`randomRotation(uvw)`.** Uniform, after Shoemake (Graphics Gems III). It goes beside the sphere
334
+ samplers in `particle_graph_distributions.js`.
335
+ - **`emitterRotation`.** It is `quatLookRotation(-EMITTER_DIRECTION, EMITTER_UP)`, and it carries the
336
+ sign. The builtin's direction is the node's −Z, so wiring it straight in shows the quad's back.
337
+
338
+ Register peaks are pinned in `particle_group_library.spec.js`, all far under 48.
339
+
340
+ **A tumbling flake:**
341
+
342
+ - **INIT:** `orientation = randomRotation(random3)`, `spin = sampleSphereSurface(random2) · speed`.
343
+ - **UPDATE:** `orientation = quatIntegrate(orientation, spin, dt)`.
344
+ - **Cost:** seven words, about 17 instructions a frame.
345
+
346
+ ## Rejected
347
+
348
+ - **A roll channel beside the quaternion** (revision 1). See "Why roll goes".
349
+ - **u32 in the record, or a VM encode opcode.** See the measurements.
350
+ - **The pre-pass writing into the record.** See "The pre-pass".
351
+ - **Two vectors, facing + alignment** (Niagara sprites, PopcornFX PlaneAligned). Six words,
352
+ degenerate when parallel, and quad-only. `quatLookRotation` already builds the quaternion from that
353
+ pair.
354
+ - **Euler angles** (Unity VFX). An order convention and gimbal lock.
355
+ - **A rotation vector.** It saves one word of a fixed stride and costs trigonometry per vertex.
356
+ - **Orientation honoured only in FACING_WORLD.** That is Godot's particle billboard, which keeps only a
357
+ roll. A channel's meaning would depend on the mode.
358
+ - **A new ORIENTED mode.** FACING_WORLD with the identity is that mode.
359
+ - **An emitter-local frame** (Shuriken "Local"). It needs the scene database in the draw.
360
+ `emitterRotation` does the same in INIT.
361
+
362
+ Precedent, read from source: Niagara meshes, Niagara sprites, Unity VFX Graph and PopcornFX all
363
+ compose the particle's rotation inside the facing frame. The mesh paths (Niagara `MeshOrientation`,
364
+ PopcornFX `Orientation`, Houdini `orient`) store a quaternion.
365
+
366
+ ## Touch list
367
+
368
+ Changes:
369
+
370
+ - `shaders/chunk_particle_render_math.js`:
371
+ - New `particle_view_rotation`, with the three frame fixes.
372
+ - `particle_billboard_offset` / `_normal` reduce to `W · (corner ⊙ extent)` and `W · ẑ`.
373
+ - `particle_billboard_radius` is unchanged, and its comment gains the rotation argument.
374
+ - `shaders/chunk_particle_billboard_vertex.js`: reads `render_orientation` (four words, identity when
375
+ absent) and drops `render_rotation`.
376
+ - `data/PARTICLE_EMITTER_STRUCT.js`: `render_rotation` becomes `render_orientation`, and FACING_WORLD's
377
+ comment is updated. `data/particle_emitter_record.js` follows.
378
+ - `runtime/ParticleEmitter.js` and `engine/graphics/ecs/particles/ParticleEffect.js`:
379
+ - In `EMITTER_RENDER_CHANNELS`, `rotation` (1) becomes `orientation` (4).
380
+ - The field, `bind_render`, `equals`, `hash`, `copy` and `from` follow.
381
+ - `engine/graphics3/GPUParticleEmitterSystem.js`: the comparison in `apply_particle_effect`.
382
+ - `ParticleEffectSerializationAdapter`:
383
+ - Goes to version 2, with `ParticleEffectSerializationUpgrader_1_2`.
384
+ - A v1 roll binding is dropped, because bytecode that writes an angle cannot be upgraded into
385
+ bytecode that writes a quaternion. A spinning v1 effect loads still, which is a hard break and
386
+ accepted ([[removing-deprecated-surface]]).
387
+ - `playground/particle_ecs/effects/{flame,smoke,soot}.json` re-authored:
388
+ - A 4-word `orientation` attribute.
389
+ - `quatFromAxisAngle(+Z, spin)` written in INIT and UPDATE, bound to `orientation`.
390
+ - `bonfire.spec.js` pins the new binding.
391
+ - `editor/particles/effect/ParticleReferenceSimulation.js`: `forEachParticle` stops reporting
392
+ `rotation`, which the preview never drew.
393
+ - Graph groups, as listed under "Library", plus the editor palette's "rotation" row.
394
+ - `DESIGN.md` §Rendering: the composition and the frame table.
395
+
396
+ No change:
397
+
398
+ - **The editor's emitter inspector.** It builds its pickers and width warnings from the channel lists.
399
+ - **The bounds pass, occupancy, the VM, the ISA and the optimizer.**
400
+
401
+ ## Ledger
402
+
403
+ Specs follow the house rules: plain `test()`, public API or what reaches the device, red first where
404
+ the item is a fix.
405
+
406
+ 1. **Every mode shows the sprite as BILLBOARD does**: +X right, +Y up, front to the eye. Red today for
407
+ STRETCHED, VERTICAL, and HORIZONTAL seen from above.
408
+ 2. **An orientation of `quatFromAxisAngle(+Z, θ)` turns counter-clockwise, seen from the front, in
409
+ every mode.**
410
+ 3. **Unbound orientation draws today's quad** (after 1), in every mode.
411
+ 4. **Two placements check the composition:**
412
+ - FACING_WORLD with a quarter turn about +X lays the quad in world XZ.
413
+ - BILLBOARD with one fixed orientation gives the same screen picture from three cameras.
414
+ 5. **STRETCHED with a turn elongates along the sprite's own +Y.**
415
+ 6. **Edge quaternions:** zero draws the identity, and 2q draws what q draws.
416
+ 7. **The normal is W·ẑ turned to the eye**, the plane normal of the drawn corners in every mode.
417
+ 8. **The bounds sweep gains random orientations.** A pin, expected green with no change.
418
+ 9. **The groups match CPU references:**
419
+ - `quatMultiply` matches `Quaternion.multiplyQuaternions`.
420
+ - `quatIntegrate` matches the closed form at dt 1/60 and 0.5, and stays unit after 10,000 steps.
421
+ - `randomRotation` gives E[qᵢ²] = ¼ and E[qᵢqⱼ] = 0.
422
+ 10. **Plumbing:** the channel lists, struct, record writer, emitter and component, and system apply;
423
+ serialization round trip; a v1 save loads with its roll binding dropped.
424
+ 11. **The bonfire's three effects bind `orientation`**, and still fit the fast register file.
425
+
426
+ ## Device check
427
+
428
+ A one-off from the scratchpad on the headless driver. A few hundred frames.
429
+
430
+ - **The bonfire.** It looks as it did, with flame, smoke and soot spinning through the quaternion. A
431
+ side-by-side against master says whether the spin direction matches. It should: none of the three
432
+ is a mirrored mode.
433
+ - **`ash`.** Tumbling, lit FACING_WORLD flakes behind `?ash`. The flakes catching the fire as they turn
434
+ are the normal path working.
435
+ - **Timings.** A paired A/B of the draw against master. The predicted difference is nothing
436
+ measurable, until a run says otherwise.
437
+ - **The pre-pass gate.** The measurement described under "The pre-pass".
438
+
439
+ ## Order of landing
440
+
441
+ 1. **The frame fix** as `particle_view_rotation`, with `rotation` still the input. Ledger 1, and 2 in
442
+ its roll form.
443
+ 2. **The `orientation` channel replaces `rotation`** end to end: struct to serialization, plus the
444
+ bonfire re-authored. Ledger 3–8, 10, 11.
445
+ 3. **The library groups**, ledger 9.
446
+ 4. **DESIGN.md, `ash`, the device check, the pre-pass gate.**
447
+
448
+ ## Out of scope
449
+
450
+ - **Mesh particles.** The channel is the one they would read.
451
+ - **Non-square sprites.** `size` stays a scalar; `k` is the mode's.
452
+ - **Per-particle locked-axis billboards.**
453
+ - **The per-view pass itself**, until the gate says build it.
@@ -67,7 +67,11 @@ export const EMITTER_BLEND: Readonly<{
67
67
  ADDITIVE: 1;
68
68
  PREMULTIPLIED: 2;
69
69
  }>;
70
- /** Projection / orientation modes (stored in flag bits [6,9)). */
70
+ /**
71
+ * Projection modes (stored in flag bits [6,9)): the frame a particle's quad is laid in. The
72
+ * particle's own `orientation` turns it inside that frame, so a mode is how a view sees the
73
+ * particle and the orientation is how the particle is turned.
74
+ */
71
75
  export const EMITTER_PROJECTION: Readonly<{
72
76
  BILLBOARD: 0;
73
77
  STRETCHED: 1;
@@ -1 +1 @@
1
- {"version":3,"file":"PARTICLE_EMITTER_STRUCT.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js"],"names":[],"mappings":"AAmIA;;;;;;;;;GASG;AACH;IAP6B,QAAQ,GAA1B,OAAO;IACW,UAAU,GAA5B,OAAO;IACW,IAAI,GAAtB,OAAO;IACU,KAAK,GAAtB,MAAM;IACW,UAAU,GAA3B,MAAM;IACJ,MAAM,CAUlB;AAED,6DAA6D;AAC7D,2CADY,MAAM,GAAkB,MAAM,CAGzC;AAED,kEAAkE;AAClE,gDADY,MAAM,GAAkB,MAAM,CAGzC;AA5JD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,sCAFU,YAAY,CA+DO;AAE7B,uDAAuD;AACvD,kDAAmD;AAEnD;;;;;;GAMG;AACH;;;;GAIG;AAEH,kGAAkG;AAClG;;;;GAIG;AAKH,kEAAkE;AAClE;;;;;;GAMG;AAmCH,uEAAuE;AACvE;;;;;GAEG;6BAnK0B,mCAAmC"}
1
+ {"version":3,"file":"PARTICLE_EMITTER_STRUCT.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js"],"names":[],"mappings":"AA2IA;;;;;;;;;GASG;AACH;IAP6B,QAAQ,GAA1B,OAAO;IACW,UAAU,GAA5B,OAAO;IACW,IAAI,GAAtB,OAAO;IACU,KAAK,GAAtB,MAAM;IACW,UAAU,GAA3B,MAAM;IACJ,MAAM,CAUlB;AAED,6DAA6D;AAC7D,2CADY,MAAM,GAAkB,MAAM,CAGzC;AAED,kEAAkE;AAClE,gDADY,MAAM,GAAkB,MAAM,CAGzC;AApKD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,sCAFU,YAAY,CAmEO;AAE7B,uDAAuD;AACvD,kDAAmD;AAEnD;;;;;;GAMG;AACH;;;;GAIG;AAEH,kGAAkG;AAClG;;;;GAIG;AAKH;;;;GAIG;AACH;;;;;;GAMG;AAmCH,uEAAuE;AACvE;;;;;GAEG;6BA3K0B,mCAAmC"}
@@ -66,8 +66,12 @@ export const PARTICLE_EMITTER_STRUCT = WebGPUStruct.from({
66
66
  render_size: u32,
67
67
  /** attribute word offset of rgba colour */
68
68
  render_color: u32,
69
- /** attribute word offset of roll angle, radians */
70
- render_rotation: u32,
69
+ /**
70
+ * attribute word offset of the orientation: a quaternion (x, y, z, w) turning the sprite inside
71
+ * its projection mode's frame — in the world under FACING_WORLD, relative to the view under
72
+ * BILLBOARD, where a turn about +Z is a roll
73
+ */
74
+ render_orientation: u32,
71
75
  /** attribute word offset of flipbook frame index */
72
76
  render_frame: u32,
73
77
  /** attribute word offset of velocity (STRETCHED projection) */
@@ -117,13 +121,17 @@ export const EMITTER_BLEND = Object.freeze({
117
121
  const BLEND_SHIFT = 4;
118
122
  const BLEND_MASK = 0b11 << BLEND_SHIFT;
119
123
 
120
- /** Projection / orientation modes (stored in flag bits [6,9)). */
124
+ /**
125
+ * Projection modes (stored in flag bits [6,9)): the frame a particle's quad is laid in. The
126
+ * particle's own `orientation` turns it inside that frame, so a mode is how a view sees the
127
+ * particle and the orientation is how the particle is turned.
128
+ */
121
129
  export const EMITTER_PROJECTION = Object.freeze({
122
130
  BILLBOARD: 0, // face the camera
123
131
  STRETCHED: 1, // billboard stretched along velocity
124
- HORIZONTAL: 2, // lie flat on the ground plane (XZ)
132
+ HORIZONTAL: 2, // lie flat on the ground plane (XZ), facing up
125
133
  VERTICAL: 3, // axis-locked to world up, yaw toward camera
126
- FACING_WORLD: 4, // oriented by the particle's own rotation attribute in world space
134
+ FACING_WORLD: 4, // the world's own axes: the orientation is the particle's rotation in the world
127
135
  });
128
136
 
129
137
  const PROJECTION_SHIFT = 6;
@@ -59,7 +59,7 @@ export function write_emitter_record(record, emitter, context) {
59
59
  record.render_position = emitter.render_position;
60
60
  record.render_size = emitter.render_size;
61
61
  record.render_color = emitter.render_color;
62
- record.render_rotation = emitter.render_rotation;
62
+ record.render_orientation = emitter.render_orientation;
63
63
  record.render_frame = emitter.render_frame;
64
64
  record.render_velocity = emitter.render_velocity;
65
65
 
@@ -93,7 +93,7 @@ export function create_emitter_record() {
93
93
  render_position: 0,
94
94
  render_size: 0,
95
95
  render_color: 0,
96
- render_rotation: 0,
96
+ render_orientation: 0,
97
97
  render_frame: 0,
98
98
  render_velocity: 0,
99
99
 
@@ -1 +1 @@
1
- {"version":3,"file":"particle_builtin_groups.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/particles/graph/groups/particle_builtin_groups.js"],"names":[],"mappings":"AA2BA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;;;;GAQG;AACH,sCAFU,OAAO,yBAAyB,EAAE,iBAAiB,EAAE,CAyB7D"}
1
+ {"version":3,"file":"particle_builtin_groups.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/particles/graph/groups/particle_builtin_groups.js"],"names":[],"mappings":"AA+BA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;;;;GAQG;AACH,sCAFU,OAAO,yBAAyB,EAAE,iBAAiB,EAAE,CAiC7D"}
@@ -1,9 +1,13 @@
1
1
  import { register_particle_group } from "../particle_group_library.js";
2
2
  import {
3
3
  PARTICLE_GROUP_ANGLE_BETWEEN,
4
+ PARTICLE_GROUP_EMITTER_ROTATION,
4
5
  PARTICLE_GROUP_QUAT_FROM_AXIS_ANGLE,
6
+ PARTICLE_GROUP_QUAT_INTEGRATE,
5
7
  PARTICLE_GROUP_QUAT_LOOK_ROTATION,
8
+ PARTICLE_GROUP_QUAT_MULTIPLY,
6
9
  PARTICLE_GROUP_QUAT_ROTATE,
10
+ PARTICLE_GROUP_SAMPLE_ROTATION,
7
11
  PARTICLE_GROUP_SAMPLE_SPHERE_SURFACE,
8
12
  PARTICLE_GROUP_SAMPLE_SPHERE_VOLUME,
9
13
  } from "./particle_groups_geometry.js";
@@ -74,6 +78,14 @@ export const PARTICLE_BUILTIN_GROUPS = [
74
78
  PARTICLE_GROUP_PSRDNOISE_3,
75
79
  PARTICLE_GROUP_CURL_3,
76
80
  PARTICLE_GROUP_CURL_4,
81
+
82
+ // rotations for the orientation channel — appended rather than filed with the rotations above,
83
+ // because a group's description id is allocated in registration order and filing them there
84
+ // would renumber every group after them
85
+ PARTICLE_GROUP_QUAT_MULTIPLY,
86
+ PARTICLE_GROUP_QUAT_INTEGRATE,
87
+ PARTICLE_GROUP_SAMPLE_ROTATION,
88
+ PARTICLE_GROUP_EMITTER_ROTATION,
77
89
  ];
78
90
 
79
91
  for (const group of PARTICLE_BUILTIN_GROUPS) {
@@ -80,4 +80,64 @@ export const PARTICLE_GROUP_QUAT_ROTATE: import("../ParticleNodeGroup.js").Parti
80
80
  * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
81
81
  */
82
82
  export const PARTICLE_GROUP_QUAT_LOOK_ROTATION: import("../ParticleNodeGroup.js").ParticleNodeGroup;
83
+ /**
84
+ * Two rotations, one after the other: the turn by `b`, then the turn by `a`.
85
+ *
86
+ * The Hamilton product, `(a.w b.xyz + b.w a.xyz + a.xyz × b.xyz, a.w b.w - a.xyz · b.xyz)`, in the
87
+ * order the engine's `Quaternion.multiplyQuaternions(a, b)` writes it — so turning a vector by the
88
+ * result is turning it by `b` and then by `a`. Not commutative: swapping the inputs turns about the
89
+ * other frame.
90
+ *
91
+ * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
92
+ */
93
+ export const PARTICLE_GROUP_QUAT_MULTIPLY: import("../ParticleNodeGroup.js").ParticleNodeGroup;
94
+ /**
95
+ * An orientation advanced by an angular velocity over a step: `quat` turned by `omega`, in radians
96
+ * per second about the axis it points along, for `dt` seconds.
97
+ *
98
+ * Exact for a constant `omega` at any `dt` — the step is the rotation itself,
99
+ * `quatFromAxisAngle(omega, |omega| dt)`, composed in front — rather than the first-order
100
+ * `q + dt/2 (omega, 0) q` a rigid-body solver takes. That one turns by `2 atan(|omega| dt / 2)` instead
101
+ * of `|omega| dt`, which a solver stepping at a fixed 1/60 never notices, and a particle does: the
102
+ * warm-up stretches its ticks to cover a whole pre-warm in at most
103
+ * {@link ../../ParticleConstants.js PARTICLE_WARMUP_MAX_TICKS} of them, 156 ms each for five seconds,
104
+ * where a 10 rad/s tumble would come out 15% slow. A program does not get to care what `dt` it is
105
+ * handed.
106
+ *
107
+ * `omega` turns in the frame the orientation is in — the world, for a FACING_WORLD emitter — which is
108
+ * why the step goes in front. The result is renormalised, so a tumble integrated for a minute is
109
+ * still a unit quaternion and `quatRotate` does not start scaling what it turns. A zero `omega` is
110
+ * no turn.
111
+ *
112
+ * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
113
+ */
114
+ export const PARTICLE_GROUP_QUAT_INTEGRATE: import("../ParticleNodeGroup.js").ParticleNodeGroup;
115
+ /**
116
+ * A rotation drawn uniformly from all of them, from three numbers in `[0, 1)`.
117
+ *
118
+ * Shoemake's construction ("Uniform random rotations", Graphics Gems III): with `u` the first number,
119
+ * the quaternion is `(sqrt(1-u) sin 2πv, sqrt(1-u) cos 2πv, sqrt(u) sin 2πw, sqrt(u) cos 2πw)`. It
120
+ * lands on the unit sphere in four dimensions uniformly, which is what a uniform rotation is. Drawing
121
+ * three Euler angles uniformly is the tempting wrong one, and clusters the turns.
122
+ *
123
+ * Feed it a three-lane `random` and it is a tumbling flake's starting orientation.
124
+ *
125
+ * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
126
+ */
127
+ export const PARTICLE_GROUP_SAMPLE_ROTATION: import("../ParticleNodeGroup.js").ParticleNodeGroup;
128
+ /**
129
+ * The emitter's own rotation: the turn that takes the world's axes to its node's.
130
+ *
131
+ * The VM hands an effect the node's axes rather than its rotation — `EMITTER_DIRECTION`, which is the
132
+ * node's forward and so its **-Z**, and `EMITTER_UP`, its +Y — and a look rotation maps **+Z** to the
133
+ * forward it is given. Wiring the two straight together therefore turns a sprite half a turn and
134
+ * shows its back. This is that wiring with the sign put right, which is the whole reason it is a
135
+ * group.
136
+ *
137
+ * Write it into a FACING_WORLD particle's orientation at birth and the sprite starts out lying in
138
+ * its emitter's XY plane, facing the emitter's +Z.
139
+ *
140
+ * @type {import("../ParticleNodeGroup.js").ParticleNodeGroup}
141
+ */
142
+ export const PARTICLE_GROUP_EMITTER_ROTATION: import("../ParticleNodeGroup.js").ParticleNodeGroup;
83
143
  //# sourceMappingURL=particle_groups_geometry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"particle_groups_geometry.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/particles/graph/groups/particle_groups_geometry.js"],"names":[],"mappings":"AAqCA;;;;;;;;;;;GAWG;AACH,mDAFU,OAAO,yBAAyB,EAAE,iBAAiB,CAsBxD;AAEL;;;;;;;;;GASG;AACH,kDAFU,OAAO,yBAAyB,EAAE,iBAAiB,CAmBxD;AAEL;;;;;;;;;;;;GAYG;AACH,2CAFU,OAAO,yBAAyB,EAAE,iBAAiB,EAAE,CAiB5D;AAEH;;;;;;;;GAQG;AACH,kDAFU,OAAO,yBAAyB,EAAE,iBAAiB,CAsBxD;AAEL;;;;;;;;;;;GAWG;AACH,yCAFU,OAAO,yBAAyB,EAAE,iBAAiB,CAuBxD;AAEL;;;;;;;;;;;;;;;;;;;GAmBG;AACH,gDAFU,OAAO,yBAAyB,EAAE,iBAAiB,CA+ExD"}
1
+ {"version":3,"file":"particle_groups_geometry.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/particles/graph/groups/particle_groups_geometry.js"],"names":[],"mappings":"AAsCA;;;;;;;;;;;GAWG;AACH,mDAFU,OAAO,yBAAyB,EAAE,iBAAiB,CAsBxD;AAEL;;;;;;;;;GASG;AACH,kDAFU,OAAO,yBAAyB,EAAE,iBAAiB,CAmBxD;AAEL;;;;;;;;;;;;GAYG;AACH,2CAFU,OAAO,yBAAyB,EAAE,iBAAiB,EAAE,CAiB5D;AAEH;;;;;;;;GAQG;AACH,kDAFU,OAAO,yBAAyB,EAAE,iBAAiB,CAsBxD;AAEL;;;;;;;;;;;GAWG;AACH,yCAFU,OAAO,yBAAyB,EAAE,iBAAiB,CAuBxD;AAEL;;;;;;;;;;;;;;;;;;;GAmBG;AACH,gDAFU,OAAO,yBAAyB,EAAE,iBAAiB,CA+ExD;AAEL;;;;;;;;;GASG;AACH,2CAFU,OAAO,yBAAyB,EAAE,iBAAiB,CA0BxD;AAEL;;;;;;;;;;;;;;;;;;;GAmBG;AACH,4CAFU,OAAO,yBAAyB,EAAE,iBAAiB,CA0BxD;AAEL;;;;;;;;;;;GAWG;AACH,6CAFU,OAAO,yBAAyB,EAAE,iBAAiB,CA6BxD;AAEL;;;;;;;;;;;;;GAaG;AACH,8CAFU,OAAO,yBAAyB,EAAE,iBAAiB,CAkBxD"}