@babylonjs/loaders 9.13.0 → 9.14.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.
- package/BVH/bvhFileLoader.d.ts +4 -67
- package/BVH/bvhFileLoader.js +6 -130
- package/BVH/bvhFileLoader.js.map +1 -1
- package/BVH/bvhFileLoader.pure.d.ts +75 -0
- package/BVH/bvhFileLoader.pure.js +154 -0
- package/BVH/bvhFileLoader.pure.js.map +1 -0
- package/BVH/bvhFileLoader.types.d.ts +11 -0
- package/BVH/bvhFileLoader.types.js +2 -0
- package/BVH/bvhFileLoader.types.js.map +1 -0
- package/BVH/pure.d.ts +3 -0
- package/BVH/pure.js +5 -0
- package/BVH/pure.js.map +1 -0
- package/FBX/fbxFileLoader.d.ts +4 -192
- package/FBX/fbxFileLoader.js +6 -2437
- package/FBX/fbxFileLoader.js.map +1 -1
- package/FBX/fbxFileLoader.pure.d.ts +190 -0
- package/FBX/fbxFileLoader.pure.js +2451 -0
- package/FBX/fbxFileLoader.pure.js.map +1 -0
- package/FBX/fbxFileLoader.types.d.ts +11 -0
- package/FBX/fbxFileLoader.types.js +2 -0
- package/FBX/fbxFileLoader.types.js.map +1 -0
- package/FBX/pure.d.ts +3 -0
- package/FBX/pure.js +4 -0
- package/FBX/pure.js.map +1 -0
- package/OBJ/objFileLoader.d.ts +4 -134
- package/OBJ/objFileLoader.js +6 -315
- package/OBJ/objFileLoader.js.map +1 -1
- package/OBJ/objFileLoader.pure.d.ts +132 -0
- package/OBJ/objFileLoader.pure.js +329 -0
- package/OBJ/objFileLoader.pure.js.map +1 -0
- package/OBJ/objFileLoader.types.d.ts +11 -0
- package/OBJ/objFileLoader.types.js +2 -0
- package/OBJ/objFileLoader.types.js.map +1 -0
- package/OBJ/pure.d.ts +5 -0
- package/OBJ/pure.js +6 -0
- package/OBJ/pure.js.map +1 -0
- package/OBJ/solidParser.js +4 -3
- package/OBJ/solidParser.js.map +1 -1
- package/SPLAT/gaussianSplattingBlockAllocator.d.ts +137 -0
- package/SPLAT/gaussianSplattingBlockAllocator.js +555 -0
- package/SPLAT/gaussianSplattingBlockAllocator.js.map +1 -0
- package/SPLAT/gaussianSplattingDownloadManager.d.ts +109 -0
- package/SPLAT/gaussianSplattingDownloadManager.js +241 -0
- package/SPLAT/gaussianSplattingDownloadManager.js.map +1 -0
- package/SPLAT/gaussianSplattingResidencyController.d.ts +133 -0
- package/SPLAT/gaussianSplattingResidencyController.js +222 -0
- package/SPLAT/gaussianSplattingResidencyController.js.map +1 -0
- package/SPLAT/gaussianSplattingStream.d.ts +122 -4
- package/SPLAT/gaussianSplattingStream.js +413 -42
- package/SPLAT/gaussianSplattingStream.js.map +1 -1
- package/SPLAT/gaussianSplattingWorkBuffer.d.ts +36 -0
- package/SPLAT/gaussianSplattingWorkBuffer.js +125 -13
- package/SPLAT/gaussianSplattingWorkBuffer.js.map +1 -1
- package/SPLAT/gaussianSplattingWorkBufferShaders.d.ts +15 -0
- package/SPLAT/gaussianSplattingWorkBufferShaders.js +82 -0
- package/SPLAT/gaussianSplattingWorkBufferShaders.js.map +1 -1
- package/SPLAT/pure.d.ts +5 -0
- package/SPLAT/pure.js +7 -0
- package/SPLAT/pure.js.map +1 -0
- package/SPLAT/sog.d.ts +1 -97
- package/SPLAT/sog.js +1 -501
- package/SPLAT/sog.js.map +1 -1
- package/SPLAT/sog.pure.d.ts +102 -0
- package/SPLAT/sog.pure.js +514 -0
- package/SPLAT/sog.pure.js.map +1 -0
- package/SPLAT/splatFileLoader.d.ts +5 -106
- package/SPLAT/splatFileLoader.js +9 -636
- package/SPLAT/splatFileLoader.js.map +1 -1
- package/SPLAT/splatFileLoader.pure.d.ts +104 -0
- package/SPLAT/splatFileLoader.pure.js +650 -0
- package/SPLAT/splatFileLoader.pure.js.map +1 -0
- package/SPLAT/splatFileLoader.types.d.ts +11 -0
- package/SPLAT/splatFileLoader.types.js +2 -0
- package/SPLAT/splatFileLoader.types.js.map +1 -0
- package/STL/pure.d.ts +2 -0
- package/STL/pure.js +3 -0
- package/STL/pure.js.map +1 -0
- package/STL/stlFileLoader.d.ts +5 -76
- package/STL/stlFileLoader.js +7 -236
- package/STL/stlFileLoader.js.map +1 -1
- package/STL/stlFileLoader.pure.d.ts +73 -0
- package/STL/stlFileLoader.pure.js +249 -0
- package/STL/stlFileLoader.pure.js.map +1 -0
- package/STL/stlFileLoader.types.d.ts +10 -0
- package/STL/stlFileLoader.types.js +2 -0
- package/STL/stlFileLoader.types.js.map +1 -0
- package/glTF/1.0/pure.d.ts +3 -0
- package/glTF/1.0/pure.js +4 -0
- package/glTF/1.0/pure.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_lights_area.d.ts +4 -39
- package/glTF/2.0/Extensions/EXT_lights_area.js +6 -91
- package/glTF/2.0/Extensions/EXT_lights_area.js.map +1 -1
- package/glTF/2.0/Extensions/EXT_lights_area.pure.d.ts +38 -0
- package/glTF/2.0/Extensions/EXT_lights_area.pure.js +106 -0
- package/glTF/2.0/Extensions/EXT_lights_area.pure.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_lights_area.types.d.ts +9 -0
- package/glTF/2.0/Extensions/EXT_lights_area.types.js +2 -0
- package/glTF/2.0/Extensions/EXT_lights_area.types.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_lights_ies.d.ts +4 -39
- package/glTF/2.0/Extensions/EXT_lights_ies.js +6 -81
- package/glTF/2.0/Extensions/EXT_lights_ies.js.map +1 -1
- package/glTF/2.0/Extensions/EXT_lights_ies.pure.d.ts +38 -0
- package/glTF/2.0/Extensions/EXT_lights_ies.pure.js +96 -0
- package/glTF/2.0/Extensions/EXT_lights_ies.pure.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_lights_ies.types.d.ts +9 -0
- package/glTF/2.0/Extensions/EXT_lights_ies.types.js +2 -0
- package/glTF/2.0/Extensions/EXT_lights_ies.types.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_lights_image_based.d.ts +4 -46
- package/glTF/2.0/Extensions/EXT_lights_image_based.js +6 -113
- package/glTF/2.0/Extensions/EXT_lights_image_based.js.map +1 -1
- package/glTF/2.0/Extensions/EXT_lights_image_based.pure.d.ts +37 -0
- package/glTF/2.0/Extensions/EXT_lights_image_based.pure.js +128 -0
- package/glTF/2.0/Extensions/EXT_lights_image_based.pure.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_lights_image_based.types.d.ts +17 -0
- package/glTF/2.0/Extensions/EXT_lights_image_based.types.js +2 -0
- package/glTF/2.0/Extensions/EXT_lights_image_based.types.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.d.ts +5 -37
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.js +7 -92
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.js.map +1 -1
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.pure.d.ts +35 -0
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.pure.js +106 -0
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.pure.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.types.d.ts +9 -0
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.types.js +2 -0
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.types.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_meshopt_compression.d.ts +4 -37
- package/glTF/2.0/Extensions/EXT_meshopt_compression.js +6 -48
- package/glTF/2.0/Extensions/EXT_meshopt_compression.js.map +1 -1
- package/glTF/2.0/Extensions/EXT_meshopt_compression.pure.d.ts +36 -0
- package/glTF/2.0/Extensions/EXT_meshopt_compression.pure.js +63 -0
- package/glTF/2.0/Extensions/EXT_meshopt_compression.pure.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_meshopt_compression.types.d.ts +9 -0
- package/glTF/2.0/Extensions/EXT_meshopt_compression.types.js +2 -0
- package/glTF/2.0/Extensions/EXT_meshopt_compression.types.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_texture_avif.d.ts +4 -32
- package/glTF/2.0/Extensions/EXT_texture_avif.js +6 -36
- package/glTF/2.0/Extensions/EXT_texture_avif.js.map +1 -1
- package/glTF/2.0/Extensions/EXT_texture_avif.pure.d.ts +31 -0
- package/glTF/2.0/Extensions/EXT_texture_avif.pure.js +51 -0
- package/glTF/2.0/Extensions/EXT_texture_avif.pure.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_texture_avif.types.d.ts +9 -0
- package/glTF/2.0/Extensions/EXT_texture_avif.types.js +2 -0
- package/glTF/2.0/Extensions/EXT_texture_avif.types.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_texture_webp.d.ts +4 -31
- package/glTF/2.0/Extensions/EXT_texture_webp.js +6 -35
- package/glTF/2.0/Extensions/EXT_texture_webp.js.map +1 -1
- package/glTF/2.0/Extensions/EXT_texture_webp.pure.d.ts +30 -0
- package/glTF/2.0/Extensions/EXT_texture_webp.pure.js +50 -0
- package/glTF/2.0/Extensions/EXT_texture_webp.pure.js.map +1 -0
- package/glTF/2.0/Extensions/EXT_texture_webp.types.d.ts +9 -0
- package/glTF/2.0/Extensions/EXT_texture_webp.types.js +2 -0
- package/glTF/2.0/Extensions/EXT_texture_webp.types.js.map +1 -0
- package/glTF/2.0/Extensions/ExtrasAsMetadata.d.ts +4 -51
- package/glTF/2.0/Extensions/ExtrasAsMetadata.js +6 -71
- package/glTF/2.0/Extensions/ExtrasAsMetadata.js.map +1 -1
- package/glTF/2.0/Extensions/ExtrasAsMetadata.pure.d.ts +50 -0
- package/glTF/2.0/Extensions/ExtrasAsMetadata.pure.js +85 -0
- package/glTF/2.0/Extensions/ExtrasAsMetadata.pure.js.map +1 -0
- package/glTF/2.0/Extensions/ExtrasAsMetadata.types.d.ts +9 -0
- package/glTF/2.0/Extensions/ExtrasAsMetadata.types.js +2 -0
- package/glTF/2.0/Extensions/ExtrasAsMetadata.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_animation_pointer.d.ts +5 -45
- package/glTF/2.0/Extensions/KHR_animation_pointer.js +7 -75
- package/glTF/2.0/Extensions/KHR_animation_pointer.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_animation_pointer.pure.d.ts +43 -0
- package/glTF/2.0/Extensions/KHR_animation_pointer.pure.js +89 -0
- package/glTF/2.0/Extensions/KHR_animation_pointer.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_animation_pointer.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_animation_pointer.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_animation_pointer.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.d.ts +4 -45
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.js +6 -90
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.pure.d.ts +44 -0
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.pure.js +105 -0
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.d.ts +4 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.js +5 -0
- package/glTF/2.0/Extensions/KHR_interactivity/pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity.d.ts +4 -36
- package/glTF/2.0/Extensions/KHR_interactivity.js +6 -148
- package/glTF/2.0/Extensions/KHR_interactivity.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_interactivity.pure.d.ts +35 -0
- package/glTF/2.0/Extensions/KHR_interactivity.pure.js +163 -0
- package/glTF/2.0/Extensions/KHR_interactivity.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_interactivity.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_interactivity.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_interactivity.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_lights_punctual.d.ts +4 -39
- package/glTF/2.0/Extensions/KHR_lights_punctual.js +6 -89
- package/glTF/2.0/Extensions/KHR_lights_punctual.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_lights_punctual.pure.d.ts +38 -0
- package/glTF/2.0/Extensions/KHR_lights_punctual.pure.js +104 -0
- package/glTF/2.0/Extensions/KHR_lights_punctual.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_lights_punctual.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_lights_punctual.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_lights_punctual.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.d.ts +4 -40
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.js +6 -63
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.pure.d.ts +39 -0
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.pure.js +78 -0
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_anisotropy.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.d.ts +4 -41
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.js +6 -77
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.pure.d.ts +40 -0
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.pure.js +92 -0
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_clearcoat.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_coat.d.ts +4 -47
- package/glTF/2.0/Extensions/KHR_materials_coat.js +6 -117
- package/glTF/2.0/Extensions/KHR_materials_coat.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_coat.pure.d.ts +46 -0
- package/glTF/2.0/Extensions/KHR_materials_coat.pure.js +132 -0
- package/glTF/2.0/Extensions/KHR_materials_coat.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_coat.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_coat.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_coat.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_roughness.d.ts +4 -41
- package/glTF/2.0/Extensions/KHR_materials_diffuse_roughness.js +6 -56
- package/glTF/2.0/Extensions/KHR_materials_diffuse_roughness.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_diffuse_roughness.pure.d.ts +40 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_roughness.pure.js +71 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_roughness.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_roughness.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_roughness.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_roughness.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.d.ts +4 -41
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.js +6 -71
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.pure.d.ts +40 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.pure.js +86 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_dispersion.d.ts +4 -41
- package/glTF/2.0/Extensions/KHR_materials_dispersion.js +6 -54
- package/glTF/2.0/Extensions/KHR_materials_dispersion.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_dispersion.pure.d.ts +40 -0
- package/glTF/2.0/Extensions/KHR_materials_dispersion.pure.js +69 -0
- package/glTF/2.0/Extensions/KHR_materials_dispersion.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_dispersion.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_dispersion.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_dispersion.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.d.ts +4 -40
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.js +6 -45
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.pure.d.ts +39 -0
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.pure.js +60 -0
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_emissive_strength.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_fuzz.d.ts +4 -41
- package/glTF/2.0/Extensions/KHR_materials_fuzz.js +6 -75
- package/glTF/2.0/Extensions/KHR_materials_fuzz.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_fuzz.pure.d.ts +40 -0
- package/glTF/2.0/Extensions/KHR_materials_fuzz.pure.js +90 -0
- package/glTF/2.0/Extensions/KHR_materials_fuzz.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_fuzz.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_fuzz.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_fuzz.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_ior.d.ts +4 -44
- package/glTF/2.0/Extensions/KHR_materials_ior.js +6 -52
- package/glTF/2.0/Extensions/KHR_materials_ior.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_ior.pure.d.ts +43 -0
- package/glTF/2.0/Extensions/KHR_materials_ior.pure.js +67 -0
- package/glTF/2.0/Extensions/KHR_materials_ior.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_ior.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_ior.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_ior.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_iridescence.d.ts +4 -40
- package/glTF/2.0/Extensions/KHR_materials_iridescence.js +6 -66
- package/glTF/2.0/Extensions/KHR_materials_iridescence.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_iridescence.pure.d.ts +39 -0
- package/glTF/2.0/Extensions/KHR_materials_iridescence.pure.js +81 -0
- package/glTF/2.0/Extensions/KHR_materials_iridescence.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_iridescence.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_iridescence.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_iridescence.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.d.ts +4 -40
- package/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.js +6 -72
- package/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.pure.d.ts +39 -0
- package/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.pure.js +87 -0
- package/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_sheen.d.ts +4 -41
- package/glTF/2.0/Extensions/KHR_materials_sheen.js +6 -71
- package/glTF/2.0/Extensions/KHR_materials_sheen.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_sheen.pure.d.ts +40 -0
- package/glTF/2.0/Extensions/KHR_materials_sheen.pure.js +86 -0
- package/glTF/2.0/Extensions/KHR_materials_sheen.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_sheen.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_sheen.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_sheen.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_specular.d.ts +4 -40
- package/glTF/2.0/Extensions/KHR_materials_specular.js +6 -74
- package/glTF/2.0/Extensions/KHR_materials_specular.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_specular.pure.d.ts +39 -0
- package/glTF/2.0/Extensions/KHR_materials_specular.pure.js +89 -0
- package/glTF/2.0/Extensions/KHR_materials_specular.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_specular.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_specular.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_specular.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_transmission.d.ts +4 -40
- package/glTF/2.0/Extensions/KHR_materials_transmission.js +6 -70
- package/glTF/2.0/Extensions/KHR_materials_transmission.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_transmission.pure.d.ts +39 -0
- package/glTF/2.0/Extensions/KHR_materials_transmission.pure.js +85 -0
- package/glTF/2.0/Extensions/KHR_materials_transmission.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_transmission.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_transmission.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_transmission.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_unlit.d.ts +4 -40
- package/glTF/2.0/Extensions/KHR_materials_unlit.js +6 -64
- package/glTF/2.0/Extensions/KHR_materials_unlit.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_unlit.pure.d.ts +39 -0
- package/glTF/2.0/Extensions/KHR_materials_unlit.pure.js +79 -0
- package/glTF/2.0/Extensions/KHR_materials_unlit.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_unlit.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_unlit.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_unlit.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_variants.d.ts +4 -110
- package/glTF/2.0/Extensions/KHR_materials_variants.js +6 -260
- package/glTF/2.0/Extensions/KHR_materials_variants.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_variants.pure.d.ts +97 -0
- package/glTF/2.0/Extensions/KHR_materials_variants.pure.js +275 -0
- package/glTF/2.0/Extensions/KHR_materials_variants.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_variants.types.d.ts +29 -0
- package/glTF/2.0/Extensions/KHR_materials_variants.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_variants.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_volume.d.ts +4 -41
- package/glTF/2.0/Extensions/KHR_materials_volume.js +6 -77
- package/glTF/2.0/Extensions/KHR_materials_volume.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_volume.pure.d.ts +40 -0
- package/glTF/2.0/Extensions/KHR_materials_volume.pure.js +92 -0
- package/glTF/2.0/Extensions/KHR_materials_volume.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_volume.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_volume.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_volume.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_volume_scatter.d.ts +4 -43
- package/glTF/2.0/Extensions/KHR_materials_volume_scatter.js +6 -113
- package/glTF/2.0/Extensions/KHR_materials_volume_scatter.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_volume_scatter.pure.d.ts +42 -0
- package/glTF/2.0/Extensions/KHR_materials_volume_scatter.pure.js +128 -0
- package/glTF/2.0/Extensions/KHR_materials_volume_scatter.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_materials_volume_scatter.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_materials_volume_scatter.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_materials_volume_scatter.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_mesh_quantization.d.ts +4 -27
- package/glTF/2.0/Extensions/KHR_mesh_quantization.js +6 -20
- package/glTF/2.0/Extensions/KHR_mesh_quantization.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_mesh_quantization.pure.d.ts +26 -0
- package/glTF/2.0/Extensions/KHR_mesh_quantization.pure.js +35 -0
- package/glTF/2.0/Extensions/KHR_mesh_quantization.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_mesh_quantization.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_mesh_quantization.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_mesh_quantization.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_node_hoverability.d.ts +4 -29
- package/glTF/2.0/Extensions/KHR_node_hoverability.js +6 -187
- package/glTF/2.0/Extensions/KHR_node_hoverability.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.d.ts +28 -0
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js +202 -0
- package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_node_hoverability.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_node_hoverability.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_node_hoverability.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_node_selectability.d.ts +4 -28
- package/glTF/2.0/Extensions/KHR_node_selectability.js +6 -121
- package/glTF/2.0/Extensions/KHR_node_selectability.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.d.ts +27 -0
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.js +136 -0
- package/glTF/2.0/Extensions/KHR_node_selectability.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_node_selectability.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_node_selectability.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_node_selectability.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_node_visibility.d.ts +4 -28
- package/glTF/2.0/Extensions/KHR_node_visibility.js +6 -64
- package/glTF/2.0/Extensions/KHR_node_visibility.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_node_visibility.pure.d.ts +27 -0
- package/glTF/2.0/Extensions/KHR_node_visibility.pure.js +79 -0
- package/glTF/2.0/Extensions/KHR_node_visibility.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_node_visibility.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_node_visibility.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_node_visibility.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_texture_basisu.d.ts +4 -31
- package/glTF/2.0/Extensions/KHR_texture_basisu.js +6 -35
- package/glTF/2.0/Extensions/KHR_texture_basisu.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_texture_basisu.pure.d.ts +30 -0
- package/glTF/2.0/Extensions/KHR_texture_basisu.pure.js +50 -0
- package/glTF/2.0/Extensions/KHR_texture_basisu.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_texture_basisu.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_texture_basisu.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_texture_basisu.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_texture_transform.d.ts +4 -35
- package/glTF/2.0/Extensions/KHR_texture_transform.js +6 -56
- package/glTF/2.0/Extensions/KHR_texture_transform.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_texture_transform.pure.d.ts +34 -0
- package/glTF/2.0/Extensions/KHR_texture_transform.pure.js +71 -0
- package/glTF/2.0/Extensions/KHR_texture_transform.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_texture_transform.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_texture_transform.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_texture_transform.types.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_xmp_json_ld.d.ts +4 -37
- package/glTF/2.0/Extensions/KHR_xmp_json_ld.js +6 -45
- package/glTF/2.0/Extensions/KHR_xmp_json_ld.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_xmp_json_ld.pure.d.ts +36 -0
- package/glTF/2.0/Extensions/KHR_xmp_json_ld.pure.js +60 -0
- package/glTF/2.0/Extensions/KHR_xmp_json_ld.pure.js.map +1 -0
- package/glTF/2.0/Extensions/KHR_xmp_json_ld.types.d.ts +9 -0
- package/glTF/2.0/Extensions/KHR_xmp_json_ld.types.js +2 -0
- package/glTF/2.0/Extensions/KHR_xmp_json_ld.types.js.map +1 -0
- package/glTF/2.0/Extensions/MSFT_audio_emitter.d.ts +5 -54
- package/glTF/2.0/Extensions/MSFT_audio_emitter.js +7 -226
- package/glTF/2.0/Extensions/MSFT_audio_emitter.js.map +1 -1
- package/glTF/2.0/Extensions/MSFT_audio_emitter.pure.d.ts +52 -0
- package/glTF/2.0/Extensions/MSFT_audio_emitter.pure.js +240 -0
- package/glTF/2.0/Extensions/MSFT_audio_emitter.pure.js.map +1 -0
- package/glTF/2.0/Extensions/MSFT_audio_emitter.types.d.ts +9 -0
- package/glTF/2.0/Extensions/MSFT_audio_emitter.types.js +2 -0
- package/glTF/2.0/Extensions/MSFT_audio_emitter.types.js.map +1 -0
- package/glTF/2.0/Extensions/MSFT_lod.d.ts +4 -102
- package/glTF/2.0/Extensions/MSFT_lod.js +6 -335
- package/glTF/2.0/Extensions/MSFT_lod.js.map +1 -1
- package/glTF/2.0/Extensions/MSFT_lod.pure.d.ts +96 -0
- package/glTF/2.0/Extensions/MSFT_lod.pure.js +350 -0
- package/glTF/2.0/Extensions/MSFT_lod.pure.js.map +1 -0
- package/glTF/2.0/Extensions/MSFT_lod.types.d.ts +14 -0
- package/glTF/2.0/Extensions/MSFT_lod.types.js +2 -0
- package/glTF/2.0/Extensions/MSFT_lod.types.js.map +1 -0
- package/glTF/2.0/Extensions/MSFT_minecraftMesh.d.ts +6 -27
- package/glTF/2.0/Extensions/MSFT_minecraftMesh.js +8 -40
- package/glTF/2.0/Extensions/MSFT_minecraftMesh.js.map +1 -1
- package/glTF/2.0/Extensions/MSFT_minecraftMesh.pure.d.ts +24 -0
- package/glTF/2.0/Extensions/MSFT_minecraftMesh.pure.js +53 -0
- package/glTF/2.0/Extensions/MSFT_minecraftMesh.pure.js.map +1 -0
- package/glTF/2.0/Extensions/MSFT_minecraftMesh.types.d.ts +9 -0
- package/glTF/2.0/Extensions/MSFT_minecraftMesh.types.js +2 -0
- package/glTF/2.0/Extensions/MSFT_minecraftMesh.types.js.map +1 -0
- package/glTF/2.0/Extensions/MSFT_sRGBFactors.d.ts +6 -27
- package/glTF/2.0/Extensions/MSFT_sRGBFactors.js +8 -38
- package/glTF/2.0/Extensions/MSFT_sRGBFactors.js.map +1 -1
- package/glTF/2.0/Extensions/MSFT_sRGBFactors.pure.d.ts +24 -0
- package/glTF/2.0/Extensions/MSFT_sRGBFactors.pure.js +51 -0
- package/glTF/2.0/Extensions/MSFT_sRGBFactors.pure.js.map +1 -0
- package/glTF/2.0/Extensions/MSFT_sRGBFactors.types.d.ts +9 -0
- package/glTF/2.0/Extensions/MSFT_sRGBFactors.types.js +2 -0
- package/glTF/2.0/Extensions/MSFT_sRGBFactors.types.js.map +1 -0
- package/glTF/2.0/Extensions/pure.d.ts +45 -0
- package/glTF/2.0/Extensions/pure.js +47 -0
- package/glTF/2.0/Extensions/pure.js.map +1 -0
- package/glTF/2.0/glTFLoader.d.ts +1 -471
- package/glTF/2.0/glTFLoader.js +3 -2539
- package/glTF/2.0/glTFLoader.js.map +1 -1
- package/glTF/2.0/glTFLoader.pure.d.ts +476 -0
- package/glTF/2.0/glTFLoader.pure.js +2563 -0
- package/glTF/2.0/glTFLoader.pure.js.map +1 -0
- package/glTF/2.0/pure.d.ts +8 -0
- package/glTF/2.0/pure.js +10 -0
- package/glTF/2.0/pure.js.map +1 -0
- package/glTF/glTFFileLoader.d.ts +5 -551
- package/glTF/glTFFileLoader.js +6 -996
- package/glTF/glTFFileLoader.js.map +1 -1
- package/glTF/glTFFileLoader.pure.d.ts +562 -0
- package/glTF/glTFFileLoader.pure.js +1024 -0
- package/glTF/glTFFileLoader.pure.js.map +1 -0
- package/glTF/glTFFileLoader.types.d.ts +11 -0
- package/glTF/glTFFileLoader.types.js +2 -0
- package/glTF/glTFFileLoader.types.js.map +1 -0
- package/glTF/pure.d.ts +6 -0
- package/glTF/pure.js +8 -0
- package/glTF/pure.js.map +1 -0
- package/package.json +56 -4
- package/pure.d.ts +8 -0
- package/pure.js +10 -0
- package/pure.js.map +1 -0
|
@@ -9,10 +9,18 @@ import { Camera } from "@babylonjs/core/Cameras/camera.js";
|
|
|
9
9
|
import { BoundingInfo } from "@babylonjs/core/Culling/boundingInfo.js";
|
|
10
10
|
import { CreateLineSystem } from "@babylonjs/core/Meshes/Builders/linesBuilder.js";
|
|
11
11
|
import { VertexBuffer } from "@babylonjs/core/Buffers/buffer.js";
|
|
12
|
-
import { ParseSogMetaAsTextures } from "./sog.js";
|
|
12
|
+
import { ParseSogMetaAsTextures } from "./sog.pure.js";
|
|
13
13
|
import { GaussianSplattingWorkBuffer } from "./gaussianSplattingWorkBuffer.js";
|
|
14
|
+
import { GaussianSplattingDownloadManager } from "./gaussianSplattingDownloadManager.js";
|
|
15
|
+
import { GaussianSplattingResidencyController } from "./gaussianSplattingResidencyController.js";
|
|
14
16
|
// tan(22.5deg): reference half-FOV for a 45-degree vertical FOV, used for FOV compensation (matches PlayCanvas).
|
|
15
17
|
const RefTanHalfFov = Math.tan((22.5 * Math.PI) / 180);
|
|
18
|
+
// Sentinel "file" ids for the residency controller's pinned (never-evicted) allocations.
|
|
19
|
+
const PaddingFileId = -2;
|
|
20
|
+
const EnvironmentFileId = -1;
|
|
21
|
+
// Approximate bytes per resident splat used to convert a memory budget (MB) to a splat budget: the four
|
|
22
|
+
// work-buffer textures cost 16+16+16+4 = 52 bytes on the GPU, plus ~32 bytes of CPU position/sort data.
|
|
23
|
+
const BytesPerResidentSplat = 84;
|
|
16
24
|
// Scratch objects reused by the per-frame optimal-LOD evaluation (avoids per-call allocations).
|
|
17
25
|
const TmpInvWorld = new Matrix();
|
|
18
26
|
const TmpLocalCamera = new Vector3();
|
|
@@ -122,18 +130,33 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
122
130
|
this._readbackCandidate = false;
|
|
123
131
|
// Set once the one-time readback validation has run (success or failure).
|
|
124
132
|
this._readbackProbed = false;
|
|
125
|
-
//
|
|
126
|
-
this.
|
|
133
|
+
// Residency controller: owns the work-buffer slot allocator, per-file blocks, and eviction cooldowns.
|
|
134
|
+
this._residency = null;
|
|
127
135
|
// Splat count of each source file (learned from its metadata before allocation).
|
|
128
136
|
this._fileCounts = new Map();
|
|
129
137
|
// Cached SOG metadata per file so on-demand decodes don't refetch the meta.json.
|
|
130
138
|
this._fileMeta = new Map();
|
|
131
|
-
// Files whose splats have been GPU-decoded into the work buffer.
|
|
139
|
+
// Files whose splats have been fully GPU-decoded into the work buffer (render-safe).
|
|
132
140
|
this._decodedFiles = new Set();
|
|
133
141
|
// Files whose decode is currently in flight (dedupes concurrent requests).
|
|
134
142
|
this._loadingFiles = new Set();
|
|
135
143
|
// FIFO of file ids waiting to be decoded (drained under a per-frame budget).
|
|
136
144
|
this._decodeQueue = [];
|
|
145
|
+
// Per-file reference count: number of leaf nodes whose active LOD renders, or whose pending target points
|
|
146
|
+
// at, each file. At zero, a decoded file is scheduled for eviction and a still-downloading file is cancelled.
|
|
147
|
+
this._fileRefs = new Map();
|
|
148
|
+
// Files whose in-flight decode was cancelled; checked at decode checkpoints to bail out cooperatively.
|
|
149
|
+
this._cancelledDecodes = new Set();
|
|
150
|
+
// Eviction streaming config: enabled only when a budget smaller than the full dataset is configured.
|
|
151
|
+
this._evictionEnabled = false;
|
|
152
|
+
this._residentBudget = 0;
|
|
153
|
+
this._evictionCooldownFrames = 100;
|
|
154
|
+
// Serializes the allocate -> decode -> readback critical section so a defrag relayout (which runs inside it)
|
|
155
|
+
// never overlaps another file's decode writing the work buffer, which would corrupt the moved data.
|
|
156
|
+
this._decodeGate = Promise.resolve();
|
|
157
|
+
// Reusable scratch for the (rare) defrag relayout, to avoid per-relayout allocations during streaming.
|
|
158
|
+
this._relayoutOldOffsets = new Map();
|
|
159
|
+
this._relayoutSrcIndex = null;
|
|
137
160
|
// Global range covered by the environment file (always rendered), or null until it loads.
|
|
138
161
|
this._environmentRange = null;
|
|
139
162
|
// Unzipped environment bundle contents, retained between count-gathering and decode.
|
|
@@ -201,6 +224,23 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
201
224
|
if (options.debugLodSource) {
|
|
202
225
|
this._debugLodSource = options.debugLodSource;
|
|
203
226
|
}
|
|
227
|
+
if (options.evictionCooldownFrames !== undefined) {
|
|
228
|
+
this._evictionCooldownFrames = Math.max(0, Math.floor(options.evictionCooldownFrames));
|
|
229
|
+
}
|
|
230
|
+
// Resolve the resident-splat budget from the splat-count and/or memory-size options (smaller wins).
|
|
231
|
+
let budget = 0;
|
|
232
|
+
if (options.maxResidentSplats !== undefined && options.maxResidentSplats > 0) {
|
|
233
|
+
budget = Math.floor(options.maxResidentSplats);
|
|
234
|
+
}
|
|
235
|
+
if (options.memoryBudgetMb !== undefined && options.memoryBudgetMb > 0) {
|
|
236
|
+
const fromMB = Math.floor((options.memoryBudgetMb * 1024 * 1024) / BytesPerResidentSplat);
|
|
237
|
+
budget = budget > 0 ? Math.min(budget, fromMB) : fromMB;
|
|
238
|
+
}
|
|
239
|
+
this._residentBudget = budget;
|
|
240
|
+
this._downloadManager = new GaussianSplattingDownloadManager({
|
|
241
|
+
maxConcurrent: options.maxConcurrentDownloads,
|
|
242
|
+
maxRetries: options.maxDownloadRetries,
|
|
243
|
+
});
|
|
204
244
|
// PlayCanvas SOG data is authored with a flipped Y; match the standard SOG loader.
|
|
205
245
|
this.scaling.y *= -1;
|
|
206
246
|
// PlayCanvas SOG LOD scenes are authored Z-up; rotate into Babylon's Y-up convention.
|
|
@@ -218,6 +258,88 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
218
258
|
getClassName() {
|
|
219
259
|
return "GaussianSplattingStream";
|
|
220
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Resolves once the scene is fully streamed and displayed for the current camera: a LOD re-evaluation has
|
|
263
|
+
* run for the current point of view, every reachable LOD file has finished downloading and decoding (no
|
|
264
|
+
* downloads, decodes, or queued work remain), and the depth sort for the resulting splats has been applied
|
|
265
|
+
* and rendered. Intended for deterministic automated testing and screenshot/image comparison.
|
|
266
|
+
*
|
|
267
|
+
* Streaming and settling require rendered frames. If an external render loop is already running, this waits
|
|
268
|
+
* on it passively; otherwise (e.g. when awaited inside an async `createScene` before the host starts its
|
|
269
|
+
* render loop) it drives `scene.render()` itself until settled, so it never deadlocks.
|
|
270
|
+
*
|
|
271
|
+
* Note: the promise only resolves while the camera is still — if the camera keeps moving, the target LODs
|
|
272
|
+
* (and the depth sort) keep changing and the stream never settles. Position the camera, then await this.
|
|
273
|
+
* @param stableFrames number of consecutive settled frames to require before resolving (defaults to 3), so
|
|
274
|
+
* the final sorted frame is actually on screen
|
|
275
|
+
* @returns a promise that resolves when loading and rendering are complete for the current view
|
|
276
|
+
*/
|
|
277
|
+
async whenSettledAsync(stableFrames = 3) {
|
|
278
|
+
if (this._disposed) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
// Re-evaluate LODs immediately so the target levels reflect the current camera before we wait.
|
|
282
|
+
this._forceLodUpdate = true;
|
|
283
|
+
const required = Math.max(1, stableFrames);
|
|
284
|
+
const scene = this._scene;
|
|
285
|
+
let stable = 0;
|
|
286
|
+
const isSettled = () => {
|
|
287
|
+
if (this._isLoadingIdle() && this._isDepthSortSettled) {
|
|
288
|
+
return ++stable >= required;
|
|
289
|
+
}
|
|
290
|
+
stable = 0;
|
|
291
|
+
return false;
|
|
292
|
+
};
|
|
293
|
+
// An external render loop is already driving frames: observe it passively.
|
|
294
|
+
if (scene.getEngine().activeRenderLoops.length > 0) {
|
|
295
|
+
await new Promise((resolve) => {
|
|
296
|
+
let observer = null;
|
|
297
|
+
observer = scene.onAfterRenderObservable.add(() => {
|
|
298
|
+
if (this._disposed || isSettled()) {
|
|
299
|
+
if (observer) {
|
|
300
|
+
scene.onAfterRenderObservable.remove(observer);
|
|
301
|
+
observer = null;
|
|
302
|
+
}
|
|
303
|
+
resolve();
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
// No render loop yet (e.g. awaited inside createScene): drive rendering ourselves so the streaming
|
|
310
|
+
// decodes and depth sort can progress, yielding between frames so async downloads/readbacks resolve.
|
|
311
|
+
// Wrap each render in beginFrame/endFrame exactly like the engine's own render loop: on WebGPU,
|
|
312
|
+
// endFrame submits the frame's command buffers and presents the swapchain, so a bare scene.render()
|
|
313
|
+
// would leave the acquired swapchain texture to be destroyed at the frame boundary before its command
|
|
314
|
+
// buffer is submitted ("destroyed texture used in a submit").
|
|
315
|
+
const engine = scene.getEngine();
|
|
316
|
+
const requestFrame = globalThis.requestAnimationFrame;
|
|
317
|
+
while (!this._disposed) {
|
|
318
|
+
engine.beginFrame();
|
|
319
|
+
scene.render();
|
|
320
|
+
engine.endFrame();
|
|
321
|
+
if (isSettled()) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
// eslint-disable-next-line no-await-in-loop
|
|
325
|
+
await new Promise((resolve) => {
|
|
326
|
+
if (typeof requestFrame === "function") {
|
|
327
|
+
requestFrame(() => resolve());
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
setTimeout(resolve, 16);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Whether the base layer is ready and there is no streaming work in flight (nothing queued for decode, no
|
|
337
|
+
* decode running, and no downloads pending).
|
|
338
|
+
* @returns true when no loading work remains
|
|
339
|
+
*/
|
|
340
|
+
_isLoadingIdle() {
|
|
341
|
+
return this._baseLayerReady && this._decodeQueue.length === 0 && this._loadingFiles.size === 0 && this._downloadManager.isIdle;
|
|
342
|
+
}
|
|
221
343
|
/**
|
|
222
344
|
* Finest (most detailed) LOD level any node is allowed to render. `0` allows full detail (level 0);
|
|
223
345
|
* `1` caps detail at the next-coarser level, and so on. Nodes already coarser than this cap (by
|
|
@@ -300,6 +422,9 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
300
422
|
this._lodObserver = null;
|
|
301
423
|
}
|
|
302
424
|
this._clearDebugDisplay();
|
|
425
|
+
this._downloadManager.dispose();
|
|
426
|
+
this._residency?.dispose();
|
|
427
|
+
this._residency = null;
|
|
303
428
|
this._workBuffer?.dispose();
|
|
304
429
|
this._workBuffer = null;
|
|
305
430
|
super.dispose(doNotRecurse);
|
|
@@ -576,26 +701,40 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
576
701
|
if (this._disposed) {
|
|
577
702
|
return;
|
|
578
703
|
}
|
|
579
|
-
// Phase 2:
|
|
704
|
+
// Phase 2: learn the full dataset size (padding + environment + every LOD file). The work buffer is
|
|
705
|
+
// sized to this unless a smaller budget enables eviction-based streaming.
|
|
580
706
|
// Index 0 is reserved as a never-decoded padding splat: the sort worker and index buffer pad unused
|
|
581
707
|
// slots with index 0, and leaving that slot zeroed (center.w = 0 => zero covariance, alpha 0) makes
|
|
582
708
|
// the padding invisible instead of ghosting a copy of the first real splat.
|
|
583
|
-
let
|
|
709
|
+
let fullCapacity = 1;
|
|
584
710
|
if (envCount > 0) {
|
|
585
|
-
|
|
586
|
-
capacity += envCount;
|
|
711
|
+
fullCapacity += envCount;
|
|
587
712
|
}
|
|
588
713
|
for (const fileId of fileIds) {
|
|
589
714
|
const count = this._fileCounts.get(fileId);
|
|
590
|
-
if (count
|
|
591
|
-
|
|
715
|
+
if (count !== undefined && count > 0) {
|
|
716
|
+
fullCapacity += count;
|
|
592
717
|
}
|
|
593
|
-
this._fileBaseSplat.set(fileId, capacity);
|
|
594
|
-
capacity += count;
|
|
595
718
|
}
|
|
596
|
-
if (
|
|
719
|
+
if (fullCapacity <= 1) {
|
|
597
720
|
return;
|
|
598
721
|
}
|
|
722
|
+
// Eviction streams the dataset through a fixed budget; only enabled when that budget is below the full set.
|
|
723
|
+
this._evictionEnabled = this._residentBudget > 0 && this._residentBudget < fullCapacity;
|
|
724
|
+
const capacity = this._evictionEnabled ? Math.max(this._residentBudget, 1) : fullCapacity;
|
|
725
|
+
this._residency = new GaussianSplattingResidencyController(capacity, this._evictionCooldownFrames, (file) => this._onFileEvicted(file));
|
|
726
|
+
// Pin splat 0 as the invisible padding splat, then the environment (always rendered) — neither is evicted.
|
|
727
|
+
this._residency.pin(PaddingFileId, 1);
|
|
728
|
+
if (envCount > 0) {
|
|
729
|
+
const envOffset = this._residency.pin(EnvironmentFileId, envCount);
|
|
730
|
+
if (envOffset !== null) {
|
|
731
|
+
this._environmentRange = { offset: envOffset, count: envCount };
|
|
732
|
+
}
|
|
733
|
+
else {
|
|
734
|
+
Logger.Warn("GaussianSplattingStream: environment does not fit the memory budget; skipping it.");
|
|
735
|
+
this._environmentFiles = null;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
599
738
|
this._workBuffer = new GaussianSplattingWorkBuffer(this._scene, capacity);
|
|
600
739
|
// GPU readback is only enabled after it is validated against a CPU decode on the first file (see
|
|
601
740
|
// _probeReadbackAsync); until then positions are decoded on the CPU so there is always a correct result.
|
|
@@ -614,7 +753,7 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
614
753
|
const baseFiles = new Set();
|
|
615
754
|
for (const node of this._leafNodes) {
|
|
616
755
|
const entry = node.lods[String(node.baseLod)];
|
|
617
|
-
if (entry && this.
|
|
756
|
+
if (entry && this._fileCounts.has(entry.file)) {
|
|
618
757
|
baseFiles.add(entry.file);
|
|
619
758
|
}
|
|
620
759
|
}
|
|
@@ -661,7 +800,7 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
661
800
|
if (this._metadata.environment) {
|
|
662
801
|
try {
|
|
663
802
|
const url = this._rootUrl + this._metadata.environment;
|
|
664
|
-
const buffer =
|
|
803
|
+
const buffer = await this._downloadManager.loadFileAsync(url);
|
|
665
804
|
const files = await this._unzipAsync(new Uint8Array(buffer));
|
|
666
805
|
const metaBytes = files.get("meta.json");
|
|
667
806
|
if (metaBytes) {
|
|
@@ -684,8 +823,8 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
684
823
|
try {
|
|
685
824
|
const metaUrl = this._rootUrl + relativePath;
|
|
686
825
|
const subRootUrl = metaUrl.substring(0, metaUrl.lastIndexOf("/") + 1);
|
|
687
|
-
const
|
|
688
|
-
const sogData = JSON.parse(
|
|
826
|
+
const metaBuffer = await this._downloadManager.loadFileAsync(metaUrl);
|
|
827
|
+
const sogData = JSON.parse(new TextDecoder().decode(new Uint8Array(metaBuffer)));
|
|
689
828
|
this._fileCounts.set(fileId, GaussianSplattingStream._GetSplatCount(sogData));
|
|
690
829
|
this._fileMeta.set(fileId, { sogData, subRootUrl });
|
|
691
830
|
}
|
|
@@ -823,7 +962,7 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
823
962
|
}
|
|
824
963
|
const range = this._environmentRange;
|
|
825
964
|
try {
|
|
826
|
-
const parsed = await ParseSogMetaAsTextures(this._environmentFiles, "", this._scene, !this._useGpuPositionReadback);
|
|
965
|
+
const parsed = await ParseSogMetaAsTextures(this._environmentFiles, "", this._scene, !this._useGpuPositionReadback, this._downloadManager);
|
|
827
966
|
const pack = parsed.sogTextures;
|
|
828
967
|
if (!pack) {
|
|
829
968
|
return;
|
|
@@ -854,32 +993,54 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
854
993
|
/**
|
|
855
994
|
* Loads one LOD source file as GPU textures, decodes it into its fixed work-buffer block, records its
|
|
856
995
|
* CPU centers for sorting, frees the source textures, then promotes any nodes that were waiting for it.
|
|
857
|
-
* Concurrent or repeat requests for the same file are ignored.
|
|
996
|
+
* Concurrent or repeat requests for the same file are ignored. If the file is cancelled mid-flight
|
|
997
|
+
* (because every node that wanted it retargeted), the decode bails cooperatively at the next checkpoint.
|
|
858
998
|
* @param fileId file index to decode
|
|
859
999
|
*/
|
|
860
1000
|
async _decodeFileAsync(fileId) {
|
|
861
|
-
if (this._decodedFiles.has(fileId) || this._loadingFiles.has(fileId)) {
|
|
1001
|
+
if (this._decodedFiles.has(fileId) || this._loadingFiles.has(fileId) || !this._residency) {
|
|
862
1002
|
return;
|
|
863
1003
|
}
|
|
864
1004
|
const meta = this._fileMeta.get(fileId);
|
|
865
|
-
const base = this._fileBaseSplat.get(fileId);
|
|
866
1005
|
const count = this._fileCounts.get(fileId);
|
|
867
|
-
if (!meta ||
|
|
1006
|
+
if (!meta || count === undefined) {
|
|
868
1007
|
return;
|
|
869
1008
|
}
|
|
870
1009
|
this._loadingFiles.add(fileId);
|
|
1010
|
+
this._cancelledDecodes.delete(fileId);
|
|
1011
|
+
let allocated = false;
|
|
871
1012
|
try {
|
|
872
|
-
const parsed = await ParseSogMetaAsTextures(meta.sogData, meta.subRootUrl, this._scene, !this._useGpuPositionReadback);
|
|
1013
|
+
const parsed = await ParseSogMetaAsTextures(meta.sogData, meta.subRootUrl, this._scene, !this._useGpuPositionReadback, this._downloadManager, fileId);
|
|
873
1014
|
const pack = parsed.sogTextures;
|
|
874
1015
|
if (!pack) {
|
|
875
1016
|
return;
|
|
876
1017
|
}
|
|
1018
|
+
// Serialize the allocate -> decode -> readback section: a relayout runs only inside it (see
|
|
1019
|
+
// _relayoutAndAllocateAsync), so it never moves a file whose decode has not finished writing.
|
|
1020
|
+
const release = await this._acquireDecodeGateAsync();
|
|
877
1021
|
try {
|
|
878
|
-
if (this._disposed || !this._workBuffer) {
|
|
1022
|
+
if (this._disposed || !this._workBuffer || this._cancelledDecodes.has(fileId)) {
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
let base = this._residency.allocate(fileId, count);
|
|
1026
|
+
if (base === null) {
|
|
1027
|
+
// Defragment the work buffer to reclaim fragmented free space, then retry.
|
|
1028
|
+
base = await this._relayoutAndAllocateAsync(fileId, count);
|
|
1029
|
+
}
|
|
1030
|
+
if (base === null) {
|
|
1031
|
+
// No room even after evicting and compacting: refuse and keep nodes on their current LOD.
|
|
1032
|
+
// A file cancelled mid-flight isn't a budget problem, so don't warn for it.
|
|
1033
|
+
if (!this._cancelledDecodes.has(fileId)) {
|
|
1034
|
+
Logger.Warn(`GaussianSplattingStream: resident memory budget full; skipping LOD file ${fileId}.`);
|
|
1035
|
+
}
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
allocated = true;
|
|
1039
|
+
if (this._disposed || !this._workBuffer || this._cancelledDecodes.has(fileId)) {
|
|
879
1040
|
return;
|
|
880
1041
|
}
|
|
881
1042
|
await this._workBuffer.decodeAsync(pack, base);
|
|
882
|
-
if (this._disposed) {
|
|
1043
|
+
if (this._disposed || this._cancelledDecodes.has(fileId)) {
|
|
883
1044
|
return;
|
|
884
1045
|
}
|
|
885
1046
|
await this._applyDecodedPositionsAsync(pack, base, count);
|
|
@@ -893,14 +1054,136 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
893
1054
|
}
|
|
894
1055
|
}
|
|
895
1056
|
finally {
|
|
896
|
-
// Always release the GPU source textures (the decode pass is the only consumer).
|
|
897
1057
|
GaussianSplattingStream._DisposePack(pack);
|
|
1058
|
+
release();
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
catch (e) {
|
|
1062
|
+
// A cancelled file rejects its downloads on purpose — swallow that; re-throw genuine failures.
|
|
1063
|
+
if (!this._cancelledDecodes.has(fileId)) {
|
|
1064
|
+
throw e;
|
|
898
1065
|
}
|
|
899
1066
|
}
|
|
900
1067
|
finally {
|
|
1068
|
+
// If a slot was allocated but the decode did not complete (cancelled/disposed), release it.
|
|
1069
|
+
if (allocated && !this._decodedFiles.has(fileId)) {
|
|
1070
|
+
this._residency.free(fileId);
|
|
1071
|
+
}
|
|
901
1072
|
this._loadingFiles.delete(fileId);
|
|
1073
|
+
this._cancelledDecodes.delete(fileId);
|
|
902
1074
|
}
|
|
903
1075
|
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Acquires the decode gate (a simple async mutex). Resolves once any prior holder releases, returning a
|
|
1078
|
+
* release function the caller must invoke in a `finally`.
|
|
1079
|
+
* @returns the release function
|
|
1080
|
+
*/
|
|
1081
|
+
async _acquireDecodeGateAsync() {
|
|
1082
|
+
const previous = this._decodeGate;
|
|
1083
|
+
let release;
|
|
1084
|
+
this._decodeGate = new Promise((resolve) => {
|
|
1085
|
+
release = resolve;
|
|
1086
|
+
});
|
|
1087
|
+
await previous;
|
|
1088
|
+
return release;
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Defragments the work buffer to make room for a file that did not fit, then allocates its slot. Runs the
|
|
1092
|
+
* compaction + GPU relayout atomically inside a single `onBeforeRender` so no inconsistent CPU/GPU layout
|
|
1093
|
+
* is ever rendered. Returns the new slot offset, or null if even compaction cannot free enough contiguous
|
|
1094
|
+
* space (the caller refuses the upgrade).
|
|
1095
|
+
* @param fileId file to allocate after compaction
|
|
1096
|
+
* @param count splats the file needs
|
|
1097
|
+
* @returns the allocated offset, or null
|
|
1098
|
+
*/
|
|
1099
|
+
async _relayoutAndAllocateAsync(fileId, count) {
|
|
1100
|
+
if (!this._residency || !this._workBuffer) {
|
|
1101
|
+
return null;
|
|
1102
|
+
}
|
|
1103
|
+
// Even a perfect compaction cannot help if the total free space is below what is needed.
|
|
1104
|
+
if (this._residency.freeSize < count) {
|
|
1105
|
+
return null;
|
|
1106
|
+
}
|
|
1107
|
+
return await new Promise((resolve) => {
|
|
1108
|
+
const attempt = () => {
|
|
1109
|
+
// Bail out (no relayout) if the file was cancelled while we waited for the shader to be ready,
|
|
1110
|
+
// so rapidly-changing targets don't trigger an expensive compaction for a file no longer needed.
|
|
1111
|
+
if (this._disposed || !this._residency || !this._workBuffer || this._cancelledDecodes.has(fileId)) {
|
|
1112
|
+
resolve(null);
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
if (!this._workBuffer.isRelayoutReady()) {
|
|
1116
|
+
this._scene.onBeforeRenderObservable.addOnce(attempt);
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
this._performRelayout();
|
|
1120
|
+
resolve(this._residency.allocate(fileId, count));
|
|
1121
|
+
};
|
|
1122
|
+
this._scene.onBeforeRenderObservable.addOnce(attempt);
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Compacts the resident set and relocates the corresponding GPU textures and CPU positions to the new
|
|
1127
|
+
* layout. Must run at a frame-safe point with the work buffer's relayout shader ready.
|
|
1128
|
+
*/
|
|
1129
|
+
_performRelayout() {
|
|
1130
|
+
if (!this._residency || !this._workBuffer || !this._splatPositions) {
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
const oldOffsets = this._relayoutOldOffsets;
|
|
1134
|
+
oldOffsets.clear();
|
|
1135
|
+
for (const block of this._residency.getResidentBlocks()) {
|
|
1136
|
+
oldOffsets.set(block.file, block.offset);
|
|
1137
|
+
}
|
|
1138
|
+
const moves = this._residency.compact();
|
|
1139
|
+
if (moves.length === 0) {
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
const capacity = this._residency.capacity;
|
|
1143
|
+
if (!this._relayoutSrcIndex || this._relayoutSrcIndex.length !== capacity) {
|
|
1144
|
+
this._relayoutSrcIndex = new Float32Array(capacity);
|
|
1145
|
+
}
|
|
1146
|
+
const srcIndexByDst = this._relayoutSrcIndex;
|
|
1147
|
+
srcIndexByDst.fill(-1);
|
|
1148
|
+
const resident = this._residency.getResidentBlocks();
|
|
1149
|
+
// Destination->source splat index map for the GPU relayout pass.
|
|
1150
|
+
for (const block of resident) {
|
|
1151
|
+
const oldOffset = oldOffsets.get(block.file);
|
|
1152
|
+
for (let k = 0; k < block.count; k++) {
|
|
1153
|
+
srcIndexByDst[block.offset + k] = oldOffset + k;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
// GPU: relocate the decoded textures in place (same texture instances).
|
|
1157
|
+
this._workBuffer.relayoutSync(srcIndexByDst);
|
|
1158
|
+
// CPU positions: compaction only ever moves a block to a lower offset, so copying in place in ascending
|
|
1159
|
+
// new-offset order is safe (a block's source is never overwritten by an earlier move). This avoids a
|
|
1160
|
+
// full capacity*4 scratch buffer.
|
|
1161
|
+
const positions = this._splatPositions;
|
|
1162
|
+
resident.sort((a, b) => a.offset - b.offset);
|
|
1163
|
+
for (const block of resident) {
|
|
1164
|
+
const oldOffset = oldOffsets.get(block.file);
|
|
1165
|
+
if (oldOffset !== block.offset) {
|
|
1166
|
+
positions.copyWithin(block.offset * 4, oldOffset * 4, (oldOffset + block.count) * 4);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
// Update the environment offset (it may have moved), re-post to the sort worker, and refresh ranges.
|
|
1170
|
+
if (this._environmentRange) {
|
|
1171
|
+
const envOffset = this._residency.offset(EnvironmentFileId);
|
|
1172
|
+
if (envOffset !== undefined) {
|
|
1173
|
+
this._environmentRange.offset = envOffset;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
this._notifyWorkerNewData();
|
|
1177
|
+
this._refreshActiveRanges();
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Drops a file evicted by the residency controller from the decoded set so it will be re-decoded on demand.
|
|
1181
|
+
* The file had no remaining references, so no node was rendering or downloading it.
|
|
1182
|
+
* @param fileId evicted file index
|
|
1183
|
+
*/
|
|
1184
|
+
_onFileEvicted(fileId) {
|
|
1185
|
+
this._decodedFiles.delete(fileId);
|
|
1186
|
+
}
|
|
904
1187
|
/**
|
|
905
1188
|
* Snaps a desired LOD level to the nearest level the node provides, while never selecting a level finer
|
|
906
1189
|
* than {@link maxDetailLod} (i.e. with an index below the cap). Ties prefer the finer allowed level. If
|
|
@@ -939,35 +1222,119 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
939
1222
|
}
|
|
940
1223
|
/**
|
|
941
1224
|
* Applies each node's {@link ISOGLODNode.targetLevel}: switches a node to its target level when that
|
|
942
|
-
* level's file is already decoded, otherwise
|
|
943
|
-
* nothing ever disappears). Nodes within their post-switch cooldown are
|
|
1225
|
+
* level's file is already decoded, otherwise records a pending download request for the file and leaves
|
|
1226
|
+
* the node on its current LOD (so nothing ever disappears). Nodes within their post-switch cooldown are
|
|
1227
|
+
* left untouched to damp oscillation (and keep their existing pending request).
|
|
1228
|
+
*
|
|
1229
|
+
* Each node tracks the single file it currently needs but lacks ({@link ISOGLODNode.pendingFile}). When a
|
|
1230
|
+
* node's target changes before that file finished downloading, the old file's reference is released; if no
|
|
1231
|
+
* other node still needs it, its queued/in-flight download is cancelled (see {@link _releaseFileRef}).
|
|
944
1232
|
* @returns true when at least one node changed LOD (callers should refresh the active ranges)
|
|
945
1233
|
*/
|
|
946
1234
|
_applyDesiredLods() {
|
|
947
1235
|
let dirty = false;
|
|
948
1236
|
for (const node of this._leafNodes) {
|
|
1237
|
+
// Nodes in cooldown keep their current LOD and their existing pending request untouched.
|
|
949
1238
|
if (node.lodCooldown && node.lodCooldown > 0) {
|
|
950
1239
|
continue;
|
|
951
1240
|
}
|
|
952
1241
|
const desired = node.targetLevel ?? node.baseLod;
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1242
|
+
let newPending;
|
|
1243
|
+
if (desired !== node.activeLod) {
|
|
1244
|
+
const entry = node.lods[String(desired)];
|
|
1245
|
+
if (entry) {
|
|
1246
|
+
if (this._decodedFiles.has(entry.file)) {
|
|
1247
|
+
this._switchActiveFile(node, entry.file);
|
|
1248
|
+
node.activeLod = desired;
|
|
1249
|
+
node.lodCooldown = this._lodCooldownFrames;
|
|
1250
|
+
dirty = true;
|
|
1251
|
+
}
|
|
1252
|
+
else {
|
|
1253
|
+
newPending = entry.file;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
964
1256
|
}
|
|
965
|
-
|
|
966
|
-
|
|
1257
|
+
// Reconcile this node's pending-download reference against its (possibly changed) target.
|
|
1258
|
+
if (node.pendingFile !== newPending) {
|
|
1259
|
+
if (node.pendingFile !== undefined) {
|
|
1260
|
+
this._releaseFileRef(node.pendingFile);
|
|
1261
|
+
}
|
|
1262
|
+
if (newPending !== undefined) {
|
|
1263
|
+
this._acquirePendingFile(newPending);
|
|
1264
|
+
}
|
|
1265
|
+
node.pendingFile = newPending;
|
|
967
1266
|
}
|
|
968
1267
|
}
|
|
969
1268
|
return dirty;
|
|
970
1269
|
}
|
|
1270
|
+
/**
|
|
1271
|
+
* Moves a node's resident reference from its previous active file to the one it now renders, so the file
|
|
1272
|
+
* count that keeps a block in the work buffer stays accurate (and cancels any pending eviction of the new
|
|
1273
|
+
* file). The new file is already decoded.
|
|
1274
|
+
* @param node leaf node switching its rendered file
|
|
1275
|
+
* @param file the file the node now renders from
|
|
1276
|
+
*/
|
|
1277
|
+
_switchActiveFile(node, file) {
|
|
1278
|
+
if (node.activeFile === file) {
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
if (node.activeFile !== undefined) {
|
|
1282
|
+
this._releaseFileRef(node.activeFile);
|
|
1283
|
+
}
|
|
1284
|
+
this._acquireFileRef(file);
|
|
1285
|
+
node.activeFile = file;
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* Adds a reference to a file (active render or pending download), cancelling any scheduled eviction.
|
|
1289
|
+
* @param fileId file index
|
|
1290
|
+
*/
|
|
1291
|
+
_acquireFileRef(fileId) {
|
|
1292
|
+
const refs = (this._fileRefs.get(fileId) ?? 0) + 1;
|
|
1293
|
+
this._fileRefs.set(fileId, refs);
|
|
1294
|
+
if (refs === 1) {
|
|
1295
|
+
// Referenced again before its eviction cooldown elapsed: keep it resident.
|
|
1296
|
+
this._residency?.cancelEviction(fileId);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Records that a node needs a not-yet-decoded file, bumping its reference count and queueing the decode.
|
|
1301
|
+
* @param fileId file index the node now targets
|
|
1302
|
+
*/
|
|
1303
|
+
_acquirePendingFile(fileId) {
|
|
1304
|
+
this._acquireFileRef(fileId);
|
|
1305
|
+
this._enqueueDecode(fileId);
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Releases a node's reference to a file. When the last reference is dropped: a decoded file is scheduled
|
|
1309
|
+
* for eviction (when streaming under a budget), and a still-downloading file has its queued decode dropped
|
|
1310
|
+
* and any in-flight download cancelled.
|
|
1311
|
+
* @param fileId file index the node no longer references
|
|
1312
|
+
*/
|
|
1313
|
+
_releaseFileRef(fileId) {
|
|
1314
|
+
const refs = (this._fileRefs.get(fileId) ?? 0) - 1;
|
|
1315
|
+
if (refs > 0) {
|
|
1316
|
+
this._fileRefs.set(fileId, refs);
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
this._fileRefs.delete(fileId);
|
|
1320
|
+
if (this._decodedFiles.has(fileId)) {
|
|
1321
|
+
// No node renders it anymore: schedule eviction (only when streaming under a budget).
|
|
1322
|
+
if (this._evictionEnabled) {
|
|
1323
|
+
this._residency?.scheduleEviction(fileId);
|
|
1324
|
+
}
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
// Still downloading/queued: drop the queued decode and cancel any in-flight download.
|
|
1328
|
+
const queueIndex = this._decodeQueue.indexOf(fileId);
|
|
1329
|
+
if (queueIndex !== -1) {
|
|
1330
|
+
this._decodeQueue.splice(queueIndex, 1);
|
|
1331
|
+
}
|
|
1332
|
+
if (this._loadingFiles.has(fileId)) {
|
|
1333
|
+
// Flag the in-flight decode to bail at its next checkpoint and cancel its image downloads.
|
|
1334
|
+
this._cancelledDecodes.add(fileId);
|
|
1335
|
+
this._downloadManager.cancelGroup(fileId);
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
971
1338
|
/**
|
|
972
1339
|
* Per-frame LOD streaming loop. Ticks cooldowns and pumps the decode queue every frame, and runs the
|
|
973
1340
|
* cheap per-node frustum test every frame so the off-screen LOD bias tracks camera rotation. The LOD
|
|
@@ -984,6 +1351,10 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
984
1351
|
node.lodCooldown--;
|
|
985
1352
|
}
|
|
986
1353
|
}
|
|
1354
|
+
// Tick eviction cooldowns: unreferenced files are freed once their cooldown elapses (budgeted streaming).
|
|
1355
|
+
if (this._evictionEnabled) {
|
|
1356
|
+
this._residency?.tick();
|
|
1357
|
+
}
|
|
987
1358
|
// In-flight/queued decodes still progress every frame.
|
|
988
1359
|
this._pumpDecodeQueue();
|
|
989
1360
|
// Per-node frustum test runs every frame (cheap) so the off-screen LOD bias tracks camera rotation,
|
|
@@ -1102,7 +1473,7 @@ export class GaussianSplattingStream extends GaussianSplattingMesh {
|
|
|
1102
1473
|
if (!entry) {
|
|
1103
1474
|
continue;
|
|
1104
1475
|
}
|
|
1105
|
-
const base = this.
|
|
1476
|
+
const base = this._residency?.offset(entry.file);
|
|
1106
1477
|
if (base === undefined) {
|
|
1107
1478
|
continue;
|
|
1108
1479
|
}
|