@woosh/meep-engine 3.23.0 → 3.24.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 (522) hide show
  1. package/editor/entity_world_bounds.d.ts +9 -3
  2. package/editor/entity_world_bounds.d.ts.map +1 -1
  3. package/editor/entity_world_bounds.js +61 -4
  4. package/package.json +1 -1
  5. package/src/core/binary/allocator/OffsetAllocator.d.ts +40 -2
  6. package/src/core/binary/allocator/OffsetAllocator.d.ts.map +1 -1
  7. package/src/core/binary/allocator/OffsetAllocator.js +124 -29
  8. package/src/core/collection/map/u32_index.d.ts +83 -0
  9. package/src/core/collection/map/u32_index.d.ts.map +1 -0
  10. package/src/core/collection/map/u32_index.js +247 -0
  11. package/src/engine/asset/loaders/GLTFSceneBundleAssetLoader.d.ts +2 -2
  12. package/src/engine/asset/loaders/GLTFSceneBundleAssetLoader.js +2 -2
  13. package/src/engine/asset/loaders/USDSceneBundleAssetLoader.d.ts +1 -2
  14. package/src/engine/asset/loaders/USDSceneBundleAssetLoader.d.ts.map +1 -1
  15. package/src/engine/asset/loaders/USDSceneBundleAssetLoader.js +4 -12
  16. package/src/engine/ecs/gpu/GPUStateAuthority.d.ts +55 -0
  17. package/src/engine/ecs/gpu/GPUStateAuthority.d.ts.map +1 -0
  18. package/src/engine/ecs/gpu/GPUStateAuthority.js +72 -0
  19. package/src/engine/ecs/gpu/GPUStateAuthorityFlags.d.ts +40 -0
  20. package/src/engine/ecs/gpu/GPUStateAuthorityFlags.d.ts.map +1 -0
  21. package/src/engine/ecs/gpu/GPUStateAuthorityFlags.js +79 -0
  22. package/src/engine/ecs/gpu/gpu_authority_assert_cpu.d.ts +18 -0
  23. package/src/engine/ecs/gpu/gpu_authority_assert_cpu.d.ts.map +1 -0
  24. package/src/engine/ecs/gpu/gpu_authority_assert_cpu.js +27 -0
  25. package/src/engine/ecs/gpu/gpu_authority_declare.d.ts +23 -0
  26. package/src/engine/ecs/gpu/gpu_authority_declare.d.ts.map +1 -0
  27. package/src/engine/ecs/gpu/gpu_authority_declare.js +39 -0
  28. package/src/engine/ecs/gpu/gpu_authority_grant.d.ts +15 -0
  29. package/src/engine/ecs/gpu/gpu_authority_grant.d.ts.map +1 -0
  30. package/src/engine/ecs/gpu/gpu_authority_grant.js +38 -0
  31. package/src/engine/ecs/gpu/gpu_authority_has.d.ts +18 -0
  32. package/src/engine/ecs/gpu/gpu_authority_has.d.ts.map +1 -0
  33. package/src/engine/ecs/gpu/gpu_authority_has.js +28 -0
  34. package/src/engine/ecs/gpu/gpu_authority_revoke.d.ts +24 -0
  35. package/src/engine/ecs/gpu/gpu_authority_revoke.d.ts.map +1 -0
  36. package/src/engine/ecs/gpu/gpu_authority_revoke.js +49 -0
  37. package/src/engine/ecs/ik/IKProblem.d.ts +14 -0
  38. package/src/engine/ecs/ik/IKProblem.d.ts.map +1 -1
  39. package/src/engine/ecs/ik/IKProblem.js +16 -0
  40. package/src/engine/ecs/ik/InverseKinematicsSystem.d.ts.map +1 -1
  41. package/src/engine/ecs/ik/InverseKinematicsSystem.js +19 -0
  42. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +2 -2
  43. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.js +2 -2
  44. package/src/engine/ecs/ik/ik_bone_chain.d.ts +11 -2
  45. package/src/engine/ecs/ik/ik_bone_chain.d.ts.map +1 -1
  46. package/src/engine/ecs/ik/ik_bone_chain.js +47 -2
  47. package/src/engine/ecs/ik/ik_write_local_rotation.d.ts.map +1 -1
  48. package/src/engine/ecs/ik/ik_write_local_rotation.js +6 -0
  49. package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
  50. package/src/engine/ecs/speaker/VoiceSystem.js +6 -0
  51. package/src/engine/ecs/transform/T64WorldCache.d.ts +50 -0
  52. package/src/engine/ecs/transform/T64WorldCache.d.ts.map +1 -0
  53. package/src/engine/ecs/transform/T64WorldCache.js +139 -0
  54. package/src/engine/ecs/transform/t64_evaluate_world.d.ts +31 -0
  55. package/src/engine/ecs/transform/t64_evaluate_world.d.ts.map +1 -0
  56. package/src/engine/ecs/transform/t64_evaluate_world.js +126 -0
  57. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts +8 -0
  58. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
  59. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +59 -30
  60. package/src/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.d.ts.map +1 -1
  61. package/src/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.js +4 -11
  62. package/src/engine/graphics/ecs/mesh-v2/SHADED_GEOMETRY_EVENT_CHANGE.d.ts +14 -0
  63. package/src/engine/graphics/ecs/mesh-v2/SHADED_GEOMETRY_EVENT_CHANGE.d.ts.map +1 -0
  64. package/src/engine/graphics/ecs/mesh-v2/SHADED_GEOMETRY_EVENT_CHANGE.js +13 -0
  65. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +2 -14
  66. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts.map +1 -1
  67. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +11 -21
  68. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.d.ts +1 -0
  69. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +7 -0
  70. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshHighlightSystem.d.ts +5 -6
  71. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshHighlightSystem.d.ts.map +1 -1
  72. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshHighlightSystem.js +13 -11
  73. package/src/engine/graphics/ecs/mesh-v2/shaded_geometry_announce_change.d.ts +14 -0
  74. package/src/engine/graphics/ecs/mesh-v2/shaded_geometry_announce_change.d.ts.map +1 -0
  75. package/src/engine/graphics/ecs/mesh-v2/shaded_geometry_announce_change.js +21 -0
  76. package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts +1 -1
  77. package/src/engine/graphics/ecs/particles/ParticleEffect.js +1 -1
  78. package/src/engine/graphics/sh3/path_tracer/populate_path_traced_scene_from_ecd.d.ts +1 -1
  79. package/src/engine/graphics/sh3/path_tracer/populate_path_traced_scene_from_ecd.js +1 -1
  80. package/src/engine/graphics3/AnimationGraphSystem.js +3 -3
  81. package/src/engine/graphics3/AnimationSystem.js +2 -2
  82. package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -1
  83. package/src/engine/graphics3/DebugDrawSystem.js +2 -4
  84. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +34 -27
  85. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
  86. package/src/engine/graphics3/GPUParticleEmitterSystem.js +185 -85
  87. package/src/engine/graphics3/HighlightOutlineSystem.d.ts +4 -3
  88. package/src/engine/graphics3/HighlightOutlineSystem.d.ts.map +1 -1
  89. package/src/engine/graphics3/HighlightOutlineSystem.js +7 -9
  90. package/src/engine/graphics3/LightSystem.d.ts +7 -5
  91. package/src/engine/graphics3/LightSystem.d.ts.map +1 -1
  92. package/src/engine/graphics3/LightSystem.js +36 -22
  93. package/src/engine/graphics3/MeshSystem.d.ts +43 -39
  94. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  95. package/src/engine/graphics3/MeshSystem.js +324 -331
  96. package/src/engine/graphics3/PathDisplaySystem.d.ts.map +1 -1
  97. package/src/engine/graphics3/PathDisplaySystem.js +2 -4
  98. package/src/engine/graphics3/PickingQuery.d.ts +15 -21
  99. package/src/engine/graphics3/PickingQuery.d.ts.map +1 -1
  100. package/src/engine/graphics3/PickingQuery.js +21 -25
  101. package/src/engine/graphics3/PickingSystem.d.ts +60 -31
  102. package/src/engine/graphics3/PickingSystem.d.ts.map +1 -1
  103. package/src/engine/graphics3/PickingSystem.js +416 -273
  104. package/src/engine/graphics3/ShadedGeometrySystem.d.ts +22 -12
  105. package/src/engine/graphics3/ShadedGeometrySystem.d.ts.map +1 -1
  106. package/src/engine/graphics3/ShadedGeometrySystem.js +309 -174
  107. package/src/engine/graphics3/TerrainSystem.d.ts +19 -11
  108. package/src/engine/graphics3/TerrainSystem.d.ts.map +1 -1
  109. package/src/engine/graphics3/TerrainSystem.js +102 -53
  110. package/src/engine/graphics3/TooltipComponentSystem.d.ts.map +1 -1
  111. package/src/engine/graphics3/TooltipComponentSystem.js +2 -14
  112. package/src/engine/graphics3/Trail3DSystem.d.ts.map +1 -1
  113. package/src/engine/graphics3/Trail3DSystem.js +2 -4
  114. package/src/engine/graphics3/animation/ClipListPlayer.d.ts +4 -4
  115. package/src/engine/graphics3/animation/ClipListPlayer.d.ts.map +1 -1
  116. package/src/engine/graphics3/animation/ClipListPlayer.js +2 -2
  117. package/src/engine/graphics3/highlight/pack_highlight_table.d.ts +9 -11
  118. package/src/engine/graphics3/highlight/pack_highlight_table.d.ts.map +1 -1
  119. package/src/engine/graphics3/highlight/pack_highlight_table.js +11 -18
  120. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts +4 -3
  121. package/src/engine/graphics3/pose/query_entity_node_world_pose.d.ts.map +1 -1
  122. package/src/engine/graphics3/pose/query_entity_node_world_pose.js +75 -74
  123. package/src/engine/graphics3/prefab/Prefab.d.ts +130 -0
  124. package/src/engine/graphics3/prefab/Prefab.d.ts.map +1 -0
  125. package/src/engine/graphics3/prefab/Prefab.js +162 -0
  126. package/src/engine/graphics3/prefab/PrefabInstance.d.ts +72 -0
  127. package/src/engine/graphics3/prefab/PrefabInstance.d.ts.map +1 -0
  128. package/src/engine/graphics3/prefab/PrefabInstance.js +80 -0
  129. package/src/engine/graphics3/prefab/prefab_compile.d.ts +23 -0
  130. package/src/engine/graphics3/prefab/prefab_compile.d.ts.map +1 -0
  131. package/src/engine/graphics3/prefab/prefab_compile.js +334 -0
  132. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts +46 -0
  133. package/src/engine/graphics3/prefab/prefab_instantiate.d.ts.map +1 -0
  134. package/src/engine/graphics3/prefab/prefab_instantiate.js +230 -0
  135. package/src/engine/graphics3/prefab/prefab_normalize_skin_frames.d.ts +70 -0
  136. package/src/engine/graphics3/prefab/prefab_normalize_skin_frames.d.ts.map +1 -0
  137. package/src/engine/graphics3/prefab/prefab_normalize_skin_frames.js +210 -0
  138. package/src/engine/graphics3/prefab/prefab_place.d.ts +60 -0
  139. package/src/engine/graphics3/prefab/prefab_place.d.ts.map +1 -0
  140. package/src/engine/graphics3/prefab/prefab_place.js +130 -0
  141. package/src/engine/graphics3/prefab/prefab_skin_clip_scale_conflicts.d.ts +60 -0
  142. package/src/engine/graphics3/prefab/prefab_skin_clip_scale_conflicts.d.ts.map +1 -0
  143. package/src/engine/graphics3/prefab/prefab_skin_clip_scale_conflicts.js +128 -0
  144. package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts +40 -0
  145. package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts.map +1 -0
  146. package/src/engine/graphics3/prefab/prefab_skin_frame.js +116 -0
  147. package/src/engine/graphics3/preview/make_model_preview_scene.d.ts +16 -14
  148. package/src/engine/graphics3/preview/make_model_preview_scene.d.ts.map +1 -1
  149. package/src/engine/graphics3/preview/make_model_preview_scene.js +126 -154
  150. package/src/engine/graphics3/preview/make_model_thumbnail.js +1 -1
  151. package/src/engine/graphics3/register_instance_animation.d.ts +6 -6
  152. package/src/engine/graphics3/register_instance_animation.d.ts.map +1 -1
  153. package/src/engine/graphics3/register_instance_animation.js +4 -4
  154. package/src/engine/graphics3/shade_bundle_bounds.d.ts +2 -6
  155. package/src/engine/graphics3/shade_bundle_bounds.d.ts.map +1 -1
  156. package/src/engine/graphics3/shade_bundle_bounds.js +47 -55
  157. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts +11 -18
  158. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts.map +1 -1
  159. package/src/engine/graphics3/terrain/pack_terrain_row_table.js +48 -53
  160. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts +17 -2
  161. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  162. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +284 -256
  163. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +13 -15
  164. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  165. package/src/engine/physics/cloth/ecs/ClothInstance.js +12 -14
  166. package/src/engine/physics/cloth/ecs/ClothRig.d.ts +7 -8
  167. package/src/engine/physics/cloth/ecs/ClothRig.d.ts.map +1 -1
  168. package/src/engine/physics/cloth/ecs/ClothRig.js +7 -8
  169. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +5 -4
  170. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  171. package/src/engine/physics/cloth/ecs/ClothSystem.js +11 -12
  172. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +19 -23
  173. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  174. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +201 -199
  175. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  176. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +8 -0
  177. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts +18 -34
  178. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.d.ts.map +1 -1
  179. package/src/engine/physics/cloth/ecs/cloth_write_back_rig.js +58 -115
  180. package/src/engine/physics/cloth/playground/README.md +11 -11
  181. package/src/engine/physics/cloth/playground/garment_build.d.ts +0 -1
  182. package/src/engine/physics/cloth/playground/garment_build.d.ts.map +1 -1
  183. package/src/engine/physics/cloth/playground/garment_build.js +64 -58
  184. package/src/engine/physics/cloth/playground/garment_main.js +59 -33
  185. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  186. package/src/shade/RENDERER_CONTRACT.md +85 -53
  187. package/src/shade/device/ShadeGPUCommandContext.d.ts +23 -0
  188. package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
  189. package/src/shade/device/ShadeGPUCommandContext.js +36 -0
  190. package/src/shade/playground/add_random_meshes.d.ts +4 -4
  191. package/src/shade/playground/add_random_meshes.d.ts.map +1 -1
  192. package/src/shade/playground/add_random_meshes.js +20 -16
  193. package/src/shade/playground/avboit/main.d.ts +1 -0
  194. package/src/shade/playground/avboit/main.d.ts.map +1 -1
  195. package/src/shade/playground/avboit/main.js +916 -875
  196. package/src/shade/playground/basis_textures/main.d.ts.map +1 -1
  197. package/src/shade/playground/basis_textures/main.js +22 -8
  198. package/src/shade/playground/basis_textures/texture_inventory.d.ts +2 -2
  199. package/src/shade/playground/basis_textures/texture_inventory.d.ts.map +1 -1
  200. package/src/shade/playground/basis_textures/texture_inventory.js +6 -7
  201. package/src/shade/playground/ground_seam/main.d.ts.map +1 -1
  202. package/src/shade/playground/ground_seam/main.js +13 -4
  203. package/src/shade/playground/ground_seam/make_ground.d.ts +13 -4
  204. package/src/shade/playground/ground_seam/make_ground.d.ts.map +1 -1
  205. package/src/shade/playground/ground_seam/make_ground.js +21 -16
  206. package/src/shade/playground/particle_ecs/bonfire_editor.js +3 -3
  207. package/src/shade/playground/particle_system/main.js +11 -10
  208. package/src/shade/playground/particle_system/particle_prototype.d.ts +15 -10
  209. package/src/shade/playground/particle_system/particle_prototype.d.ts.map +1 -1
  210. package/src/shade/playground/particle_system/particle_prototype.js +56 -15
  211. package/src/shade/playground/particle_system/particle_scene.d.ts +68 -28
  212. package/src/shade/playground/particle_system/particle_scene.d.ts.map +1 -1
  213. package/src/shade/playground/particle_system/particle_scene.js +149 -53
  214. package/src/shade/playground/readback_crossover/index.html +41 -0
  215. package/src/shade/playground/readback_crossover/main.d.ts +2 -0
  216. package/src/shade/playground/readback_crossover/main.d.ts.map +1 -0
  217. package/src/shade/playground/readback_crossover/main.js +372 -0
  218. package/src/shade/playground/skinned_blas_refit/README.md +11 -7
  219. package/src/shade/playground/skinned_blas_refit/add_floor.d.ts +13 -44
  220. package/src/shade/playground/skinned_blas_refit/add_floor.d.ts.map +1 -1
  221. package/src/shade/playground/skinned_blas_refit/add_floor.js +19 -59
  222. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
  223. package/src/shade/playground/skinned_blas_refit/main.js +67 -58
  224. package/src/shade/playground/skinned_blas_refit/place_character.d.ts +40 -54
  225. package/src/shade/playground/skinned_blas_refit/place_character.d.ts.map +1 -1
  226. package/src/shade/playground/skinned_blas_refit/place_character.js +47 -74
  227. package/src/shade/playground/skinned_blas_refit/sweep_views.d.ts +3 -3
  228. package/src/shade/playground/skinned_blas_refit/sweep_views.d.ts.map +1 -1
  229. package/src/shade/playground/skinned_blas_refit/sweep_views.js +4 -3
  230. package/src/shade/playground/skinned_blas_refit/verify_clone_leaves.d.ts +3 -3
  231. package/src/shade/playground/skinned_blas_refit/verify_clone_leaves.d.ts.map +1 -1
  232. package/src/shade/playground/skinned_blas_refit/verify_clone_leaves.js +11 -4
  233. package/src/shade/playground/skinned_blas_refit/verify_instance_bounds.d.ts.map +1 -1
  234. package/src/shade/playground/skinned_blas_refit/verify_instance_bounds.js +38 -9
  235. package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.d.ts +3 -3
  236. package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.d.ts.map +1 -1
  237. package/src/shade/playground/skinned_blas_refit/verify_skinned_blas_refit.js +9 -6
  238. package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.d.ts +3 -3
  239. package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.d.ts.map +1 -1
  240. package/src/shade/playground/skinned_blas_refit/verify_traversal_reachability.js +3 -3
  241. package/src/shade/playground/skinned_mesh_soup/README.md +6 -6
  242. package/src/shade/playground/skinned_mesh_soup/main.d.ts.map +1 -1
  243. package/src/shade/playground/skinned_mesh_soup/main.js +44 -102
  244. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts +5 -5
  245. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.d.ts.map +1 -1
  246. package/src/shade/playground/skinned_mesh_soup/verify_clone_vertices.js +42 -33
  247. package/src/shade/playground/sponza_path_trace/main.d.ts +1 -0
  248. package/src/shade/playground/sponza_path_trace/main.d.ts.map +1 -1
  249. package/src/shade/playground/sponza_path_trace/main.js +393 -363
  250. package/src/shade/playground/ssr_reprojection/main.js +11 -9
  251. package/src/shade/playground/ssr_reprojection/scene.d.ts +15 -4
  252. package/src/shade/playground/ssr_reprojection/scene.d.ts.map +1 -1
  253. package/src/shade/playground/ssr_reprojection/scene.js +32 -11
  254. package/src/shade/playground/ssr_variance/main.js +1 -1
  255. package/src/shade/playground/ssr_variance/scene.d.ts +10 -4
  256. package/src/shade/playground/ssr_variance/scene.d.ts.map +1 -1
  257. package/src/shade/playground/ssr_variance/scene.js +39 -15
  258. package/src/shade/playground/vgeo_viewer/main.js +6 -2
  259. package/src/shade/playground/volumetrics_froxel/main.d.ts.map +1 -1
  260. package/src/shade/playground/volumetrics_froxel/main.js +936 -922
  261. package/src/shade/renderer/GraphicsContext.d.ts +7 -0
  262. package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
  263. package/src/shade/renderer/GraphicsContext.js +11 -0
  264. package/src/shade/renderer/Renderer.d.ts +3 -2
  265. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  266. package/src/shade/renderer/Renderer.js +3 -2
  267. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +39 -47
  268. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  269. package/src/shade/renderer/animation/GPUAnimationManager.js +319 -256
  270. package/src/shade/renderer/animation/ShadeAnimationChannel.d.ts +26 -22
  271. package/src/shade/renderer/animation/ShadeAnimationChannel.d.ts.map +1 -1
  272. package/src/shade/renderer/animation/ShadeAnimationChannel.js +28 -23
  273. package/src/shade/renderer/animation/ShadeAnimationClip.d.ts +14 -6
  274. package/src/shade/renderer/animation/ShadeAnimationClip.d.ts.map +1 -1
  275. package/src/shade/renderer/animation/ShadeAnimationClip.js +20 -8
  276. package/src/shade/renderer/animation/Skin.d.ts +19 -19
  277. package/src/shade/renderer/animation/Skin.d.ts.map +1 -1
  278. package/src/shade/renderer/animation/Skin.js +15 -13
  279. package/src/shade/renderer/animation/pose/pose_evaluate_local.d.ts +6 -5
  280. package/src/shade/renderer/animation/pose/pose_evaluate_local.d.ts.map +1 -1
  281. package/src/shade/renderer/animation/pose/pose_evaluate_local.js +9 -9
  282. package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts +5 -59
  283. package/src/shade/renderer/animation/skin_clip_scale_conflicts.d.ts.map +1 -1
  284. package/src/shade/renderer/animation/skin_clip_scale_conflicts.js +8 -132
  285. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +65 -62
  286. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  287. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +148 -194
  288. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts.map +1 -1
  289. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.js +4 -7
  290. package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.d.ts +2 -2
  291. package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.js +2 -2
  292. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts +74 -0
  293. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.d.ts.map +1 -0
  294. package/src/shade/renderer/buffer/GPUBufferReadbackAllocator.js +240 -0
  295. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts +14 -0
  296. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  297. package/src/shade/renderer/buffer/table/GPUDatabase.js +64 -6
  298. package/src/shade/renderer/buffer/table/GPUDatabaseReadback.d.ts +190 -0
  299. package/src/shade/renderer/buffer/table/GPUDatabaseReadback.d.ts.map +1 -0
  300. package/src/shade/renderer/buffer/table/GPUDatabaseReadback.js +1323 -0
  301. package/src/shade/renderer/buffer/table/GPUPageMetadata.d.ts +10 -0
  302. package/src/shade/renderer/buffer/table/GPUPageMetadata.d.ts.map +1 -1
  303. package/src/shade/renderer/buffer/table/GPUPageMetadata.js +12 -0
  304. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts +96 -0
  305. package/src/shade/renderer/buffer/table/GPUReadbackStagingRing.d.ts.map +1 -0
  306. package/src/shade/renderer/buffer/table/GPUReadbackStatus.d.ts +15 -0
  307. package/src/shade/renderer/buffer/table/GPUReadbackStatus.d.ts.map +1 -0
  308. package/src/shade/renderer/buffer/table/GPUReadbackStatus.js +34 -0
  309. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +75 -7
  310. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  311. package/src/shade/renderer/buffer/table/GPUTypedTable.js +518 -135
  312. package/src/shade/renderer/buffer/table/GPU_TABLE_GATHER_DESCRIPTOR_WORDS.d.ts +19 -0
  313. package/src/shade/renderer/buffer/table/GPU_TABLE_GATHER_DESCRIPTOR_WORDS.d.ts.map +1 -0
  314. package/src/shade/renderer/buffer/table/GPU_TABLE_GATHER_DESCRIPTOR_WORDS.js +18 -0
  315. package/src/shade/renderer/buffer/table/WordViews.d.ts +39 -0
  316. package/src/shade/renderer/buffer/table/WordViews.d.ts.map +1 -0
  317. package/src/shade/renderer/buffer/table/WordViews.js +62 -0
  318. package/src/shade/renderer/buffer/table/gpu_table_gather_shader.d.ts +27 -0
  319. package/src/shade/renderer/buffer/table/gpu_table_gather_shader.d.ts.map +1 -0
  320. package/src/shade/renderer/buffer/table/gpu_table_gather_shader.js +117 -0
  321. package/src/shade/renderer/buffer/table/serde/generate_record_writer.d.ts +121 -0
  322. package/src/shade/renderer/buffer/table/serde/generate_record_writer.d.ts.map +1 -0
  323. package/src/shade/renderer/buffer/table/serde/generate_record_writer.js +395 -0
  324. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
  325. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +70 -20
  326. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +1 -1
  327. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  328. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +6 -5
  329. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +3 -3
  330. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  331. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +15 -11
  332. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_bake_for_scene.d.ts +1 -1
  333. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_bake_for_scene.js +4 -4
  334. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_generate_tree_from_scene.d.ts +1 -3
  335. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_generate_tree_from_scene.d.ts.map +1 -1
  336. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_generate_tree_from_scene.js +5 -4
  337. package/src/shade/renderer/global_illumination/brick4/gpu/bake/brick4_bake_basic.js +1 -1
  338. package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.d.ts.map +1 -1
  339. package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.js +1 -4
  340. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts +8 -3
  341. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts.map +1 -1
  342. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.js +19 -14
  343. package/src/shade/renderer/global_illumination/lpv/placement/graph_generate_probe_locations.d.ts.map +1 -1
  344. package/src/shade/renderer/global_illumination/lpv/placement/graph_generate_probe_locations.js +9 -1
  345. package/src/shade/renderer/global_illumination/lpv/placement/software/lpv_generate_probe_locations2.d.ts +3 -3
  346. package/src/shade/renderer/global_illumination/lpv/placement/software/lpv_generate_probe_locations2.d.ts.map +1 -1
  347. package/src/shade/renderer/global_illumination/lpv/placement/software/lpv_generate_probe_locations2.js +12 -5
  348. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +1 -1
  349. package/src/shade/renderer/light/GPULightCollection.d.ts +29 -0
  350. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  351. package/src/shade/renderer/light/GPULightCollection.js +444 -329
  352. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.d.ts.map +1 -1
  353. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.js +7 -1
  354. package/src/shade/renderer/light/LightCollection.d.ts +29 -1
  355. package/src/shade/renderer/light/LightCollection.d.ts.map +1 -1
  356. package/src/shade/renderer/light/LightCollection.js +50 -1
  357. package/src/shade/renderer/light/make_sunlight.js +2 -2
  358. package/src/shade/renderer/light/model/Light.d.ts +29 -2
  359. package/src/shade/renderer/light/model/Light.d.ts.map +1 -1
  360. package/src/shade/renderer/light/model/Light.js +30 -2
  361. package/src/shade/renderer/light/model/io/light_record_directional.d.ts +3 -1
  362. package/src/shade/renderer/light/model/io/light_record_directional.d.ts.map +1 -1
  363. package/src/shade/renderer/light/model/io/light_record_directional.js +8 -5
  364. package/src/shade/renderer/light/model/io/light_record_point.d.ts +3 -1
  365. package/src/shade/renderer/light/model/io/light_record_point.d.ts.map +1 -1
  366. package/src/shade/renderer/light/model/io/light_record_point.js +5 -2
  367. package/src/shade/renderer/light/model/io/light_record_spot.d.ts +4 -1
  368. package/src/shade/renderer/light/model/io/light_record_spot.d.ts.map +1 -1
  369. package/src/shade/renderer/light/model/io/light_record_spot.js +10 -6
  370. package/src/shade/renderer/light/place_light.d.ts +16 -0
  371. package/src/shade/renderer/light/place_light.d.ts.map +1 -0
  372. package/src/shade/renderer/light/place_light.js +36 -0
  373. package/src/shade/renderer/light/shader_refresh_light_poses.d.ts +44 -0
  374. package/src/shade/renderer/light/shader_refresh_light_poses.d.ts.map +1 -0
  375. package/src/shade/renderer/light/shader_refresh_light_poses.js +154 -0
  376. package/src/shade/renderer/lightmap/GPULightMap.js +1 -1
  377. package/src/shade/renderer/lightmap/bake/raster/graph_draw_lightmap_viz_buffer.d.ts.map +1 -1
  378. package/src/shade/renderer/lightmap/bake/raster/graph_draw_lightmap_viz_buffer.js +12 -14
  379. package/src/shade/renderer/loader/SceneBundle.d.ts +53 -28
  380. package/src/shade/renderer/loader/SceneBundle.d.ts.map +1 -1
  381. package/src/shade/renderer/loader/SceneBundle.js +111 -56
  382. package/src/shade/renderer/loader/SceneNode.d.ts +81 -0
  383. package/src/shade/renderer/loader/SceneNode.d.ts.map +1 -0
  384. package/src/shade/renderer/loader/SceneNode.js +114 -0
  385. package/src/shade/renderer/loader/gltf/load_gltf.d.ts +3 -2
  386. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  387. package/src/shade/renderer/loader/gltf/load_gltf.js +110 -142
  388. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  389. package/src/shade/renderer/loader/usd/UsdExtensionRegistry.d.ts +4 -4
  390. package/src/shade/renderer/loader/usd/UsdExtensionRegistry.d.ts.map +1 -1
  391. package/src/shade/renderer/loader/usd/UsdExtensionRegistry.js +2 -2
  392. package/src/shade/renderer/loader/usd/load_usd.d.ts +3 -2
  393. package/src/shade/renderer/loader/usd/load_usd.d.ts.map +1 -1
  394. package/src/shade/renderer/loader/usd/load_usd.js +4 -5
  395. package/src/shade/renderer/loader/usd/usd_build_scene.d.ts +3 -3
  396. package/src/shade/renderer/loader/usd/usd_build_scene.d.ts.map +1 -1
  397. package/src/shade/renderer/loader/usd/usd_build_scene.js +47 -55
  398. package/src/shade/renderer/material/GPUMaterialManager.js +1 -1
  399. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +5 -4
  400. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  401. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +8 -15
  402. package/src/shade/renderer/object_property/shader_refresh_all_mesh_bounds.d.ts +15 -13
  403. package/src/shade/renderer/object_property/shader_refresh_all_mesh_bounds.d.ts.map +1 -1
  404. package/src/shade/renderer/object_property/shader_refresh_all_mesh_bounds.js +40 -21
  405. package/src/shade/renderer/particles/DESIGN.md +53 -50
  406. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +31 -17
  407. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  408. package/src/shade/renderer/particles/GPUParticleSystem.js +54 -91
  409. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +12 -11
  410. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
  411. package/src/shade/renderer/particles/runtime/EmitterRegistry.js +12 -11
  412. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +13 -19
  413. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -1
  414. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +19 -25
  415. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +34 -24
  416. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
  417. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +53 -40
  418. package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.js +1 -1
  419. package/src/shade/renderer/path_tracer/graph_path_trace_scene.js +1 -1
  420. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  421. package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_meshes_classify_buckets.d.ts.map +1 -1
  422. package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_meshes_classify_buckets.js +2 -1
  423. package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_scene_meshes_cull_and_classify_buckets.d.ts.map +1 -1
  424. package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_scene_meshes_cull_and_classify_buckets.js +5 -2
  425. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +1 -1
  426. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +1 -1
  427. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.js +1 -1
  428. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +1 -1
  429. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +1 -1
  430. package/src/shade/renderer/scene/DynamicMesh.d.ts +13 -4
  431. package/src/shade/renderer/scene/DynamicMesh.d.ts.map +1 -1
  432. package/src/shade/renderer/scene/DynamicMesh.js +14 -4
  433. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts +38 -18
  434. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts.map +1 -1
  435. package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.js +112 -60
  436. package/src/shade/renderer/scene/GPUSceneContext.d.ts +55 -48
  437. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  438. package/src/shade/renderer/scene/GPUSceneContext.js +594 -928
  439. package/src/shade/renderer/scene/NODE3D_STRUCT.d.ts +5 -5
  440. package/src/shade/renderer/scene/NODE3D_STRUCT.js +5 -5
  441. package/src/shade/renderer/scene/Node3D.d.ts +27 -8
  442. package/src/shade/renderer/scene/Node3D.d.ts.map +1 -1
  443. package/src/shade/renderer/scene/Node3DDirtyList.d.ts +59 -0
  444. package/src/shade/renderer/scene/Node3DDirtyList.d.ts.map +1 -0
  445. package/src/shade/renderer/scene/Scene.d.ts +18 -60
  446. package/src/shade/renderer/scene/Scene.d.ts.map +1 -1
  447. package/src/shade/renderer/scene/Scene.js +53 -146
  448. package/src/shade/renderer/scene/SkinnedMesh.d.ts +10 -93
  449. package/src/shade/renderer/scene/SkinnedMesh.d.ts.map +1 -1
  450. package/src/shade/renderer/scene/bvh/StaticSceneBVH.d.ts +24 -3
  451. package/src/shade/renderer/scene/bvh/StaticSceneBVH.d.ts.map +1 -1
  452. package/src/shade/renderer/scene/bvh/StaticSceneBVH.js +53 -13
  453. package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.d.ts +5 -6
  454. package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.d.ts.map +1 -1
  455. package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.js +5 -6
  456. package/src/shade/renderer/scene/optimization/scene_optimize.d.ts +10 -2
  457. package/src/shade/renderer/scene/optimization/scene_optimize.d.ts.map +1 -1
  458. package/src/shade/renderer/scene/optimization/scene_optimize.js +266 -230
  459. package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.d.ts +53 -0
  460. package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.d.ts.map +1 -0
  461. package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.js +144 -0
  462. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts +227 -0
  463. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -0
  464. package/src/shade/renderer/scene/rows/GPUSceneRows.js +1136 -0
  465. package/src/shade/renderer/scene/rows/place_primitive.d.ts +48 -0
  466. package/src/shade/renderer/scene/rows/place_primitive.d.ts.map +1 -0
  467. package/src/shade/renderer/scene/rows/place_primitive.js +98 -0
  468. package/src/shade/renderer/scene/serialization/deserialize_scene.d.ts +10 -8
  469. package/src/shade/renderer/scene/serialization/deserialize_scene.d.ts.map +1 -1
  470. package/src/shade/renderer/scene/serialization/deserialize_scene.js +24 -27
  471. package/src/shade/renderer/scene/serialization/serialize_scene.d.ts +9 -2
  472. package/src/shade/renderer/scene/serialization/serialize_scene.d.ts.map +1 -1
  473. package/src/shade/renderer/scene/serialization/serialize_scene.js +25 -4
  474. package/src/shade/renderer/scene/verify_gpu_tlas_build.js +2 -2
  475. package/src/shade/renderer/shader/chunk/light/DIRECTIONAL_LIGHT_STRUCT.d.ts.map +1 -1
  476. package/src/shade/renderer/shader/chunk/light/DIRECTIONAL_LIGHT_STRUCT.js +5 -0
  477. package/src/shade/renderer/shader/chunk/light/POINT_LIGHT_STRUCT.d.ts.map +1 -1
  478. package/src/shade/renderer/shader/chunk/light/POINT_LIGHT_STRUCT.js +5 -0
  479. package/src/shade/renderer/shader/chunk/light/SPOT_LIGHT_STRUCT.d.ts.map +1 -1
  480. package/src/shade/renderer/shader/chunk/light/SPOT_LIGHT_STRUCT.js +5 -0
  481. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts +39 -0
  482. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts.map +1 -1
  483. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +112 -64
  484. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +7 -0
  485. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  486. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +1541 -1352
  487. package/src/shade/renderer/shadow/map/PointLightShadowmap.js +1 -1
  488. package/src/shade/renderer/shadow/map/SpotLightShadowmap.js +1 -1
  489. package/src/shade/renderer/shadow/map/TetrahedronPointLightShadowmap.js +1 -1
  490. package/src/shade/renderer/shadow/map/csm/CSM_CASTER_RANGE_STRUCT.d.ts +29 -0
  491. package/src/shade/renderer/shadow/map/csm/CSM_CASTER_RANGE_STRUCT.d.ts.map +1 -0
  492. package/src/shade/renderer/shadow/map/csm/CSM_CASTER_RANGE_STRUCT.js +43 -0
  493. package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_CASTER_RANGE_MARGIN_FRACTION.d.ts +13 -0
  494. package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_CASTER_RANGE_MARGIN_FRACTION.d.ts.map +1 -0
  495. package/src/shade/renderer/shadow/map/csm/SHADOWMAP_CSM_CASTER_RANGE_MARGIN_FRACTION.js +12 -0
  496. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts +49 -0
  497. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts.map +1 -0
  498. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.js +194 -0
  499. package/src/shade/renderer/shadow/map/csm_debug_draw_preview.js +1 -1
  500. package/src/shade/renderer/shadow/map/shadowmap_update_score.js +1 -1
  501. package/src/shade/renderer/shadow/ray/RTXShadows.js +1 -1
  502. package/src/shade/renderer/shadow/ray/staged/trace/graph_trace_rays.js +1 -1
  503. package/src/shade/renderer/shadow/sdf/cascade/CascadedSceneSDF.d.ts.map +1 -1
  504. package/src/shade/renderer/shadow/sdf/cascade/CascadedSceneSDF.js +3 -1
  505. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +8 -8
  506. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  507. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +4 -3
  508. package/src/engine/graphics3/instantiate_scene_bundle.js +0 -164
  509. package/src/engine/graphics3/shade_node_to_entity_composition.js +0 -88
  510. package/src/shade/renderer/animation/compute_skin_world_bounds.js +0 -146
  511. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.js +0 -531
  512. package/src/shade/renderer/animation/pose/pose_evaluate_world.js +0 -76
  513. package/src/shade/renderer/animation/skin_bind_transform.js +0 -33
  514. package/src/shade/renderer/animation/skin_frame_defect.js +0 -132
  515. package/src/shade/renderer/animation/skin_joint_matrix.js +0 -46
  516. package/src/shade/renderer/animation/skin_normalize_mesh_frame.js +0 -216
  517. package/src/shade/renderer/scene/InstanceBatch.js +0 -235
  518. package/src/shade/renderer/scene/Mesh.js +0 -168
  519. package/src/shade/renderer/scene/Node3D.js +0 -263
  520. package/src/shade/renderer/scene/SceneNodeBinding.js +0 -56
  521. package/src/shade/renderer/scene/SkinnedMesh.js +0 -170
  522. package/src/shade/renderer/scene/TransformAuthority.js +0 -33
@@ -1,928 +1,594 @@
1
- import { assert } from "../../../core/assert.js";
2
- import { typed_array_copy } from "../../../core/collection/array/typed/typed_array_copy.js";
3
- import { ShadeGPUCommandContext } from "../../device/ShadeGPUCommandContext.js";
4
- import { GPUAnimationManager } from "../animation/GPUAnimationManager.js";
5
- import { GPUDatabase } from "../buffer/table/GPUDatabase.js";
6
- import { Brick4LightMap } from "../global_illumination/brick4/Brick4LightMap.js";
7
- import { GPULightProbeVolume } from "../global_illumination/lpv/GPULightProbeVolume.js";
8
- import { GPULightCollection } from "../light/GPULightCollection.js";
9
- import { GPUSceneVolumetrics } from "../volumetrics/GPUSceneVolumetrics.js";
10
- import { Scene } from "./Scene.js";
11
- import { GPUInstancesAccelerationStructure } from "./GPUInstancesAccelerationStructure.js";
12
- import { GPUMeshSkinningContext } from "../animation/skinning/GPUMeshSkinningContext.js";
13
- import { NODE3D_SCENE_ID } from "./NODE3D_STRUCT.js";
14
- import { SCENE_DATABASE_SPEC } from "./SCENE_DATABASE_SPEC.js";
15
- import { SceneNodeBinding } from "./SceneNodeBinding.js";
16
- import { TransformAuthority } from "./TransformAuthority.js";
17
-
18
- /**
19
- * @typedef {import("../GraphicsContext.js").GraphicsContext} GraphicsContext
20
- * @typedef {import("../geometry/GPUGeometryManager.js").GPUGeometryManager} GPUGeometryManager
21
- * @typedef {import("../material/GPUMaterialManager.js").GPUMaterialManager} GPUMaterialManager
22
- * @typedef {import("./Node3D.js").Node3D} Node3D
23
- */
24
-
25
-
26
- let id_counter = 0;
27
-
28
- /**
29
- * Staging for one `transforms` row. Reused across every write — the table serializes it into its
30
- * page shadow synchronously, so nothing outlives the call.
31
- */
32
- const TRANSFORM_RECORD = {
33
- local_translation: new Float32Array(3),
34
- local_rotation: new Float32Array(4),
35
- local_scale: new Float32Array(3),
36
- global: new Float32Array(16),
37
- prev_global: new Float32Array(16),
38
- parent: NODE3D_SCENE_ID,
39
- };
40
-
41
- /**
42
- * Placeholder for claiming a row before its contents are known — {@link GPUTypedTable.add} chooses
43
- * the row, and the record has to name it. Overwritten in the same breath, and the table's upload
44
- * de-duplication collapses the pair into a single record.
45
- */
46
- const EMPTY_TRANSFORM_RECORD = {
47
- local_translation: new Float32Array(3),
48
- local_rotation: new Float32Array(4),
49
- local_scale: new Float32Array(3),
50
- global: new Float32Array(16),
51
- prev_global: new Float32Array(16),
52
- parent: NODE3D_SCENE_ID,
53
- };
54
-
55
- /**
56
- * Staging for one `meshes` row, on the same terms as {@link TRANSFORM_RECORD}. The two bounds
57
- * fields are references to the mesh's own arrays rather than copies — the table reads them before
58
- * the next call replaces them.
59
- */
60
- const MESH_RECORD = {
61
- geometry: 0,
62
- material: 0,
63
- node: NODE3D_SCENE_ID,
64
- bounding_box: undefined,
65
- bounding_sphere: undefined,
66
- };
67
-
68
- /**
69
- * Abstraction on the context of a scene, there are no hierarchies, just a collection of meshes and a geometry context
70
- */
71
- export class GPUSceneContext {
72
-
73
- /**
74
- * @readonly
75
- * @type {number}
76
- */
77
- id = id_counter++;
78
-
79
- /**
80
- * @type {GPUGeometryManager}
81
- */
82
- geometries;
83
-
84
- /**
85
- * @type {GPUMaterialManager}
86
- */
87
- materials;
88
-
89
-
90
- /**
91
- * @type {Brick4LightMap}
92
- */
93
- volumetric_light_map;
94
-
95
-
96
- /**
97
- *
98
- * @type {Scene}
99
- */
100
- #scene;
101
-
102
- /**
103
- *
104
- * @return {Scene}
105
- */
106
- get scene() {
107
- return this.#scene;
108
- }
109
-
110
- /**
111
- * @type {GPUSceneVolumetrics}
112
- */
113
- #volumetrics;
114
-
115
- get volumetrics() {
116
- return this.#volumetrics;
117
- }
118
-
119
- /**
120
- * @type {GPULightCollection}
121
- */
122
- #lights;
123
-
124
-
125
- /**
126
- *
127
- * @returns {GPULightCollection}
128
- */
129
- get lights() {
130
- return this.#lights;
131
- }
132
-
133
- /**
134
- * @type {GPULightProbeVolume}
135
- */
136
- #light_probe_volume;
137
-
138
- /**
139
- *
140
- * @returns {GPULightProbeVolume}
141
- */
142
- get light_probe_volume() {
143
- return this.#light_probe_volume;
144
- }
145
-
146
- /**
147
- * @type {GPUInstancesAccelerationStructure}
148
- */
149
- #tlas
150
-
151
- /**
152
- *
153
- * @returns {GPUInstancesAccelerationStructure}
154
- */
155
- get tlas() {
156
- return this.#tlas;
157
- }
158
-
159
- /**
160
- * GPU-resident scene database — mesh metadata in the `meshes` table,
161
- * scene-graph nodes (transforms) in the `transforms` table. Replaces
162
- * the old flat `instance_buffer`. Consumers bind `scene_database.buffer`
163
- * as `array<u32>` and read records via `scene_read_mesh` /
164
- * `scene_read_node` (see `chunk_scene_database_access`).
165
- *
166
- * @type {GPUDatabase}
167
- */
168
- #scene_database;
169
-
170
- /**
171
- *
172
- * @type {Uint32Array}
173
- */
174
- #instance_metadata = new Uint32Array();
175
-
176
- /**
177
- * Mesh → instance index. Rebuilt each frame in {@link build}. The
178
- * Lookup from a node's stable JS-side {@link Node3D.id} to its row
179
- * in the scene database's `transforms` table. Built during
180
- * {@link build} as each node is allocated via
181
- * {@link GPUTypedTable.add}; the table itself owns the row
182
- * allocation, this map just bridges between Node3D handles and the
183
- * GPU rows they live at.
184
- *
185
- * Public so external code can do partial updates: looking up a
186
- * single node's row lets a system patch one `transforms_table`
187
- * entry instead of re-uploading the whole scene.
188
- *
189
- * @type {Map<number, number>}
190
- */
191
- id_mapping = new Map();
192
-
193
- /**
194
- * Per-scene skinning state — clone-index cache today, plus
195
- * Skin-bindings and the per-frame skinning compute dispatch in
196
- * later phases. Lazily constructed because it depends on
197
- * {@link geometries}, which {@link SceneManager#create} assigns
198
- * externally after this constructor runs. See {@link skinning} for
199
- * access.
200
- *
201
- * @type {GPUMeshSkinningContext|null}
202
- */
203
- #skinning = null;
204
-
205
- /**
206
- * Per-scene animation system — clips, tracks, curves, skins, and
207
- * the skin-matrix scratch buffer. Owned here (rather than passed
208
- * in) so that consumers fetching `gpu_scene.animation_manager`
209
- * always see the same instance, and so per-frame database flush
210
- * can be wired into {@link update} alongside the rest of the
211
- * scene's bookkeeping.
212
- *
213
- * @type {GPUAnimationManager}
214
- */
215
- #animation_manager;
216
-
217
- /**
218
- *
219
- * @param {GraphicsContext} graphics
220
- * @param {Scene} scene
221
- */
222
- constructor(graphics, scene) {
223
- assert.defined(scene, 'scene');
224
- assert.isObject(scene, 'scene');
225
- assert.equal(scene.isScene, true, 'scene.isScene !== true');
226
-
227
- const device = graphics.device;
228
-
229
- this.#scene = scene;
230
- this.#device = device;
231
- this.#graphics = graphics;
232
-
233
- this.#tlas = new GPUInstancesAccelerationStructure(graphics);
234
-
235
- // Pass `this` so the light collection (and its child shadow context) can use
236
- // this scene's GPUSceneContext when building its own ViewManager — avoids
237
- // threading the renderer-level ViewManager / SceneManager through every layer.
238
- this.#lights = new GPULightCollection(graphics, this);
239
-
240
- this.#scene_database = new GPUDatabase({
241
- device,
242
- definition: SCENE_DATABASE_SPEC,
243
- label: "GPUSceneContext/Database",
244
- });
245
-
246
- this.#light_probe_volume = new GPULightProbeVolume(device, scene.light_probe_volume);
247
-
248
- this.volumetric_light_map = new Brick4LightMap(device);
249
-
250
- this.#volumetrics = new GPUSceneVolumetrics(device, scene.volumetrics);
251
-
252
- this.#animation_manager = new GPUAnimationManager(device, `GPUSceneContext[${this.id}]/Animation`, this);
253
- }
254
-
255
- /**
256
- * @returns {GPUAnimationManager}
257
- */
258
- get animation_manager() {
259
- return this.#animation_manager;
260
- }
261
-
262
- #instances_version = -1;
263
-
264
-
265
- /**
266
- * @type {GPUDevice}
267
- */
268
- #device;
269
-
270
- /**
271
- * @type {GraphicsContext}
272
- */
273
- #graphics;
274
-
275
- /**
276
- *
277
- * @returns {GPUDatabase}
278
- */
279
- get scene_database() {
280
- return this.#scene_database;
281
- }
282
-
283
- /**
284
- * The underlying buffer that backs {@link scene_database} — bind this
285
- * as `array<u32>` in shaders that read mesh / transform records.
286
- *
287
- * @returns {GPUBuffer}
288
- */
289
- get scene_database_buffer() {
290
- return this.#scene_database.buffer;
291
- }
292
-
293
- /**
294
- * Per-scene skinning subsystem. Routes {@link SkinnedMesh}
295
- * instances through per-instance geometry clones; later phases
296
- * grow Skin-binding management and the per-frame skinning compute
297
- * onto it.
298
- *
299
- * Lazy because it depends on {@link geometries}, which is assigned
300
- * externally after this object's constructor returns
301
- * (see {@link SceneManager}). The first access happens during
302
- * {@link build}, which runs well after that assignment.
303
- *
304
- * @returns {GPUMeshSkinningContext}
305
- */
306
- get skinning() {
307
- if (this.#skinning === null) {
308
- this.#skinning = new GPUMeshSkinningContext({
309
- geometries: this.geometries,
310
- animation_manager: this.#animation_manager,
311
- scene_context: this,
312
- device: this.#device,
313
- });
314
- }
315
- return this.#skinning;
316
- }
317
-
318
- get gpu_memory_usage(){
319
- let r = 0;
320
-
321
- r+= this.#scene_database.gpu_memory_usage;
322
-
323
- r += this.#lights.gpu_memory_usage;
324
- r += this.#light_probe_volume.gpu_memory_usage;
325
- r += this.volumetric_light_map.gpu_memory_usage;
326
-
327
- return r;
328
- }
329
-
330
- /**
331
- * Grow the per-row mesh metadata to cover `size` rows. Never shrinks: rows are addresses, and a
332
- * table that has held N rows can hand any of them out again.
333
- *
334
- * @param {number} size
335
- */
336
- #allocate_instances(size) {
337
- const required = 2 * size;
338
-
339
- if (this.#instance_metadata.length >= required) {
340
- return;
341
- }
342
-
343
- const previous = this.#instance_metadata;
344
-
345
- this.#instance_metadata = new Uint32Array(required);
346
-
347
- typed_array_copy(previous, this.#instance_metadata);
348
- }
349
-
350
- /**
351
- * World matrix last published for each `transforms` row, 16 floats at `row * 16`.
352
- *
353
- * The GPU hierarchy pass takes whatever is in a row's `global` at the start of the frame and
354
- * moves it to `prev_global` before composing the new one, so what the CPU puts in `global` is
355
- * only ever read as *last* frame's world matrix. Handing it the current one collapses the
356
- * per-object velocity that motion vectors are derived from, which is why this cache exists
357
- * rather than reading `node.transform_global` twice.
358
- *
359
- * @type {Float32Array}
360
- */
361
- #published_globals = new Float32Array();
362
-
363
- /**
364
- * Rows this context owns, by node. Also the answer to "is this node already in the database".
365
- *
366
- * @type {Map<Node3D, SceneNodeBinding>}
367
- */
368
- #bindings = new Map();
369
-
370
- /**
371
- * @type {number}
372
- */
373
- #epoch = 0;
374
-
375
- /**
376
- * @param {number} row
377
- */
378
- #reserve_published_global(row) {
379
- const required = (row + 1) * 16;
380
-
381
- if (this.#published_globals.length >= required) {
382
- return;
383
- }
384
-
385
- const grown = new Float32Array(Math.max(required, this.#published_globals.length * 2));
386
-
387
- typed_array_copy(this.#published_globals, grown);
388
-
389
- this.#published_globals = grown;
390
- }
391
-
392
- /**
393
- * Fill the shared record with `node`'s local TRS, the parent row, and the world matrix last
394
- * published for `row` — see {@link #published_globals} for why that is the previous one and not
395
- * the current one. Leaves `#published_globals` holding the node's current world matrix.
396
- *
397
- * @param {Node3D} node
398
- * @param {number} row
399
- * @param {number} parent_row
400
- * @returns {object} the module-static record, valid until the next call
401
- */
402
- #write_transform_record(node, row, parent_row) {
403
- // read through the scalar accessors: the `translation` / `rotation` / `scale` properties are
404
- // live views, freshly allocated on every access, and this runs once per changed row per frame
405
- const tl = node.transform_local;
406
-
407
- TRANSFORM_RECORD.local_translation[0] = tl.translation_x;
408
- TRANSFORM_RECORD.local_translation[1] = tl.translation_y;
409
- TRANSFORM_RECORD.local_translation[2] = tl.translation_z;
410
-
411
- TRANSFORM_RECORD.local_rotation[0] = tl.rotation_x;
412
- TRANSFORM_RECORD.local_rotation[1] = tl.rotation_y;
413
- TRANSFORM_RECORD.local_rotation[2] = tl.rotation_z;
414
- TRANSFORM_RECORD.local_rotation[3] = tl.rotation_w;
415
-
416
- TRANSFORM_RECORD.local_scale[0] = tl.scale_x;
417
- TRANSFORM_RECORD.local_scale[1] = tl.scale_y;
418
- TRANSFORM_RECORD.local_scale[2] = tl.scale_z;
419
-
420
- this.#reserve_published_global(row);
421
-
422
- const published = this.#published_globals;
423
- const base = row * 16;
424
-
425
- for (let i = 0; i < 16; i++) {
426
- const previous = published[base + i];
427
-
428
- TRANSFORM_RECORD.global[i] = previous;
429
- TRANSFORM_RECORD.prev_global[i] = previous;
430
- }
431
-
432
- const current = node.transform_global;
433
-
434
- for (let i = 0; i < 16; i++) {
435
- published[base + i] = current[i];
436
- }
437
-
438
- TRANSFORM_RECORD.parent = parent_row;
439
-
440
- return TRANSFORM_RECORD;
441
- }
442
-
443
- /**
444
- * Seed a row's published world matrix with the node's current one, so the row's first write
445
- * reports zero velocity instead of motion away from the origin.
446
- *
447
- * @param {Node3D} node
448
- * @param {number} row
449
- */
450
- #seed_published_global(node, row) {
451
- this.#reserve_published_global(row);
452
-
453
- const current = node.transform_global;
454
- const base = row * 16;
455
-
456
- for (let i = 0; i < 16; i++) {
457
- this.#published_globals[base + i] = current[i];
458
- }
459
- }
460
-
461
- /**
462
- * @param {Mesh} mesh
463
- * @param {number} transform_row
464
- * @returns {object} the module-static record, valid until the next call
465
- */
466
- #write_mesh_record(mesh, transform_row) {
467
- // A skinned mesh's world bounds are a property of its *skeleton*, and the skeleton is not
468
- // in the mesh's own subtree — Michelle's joint root is the mesh node's next sibling, which
469
- // is the shape every glTF character has. `Node3D.updateMatrices` walks pre-order, so when
470
- // the mesh's own bounds pass ran the joints it reads had not been visited yet and it
471
- // described where the character stood before the move; a second walk would catch up, and
472
- // nothing calls one. Re-deriving here costs a matrix per joint on a mesh that just moved,
473
- // and here every walk is over — which is the only point at which the answer is knowable.
474
- if (mesh.isSkinnedMesh === true) {
475
- mesh.updateBoundsBasic();
476
- }
477
-
478
- // SkinnedMesh routes to its per-instance clone (allocated + cached by the skinning
479
- // context); regular meshes get the source's id. obtain_geometry_index handles both,
480
- // idempotent.
481
- MESH_RECORD.geometry = this.skinning.obtain_geometry_index(mesh);
482
- MESH_RECORD.material = mesh.material.id;
483
- MESH_RECORD.node = transform_row;
484
- MESH_RECORD.bounding_box = mesh.bounding_box;
485
- MESH_RECORD.bounding_sphere = mesh.bounding_sphere;
486
-
487
- return MESH_RECORD;
488
- }
489
-
490
- /**
491
- * Which row of the `meshes` table a node occupies — **the value the visibility buffer writes
492
- * for every pixel that node covers**, which is what makes it worth reading from outside.
493
- *
494
- * `id_mapping` is not this. That map goes from a node's id to its row in the `transforms`
495
- * table, which is a different table with different rows; a caller that used it to index the
496
- * visibility buffer would be reading somebody else's mesh.
497
- *
498
- * @param {Node3D} node
499
- * @returns {number} the row, or `-1` for a node that is not in this scene or carries no geometry
500
- */
501
- mesh_row_of(node) {
502
- const binding = this.#bindings.get(node);
503
-
504
- return binding === undefined ? -1 : binding.mesh_row;
505
- }
506
-
507
- /**
508
- * Bumped every time the `meshes` table gains or loses a row. **Rows are reused** — the table
509
- * hands out the lowest free one — so a row read through {@link mesh_row_of} and kept is only
510
- * valid while this number is unchanged. Anything holding one compares against its own copy and
511
- * re-reads when they differ.
512
- *
513
- * @returns {number}
514
- */
515
- get mesh_rows_version() {
516
- return this.#mesh_rows_version;
517
- }
518
-
519
- /**
520
- * @see mesh_rows_version
521
- * @type {number}
522
- */
523
- #mesh_rows_version = 0;
524
-
525
- /**
526
- * Parent's row if the parent is already in the database, the scene root otherwise. The fallback
527
- * covers top-level nodes and parents that are not in this scene at all; a parent that is in the
528
- * scene but not yet added is handled by the caller, which revisits the node once the sweep has
529
- * placed everyone.
530
- *
531
- * @param {Node3D} node
532
- * @returns {number}
533
- */
534
- #resolve_parent_row(node) {
535
- const parent = node.parent;
536
-
537
- if (parent === null) {
538
- return NODE3D_SCENE_ID;
539
- }
540
-
541
- const row = this.id_mapping.get(parent.id);
542
-
543
- return row !== undefined ? row : NODE3D_SCENE_ID;
544
- }
545
-
546
- /**
547
- * Give a node rows in the database — one in `transforms`, plus one in `meshes` when it carries
548
- * geometry.
549
- *
550
- * @param {Node3D} node
551
- * @param {GPUTypedTable} transforms_table
552
- * @param {GPUTypedTable} meshes_table
553
- * @returns {SceneNodeBinding}
554
- */
555
- #add_node(node, transforms_table, meshes_table) {
556
- const binding = new SceneNodeBinding();
557
-
558
- const transform_row = this.#add_transform_row(node, this.#resolve_parent_row(node), transforms_table);
559
-
560
- binding.transform_row = transform_row;
561
- binding.version = node.version;
562
- // Seeding a row is the CPU's job whoever owns it afterwards — the row has to exist and hold
563
- // a starting pose before the GPU has written anything into it.
564
- binding.authority = node.transform_authority;
565
-
566
- this.id_mapping.set(node.id, transform_row);
567
-
568
- if (node.isMesh === true) {
569
- this.materials.obtain(node.material);
570
-
571
- const mesh_row = meshes_table.add(this.#write_mesh_record(node, transform_row));
572
-
573
- binding.mesh_row = mesh_row;
574
-
575
- this.#mesh_rows_version++;
576
-
577
- this.#allocate_instances(meshes_table.element_capacity);
578
-
579
- this.#instance_metadata[mesh_row * 2] = node.id;
580
- this.#instance_metadata[mesh_row * 2 + 1] = node.version;
581
-
582
- this.#tlas.instance_add(mesh_row, node);
583
- }
584
-
585
- this.#bindings.set(node, binding);
586
-
587
- return binding;
588
- }
589
-
590
- /**
591
- * Allocate a `transforms` row for a node. The row is not known until the table hands one back,
592
- * and the record has to carry that row's published world matrix — so the row is claimed first
593
- * with a placeholder and written properly immediately after.
594
- *
595
- * @param {Node3D} node
596
- * @param {number} parent_row
597
- * @param {GPUTypedTable} transforms_table
598
- * @returns {number}
599
- */
600
- #add_transform_row(node, parent_row, transforms_table) {
601
- const row = transforms_table.add(EMPTY_TRANSFORM_RECORD);
602
-
603
- this.#seed_published_global(node, row);
604
-
605
- transforms_table.set(row, this.#write_transform_record(node, row, parent_row));
606
-
607
- return row;
608
- }
609
-
610
- /**
611
- * Take a node's rows back. The rows are freed, not reassigned — see {@link SceneNodeBinding}.
612
- *
613
- * @param {Node3D} node
614
- * @param {SceneNodeBinding} binding
615
- * @param {GPUTypedTable} transforms_table
616
- * @param {GPUTypedTable} meshes_table
617
- */
618
- #remove_node(node, binding, transforms_table, meshes_table) {
619
- if (node.isMesh === true) {
620
- const mesh_row = binding.mesh_row;
621
-
622
- meshes_table.remove(mesh_row);
623
- this.#tlas.instance_remove(mesh_row);
624
-
625
- this.#mesh_rows_version++;
626
-
627
- this.#instance_metadata[mesh_row * 2] = 0;
628
- this.#instance_metadata[mesh_row * 2 + 1] = 0;
629
-
630
- // A skinned mesh renders a per-instance copy of its geometry, and the row just
631
- // given back was the only thing naming it. This is where that copy — its vertex
632
- // region, its BLAS and its prev-position slice — goes back too; nothing else in
633
- // the engine sees a mesh leave, and unbinding deliberately does not free it.
634
- if (node.isSkinnedMesh === true) {
635
- this.skinning.release_clone(node);
636
- }
637
- }
638
-
639
- transforms_table.remove(binding.transform_row);
640
-
641
- this.id_mapping.delete(node.id);
642
- this.#bindings.delete(node);
643
- }
644
-
645
- /**
646
- * Bring the database's membership in line with the scene's: nodes that arrived get rows, nodes
647
- * that left give theirs back. Runs only when the batch reports a change, so the per-frame path
648
- * never pays for it.
649
- *
650
- * @param {GPUTypedTable} transforms_table
651
- * @param {GPUTypedTable} meshes_table
652
- * @returns {number} rows written
653
- */
654
- #sync_membership(transforms_table, meshes_table) {
655
- const epoch = ++this.#epoch;
656
-
657
- let written = 0;
658
-
659
- const scene = this.#scene;
660
-
661
- // The scene root must land at row 0 — it is both the hierarchy walk's terminator and the
662
- // natural value of any zero-initialised buffer.
663
- let scene_binding = this.#bindings.get(scene);
664
-
665
- if (scene_binding === undefined) {
666
- scene_binding = this.#add_node(scene, transforms_table, meshes_table);
667
-
668
- assert.equal(scene_binding.transform_row, NODE3D_SCENE_ID, 'scene must land at transforms table row 0');
669
-
670
- written++;
671
- }
672
-
673
- scene_binding.epoch = epoch;
674
-
675
- const nodes = this.#scene.instances.nodes;
676
- const node_count = nodes.length;
677
-
678
- // Nodes whose parent had not been placed when they were. `Scene.add` walks parents before
679
- // children, so this is empty unless a caller added a child to the scene ahead of its
680
- // parent.
681
- const orphaned = [];
682
-
683
- for (let i = 0; i < node_count; i++) {
684
- const node = nodes[i];
685
-
686
- let binding = this.#bindings.get(node);
687
-
688
- if (binding === undefined) {
689
- binding = this.#add_node(node, transforms_table, meshes_table);
690
-
691
- written++;
692
-
693
- if (node.parent !== null && this.id_mapping.get(node.parent.id) === undefined) {
694
- orphaned.push(node);
695
- }
696
- }
697
-
698
- binding.epoch = epoch;
699
- }
700
-
701
- for (let i = 0; i < orphaned.length; i++) {
702
- const node = orphaned[i];
703
- const parent_row = this.id_mapping.get(node.parent.id);
704
-
705
- if (parent_row === undefined) {
706
- // the parent really is not in this scene — the scene root stands
707
- continue;
708
- }
709
-
710
- const binding = this.#bindings.get(node);
711
-
712
- transforms_table.set(
713
- binding.transform_row,
714
- this.#write_transform_record(node, binding.transform_row, parent_row)
715
- );
716
- }
717
-
718
- for (const [node, binding] of this.#bindings) {
719
- if (binding.epoch !== epoch) {
720
- this.#remove_node(node, binding, transforms_table, meshes_table);
721
-
722
- written++;
723
- }
724
- }
725
-
726
- return written;
727
- }
728
-
729
- /**
730
- * Push every node that has moved since its row was last written, and nothing else.
731
- *
732
- * Rows the GPU owns are left alone entirely — see {@link TransformAuthority}. Their nodes still
733
- * report movement (a CPU-driven parent recursing through `updateMatrices` is enough to mark
734
- * every joint under it), and acting on that report is exactly the collision authority exists to
735
- * prevent.
736
- *
737
- * @param {GPUTypedTable} transforms_table
738
- * @param {GPUTypedTable} meshes_table
739
- * @returns {number} rows written
740
- */
741
- #sync_transforms(transforms_table, meshes_table) {
742
- let written = 0;
743
-
744
- for (const [node, binding] of this.#bindings) {
745
- const authority = node.transform_authority;
746
- const handed_back = authority !== binding.authority && authority === TransformAuthority.CPU;
747
-
748
- binding.authority = authority;
749
-
750
- if (authority === TransformAuthority.GPU) {
751
- continue;
752
- }
753
-
754
- const version = node.version;
755
-
756
- // A row just handed back has to be written whatever the version says: nothing moved it
757
- // while the GPU held it, so there is no change to notice, and the row it is taking over
758
- // holds a pose the CPU never wrote.
759
- if (version === binding.version && !handed_back) {
760
- continue;
761
- }
762
-
763
- if (handed_back) {
764
- // Taking over from an unknown pose — seed the published matrix the way a fresh row
765
- // is seeded, so the first frame back reports no velocity rather than a jump.
766
- this.#seed_published_global(node, binding.transform_row);
767
- }
768
-
769
- binding.version = version;
770
- written++;
771
-
772
- const transform_row = binding.transform_row;
773
-
774
- transforms_table.set(
775
- transform_row,
776
- this.#write_transform_record(node, transform_row, this.#resolve_parent_row(node))
777
- );
778
-
779
- if (node.isMesh !== true) {
780
- continue;
781
- }
782
-
783
- // World-space bounds moved with the node, and culling reads them off the mesh row.
784
- const mesh_row = binding.mesh_row;
785
-
786
- meshes_table.set(mesh_row, this.#write_mesh_record(node, transform_row));
787
-
788
- this.#instance_metadata[mesh_row * 2 + 1] = version;
789
-
790
- this.#tlas.instance_update(mesh_row, node);
791
- }
792
-
793
- return written;
794
- }
795
-
796
- /**
797
- * Bring the GPU scene database in line with the scene, writing only the rows that changed.
798
- *
799
- * Membership is reconciled when the batch says it moved; transforms are checked every frame,
800
- * because a node moving does not touch the batch. Both walk the scene once and write nothing
801
- * for a node that has not changed.
802
- */
803
- build() {
804
-
805
- const batch = this.#scene.instances;
806
-
807
- const meshes_table = this.#scene_database.get('meshes');
808
- const transforms_table = this.#scene_database.get('transforms');
809
-
810
- let written = 0;
811
-
812
- if (this.#instances_version !== batch.version) {
813
- written += this.#sync_membership(transforms_table, meshes_table);
814
-
815
- this.#instances_version = batch.version;
816
- }
817
-
818
- written += this.#sync_transforms(transforms_table, meshes_table);
819
-
820
- if (written === 0) {
821
- return;
822
- }
823
-
824
- // Flush the scene database — only the rows that changed carry an upload record.
825
- const cmd = ShadeGPUCommandContext.create(this.#graphics, 'GPUSceneContext/database-build');
826
-
827
- // Also flush the global geometry manager. The first time a scene
828
- // sees a new mesh, scene.build's `obtain_geometry_index` calls
829
- // `geometries.add(...)` which registers the source MeshletGeometry
830
- // and flips `geometries.__needs_update = true`. The next per-frame
831
- // `graphics.update()` would normally rebuild
832
- // `geometries.buffer_metadata` to reflect those new entries — but
833
- // `graphics.update()` runs at the *head* of `Renderer.#begin_frame`,
834
- // *before* this scene.build, so the buffer_metadata stays whatever
835
- // it was at the start of the frame (often the zero-record placeholder
836
- // from the renderer's startup build, when the scene's geometries
837
- // hadn't been registered yet).
838
- //
839
- // Any pass reading `geometries[mesh.geometry]` later in the frame
840
- // (rasterization meshlet expansion, `shader_refresh_all_mesh_bounds`,
841
- // etc.) sees zeros — `meshlets_count = 0` produces no triangles and
842
- // `bounding_box = (0,0,0)-(0,0,0)` collapses world bounds to a
843
- // single point in `shader_refresh_all_mesh_bounds`, which then writes
844
- // those collapsed bounds back into `meshes_table`. Subsequent frames
845
- // get a correct `buffer_metadata` from the next `graphics.update()`,
846
- // but the `meshes_table` bounds stay collapsed until refresh_all
847
- // overwrites them again — and frustum cull on the collapsed bounds
848
- // can drop meshes whose collapsed point sits outside the frustum.
849
- //
850
- // Symptom: stress test rendered ground (whose collapsed point at the
851
- // origin survives the cull) but dropped most trees (whose collapsed
852
- // points scattered across the grid trigger cull edge cases).
853
- //
854
- // Calling `geometries.update(cmd)` here ensures the new buffer is in
855
- // place before any pass in the same frame reads it. Idempotent / no-op
856
- // when nothing's queued, so the per-frame `graphics.update` head call
857
- // and this build-time call together leave the buffer in the right
858
- // state under both lifetimes.
859
- this.geometries.update(cmd);
860
-
861
- this.#scene_database.update(cmd);
862
- cmd.finish();
863
- }
864
-
865
- /**
866
- *
867
- * @param {GraphicsContext} ctx
868
- */
869
- update(ctx) {
870
- assert.defined(ctx, 'ctx');
871
-
872
- // TODO add a fast update check, so that calling this multiple times per frame can be fast.
873
-
874
- this.#light_probe_volume.update();
875
- this.#lights.update(ctx);
876
- this.#volumetrics.update(ctx, 0);
877
-
878
- // Per-frame animation database flush — picks up any new clips,
879
- // tracks, skins, or per-frame `set_time` writes queued since
880
- // last frame. Idempotent / cheap when nothing's queued.
881
- const animation_cmd = ShadeGPUCommandContext.create(this.#graphics, 'GPUSceneContext/animation-flush');
882
- this.#animation_manager.update(animation_cmd);
883
- animation_cmd.finish();
884
-
885
- // TODO update SDF
886
-
887
- this.build();
888
-
889
- // After the build, which is what feeds the TLAS this frame's arrivals, departures and moves —
890
- // and, for the GPU build, writes the world AABBs it reads out of the `meshes` table.
891
- this.#tlas.update(this.scene_database_buffer);
892
- }
893
-
894
- /**
895
- * Per-frame animation tick — drains pending registrations,
896
- * advances `clip.time` on the GPU, runs apply → resolve →
897
- * hierarchy propagate → skin-matrix prep → skinning. Thin
898
- * passthrough to {@link GPUAnimationManager#tick}; lives here
899
- * so the renderer can call it on every scene it renders without
900
- * reaching past `GPUSceneContext` for an internal manager.
901
- *
902
- * `dt_seconds` is wall-clock seconds since the last call (the
903
- * renderer's `time_delta_seconds` argument to `render()`).
904
- *
905
- * @param {ShadeGPUCommandContext} cmd_ctx
906
- * @param {number} dt_seconds wall-clock seconds since last call
907
- */
908
- tick(cmd_ctx, dt_seconds) {
909
- this.#animation_manager.tick(cmd_ctx, dt_seconds);
910
- }
911
-
912
- destroy() {
913
- this.#scene_database.destroy();
914
- this.#lights.destroy();
915
- this.#light_probe_volume.destroy();
916
- this.#animation_manager.destroy();
917
- if (this.#skinning !== null) {
918
- this.#skinning.destroy();
919
- }
920
- }
921
-
922
- }
923
-
924
- /**
925
- * @readonly
926
- * @type {boolean}
927
- */
928
- GPUSceneContext.prototype.isGPUSceneContext = true;
1
+ import { assert } from "../../../core/assert.js";
2
+ import { ShadeGPUCommandContext } from "../../device/ShadeGPUCommandContext.js";
3
+ import { GPUAnimationManager } from "../animation/GPUAnimationManager.js";
4
+ import { GPUDatabase } from "../buffer/table/GPUDatabase.js";
5
+ import { Brick4LightMap } from "../global_illumination/brick4/Brick4LightMap.js";
6
+ import { GPULightProbeVolume } from "../global_illumination/lpv/GPULightProbeVolume.js";
7
+ import { GPULightCollection } from "../light/GPULightCollection.js";
8
+ import { GPUSceneVolumetrics } from "../volumetrics/GPUSceneVolumetrics.js";
9
+ import { Scene } from "./Scene.js";
10
+ import { GPUInstancesAccelerationStructure } from "./GPUInstancesAccelerationStructure.js";
11
+ import { GPUMeshSkinningContext } from "../animation/skinning/GPUMeshSkinningContext.js";
12
+ import {
13
+ shader_refresh_all_mesh_bounds,
14
+ WORKGROUP_SIZE as REFRESH_ALL_MESH_BOUNDS_WORKGROUP_SIZE
15
+ } from "../object_property/shader_refresh_all_mesh_bounds.js";
16
+ import { GPUEntityBoundsReadback } from "./rows/GPUEntityBoundsReadback.js";
17
+ import { GPUSceneRows } from "./rows/GPUSceneRows.js";
18
+ import { generate_record_writer } from "../buffer/table/serde/generate_record_writer.js";
19
+ import { NODE3D_SCENE_ID, NODE3D_STRUCT } from "./NODE3D_STRUCT.js";
20
+ import { SCENE_DATABASE_SPEC } from "./SCENE_DATABASE_SPEC.js";
21
+
22
+ /**
23
+ * @typedef {import("../GraphicsContext.js").GraphicsContext} GraphicsContext
24
+ * @typedef {import("../geometry/GPUGeometryManager.js").GPUGeometryManager} GPUGeometryManager
25
+ * @typedef {import("../material/GPUMaterialManager.js").GPUMaterialManager} GPUMaterialManager
26
+ * @typedef {import("../material/ShadeMaterial.js").ShadeMaterial} ShadeMaterial
27
+ * @typedef {import("../buffer/table/serde/generate_record_writer.js").GPURecordWriter} GPURecordWriter
28
+ */
29
+
30
+
31
+ let id_counter = 0;
32
+
33
+ /**
34
+ * Row 0 of the `transforms` table: the scene root. Identity, and its own parent — which is what the
35
+ * hierarchy pass takes as "no further ancestor" — so an entity whose attachment names no entity
36
+ * with a row is posed under it in world space, and the composition is exact. Written once, at the
37
+ * first {@link GPUSceneContext.build}, so it goes up with the first rows rather than being left to
38
+ * whatever the buffer held.
39
+ */
40
+ const ROOT_RECORD = {
41
+ local_translation: new Float32Array([0, 0, 0]),
42
+ local_rotation: new Float32Array([0, 0, 0, 1]),
43
+ local_scale: new Float32Array([1, 1, 1]),
44
+ global: new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
45
+ prev_global: new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
46
+ parent: NODE3D_SCENE_ID,
47
+ };
48
+
49
+ /**
50
+ * @type {GPURecordWriter}
51
+ */
52
+ const ROOT_RECORD_WRITER = generate_record_writer(NODE3D_STRUCT);
53
+
54
+ /**
55
+ * What a scene with no rows draws with.
56
+ *
57
+ * @type {ShadeMaterial[]}
58
+ */
59
+ const NO_MATERIALS = Object.freeze([]);
60
+
61
+ /**
62
+ * The GPU side of one {@link Scene}: its database — the `transforms` and `meshes` tables, one row
63
+ * per entity that is drawn or posed, at `entity + 1` — and what is built over that database each
64
+ * frame: the lights' records, the probe volume, the volumetrics, the animation, the TLAS.
65
+ *
66
+ * Nothing here holds a hierarchy of its own. An entity's row names its parent's row and the GPU
67
+ * composes the chain each frame, derives every mesh row's bounds under the composed matrix and
68
+ * builds the tree over them — see {@link tick}. What the CPU writes is what it owns: an entity's
69
+ * local TRS and the row of its parent, through {@link rows}.
70
+ */
71
+ export class GPUSceneContext {
72
+
73
+ /**
74
+ * @readonly
75
+ * @type {number}
76
+ */
77
+ id = id_counter++;
78
+
79
+ /**
80
+ * @type {GPUGeometryManager}
81
+ */
82
+ geometries;
83
+
84
+ /**
85
+ * @type {GPUMaterialManager}
86
+ */
87
+ materials;
88
+
89
+
90
+ /**
91
+ * @type {Brick4LightMap}
92
+ */
93
+ volumetric_light_map;
94
+
95
+
96
+ /**
97
+ *
98
+ * @type {Scene}
99
+ */
100
+ #scene;
101
+
102
+ /**
103
+ *
104
+ * @return {Scene}
105
+ */
106
+ get scene() {
107
+ return this.#scene;
108
+ }
109
+
110
+ /**
111
+ * @type {GPUSceneVolumetrics}
112
+ */
113
+ #volumetrics;
114
+
115
+ get volumetrics() {
116
+ return this.#volumetrics;
117
+ }
118
+
119
+ /**
120
+ * @type {GPULightCollection}
121
+ */
122
+ #lights;
123
+
124
+
125
+ /**
126
+ *
127
+ * @returns {GPULightCollection}
128
+ */
129
+ get lights() {
130
+ return this.#lights;
131
+ }
132
+
133
+ /**
134
+ * @type {GPULightProbeVolume}
135
+ */
136
+ #light_probe_volume;
137
+
138
+ /**
139
+ *
140
+ * @returns {GPULightProbeVolume}
141
+ */
142
+ get light_probe_volume() {
143
+ return this.#light_probe_volume;
144
+ }
145
+
146
+ /**
147
+ * @type {GPUInstancesAccelerationStructure}
148
+ */
149
+ #tlas
150
+
151
+ /**
152
+ *
153
+ * @returns {GPUInstancesAccelerationStructure}
154
+ */
155
+ get tlas() {
156
+ return this.#tlas;
157
+ }
158
+
159
+ /**
160
+ * GPU-resident scene database — mesh metadata in the `meshes` table,
161
+ * transforms in the `transforms` table, one row per entity in each.
162
+ * Consumers bind `scene_database.buffer` as `array<u32>` and read
163
+ * records via `scene_read_mesh` / `scene_read_node` (see
164
+ * `chunk_scene_database_access`).
165
+ *
166
+ * @type {GPUDatabase}
167
+ */
168
+ #scene_database;
169
+
170
+ /**
171
+ * Entities as rows of {@link scene_database} — see {@link rows}. Built the first time it is
172
+ * asked for, which needs the scene to name its dataset by then.
173
+ *
174
+ * @type {GPUSceneRows|null}
175
+ */
176
+ #rows = null;
177
+
178
+ /**
179
+ * Whether {@link ROOT_RECORD} has been written to row 0 — once, at the first build.
180
+ *
181
+ * @type {boolean}
182
+ */
183
+ #root_written = false;
184
+
185
+ /**
186
+ * Per-scene skinning state — clone-index cache today, plus
187
+ * Skin-bindings and the per-frame skinning compute dispatch in
188
+ * later phases. Lazily constructed because it depends on
189
+ * {@link geometries}, which {@link SceneManager#create} assigns
190
+ * externally after this constructor runs. See {@link skinning} for
191
+ * access.
192
+ *
193
+ * @type {GPUMeshSkinningContext|null}
194
+ */
195
+ #skinning = null;
196
+
197
+ /**
198
+ * Per-scene animation system — clips, tracks, curves, skins, and
199
+ * the skin-matrix scratch buffer. Owned here (rather than passed
200
+ * in) so that consumers fetching `gpu_scene.animation_manager`
201
+ * always see the same instance, and so per-frame database flush
202
+ * can be wired into {@link update} alongside the rest of the
203
+ * scene's bookkeeping.
204
+ *
205
+ * @type {GPUAnimationManager}
206
+ */
207
+ #animation_manager;
208
+
209
+ /**
210
+ *
211
+ * @param {GraphicsContext} graphics
212
+ * @param {Scene} scene
213
+ */
214
+ constructor(graphics, scene) {
215
+ assert.defined(scene, 'scene');
216
+ assert.isObject(scene, 'scene');
217
+ assert.equal(scene.isScene, true, 'scene.isScene !== true');
218
+
219
+ const device = graphics.device;
220
+
221
+ this.#scene = scene;
222
+ this.#device = device;
223
+ this.#graphics = graphics;
224
+
225
+ this.#tlas = new GPUInstancesAccelerationStructure(graphics);
226
+
227
+ // Pass `this` so the light collection (and its child shadow context) can use
228
+ // this scene's GPUSceneContext when building its own ViewManager — avoids
229
+ // threading the renderer-level ViewManager / SceneManager through every layer.
230
+ this.#lights = new GPULightCollection(graphics, this);
231
+
232
+ this.#scene_database = new GPUDatabase({
233
+ device,
234
+ definition: SCENE_DATABASE_SPEC,
235
+ label: "GPUSceneContext/Database",
236
+ });
237
+
238
+ this.#light_probe_volume = new GPULightProbeVolume(device, scene.light_probe_volume);
239
+
240
+ this.volumetric_light_map = new Brick4LightMap(device);
241
+
242
+ this.#volumetrics = new GPUSceneVolumetrics(device, scene.volumetrics);
243
+
244
+ this.#animation_manager = new GPUAnimationManager(device, `GPUSceneContext[${this.id}]/Animation`, this);
245
+ }
246
+
247
+ /**
248
+ * @returns {GPUAnimationManager}
249
+ */
250
+ get animation_manager() {
251
+ return this.#animation_manager;
252
+ }
253
+
254
+ /**
255
+ * @type {GPUDevice}
256
+ */
257
+ #device;
258
+
259
+ /**
260
+ * @type {GraphicsContext}
261
+ */
262
+ #graphics;
263
+
264
+ /**
265
+ *
266
+ * @returns {GPUDatabase}
267
+ */
268
+ get scene_database() {
269
+ return this.#scene_database;
270
+ }
271
+
272
+ /**
273
+ * The underlying buffer that backs {@link scene_database} — bind this
274
+ * as `array<u32>` in shaders that read mesh / transform records.
275
+ *
276
+ * @returns {GPUBuffer}
277
+ */
278
+ get scene_database_buffer() {
279
+ return this.#scene_database.buffer;
280
+ }
281
+
282
+ /**
283
+ * Per-scene skinning subsystem. Routes skinned rows through
284
+ * per-instance geometry clones; later phases grow Skin-binding
285
+ * management and the per-frame skinning compute onto it.
286
+ *
287
+ * Lazy because it depends on {@link geometries}, which is assigned
288
+ * externally after this object's constructor returns
289
+ * (see {@link SceneManager}). The first access happens during
290
+ * {@link build}, which runs well after that assignment.
291
+ *
292
+ * @returns {GPUMeshSkinningContext}
293
+ */
294
+ get skinning() {
295
+ if (this.#skinning === null) {
296
+ this.#skinning = new GPUMeshSkinningContext({
297
+ geometries: this.geometries,
298
+ animation_manager: this.#animation_manager,
299
+ scene_context: this,
300
+ device: this.#device,
301
+ });
302
+ }
303
+ return this.#skinning;
304
+ }
305
+
306
+ get gpu_memory_usage(){
307
+ let r = 0;
308
+
309
+ r+= this.#scene_database.gpu_memory_usage;
310
+
311
+ r += this.#lights.gpu_memory_usage;
312
+ r += this.#light_probe_volume.gpu_memory_usage;
313
+ r += this.volumetric_light_map.gpu_memory_usage;
314
+
315
+ return r;
316
+ }
317
+
318
+ /**
319
+ * Entities as rows of the scene database, at `entity + 1` in both tables.
320
+ *
321
+ * A system that places an entity acquires its row here and marks it on the dataset's change
322
+ * events; a scene with no systems places through `prefab_place` and `place_primitive`, which
323
+ * do the same by hand; and {@link build} flushes what was marked. The scene has to name its
324
+ * dataset ({@link Scene.dataset}) before this is first asked for, because the rows are written
325
+ * from that dataset's components.
326
+ *
327
+ * @returns {GPUSceneRows}
328
+ */
329
+ get rows() {
330
+ return this.#obtain_rows();
331
+ }
332
+
333
+ /**
334
+ * An entity's world bounds as the GPU holds them, read back — what a consumer that wants the
335
+ * box that is drawn asks, a frame or two behind the device. Built on demand, over the rows.
336
+ *
337
+ * @returns {GPUEntityBoundsReadback}
338
+ */
339
+ get bounds() {
340
+ if (this.#bounds === null) {
341
+ this.#bounds = new GPUEntityBoundsReadback(this.#scene_database.readback, this.rows);
342
+ }
343
+
344
+ return this.#bounds;
345
+ }
346
+
347
+ /**
348
+ * @type {GPUEntityBoundsReadback|null}
349
+ */
350
+ #bounds = null;
351
+
352
+ /**
353
+ * Every material something in the scene draws with, each once — the rows' own list, kept
354
+ * current as meshes attach and detach. What the rasterizers iterate to decide which buckets
355
+ * and pipelines a frame needs. The array is reused until the set changes; a scene with no
356
+ * rows draws with nothing.
357
+ *
358
+ * @returns {ShadeMaterial[]}
359
+ */
360
+ get drawn_materials() {
361
+ return this.#rows === null ? NO_MATERIALS : this.#rows.materials;
362
+ }
363
+
364
+ /**
365
+ * @returns {GPUSceneRows}
366
+ */
367
+ #obtain_rows() {
368
+ if (this.#rows === null) {
369
+ const dataset = this.#scene.dataset;
370
+
371
+ assert.notNull(dataset, 'the scene names no dataset — set Scene.dataset before asking for its rows');
372
+ assert.defined(dataset, 'the scene names no dataset — set Scene.dataset before asking for its rows');
373
+
374
+ this.#rows = new GPUSceneRows({
375
+ dataset,
376
+ transforms: this.#scene_database.get('transforms'),
377
+ meshes: this.#scene_database.get('meshes'),
378
+ geometries: this.geometries,
379
+ materials: this.materials,
380
+ tlas: this.#tlas,
381
+ skinning: () => this.skinning,
382
+ });
383
+ }
384
+
385
+ return this.#rows;
386
+ }
387
+
388
+ /**
389
+ * Bring the GPU scene database in line with the scene, writing only the rows that changed:
390
+ * the scene root's, once; a light's, as it arrives; and every entity's row that a system
391
+ * marked since the last build. Nothing is walked — the rows keep what was marked.
392
+ */
393
+ build() {
394
+ let written = 0;
395
+
396
+ if (!this.#root_written) {
397
+ this.#scene_database.get('transforms').set_record(NODE3D_SCENE_ID, ROOT_RECORD, ROOT_RECORD_WRITER);
398
+
399
+ this.#root_written = true;
400
+ written++;
401
+ }
402
+
403
+ // Entities are rows — marked by the systems that place them, written here. Built on demand
404
+ // because the scene may name its dataset after this context was made.
405
+ if (this.#rows === null && this.#scene.dataset !== null && this.#scene.dataset !== undefined) {
406
+ this.rows;
407
+ }
408
+
409
+ if (this.#rows !== null) {
410
+ // A light is an entity's row, held here on the light collection's behalf — before the
411
+ // flush, so a light that arrived this frame is written this frame.
412
+ this.#lights.sync_rows(this.#rows);
413
+
414
+ written += this.#rows.flush();
415
+ } else {
416
+ assert.equal(this.#scene.lights.elements.length, 0, 'the scene has lights and names no dataset; a light is an entity of one');
417
+ }
418
+
419
+ if (written === 0) {
420
+ return;
421
+ }
422
+
423
+ // Flush the scene database — only the rows that changed carry an upload record.
424
+ const cmd = ShadeGPUCommandContext.create(this.#graphics, 'GPUSceneContext/database-build');
425
+
426
+ // Also flush the global geometry manager. The first time a scene
427
+ // sees a new mesh, the rows' flush calls `geometries.add(...)`,
428
+ // which registers the source MeshletGeometry and flips
429
+ // `geometries.__needs_update = true`. The next per-frame
430
+ // `graphics.update()` would normally rebuild
431
+ // `geometries.buffer_metadata` to reflect those new entries — but
432
+ // `graphics.update()` runs at the *head* of `Renderer.#begin_frame`,
433
+ // *before* this scene.build, so the buffer_metadata stays whatever
434
+ // it was at the start of the frame (often the zero-record placeholder
435
+ // from the renderer's startup build, when the scene's geometries
436
+ // hadn't been registered yet).
437
+ //
438
+ // Any pass reading `geometries[mesh.geometry]` later in the frame
439
+ // (rasterization meshlet expansion, `shader_refresh_all_mesh_bounds`,
440
+ // etc.) sees zeros — `meshlets_count = 0` produces no triangles and
441
+ // `bounding_box = (0,0,0)-(0,0,0)` collapses world bounds to a
442
+ // single point in `shader_refresh_all_mesh_bounds`, which then writes
443
+ // those collapsed bounds back into `meshes_table`. Subsequent frames
444
+ // get a correct `buffer_metadata` from the next `graphics.update()`,
445
+ // but the `meshes_table` bounds stay collapsed until refresh_all
446
+ // overwrites them again — and frustum cull on the collapsed bounds
447
+ // can drop meshes whose collapsed point sits outside the frustum.
448
+ //
449
+ // Symptom: stress test rendered ground (whose collapsed point at the
450
+ // origin survives the cull) but dropped most trees (whose collapsed
451
+ // points scattered across the grid trigger cull edge cases).
452
+ //
453
+ // Calling `geometries.update(cmd)` here ensures the new buffer is in
454
+ // place before any pass in the same frame reads it. Idempotent / no-op
455
+ // when nothing's queued, so the per-frame `graphics.update` head call
456
+ // and this build-time call together leave the buffer in the right
457
+ // state under both lifetimes.
458
+ this.geometries.update(cmd);
459
+
460
+ this.#scene_database.update(cmd);
461
+ cmd.finish();
462
+ }
463
+
464
+ /**
465
+ *
466
+ * @param {GraphicsContext} ctx
467
+ */
468
+ update(ctx) {
469
+ assert.defined(ctx, 'ctx');
470
+
471
+ // TODO add a fast update check, so that calling this multiple times per frame can be fast.
472
+
473
+ // The apply point of the scene database's readback: whatever the device has answered since
474
+ // — an entity's drawn bounds, asked for through {@link bounds} — is delivered before
475
+ // anything this frame reads it, and never mid-update.
476
+ this.#scene_database.readback.apply();
477
+
478
+ this.#light_probe_volume.update();
479
+ this.#lights.update(ctx);
480
+ this.#volumetrics.update(ctx, 0);
481
+
482
+ // Per-frame animation database flush — picks up any new clips,
483
+ // tracks, skins, or per-frame `set_time` writes queued since
484
+ // last frame. Idempotent / cheap when nothing's queued.
485
+ const animation_cmd = ShadeGPUCommandContext.create(this.#graphics, 'GPUSceneContext/animation-flush');
486
+ this.#animation_manager.update(animation_cmd);
487
+ animation_cmd.finish();
488
+
489
+ // TODO update SDF
490
+
491
+ this.build();
492
+ }
493
+
494
+ /**
495
+ * Per-frame GPU-side scene update, once per scene per frame, after every view's {@link update}
496
+ * has flushed what the CPU changed:
497
+ *
498
+ * 1. the animation tick — pending registrations drained, `clip.time` advanced, apply → resolve
499
+ * → hierarchy propagate → skin-matrix prep → skinning, through {@link GPUAnimationManager#tick};
500
+ * 2. render bounds — every mesh row's world box and sphere, derived from its geometry under
501
+ * the `global` the hierarchy pass just composed, because the CPU does not hold that matrix
502
+ * for a subtree the GPU drives;
503
+ * 3. light poses — every light record's position and direction, from its entity's row, for
504
+ * the same reason;
505
+ * 4. the TLAS — rebuilt from those bounds when anything moved, on either side.
506
+ *
507
+ * All four into `cmd_ctx`, in that order, so the tree the frame's ray passes traverse is built
508
+ * over this frame's bounds rather than last frame's, and what lights the frame is where it is
509
+ * this frame.
510
+ *
511
+ * `dt_seconds` is wall-clock seconds since the last call (the renderer's `time_delta_seconds`
512
+ * argument to `render()`).
513
+ *
514
+ * @param {ShadeGPUCommandContext} cmd_ctx
515
+ * @param {number} dt_seconds wall-clock seconds since last call
516
+ */
517
+ tick(cmd_ctx, dt_seconds) {
518
+ const animated = this.#animation_manager.tick(cmd_ctx, dt_seconds);
519
+
520
+ this.#refresh_mesh_bounds(cmd_ctx);
521
+
522
+ this.#lights.refresh_poses(cmd_ctx, this.scene_database_buffer);
523
+
524
+ if (animated) {
525
+ // Rows moved on the GPU, where no version was bumped: a clip resolved into a TRS, a
526
+ // skinning pass moved a clone's vertices. The bounds pass just re-derived their boxes,
527
+ // and the tree is built over boxes.
528
+ this.#tlas.invalidate();
529
+ }
530
+
531
+ this.#tlas.update(this.scene_database_buffer, cmd_ctx);
532
+
533
+ // What was asked of the scene database this frame is copied out at the tail of the
534
+ // database's own update when rows were written this frame, and here — after the bounds
535
+ // pass — when none were; either way what lands, at the head of a later frame's update, is
536
+ // the box the GPU held when the copy ran.
537
+ this.#scene_database.readback.encode(cmd_ctx);
538
+ }
539
+
540
+ /**
541
+ * Recompute every mesh row's world bounds from its geometry under its composed `global`.
542
+ * Skipped when there is no mesh row; otherwise one thread per slot of the `meshes` table's
543
+ * pages, occupancy-masked.
544
+ *
545
+ * @param {ShadeGPUCommandContext} cmd_ctx
546
+ */
547
+ #refresh_mesh_bounds(cmd_ctx) {
548
+ const meshes_table = this.#scene_database.get('meshes');
549
+
550
+ const group_count = meshes_table.dispatch_group_count(REFRESH_ALL_MESH_BOUNDS_WORKGROUP_SIZE);
551
+
552
+ if (group_count === 0) {
553
+ return;
554
+ }
555
+
556
+ const geometries = this.geometries.buffer_metadata;
557
+
558
+ if (geometries === null) {
559
+ // a mesh row names a geometry, and a geometry is registered before its row is written
560
+ // — so this is a scene whose first frame has not flushed the geometry manager yet
561
+ return;
562
+ }
563
+
564
+ shader_refresh_all_mesh_bounds.dispatch({
565
+ encoder: cmd_ctx,
566
+ group_count_x: group_count,
567
+ bindings: {
568
+ scene_database: this.scene_database_buffer,
569
+ geometries,
570
+ },
571
+ });
572
+ }
573
+
574
+ destroy() {
575
+ if (this.#rows !== null) {
576
+ this.#rows.destroy();
577
+ }
578
+
579
+ this.#scene_database.destroy();
580
+ this.#lights.destroy();
581
+ this.#light_probe_volume.destroy();
582
+ this.#animation_manager.destroy();
583
+ if (this.#skinning !== null) {
584
+ this.#skinning.destroy();
585
+ }
586
+ }
587
+
588
+ }
589
+
590
+ /**
591
+ * @readonly
592
+ * @type {boolean}
593
+ */
594
+ GPUSceneContext.prototype.isGPUSceneContext = true;