@woosh/meep-engine 3.26.0 → 3.28.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/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +542 -0
- package/src/core/binary/lz4/LZ4_LEVEL.d.ts +33 -0
- package/src/core/binary/lz4/LZ4_LEVEL.d.ts.map +1 -0
- package/src/core/binary/lz4/LZ4_LEVEL.js +32 -0
- package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts +33 -0
- package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts.map +1 -0
- package/src/core/binary/lz4/lz4_compress_block_at_level.js +47 -0
- package/src/core/binary/lz4/lz4_compress_block_hc.d.ts +40 -0
- package/src/core/binary/lz4/lz4_compress_block_hc.d.ts.map +1 -0
- package/src/core/binary/lz4/lz4_compress_block_hc.js +1382 -0
- package/src/core/binary/lz4/lz4_decompress_block.d.ts +2 -1
- package/src/core/binary/lz4/lz4_decompress_block.d.ts.map +1 -1
- package/src/core/binary/lz4/lz4_decompress_block.js +31 -6
- package/src/core/geom/3d/mat4/m4_linear_determinant.d.ts +15 -0
- package/src/core/geom/3d/mat4/m4_linear_determinant.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_linear_determinant.js +24 -0
- package/src/core/geom/3d/mat4/m4_normal_matrix3.d.ts +4 -2
- package/src/core/geom/3d/mat4/m4_normal_matrix3.d.ts.map +1 -1
- package/src/core/geom/3d/mat4/m4_normal_matrix3.js +21 -11
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +14 -7
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/HeightMapShape3D.js +87 -78
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +38 -1
- package/src/engine/graphics3/GraphicsEngine.d.ts +5 -1
- package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -1
- package/src/engine/graphics3/GraphicsEngine.js +834 -830
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/RENDERER_CONTRACT.md +19 -10
- package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +1 -1
- package/src/shade/playground/vgeo_runtime/README.md +186 -27
- package/src/shade/playground/vgeo_runtime/index.html +112 -62
- package/src/shade/playground/vgeo_runtime/main.js +678 -88
- package/src/shade/playground/vgeo_runtime/sample_asset.d.ts +18 -0
- package/src/shade/playground/vgeo_runtime/sample_asset.d.ts.map +1 -0
- package/src/shade/playground/{vgeo_viewer → vgeo_runtime}/sample_asset.js +23 -5
- package/src/shade/playground/vgeo_scene/README.md +408 -0
- package/src/shade/playground/vgeo_scene/index.html +144 -0
- package/src/shade/playground/vgeo_scene/main.d.ts +2 -0
- package/src/shade/playground/vgeo_scene/main.d.ts.map +1 -0
- package/src/shade/playground/vgeo_scene/main.js +1716 -0
- package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.d.ts +4 -1
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +5 -2
- package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +1 -2
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +11 -0
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +16 -8
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +16 -11
- package/src/shade/renderer/geometry/meshlet/MeshletBatch.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +3 -29
- package/src/shade/renderer/geometry/meshlet/encoding/ENCODED_ATTRIBUTE_DEFAULT_VALUES.d.ts +22 -0
- package/src/shade/renderer/geometry/meshlet/encoding/ENCODED_ATTRIBUTE_DEFAULT_VALUES.d.ts.map +1 -0
- package/src/shade/renderer/geometry/meshlet/encoding/ENCODED_ATTRIBUTE_DEFAULT_VALUES.js +49 -0
- package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +77 -7
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +36 -23
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +17 -14
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +19 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +21 -1
- package/src/shade/renderer/geometry/virtual/build/gltf/gltf_open_document.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/gltf/gltf_open_document.js +5 -9
- package/src/shade/renderer/geometry/virtual/build/level/VGeoLevel.d.ts +32 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoLevel.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelOptions.d.ts +59 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelOptions.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelSummary.d.ts +44 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelSummary.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts +36 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_build_levels.js → level/vgeo_build_levels.js} +61 -95
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_root_group.d.ts +19 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_root_group.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_build_root_group.js → level/vgeo_build_root_group.js} +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VirtualGeometryMesh.d.ts +73 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/VirtualGeometryMesh.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{VirtualGeometryMesh.js → mesh/VirtualGeometryMesh.js} +7 -7
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +29 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_compute_vertex_normals.js → mesh/vgeo_compute_vertex_normals.js} +3 -3
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.d.ts +31 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_compute_vertex_tangents.js → mesh/vgeo_compute_vertex_tangents.js} +5 -5
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +46 -0
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_normalize_source.js → mesh/vgeo_normalize_source.js} +9 -9
- package/src/shade/renderer/geometry/virtual/build/page/vgeo_assemble_pages.d.ts +13 -0
- package/src/shade/renderer/geometry/virtual/build/page/vgeo_assemble_pages.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_assemble_pages.js → page/vgeo_assemble_pages.js} +63 -16
- package/src/shade/renderer/geometry/virtual/build/page/vgeo_build_page_nodes.d.ts +13 -0
- package/src/shade/renderer/geometry/virtual/build/page/vgeo_build_page_nodes.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_build_page_nodes.js → page/vgeo_build_page_nodes.js} +4 -4
- package/src/shade/renderer/geometry/virtual/build/page/vgeo_page_node_count.d.ts +22 -0
- package/src/shade/renderer/geometry/virtual/build/page/vgeo_page_node_count.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_page_node_count.js → page/vgeo_page_node_count.js} +2 -2
- package/src/shade/renderer/geometry/virtual/build/partition/VGeoFaceGraph.d.ts +52 -0
- package/src/shade/renderer/geometry/virtual/build/partition/VGeoFaceGraph.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{VGeoFaceGraph.js → partition/VGeoFaceGraph.js} +1 -1
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_graph_components.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_graph.d.ts +29 -0
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_graph.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_partition_graph.js → partition/vgeo_partition_graph.js} +2 -2
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_subgraph.d.ts +41 -0
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_subgraph.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_partition_subgraph.js +92 -0
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set.d.ts +10 -0
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_split_face_set.js → partition/vgeo_split_face_set.js} +12 -55
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_split_face_set_packed.js → partition/vgeo_split_face_set_packed.js} +3 -3
- package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_bounding_sphere.d.ts +12 -0
- package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_bounding_sphere.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_bounding_sphere.js → sphere/vgeo_bounding_sphere.js} +3 -3
- package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_containing_sphere.d.ts +18 -0
- package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_containing_sphere.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_containing_sphere.js → sphere/vgeo_containing_sphere.js} +3 -3
- package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_sphere_inflate_to_contain.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/build/sphere/vgeo_sphere_inflate_to_contain.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_sphere_inflate_to_contain.js → sphere/vgeo_sphere_inflate_to_contain.js} +1 -1
- package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.d.ts +24 -0
- package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.d.ts +20 -0
- package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_extract_submesh.js → submesh/vgeo_extract_submesh.js} +5 -5
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.d.ts +12 -0
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_gather_faces.js → submesh/vgeo_gather_faces.js} +2 -2
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_narrow_indices.d.ts +11 -0
- package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_narrow_indices.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/build/{vgeo_narrow_indices.js → submesh/vgeo_narrow_indices.js} +3 -3
- package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +10 -11
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +22 -0
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +24 -0
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.d.ts +8 -2
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.js +8 -2
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +12 -0
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +13 -0
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +8 -1
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +11 -3
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +10 -1
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_OFFSET.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_OFFSET.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_OFFSET.js +15 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts +18 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.js +17 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts +8 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.js +7 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.js +13 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts +11 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.js +10 -0
- package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.d.ts +28 -0
- package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.js +7 -3
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +20 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +20 -2
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +4 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +4 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +29 -3
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +81 -122
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +40 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +44 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +69 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +236 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +15 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts +31 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.js +32 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +10 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +21 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.js +84 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts +22 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +96 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +63 -3
- package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +219 -17
- package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +156 -11
- package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +656 -0
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +33 -36
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +109 -193
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +109 -29
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +173 -105
- package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +37 -0
- package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +109 -26
- package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +548 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +29 -50
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +55 -487
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts +84 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +393 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts +234 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +1388 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts +81 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.js +89 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +53 -34
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +407 -124
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +100 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +219 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.js +47 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts +20 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.js +19 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +30 -12
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts +8 -8
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +11 -73
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.d.ts +19 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.js +98 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.d.ts +31 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.js +99 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_queue.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_queue.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_queue.js +39 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +18 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +5 -15
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.js +77 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.js +130 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +32 -37
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +576 -230
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +15 -18
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +19 -28
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +45 -25
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +11 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +0 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +12 -10
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +8 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +7 -2
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +8 -3
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +2 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +19 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts +5 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.js +22 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.js +13 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.js +16 -0
- package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.js +16 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts +23 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.js +28 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts +2 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.js +13 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +10 -5
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +15 -6
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +6 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +38 -1
- package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +4 -3
- package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/load_gltf.js +0 -19
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/material/chunk_material_draw_side.d.ts +14 -0
- package/src/shade/renderer/material/chunk_material_draw_side.d.ts.map +1 -0
- package/src/shade/renderer/material/chunk_material_draw_side.js +34 -0
- package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
- package/src/shade/renderer/material/standard/fragment_gbuffer.js +8 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +6 -3
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +6 -3
- package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +13 -1
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts +19 -5
- package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +23 -5
- package/src/shade/renderer/rasterize/bucket/filter_materials_by_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/filter_materials_by_bucket.js +12 -5
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +12 -4
- package/src/shade/renderer/rasterize/bucket/rasterization_opaque_buckets.d.ts +22 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_opaque_buckets.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_opaque_buckets.js +36 -0
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +2 -0
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +58 -57
- package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts +15 -0
- package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/chunk_triangle_winding_is_reversed.js +35 -0
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +3 -5
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +3 -4
- package/src/shade/renderer/rasterize/expand/bucket/RASTERIZATION_BUCKET_LIMIT.d.ts +10 -1
- package/src/shade/renderer/rasterize/expand/bucket/RASTERIZATION_BUCKET_LIMIT.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/RASTERIZATION_BUCKET_LIMIT.js +38 -29
- package/src/shade/renderer/rasterize/expand/bucket/chunk_rasterization_material_bucket.d.ts +5 -0
- package/src/shade/renderer/rasterize/expand/bucket/chunk_rasterization_material_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/chunk_rasterization_material_bucket.js +63 -55
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -4
- package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.js +1 -0
- package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.js +7 -7
- package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +83 -78
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +44 -53
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.js +6 -2
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.js +6 -2
- package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.js +19 -2
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +7 -4
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +3 -2
- package/src/shade/renderer/rasterize/native/chunk_rasterize_triangle.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/chunk_rasterize_triangle.js +15 -4
- package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.js +16 -5
- package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_pass_descriptor.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_pass_descriptor.js +16 -5
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +2 -1
- package/src/shade/renderer/rasterize/native/rasterization_shader_resources.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/rasterization_shader_resources.js +4 -0
- package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.js +16 -7
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +85 -89
- package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +28 -32
- package/src/shade/renderer/scene/GPUSceneContext.d.ts +22 -2
- package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUSceneContext.js +61 -4
- package/src/shade/renderer/scene/NODE3D_STRUCT.d.ts +19 -0
- package/src/shade/renderer/scene/NODE3D_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/scene/NODE3D_STRUCT.js +34 -0
- package/src/shade/renderer/scene/chunk_node3d_flags.d.ts +9 -0
- package/src/shade/renderer/scene/chunk_node3d_flags.d.ts.map +1 -0
- package/src/shade/renderer/scene/chunk_node3d_flags.js +23 -0
- package/src/shade/renderer/scene/chunk_scene_database_access.d.ts.map +1 -1
- package/src/shade/renderer/scene/chunk_scene_database_access.js +15 -1
- package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
- package/src/shade/renderer/scene/rows/GPUSceneRows.js +9 -1
- package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_compute_normal_matrix_from_m4.d.ts +7 -0
- package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_compute_normal_matrix_from_m4.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_compute_normal_matrix_from_m4.js +16 -4
- package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_mat4_linear_determinant.d.ts +12 -0
- package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_mat4_linear_determinant.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/mat4/chunk_mat4_linear_determinant.js +18 -0
- package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_triangle_list_reverse_winding.d.ts +24 -0
- package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_triangle_list_reverse_winding.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_triangle_list_reverse_winding.js +33 -0
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +92 -16
- package/src/shade/renderer/view/GPUViewContext.d.ts +5 -0
- package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
- package/src/shade/renderer/view/GPUViewContext.js +21 -0
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +74 -3
- package/src/shade/playground/vgeo_viewer/README.md +0 -150
- package/src/shade/playground/vgeo_viewer/cut_geometry.js +0 -460
- package/src/shade/playground/vgeo_viewer/index.html +0 -77
- package/src/shade/playground/vgeo_viewer/main.js +0 -1343
- package/src/shade/playground/vgeo_viewer/select_cut.js +0 -481
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts +0 -258
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +0 -723
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts +0 -49
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.d.ts.map +0 -1
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +0 -50
- package/src/shade/renderer/loader/gltf/fix_up_material_sides.js +0 -109
- package/src/shade/renderer/rasterize/expand/graph_triangles_filter_by_material_side.js +0 -78
- package/src/shade/renderer/rasterize/expand/shader_filter_triangle_by_material_side.js +0 -100
- package/src/shade/renderer/rasterize/forward/chunk_material_side_should_draw.js +0 -26
- package/src/shade/renderer/shader/chunk/jobs/NOTES.md +0 -47
- package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.d.ts +0 -3
- package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.d.ts.map +0 -1
- package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.js +0 -102
- /package/src/shade/renderer/geometry/virtual/build/{VGeoLevel.js → level/VGeoLevel.js} +0 -0
- /package/src/shade/renderer/geometry/virtual/build/{VGeoLevelOptions.js → level/VGeoLevelOptions.js} +0 -0
- /package/src/shade/renderer/geometry/virtual/build/{VGeoLevelSummary.js → level/VGeoLevelSummary.js} +0 -0
- /package/src/shade/renderer/geometry/virtual/build/{vgeo_graph_components.js → partition/vgeo_graph_components.js} +0 -0
- /package/src/shade/renderer/geometry/virtual/build/{VGeoGatheredFaces.js → submesh/VGeoGatheredFaces.js} +0 -0
- /package/src/shade/renderer/geometry/virtual/build/{VGeoSubmesh.js → submesh/VGeoSubmesh.js} +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a sample container and hand back a source over it.
|
|
3
|
+
*
|
|
4
|
+
* The page size is deliberately far below the 256 KB default: a sample that came out as one page
|
|
5
|
+
* would be a container with nothing to stream, and the point of opening this one is to watch it
|
|
6
|
+
* arrive.
|
|
7
|
+
*
|
|
8
|
+
* @param {number} [major]
|
|
9
|
+
* @param {number} [minor]
|
|
10
|
+
* @param {number} [page_size] target decoded bytes per page
|
|
11
|
+
* @returns {{source: VGeoByteSource, build_ms: number}}
|
|
12
|
+
*/
|
|
13
|
+
export function vgeo_sample_source(major?: number, minor?: number, page_size?: number): {
|
|
14
|
+
source: VGeoByteSource;
|
|
15
|
+
build_ms: number;
|
|
16
|
+
};
|
|
17
|
+
import { VGeoByteSource } from "../../renderer/geometry/virtual/format/read/VGeoByteSource.js";
|
|
18
|
+
//# sourceMappingURL=sample_asset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample_asset.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/vgeo_runtime/sample_asset.js"],"names":[],"mappings":"AA2GA;;;;;;;;;;;GAWG;AACH,2CALW,MAAM,UACN,MAAM,cACN,MAAM,GACJ;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CAiBtD;+BA3HM,+DAA+D"}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "../../renderer/geometry/virtual/format/read/VGeoByteSource.js";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* A `.vgeo` built in the page, so
|
|
15
|
+
* A `.vgeo` built in the page, so there is something to open without a file.
|
|
16
16
|
*
|
|
17
17
|
* The builder is environment-agnostic by design (`VIRTUAL_GEOMETRY_DESIGN.md` §8) — typed arrays and
|
|
18
18
|
* topology, no file or process API anywhere under it — so the same call the node CLI makes runs here.
|
|
@@ -31,8 +31,8 @@ import {
|
|
|
31
31
|
*
|
|
32
32
|
* Curvature is what makes it a useful sample rather than a shape: a flat face simplifies at zero
|
|
33
33
|
* quadric cost, so a box would produce a DAG whose every step records no error and whose every
|
|
34
|
-
* threshold selects the same cut. A torus has an error at every level, which is the thing the
|
|
35
|
-
* is
|
|
34
|
+
* threshold selects the same cut. A torus has an error at every level, which is the thing the cut
|
|
35
|
+
* is selecting against.
|
|
36
36
|
*
|
|
37
37
|
* @param {number} major segments the long way round
|
|
38
38
|
* @param {number} minor segments around the tube
|
|
@@ -56,13 +56,31 @@ function torus(major, minor) {
|
|
|
56
56
|
|
|
57
57
|
const stride = minor + 1;
|
|
58
58
|
|
|
59
|
+
/*
|
|
60
|
+
Wound so that a triangle seen from **outside** the tube is counter-clockwise, which is what
|
|
61
|
+
`CullPolicy.Standard` means by a front face and what `vgeo_compute_vertex_normals` takes the
|
|
62
|
+
sign of its normals from.
|
|
63
|
+
|
|
64
|
+
It was the other way round, and the CPU viewer this sample was written for could not see it:
|
|
65
|
+
that page drew its cut with `cullMode: 'none'` and coloured it per cluster, so neither the
|
|
66
|
+
culling nor the shading could report it. The moment the same sample went through the engine's
|
|
67
|
+
material path — this page, where a `Front`-sided material culls back faces — the torus
|
|
68
|
+
rendered as its own far inner wall with the near surface missing, and the normals pointed into
|
|
69
|
+
the tube so what survived was lit from inside. The viewer has since been retired; this is the
|
|
70
|
+
only page that builds it now, and it is the one that could have caught it.
|
|
71
|
+
|
|
72
|
+
The winding of a sample is not a detail of the sample. Everything downstream of the builder
|
|
73
|
+
carries it: the cluster's triangles are stored in this order, the DAG's simplification
|
|
74
|
+
preserves it, and the pool hands it to the rasterizer untouched — so this one line decides
|
|
75
|
+
whether the whole chain has ever been seen drawing a surface the right way out.
|
|
76
|
+
*/
|
|
59
77
|
for (let i = 0; i < major; i++) {
|
|
60
78
|
for (let j = 0; j < minor; j++) {
|
|
61
79
|
const a = i * stride + j;
|
|
62
80
|
const b = a + stride;
|
|
63
81
|
|
|
64
|
-
indices.push(a,
|
|
65
|
-
indices.push(a + 1, b
|
|
82
|
+
indices.push(a, a + 1, b);
|
|
83
|
+
indices.push(a + 1, b + 1, b);
|
|
66
84
|
}
|
|
67
85
|
}
|
|
68
86
|
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
# `vgeo_scene` — a whole converted scene, one cut
|
|
2
|
+
|
|
3
|
+
Thousands of `.vgeo` containers, tens of thousands of instances, **one** compute cut, drawn through
|
|
4
|
+
the ordinary meshlet pipeline.
|
|
5
|
+
|
|
6
|
+
[`../vgeo_runtime/`](../vgeo_runtime/README.md) is the page that proves the engine seam, and it does
|
|
7
|
+
it with one container framed on its own bounding sphere. That makes it a *viewer*, and by
|
|
8
|
+
construction it cannot show the other half of what
|
|
9
|
+
[`VIRTUAL_GEOMETRY_DESIGN.md`](../../renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md) §1
|
|
10
|
+
claims — that rendering cost is a function of the threshold and the resolution rather than of the
|
|
11
|
+
source, **across every asset in view at once**, with instances sharing pages and one residency
|
|
12
|
+
budget arbitrating between all of them. With one reader there is nothing to arbitrate.
|
|
13
|
+
|
|
14
|
+
So everything here that the runtime page does not do is about breadth:
|
|
15
|
+
|
|
16
|
+
- **One residency, N containers.** Every asset registers with the same `VGeoResidency`, whose two
|
|
17
|
+
budgets are scene-wide by construction: the RAM tier's bytes and the VRAM tier's slots are counted
|
|
18
|
+
across every reader, and a page evicted from one asset is room for another's.
|
|
19
|
+
- **One cut, N instances.** `shader_vgeo_cut_collect` runs over the visible mesh rows and emits one
|
|
20
|
+
instance record per virtual one; the descent is seeded with one item per instance and every cull
|
|
21
|
+
and error test downstream runs in that instance's own object space. Seventeen thousand instances
|
|
22
|
+
are seventeen thousand seeds of **one** wavefront, not seventeen thousand cuts.
|
|
23
|
+
- **Instances share the asset.** A geometry placed by 381 nodes is one reader, one geometry row, one
|
|
24
|
+
page lookup and one set of resident pages — which is `VirtualGeometry.equals`, and most of why
|
|
25
|
+
this is affordable at all.
|
|
26
|
+
|
|
27
|
+
## Running it
|
|
28
|
+
|
|
29
|
+
Three things: the dev server in front of the page, an asset server in front of the containers, and
|
|
30
|
+
a scene manifest telling the page which is which.
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
npm run dev --workspace @woosh/meep-engine
|
|
34
|
+
|
|
35
|
+
node tools/geometry/virtual/vgeo_scene.js <manifest.vgeo.json> --camera "..." --sun "..."
|
|
36
|
+
node tools/geometry/virtual/vgeo_serve.js <container directory>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Then open `/src/shade/playground/vgeo_scene/index.html`. With no parameters it asks the asset server
|
|
40
|
+
what it is holding and opens the one scene that is there; `?scene=<url>` overrides.
|
|
41
|
+
|
|
42
|
+
**The asset server is not optional and vite cannot replace it.** A `.vgeo` is opened out of its head
|
|
43
|
+
and streamed by `Range`, and `vgeo_fetch_byte_source` refuses anything but a `206` naming the range
|
|
44
|
+
it asked for — a `200` is a server ignoring the request and answering the head of the file where the
|
|
45
|
+
reader asked for the middle of a frame, silently and with plausible numbers. Vite also refuses
|
|
46
|
+
`/@fs/` outside the workspace, and a converted scene is tens of gigabytes that has no business
|
|
47
|
+
inside one. `vgeo_serve.js` is ranges, CORS and nothing else; the header that is easy to miss is
|
|
48
|
+
`Access-Control-Expose-Headers`, because a cross-origin response's `Content-Range` is invisible to
|
|
49
|
+
the page without it.
|
|
50
|
+
|
|
51
|
+
## What a scene manifest is, and what it is not
|
|
52
|
+
|
|
53
|
+
`gltf_to_vgeo.js` already writes everything the page needs — a glTF primitive is one container and
|
|
54
|
+
the nodes that placed it are its instances — but its manifest is a *build report*: every level of
|
|
55
|
+
every DAG, every cluster and group count, the weld distance each geometry settled on. At this scale
|
|
56
|
+
that is twenty-odd megabytes of numbers a renderer has no use for. `vgeo_scene.js` is the projection
|
|
57
|
+
to four fields and a list of matrices: **2.2 MiB for Zorah's 2,966 containers and 17,424 instances**,
|
|
58
|
+
and nothing in it is discovered — it is all in the build manifest or in the containers' own headers.
|
|
59
|
+
|
|
60
|
+
The headers are **read rather than trusted**. A manifest is written by the builder that produced the
|
|
61
|
+
files and a directory is whatever is on disk now, so the probe is what catches a half-finished
|
|
62
|
+
conversion and a container rebuilt at another page size. It costs one head read each and 1.8 s for
|
|
63
|
+
all 2,966.
|
|
64
|
+
|
|
65
|
+
Two fields are neither: `--camera` and `--sun`.
|
|
66
|
+
|
|
67
|
+
- **A bounding box is a bad place to put a camera.** Zorah's instances span 107 km, almost all of it
|
|
68
|
+
terrain, and the town the scene is *about* is forty metres across at the origin — a viewer framed
|
|
69
|
+
on the box opens a hundred kilometres up looking at a speck. The pose belongs to the source, and
|
|
70
|
+
Zorah's own `.cfg` carries one, so it is passed in rather than guessed at either end.
|
|
71
|
+
- **A converted container carries geometry and nothing else.** Design §7: VG is geometry only, so a
|
|
72
|
+
converted set arrives with normals, no material authoring and no lights. The sun is most of what
|
|
73
|
+
there is to shade it with, and the engine's default direction over a scene authored around a
|
|
74
|
+
different one puts every façade a viewer stands in front of into ambient.
|
|
75
|
+
|
|
76
|
+
## What it measures
|
|
77
|
+
|
|
78
|
+
Zorah, 2,966 containers and 17,424 instances of them, **46.71 GiB** on the server across 947,664
|
|
79
|
+
pages, 1.36 billion source triangles and **10.75 billion instanced** ones. Measured on an
|
|
80
|
+
nvidia/lovelace adapter at a render target of 1578×746, from the scene's authored viewpoint, with a
|
|
81
|
+
**fresh page load per row** — residency is a high-water mark, so a page swept downwards through the
|
|
82
|
+
thresholds reports at every step what the busiest setting it has already been at asked for, and a
|
|
83
|
+
row of this table is only about τ if the page has been at nothing else.
|
|
84
|
+
|
|
85
|
+
| τ (px) | drawn clusters | pages visited | clusters tested | resident pages | bytes read | frame |
|
|
86
|
+
|---:|---:|---:|---:|---:|---:|---:|
|
|
87
|
+
| 0.25 | 387,875 | 79,574 | 1,232,352 | 12,288 *(full)* | 452 MB | 7.3 ms |
|
|
88
|
+
| 0.5 | 182,887 | 51,035 | 617,540 | 9,365 | 242 MB | 5.0 ms |
|
|
89
|
+
| 1 | 84,481 | 31,842 | 279,088 | 6,387 | 128 MB | 4.7 ms |
|
|
90
|
+
| 2 | 45,302 | 22,356 | 139,290 | 4,939 | 76 MB | 4.8 ms |
|
|
91
|
+
| 4 | 28,874 | 17,483 | 79,651 | 4,121 | 52 MB | 5.2 ms |
|
|
92
|
+
| 8 | 21,334 | 15,235 | 56,561 | 3,704 | 40 MB | 4.8 ms |
|
|
93
|
+
| 16 | 18,137 | 14,289 | 45,717 | 3,489 | 35 MB | 6.0 ms |
|
|
94
|
+
|
|
95
|
+
Monotone in τ, and a *fraction* of the asset at every setting: at τ=1 the scene is on screen out of
|
|
96
|
+
**0.67% of its pages** and 128 MB of 46.71 GiB, and at τ=16 out of 0.37% and 35 MB. `clamped` is
|
|
97
|
+
zero at every row but the first, which is the streaming having finished rather than a budget having
|
|
98
|
+
given up — the distinction the `refused` counter beside it exists to make.
|
|
99
|
+
|
|
100
|
+
**τ=0.25 is the budget wall, and it is in the table on purpose.** At the slider's minimum the cut
|
|
101
|
+
wants more than 12,288 page slots, `refused` climbs to 1.1 million, `clamped` stops falling to zero,
|
|
102
|
+
and the cut is then being selected by a **budget** rather than by a threshold — which is the one
|
|
103
|
+
thing this page is not meant to be showing you. It is one slider notch away at all times, and
|
|
104
|
+
`refused` going red is how you know that is what you are looking at. `?pages=` raises the tier.
|
|
105
|
+
|
|
106
|
+
A tour of five viewpoints at τ=1 — a hundred metres up, three hundred out, a nose against one
|
|
107
|
+
façade, the whole 107 km box, and back to the authored pose — held 4.5 to 5.8 ms a frame with
|
|
108
|
+
`clamped`, `refused` and every drop counter at zero throughout, and residency settling at 7,948 of
|
|
109
|
+
12,288 pages without a single eviction.
|
|
110
|
+
|
|
111
|
+
## Opening it, and what the first five seconds are
|
|
112
|
+
|
|
113
|
+
Measured cold, three times: **2,966 containers open in about four seconds**, and the whole scene is
|
|
114
|
+
drawing about a second and a half later.
|
|
115
|
+
|
|
116
|
+
The opens are one range request each. §10's always-resident set — header, level table, root frame —
|
|
117
|
+
is 2,560 bytes at the median across this set and 6,528 at the very worst, so the page asks for an
|
|
118
|
+
**8 KB head prefix** rather than the reader's default of 64 KB: every container in the set opens in
|
|
119
|
+
exactly one round trip and the cold read is 7.4 MB of heads instead of 190 MB of over-fetch. The
|
|
120
|
+
byte length comes from the manifest rather than from a `HEAD`, which is 2,966 round trips not spent
|
|
121
|
+
learning something the page was already holding.
|
|
122
|
+
|
|
123
|
+
**About four and a half seconds of that is not this page.** The first frame that draws geometry pays
|
|
124
|
+
the engine's pipeline warm-up, and `vgeo_runtime` — driven the same way, with a thirteen-page torus
|
|
125
|
+
built in-page — sits on exactly the same stall before *its* first frame. It is a fixed cost of a
|
|
126
|
+
cold device under a dev server, it is not a function of the scene, and a bundled build does not pay
|
|
127
|
+
all of it. Containers keep opening underneath it.
|
|
128
|
+
|
|
129
|
+
Containers are **placed as they land** rather than at the end, which costs nothing: a geometry that
|
|
130
|
+
is not registered yet is one the cut does not collect, and both residency tiers recompute their
|
|
131
|
+
budgets per reading rather than at registration, so a scene that grows under the camera is the case
|
|
132
|
+
they were designed for. A container that refuses leaves every other asset exactly as it was and is
|
|
133
|
+
counted — 2,965 of 2,966 is a scene, and the count is what says there is a hole in it.
|
|
134
|
+
|
|
135
|
+
## The four capacities a scene reaches first
|
|
136
|
+
|
|
137
|
+
These are the page's real finding, because every one of them is an engine default that a
|
|
138
|
+
single-asset page never touches, and two of them degrade *silently*.
|
|
139
|
+
|
|
140
|
+
- **`queue_capacity`, and this is the one that hurt.** At τ=0.5 with 17,424 instances the descent
|
|
141
|
+
pushed past the engine's 65,536 items in flight and `VGEO_CUT_STAT.QUEUE_DROPPED` came back at
|
|
142
|
+
**32,676** — a third of the frontier thrown away. It does not surface as an error or as a visible
|
|
143
|
+
hole; it surfaces as `drawn` wandering over ten thousand clusters between one frame and the next,
|
|
144
|
+
as different subtrees lose the race. At `1 << 18` the same view drops nothing and `drawn` is
|
|
145
|
+
stable, at a cost of 4 MiB a site against 1 MiB.
|
|
146
|
+
- **`lookup_words`** is one word per page of every registered container out of one arena, and the
|
|
147
|
+
default of 65,536 holds a fourteenth of Zorah's 947,664. It is allocated out of an
|
|
148
|
+
`OffsetAllocator` whose bins round *down* — it can refuse an allocation that fits — so this is
|
|
149
|
+
sized to the next power of two above 1.5× the total rather than to the total.
|
|
150
|
+
- **`geometry_capacity`** is one row per container against a default of 256.
|
|
151
|
+
- **`claim_word_capacity`** is one bit per (collected instance, page ordinal of its geometry), and
|
|
152
|
+
the engine derives it from a hint of a thousand instances times the whole tier. At this scale that
|
|
153
|
+
is both too small and too large, and the real bound is knowable exactly: ordinals come out of the
|
|
154
|
+
tier, so `Σ instances × ordinals` is maximised by giving every slot to the most-instanced asset,
|
|
155
|
+
which makes it `max instances of any one geometry × page capacity`. For Zorah that is 381 × the
|
|
156
|
+
tier — a fifth of what the default derivation asks for — doubled here, because an ordinal capacity
|
|
157
|
+
is a high-water mark and a scene that has churned can hold more of them than the tier holds pages.
|
|
158
|
+
|
|
159
|
+
`RasterizationCollectionType.Meshes` is a fifth, and it self-corrects: it grows from what the frame
|
|
160
|
+
reports, so priming it to the instance count only buys the first seconds. But the first seconds are
|
|
161
|
+
when the scene is being placed, and against a default of 1e4 the other 7,424 instances would be
|
|
162
|
+
counted as `instances_dropped` while the collection caught up.
|
|
163
|
+
|
|
164
|
+
## Two things it approximates, and says so
|
|
165
|
+
|
|
166
|
+
- **Shear.** A transform row carries a TRS and the GPU composes the world from it, so an instance
|
|
167
|
+
whose matrix has shear in it cannot be represented exactly and is placed at the closest
|
|
168
|
+
rigid-plus-scale fit. 391 of Zorah's 17,424 have any and the worst is about eleven degrees off
|
|
169
|
+
orthogonal; the other 17,033 are exact, including the 2,722 reflected ones — `m4_decompose_array`
|
|
170
|
+
folds a negative determinant into a scale axis, so a reflection survives. This is a property of
|
|
171
|
+
the engine's transform model rather than of this page. The reflections surviving is what the next
|
|
172
|
+
section is about.
|
|
173
|
+
- **One material for the whole scene.** Not a simplification being made here: a `.vgeo` carries
|
|
174
|
+
geometry only, so the source's 2,714 materials did not survive a conversion that never asked them
|
|
175
|
+
to. Tinting each container would read better, would be a lie about where the colour came from, and
|
|
176
|
+
would put 2,714 material buckets in front of the draw path to say it with.
|
|
177
|
+
|
|
178
|
+
## Reflected instances — the bug this page was built to show, and where it went
|
|
179
|
+
|
|
180
|
+
2,722 of Zorah's 17,424 instances have a negative-determinant transform: the courtyard is
|
|
181
|
+
bilaterally symmetric and the left half is the mirror of the right. Until 2026-09-15 every one of
|
|
182
|
+
them rendered with its near surface culled and its far surface showing through, because:
|
|
183
|
+
|
|
184
|
+
1. A reflection reverses the orientation of every triangle it transforms, so a reflected instance
|
|
185
|
+
presents the **opposite screen-space winding** from the same geometry under a rotation.
|
|
186
|
+
2. Front-face determination is fixed-function and reads that winding and nothing else.
|
|
187
|
+
3. `cullMode` is **pipeline state chosen per material bucket**, and the bucket key was three fields
|
|
188
|
+
of a *material* — transparency, topology and side — with `construct_primitive_state` turning the
|
|
189
|
+
third into a cull mode. Nothing from there down to the rasterizer saw a transform.
|
|
190
|
+
|
|
191
|
+
The sign was never lost — `m4_decompose_array` preserves it and the row the GPU composes reflects
|
|
192
|
+
exactly as the source did — it was simply never consulted.
|
|
193
|
+
|
|
194
|
+
**It is consulted now, and not through the bucket key.** A node's row carries
|
|
195
|
+
`NODE3D_GLOBAL_FLAG_MIRRORED`, derived from its composed world matrix by whoever publishes it, and
|
|
196
|
+
every vertex shader over a meshlet emits that instance's triangle corners in the opposite order —
|
|
197
|
+
`triangle_list_reverse_winding`. The draw is non-indexed and the vertex shader resolves its own
|
|
198
|
+
index, so which corner lands where is already the shader's choice; reversing it costs a `select`,
|
|
199
|
+
no second pipeline, and no fourth field in the bucket key. It is what Nanite does for the same
|
|
200
|
+
reason (`FInstanceSceneData::DeterminantSign`, read in `HWRasterizeVS`), and what the glTF spec
|
|
201
|
+
requires of a conformant renderer. The tangent frame's handedness flips with it.
|
|
202
|
+
|
|
203
|
+
The parameters remain, and now read as diagnostics rather than as fixes:
|
|
204
|
+
|
|
205
|
+
- `?mirrored=tint` colours reflected instances red — in this view the **whole left arcade** comes up
|
|
206
|
+
red while the right stays grey. Nothing about which of them is *drawn* changes.
|
|
207
|
+
- `?mirrored=flip` draws them `Back`-sided. This used to be the page's own fix; `Back` is now drawn
|
|
208
|
+
by reversing winding too, so on a reflected instance the two cancel and it reproduces the old bug
|
|
209
|
+
on demand.
|
|
210
|
+
- `?mirrored=double` draws both sides of them — the fix people reach for first, and still the wrong
|
|
211
|
+
one: it doubles the work and gets the shading wrong.
|
|
212
|
+
- `?side=front|back|double` sets the whole scene's side, for the cruder question of whether a
|
|
213
|
+
surface is missing or merely culled.
|
|
214
|
+
|
|
215
|
+
The bug was hard to recognise because `fragment_gbuffer` flips normal, tangent and face normal when
|
|
216
|
+
`dot(world_face_normal, view_direction) < 0` — a test about the *view*, not about the winding — so
|
|
217
|
+
the far wall you were left looking at was correctly lit, and it read as bad geometry rather than as
|
|
218
|
+
a culling problem. Nothing about any of it was virtual-geometry-specific: it reached every mesh
|
|
219
|
+
placed under a mirroring transform, by any loader or prefab.
|
|
220
|
+
|
|
221
|
+
## Two different things are called flicker here, and they have different causes
|
|
222
|
+
|
|
223
|
+
**A dropout is not a shimmer and they do not measure alike.** A shimmer moves a tenth of a per cent
|
|
224
|
+
of the pixels and comes from the TAA jitter under sub-pixel geometry; a frame missing a large part
|
|
225
|
+
of what the frames either side of it drew moves tens of per cent and comes from the descent running
|
|
226
|
+
out of wavefronts. One section each, below. Measuring the first when asked about the second cost a
|
|
227
|
+
whole pass of this investigation, and the tell that separates them is the amplified frame
|
|
228
|
+
difference: an **edge map** is the shimmer, **solid blobs** are the dropout.
|
|
229
|
+
|
|
230
|
+
## The shimmer is the TAA jitter, and the geometry is finer than a pixel
|
|
231
|
+
|
|
232
|
+
There is a visible shimmer over the ornament, and it is **exactly 16 frames long**.
|
|
233
|
+
|
|
234
|
+
Measured over 600 consecutive frame pairs at 780×368 samples (~2×2 screen pixels each), camera
|
|
235
|
+
static, everything settled:
|
|
236
|
+
|
|
237
|
+
| | pixels changing >8/255 per frame | >24/255 | worst single step | period |
|
|
238
|
+
|---|---:|---:|---:|---:|
|
|
239
|
+
| as shipped | 350 (0.12%) | 17 | 57/255 | 16 (r=0.97) |
|
|
240
|
+
| τ=16 | 182 (0.06%) | 13 | 69/255 | 16 (r=0.95) |
|
|
241
|
+
| `?mirrored=flip` | 314 (0.11%) | 21 | 56/255 | 16 (r=0.96) |
|
|
242
|
+
| TAA off | **79,391 (27.66%)** | 33,841 | 161/255 | 16 (r=0.97) |
|
|
243
|
+
| jitter pinned | 89 (0.03%) | 3 | 88/255 | 16 (r=0.96) |
|
|
244
|
+
|
|
245
|
+
Sixteen is `TAA.#jitter_sequence_size`, and the attribution follows from the last two rows. **Pin the
|
|
246
|
+
jitter and fifteen frames out of every sixteen go pixel-static** — 18 to 123 changed samples out of
|
|
247
|
+
287,040, which is the noise floor — against 240 to 470 *every* frame as shipped. The flicker is the
|
|
248
|
+
Halton jitter cycling the projection under geometry whose detail is finer than a pixel, with TAA
|
|
249
|
+
resolving most but not all of it.
|
|
250
|
+
|
|
251
|
+
An amplified `|frame(t) − frame(t−1)|` over eighteen consecutive pairs says the same thing in one
|
|
252
|
+
picture: it is an **edge map**. Every silhouette and every piece of filigree sparkles; the flat
|
|
253
|
+
courtyard floor is dead black. LOD popping would light up in cluster-shaped patches and does not.
|
|
254
|
+
|
|
255
|
+
Three things fall out of it that are worth writing down:
|
|
256
|
+
|
|
257
|
+
- **`feature_taa_enabled = false` does not turn the jitter off.** `Renderer` writes
|
|
258
|
+
`view_ctx.camera.setViewportOffset` from the jitter sequence unconditionally, and only the
|
|
259
|
+
*resolve* is behind the flag. So TAA off is not "no temporal AA", it is "jitter with nothing to
|
|
260
|
+
resolve it": 27.66% of pixels move every frame, which is forty times worse than shipping it on and
|
|
261
|
+
worse than never jittering at all. Anyone A/B-ing TAA on this content is not measuring what they
|
|
262
|
+
think.
|
|
263
|
+
- **The jitter does move the cut, slightly, and it is not where the flicker comes from.** `drawn`
|
|
264
|
+
and `pages visited` are weakly 16-periodic (r=0.34 and r=0.40) because the cut's frustum planes
|
|
265
|
+
come out of the *jittered* view-projection while `projection_k` — the error metric — does not. So
|
|
266
|
+
what moves is which clusters are inside the frustum, by up to 117 of 84,455 (0.14%), confined to
|
|
267
|
+
the screen border. `vgeo_runtime`'s README says the jitter does not move the cut and its τ table is
|
|
268
|
+
identical either way; at this scale that is very nearly true rather than exactly true, and the
|
|
269
|
+
difference is not visible in the diff image.
|
|
270
|
+
- **`GPUViewContext.setJitter` and `setJitterDelta` write the same two fields.** Only the first is
|
|
271
|
+
called, so nothing is broken today; a caller that used the second would silently overwrite the
|
|
272
|
+
jitter with its delta.
|
|
273
|
+
|
|
274
|
+
None of this is the scene's fault and τ=16 halving the count is the proof: less sub-pixel detail,
|
|
275
|
+
less shimmer, same period. It is what a temporal filter does on content authored at a density no
|
|
276
|
+
rasterizer resolves, which is the content virtual geometry exists to put on screen — so it is worth
|
|
277
|
+
knowing that the page's picture has a floor set by TAA rather than by the cut.
|
|
278
|
+
|
|
279
|
+
## The dropout: the descent's wavefront bound, and how the engine finds it
|
|
280
|
+
|
|
281
|
+
**`max_iterations` starts at 8, and at a large viewport that is the binding bound rather than the
|
|
282
|
+
safety one.** The descent then stops with items still queued, and a queued item is a **subtree that
|
|
283
|
+
was never expanded** — so what it would have drawn is not on screen that frame. It is the one
|
|
284
|
+
degradation of this cut that costs a *hole* rather than a coarser surface, which is why it reads as
|
|
285
|
+
geometry disappearing rather than as anything softening.
|
|
286
|
+
|
|
287
|
+
Reported from a live session at **3441×1440** with `dropped: queue 82` in the panel and `wavefronts`
|
|
288
|
+
jittering between 8 and 13. Reproduced at that pose and viewport, 900 frames, camera static, with
|
|
289
|
+
the bound pinned:
|
|
290
|
+
|
|
291
|
+
| pinned `max_iterations` | `queue_remaining` non-zero | worst | `drawn` swing |
|
|
292
|
+
|---|---:|---:|---:|
|
|
293
|
+
| **8** | **750 of 900 frames** | 13,467 items | **11,857 clusters** |
|
|
294
|
+
| 16 / 32 / 64 | 0 | 0 | 81 |
|
|
295
|
+
|
|
296
|
+
`drawn` going from a swing of 11,857 clusters to **81** is the flicker, in one number. An amplified
|
|
297
|
+
`|frame(t) − frame(t−1)|` says the same thing in a picture: at 8 it is **solid white blobs** — whole
|
|
298
|
+
pieces of carved ornament blinking on and off — and above it those are gone, leaving only the thin
|
|
299
|
+
edge shimmer of the section above. The two phenomena look nothing alike once they are separated.
|
|
300
|
+
|
|
301
|
+
**It is a resolution story, and that is why it took so long to find.** The cut is a function of the
|
|
302
|
+
render target, so the same viewpoint at 1578×746 — a quarter of the pixels — drains inside 8
|
|
303
|
+
wavefronts and never drops an item. Every negative result in this file's earlier drafts was measured
|
|
304
|
+
at that size. A quarter-sized window is not a smaller version of this test.
|
|
305
|
+
|
|
306
|
+
### The bound raises itself
|
|
307
|
+
|
|
308
|
+
Nothing here pins it. `GPUVirtualGeometryRuntime.note_incomplete_descent` takes the one reading that
|
|
309
|
+
says the descent was truncated and **doubles the bound, permanently**, which is the same shape the
|
|
310
|
+
rasterizer already uses for meshlet counts: a quantity that cannot be known before the work runs,
|
|
311
|
+
learned from what the work reported, kept as a high-water mark.
|
|
312
|
+
|
|
313
|
+
It has to be learned, because how many wavefronts a cut needs is a function of the frontier's
|
|
314
|
+
*breadth* — the scene, the viewpoint and the render target together — and neither the kernel before
|
|
315
|
+
it runs nor the host at any time can compute it. Doubling rather than solving for it, because
|
|
316
|
+
`QUEUE_REMAINING` is a count of *items* and there is no ratio converting those into wavefronts. It
|
|
317
|
+
is never lowered: a frame that drained is evidence about that frame, not that the scene got smaller,
|
|
318
|
+
and a bound that fell back would re-learn the same lesson at a hole a time every time the camera
|
|
319
|
+
turned away and back. An unused wavefront is an empty indirect dispatch, which is the cheap side of
|
|
320
|
+
that trade.
|
|
321
|
+
|
|
322
|
+
**What it costs when it is wrong is one frame.** Measured cold at 3419×1286 on the reported
|
|
323
|
+
viewpoint: `queue_remaining` non-zero on **1 frame of 600**, and zero for the rest of the session.
|
|
324
|
+
The ceiling is 64, so the worst case is three such frames, once, ever.
|
|
325
|
+
|
|
326
|
+
The panel shows `wavefronts` as *used / bound*, with an arrow and a count when the bound has moved,
|
|
327
|
+
because eight wavefronts is a drained descent under a bound of 32 and a truncated one under a bound
|
|
328
|
+
of 8 — and the reading could not tell them apart while it showed only the count.
|
|
329
|
+
|
|
330
|
+
`?iterations=N` pins both the start and the ceiling, which turns the escalation off and reproduces
|
|
331
|
+
the hole on demand: at 8 the same view gives `queue_remaining` on 395 frames of 500 and a `drawn`
|
|
332
|
+
swing of 15,874.
|
|
333
|
+
|
|
334
|
+
**`descent_steps` is the wrong knob for this.** It sets how many levels one dispatch advances, so it
|
|
335
|
+
answers depth; what runs out here is *breadth* — a wave keeps one child per lane and spills the
|
|
336
|
+
rest, and the spill generations are what consume the bound. Measured at the small viewport, 24
|
|
337
|
+
against 48 left `drawn` bit-identical.
|
|
338
|
+
|
|
339
|
+
### Catching it where it happens
|
|
340
|
+
|
|
341
|
+
`?catch=0.15` arms {@link FlickerCatcher} — a per-frame detector in the page itself. It judges each
|
|
342
|
+
frame against the pair before it **and** the pair after it, taking the smaller of the two
|
|
343
|
+
departures and only when both point the same way. Judging against the median of all four is the
|
|
344
|
+
obvious thing and is wrong: when the picture takes a persistent *step* — the scene streaming in, a
|
|
345
|
+
coarse level replaced by a fine one — two of the four sit on the far side, the median lands between
|
|
346
|
+
the levels, and the frame *before* the step is convicted for being where it always was. Fourteen
|
|
347
|
+
poses each "caught" one that way. On a step the smaller departure is ~0 by construction, which is
|
|
348
|
+
what makes the corrected test score the reported event at 62% and every one of those artifacts at
|
|
349
|
+
or under 1%.
|
|
350
|
+
|
|
351
|
+
It works on **pixels rather than counters**:
|
|
352
|
+
the cut's statistics come from a readback capped at two in flight and skipped on more than half the
|
|
353
|
+
frames, so `drawn` on any given frame is a reading from one to three frames ago and a one-frame
|
|
354
|
+
disappearance need never appear in it at all. That is why the panel's numbers look calm during one.
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
?catch=0.15 count them, panel shows a running tally — fly around looking for one
|
|
358
|
+
?catch=0.15&freeze=1 stop on the first one and leave that frame on screen
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**"copy camera link" is how a viewpoint gets out of the browser.** A viewpoint is the one piece of
|
|
362
|
+
state a person has and a session does not: everything else this page can be told is a URL parameter
|
|
363
|
+
already, and a phenomenon that happens "in many places" is not chaseable without one of them. The
|
|
364
|
+
button writes a link that reopens the page where the camera is standing — `?eye=`/`?at=` from the
|
|
365
|
+
live pose, `?tau=` from the slider as it stands rather than as the page was opened, and every other
|
|
366
|
+
parameter left exactly as it was, so a link captured with `?catch=0.15&mirrored=tint` on comes back
|
|
367
|
+
with both still armed. It goes to the clipboard, and to a selected box under the button when a
|
|
368
|
+
browser declines that. `__camera_url()` is the same string for a session with no pointer.
|
|
369
|
+
|
|
370
|
+
**An event carries its own camera link**, captured at the instant it fires, so `__caught()` is
|
|
371
|
+
self-contained: where it happened is the one thing a report of a one-frame dropout cannot be
|
|
372
|
+
reconstructed without, and by the time anybody reads the report the camera may have moved. The held
|
|
373
|
+
frame goes on *under* the panel, so freezing does not hide the readings that explain it.
|
|
374
|
+
|
|
375
|
+
`__caught()` reports what it has seen and the counters for the five frames around the last one;
|
|
376
|
+
`__catch_rows()` is the per-frame log. Freezing also holds the five frames around it, and
|
|
377
|
+
`__show_frame(n)` pages between them — the frame before and the frame itself, side by side, is what
|
|
378
|
+
says whether the geometry went missing or merely moved.
|
|
379
|
+
|
|
380
|
+
It costs a whole-canvas `drawImage` and a small `getImageData` per frame: 4.2 ms a frame becomes
|
|
381
|
+
10.3 ms here, which is slack on a 60 Hz display and is why the full-resolution ring is only kept
|
|
382
|
+
when `freeze=1` is asked for.
|
|
383
|
+
|
|
384
|
+
## Driving it
|
|
385
|
+
|
|
386
|
+
`__state()` is the whole surface a headless session needs and the panel shows nothing it does not:
|
|
387
|
+
the scene's counts, the cut's counters, both residency tiers, the render target's size and the
|
|
388
|
+
camera. `__page.runtime.tau` is the threshold, `__look(eye, target)` stands the camera somewhere,
|
|
389
|
+
and `__page.viewpoints` is what the buttons in the panel are.
|
|
390
|
+
|
|
391
|
+
URL parameters, all of them for a session rather than for a person: `?scene=` the manifest,
|
|
392
|
+
`?tau=` the threshold **before the first container** (see the table above for why a load per row),
|
|
393
|
+
`?pages=` the VRAM tier's slots, `?iterations=` the descent's wavefront ceiling,
|
|
394
|
+
`?eye=x,y,z&at=x,y,z` a viewpoint, `?side=front|back|double` the whole scene's draw side,
|
|
395
|
+
`?mirrored=flip|tint|double` the reflected instances' — and `?catch=<fraction>[&freeze=1]` the
|
|
396
|
+
dropout catcher. `__state().scene.mirrored` is the reflected count the panel shows, and `__caught()`
|
|
397
|
+
the catcher's report.
|
|
398
|
+
|
|
399
|
+
**`T` records a GPU capture and `T` again downloads an `.sgpt`** — the same key and the same module
|
|
400
|
+
(`playground/profile_hotkey.js`) every other playground binds. It answers the question the panel
|
|
401
|
+
cannot: every reading above is a *count* and not one of them is a cost. The capture's note carries
|
|
402
|
+
τ, the container and instance counts, the cut it selected and the resolution, because the same
|
|
403
|
+
0.4 ms is a triumph at eighty thousand clusters and a scandal at eighteen thousand.
|
|
404
|
+
|
|
405
|
+
The headless recipe is `vgeo_runtime`'s and has not changed — `--enable-unsafe-webgpu` and nothing
|
|
406
|
+
else, pick the CDP target by URL, resize the window rather than the viewport, and poll for `__state`
|
|
407
|
+
rather than trusting `load`. Its README is where those four are written down and why each one costs
|
|
408
|
+
an hour.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>meep — a whole virtual-geometry scene</title>
|
|
6
|
+
|
|
7
|
+
<link rel="icon" href="data:,">
|
|
8
|
+
|
|
9
|
+
<style>
|
|
10
|
+
:root { color-scheme: dark; }
|
|
11
|
+
|
|
12
|
+
html, body { height: 100%; margin: 0; overflow: hidden; background: #070b10; }
|
|
13
|
+
|
|
14
|
+
/* Placed, not sized — `Renderer` writes an inline `style.width`/`style.height` every time
|
|
15
|
+
it configures the context, and an inline style beats a rule in here. `main.js` measures
|
|
16
|
+
the document for the same reason. */
|
|
17
|
+
#view { position: absolute; top: 0; left: 0; display: block; }
|
|
18
|
+
|
|
19
|
+
#panel {
|
|
20
|
+
position: absolute; top: 0; right: 0; width: 330px; max-height: 100vh; overflow-y: auto;
|
|
21
|
+
z-index: 10; padding: 12px 14px; box-sizing: border-box;
|
|
22
|
+
font: 12px/1.45 ui-monospace, "Cascadia Mono", Consolas, monospace;
|
|
23
|
+
color: #dfe6ee; background: rgba(12, 16, 22, 0.88);
|
|
24
|
+
border-left: 1px solid #2b3947;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#panel h1 { margin: 0 0 8px; font-size: 13px; letter-spacing: 0.06em; color: #7fd2ff; }
|
|
28
|
+
|
|
29
|
+
#panel h2 {
|
|
30
|
+
margin: 14px 0 6px; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase;
|
|
31
|
+
color: #6b7c8d; border-bottom: 1px solid #24313d; padding-bottom: 3px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#panel .row { display: flex; justify-content: space-between; gap: 8px; }
|
|
35
|
+
|
|
36
|
+
#panel .row span:last-child {
|
|
37
|
+
color: #f2f6fa; text-align: right;
|
|
38
|
+
min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#panel .row span:first-child { flex: none; }
|
|
42
|
+
#panel .muted { color: #6b7c8d; }
|
|
43
|
+
#panel .bad { color: #ff8a7a; }
|
|
44
|
+
#panel .good { color: #8fe388; }
|
|
45
|
+
#panel input[type=range] { width: 100%; }
|
|
46
|
+
#panel label { display: block; margin: 6px 0 2px; }
|
|
47
|
+
|
|
48
|
+
#status { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
49
|
+
#status.error { color: #ff8a7a; }
|
|
50
|
+
|
|
51
|
+
/* The one thing on this page that is not a number: how much of the scene is open. A scene
|
|
52
|
+
arrives container by container and the picture fills in as it does, so a bar is the
|
|
53
|
+
honest shape for it — the page is usable long before it is finished. */
|
|
54
|
+
#progress {
|
|
55
|
+
margin: 8px 0 2px; height: 4px; background: #1b2530; border-radius: 2px;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
#progress > div { height: 100%; width: 0; background: #7fd2ff; transition: width 0.2s; }
|
|
60
|
+
|
|
61
|
+
#views { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
|
|
62
|
+
|
|
63
|
+
#views button {
|
|
64
|
+
flex: 1 1 auto; padding: 3px 6px; cursor: pointer;
|
|
65
|
+
font: inherit; font-size: 11px; color: #dfe6ee;
|
|
66
|
+
background: #1b2530; border: 1px solid #2b3947; border-radius: 3px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#views button:hover { background: #24313d; border-color: #3d5164; }
|
|
70
|
+
|
|
71
|
+
#capture { margin-top: 6px; }
|
|
72
|
+
|
|
73
|
+
#capture button {
|
|
74
|
+
width: 100%; padding: 4px 6px; cursor: pointer;
|
|
75
|
+
font: inherit; font-size: 11px; color: #dfe6ee;
|
|
76
|
+
background: #1b2530; border: 1px solid #2b3947; border-radius: 3px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#capture button:hover { background: #24313d; border-color: #3d5164; }
|
|
80
|
+
|
|
81
|
+
/* Selectable and wrapped: the clipboard is the happy path and this is what is left when a
|
|
82
|
+
browser declines it, so it has to be something a person can drag over. */
|
|
83
|
+
#camera-url {
|
|
84
|
+
margin-top: 5px; padding: 4px 6px; user-select: all; word-break: break-all;
|
|
85
|
+
font-size: 11px; color: #9fb4c7; background: #10171f;
|
|
86
|
+
border: 1px solid #24313d; border-radius: 3px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#hint, #profile-note { margin-top: 10px; color: #6b7c8d; }
|
|
90
|
+
|
|
91
|
+
#profile-status { margin-top: 4px; color: #dfe6ee; word-break: break-word; }
|
|
92
|
+
#profile-status.recording { color: #ff8a7a; }
|
|
93
|
+
</style>
|
|
94
|
+
</head>
|
|
95
|
+
<body tabindex="0">
|
|
96
|
+
|
|
97
|
+
<canvas id="view"></canvas>
|
|
98
|
+
|
|
99
|
+
<div id="panel">
|
|
100
|
+
<h1>a whole VG scene</h1>
|
|
101
|
+
<div id="status" class="muted">starting…</div>
|
|
102
|
+
<div id="progress"><div></div></div>
|
|
103
|
+
|
|
104
|
+
<label>threshold τ <span id="tau-value">1.0</span> px</label>
|
|
105
|
+
<input id="tau" type="range" min="0.25" max="16" step="0.25" value="1">
|
|
106
|
+
|
|
107
|
+
<div id="views"></div>
|
|
108
|
+
|
|
109
|
+
<div id="capture">
|
|
110
|
+
<button id="copy-camera" type="button">copy camera link</button>
|
|
111
|
+
<div id="camera-url" hidden></div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<h2>scene</h2>
|
|
115
|
+
<div id="scene"></div>
|
|
116
|
+
|
|
117
|
+
<h2>cut</h2>
|
|
118
|
+
<div id="cut"></div>
|
|
119
|
+
|
|
120
|
+
<h2>residency</h2>
|
|
121
|
+
<div id="residency"></div>
|
|
122
|
+
|
|
123
|
+
<div id="catch-section" hidden>
|
|
124
|
+
<h2>dropout catcher</h2>
|
|
125
|
+
<div id="catch"></div>
|
|
126
|
+
<div class="muted" style="margin-top:6px">a frame unlike the two either side of it, by
|
|
127
|
+
luminance. <code>&freeze=1</code> stops on the first one and leaves it on screen.
|
|
128
|
+
<code>__caught()</code> reports, <code>__catch_rows()</code> is the per-frame log.</div>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<h2>profiling</h2>
|
|
132
|
+
<div id="profile-status">idle · T to record</div>
|
|
133
|
+
<div id="profile-note"><strong>T</strong> starts a GPU capture and <strong>T</strong> again
|
|
134
|
+
stops it and downloads an <code>.sgpt</code>. The note carries τ, the instance count and the
|
|
135
|
+
cut it selected, because a pass timing means nothing without them.</div>
|
|
136
|
+
|
|
137
|
+
<div id="hint">W/A/S/D to move, drag to look, wheel to close in.
|
|
138
|
+
<code>?scene=<url></code> opens another one.</div>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<script type="module" src="./main.js"></script>
|
|
142
|
+
|
|
143
|
+
</body>
|
|
144
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/vgeo_scene/main.js"],"names":[],"mappings":""}
|