@woosh/meep-engine 3.29.0 → 3.30.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-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +14 -2
- package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/BVH.js +14 -1
- package/src/core/cache/FrequencySketch.d.ts +3 -1
- package/src/core/cache/FrequencySketch.d.ts.map +1 -1
- package/src/core/cache/FrequencySketch.js +10 -4
- package/src/core/cache/wtinylfu/CacheWTinylfu.d.ts.map +1 -1
- package/src/core/cache/wtinylfu/CacheWTinylfu.js +24 -2
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts +20 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +69 -4
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +48 -18
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +262 -70
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts +25 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.js +228 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts +13 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.js +10 -128
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js +11 -1
- package/src/core/graph/mn_graph_collapse_weighted_edge.js +6 -6
- package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
- package/src/core/math/lookup/ParameterLookupTable.js +10 -5
- package/src/core/math/noise/sdnoise.d.ts.map +1 -1
- package/src/core/math/noise/sdnoise.js +16 -10
- package/src/core/model/object/ImmutableObjectPool.d.ts.map +1 -1
- package/src/core/model/object/ImmutableObjectPool.js +17 -7
- package/src/core/process/executor/ConcurrentExecutor.d.ts +1 -5
- package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
- package/src/core/process/executor/ConcurrentExecutor.js +95 -1
- package/src/core/process/task/task_find_dependency_cycle.d.ts +17 -0
- package/src/core/process/task/task_find_dependency_cycle.d.ts.map +1 -0
- package/src/core/process/task/task_find_dependency_cycle.js +81 -0
- package/src/core/wfc/WFCCellChoice.d.ts +17 -0
- package/src/core/wfc/WFCCellChoice.d.ts.map +1 -0
- package/src/core/wfc/WFCCellChoice.js +36 -0
- package/src/core/wfc/WFCLattice.d.ts +105 -0
- package/src/core/wfc/WFCLattice.d.ts.map +1 -0
- package/src/core/wfc/WFCLattice.js +235 -0
- package/src/core/wfc/WFCRuleTable.d.ts +172 -0
- package/src/core/wfc/WFCRuleTable.d.ts.map +1 -0
- package/src/core/wfc/WFCRuleTable.js +334 -0
- package/src/core/wfc/WFCState.d.ts +273 -0
- package/src/core/wfc/WFCState.d.ts.map +1 -0
- package/src/core/wfc/WFCState.js +552 -0
- package/src/core/wfc/WFCStatus.d.ts +11 -0
- package/src/core/wfc/WFCStatus.d.ts.map +1 -0
- package/src/core/wfc/WFCStatus.js +28 -0
- package/src/core/wfc/WFCTileWeights.d.ts +48 -0
- package/src/core/wfc/WFCTileWeights.d.ts.map +1 -0
- package/src/core/wfc/WFCTileWeights.js +86 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts +12 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts.map +1 -0
- package/src/core/wfc/WFC_UNRESOLVED.js +11 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts +24 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts.map +1 -0
- package/src/core/wfc/wfc_estimate_bytes.js +47 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts +27 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts.map +1 -0
- package/src/core/wfc/wfc_rule_table_tile_components.js +80 -0
- package/src/core/wfc/wfc_solve.d.ts +21 -0
- package/src/core/wfc/wfc_solve.d.ts.map +1 -0
- package/src/core/wfc/wfc_solve.js +154 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts +18 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_apply_boundary.js +61 -0
- package/src/core/wfc/wfc_state_assign.d.ts +11 -0
- package/src/core/wfc/wfc_state_assign.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_assign.js +36 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts +17 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_ban_bits.js +81 -0
- package/src/core/wfc/wfc_state_collapse.d.ts +12 -0
- package/src/core/wfc/wfc_state_collapse.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_collapse.js +73 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts +12 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_flush_dirty.js +39 -0
- package/src/core/wfc/wfc_state_propagate.d.ts +14 -0
- package/src/core/wfc/wfc_state_propagate.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_propagate.js +155 -0
- package/src/core/wfc/wfc_state_read.d.ts +11 -0
- package/src/core/wfc/wfc_state_read.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_read.js +38 -0
- package/src/core/wfc/wfc_state_restrict.d.ts +18 -0
- package/src/core/wfc/wfc_state_restrict.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_restrict.js +39 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts +24 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_set_eligible.js +49 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts +13 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_undo_to.js +84 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts +11 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts.map +1 -0
- package/src/core/wfc/wfc_words_per_cell.js +16 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts +8 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +37 -14
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts +8 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +37 -2
- package/src/engine/ecs/guid/UUID.d.ts.map +1 -1
- package/src/engine/ecs/guid/UUID.js +45 -17
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts.map +1 -1
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +3 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +366 -360
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.js +24 -10
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +24 -5
- package/src/engine/interpolation/Interpoland.d.ts +7 -1
- package/src/engine/interpolation/Interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/Interpoland.js +8 -1
- package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
- package/src/engine/interpolation/InterpolationSystem.js +3 -0
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +5 -3
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -1
- package/src/engine/interpolation/TransformPoseSerializationAdapter.js +14 -3
- package/src/engine/interpolation/pose_interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/pose_interpoland.js +2 -0
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +15 -10
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +17 -0
- package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
- package/src/engine/physics/mls-mpm/MLS_MPM.js +14 -0
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +1 -1
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +12 -3
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.js +4 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.d.ts.map +1 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.js +248 -259
- package/src/format/image/avif/av1/decode/read_golomb.d.ts +21 -0
- package/src/format/image/avif/av1/decode/read_golomb.d.ts.map +1 -0
- package/src/format/image/avif/av1/decode/read_golomb.js +49 -0
- package/src/format/image/avif/av1/filter/loop_restoration.js +461 -451
- package/src/format/image/avif/av1/util/round2.d.ts +19 -2
- package/src/format/image/avif/av1/util/round2.d.ts.map +1 -1
- package/src/format/image/avif/av1/util/round2.js +51 -27
- package/src/format/image/avif/heif/parse_avif_file.js +24 -0
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +14 -0
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +46 -3
- package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +91 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +0 -13
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +0 -15
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +5 -5
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts +11 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js +11 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +18 -9
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js +20 -26
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +1 -3
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.js +2 -5
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +14 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +12 -3
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.js +7 -1
- package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/GPULightMap.js +349 -336
- package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/load_gltf.js +1137 -1128
- package/src/shade/renderer/particles/DESIGN.md +14 -5
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +25 -10
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +182 -38
- package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/simplex_reference.js +16 -10
- package/src/shade/renderer/particles/graph_particles.d.ts +4 -2
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +8 -2
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +8 -2
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +10 -4
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts +31 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.js +62 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +13 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.js +95 -17
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +21 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +28 -0
- 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 +19 -2
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +19 -2
- package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/WebGPUStruct.js +12 -0
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts +8 -2
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts.map +1 -1
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +41 -6
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +2383 -2356
- package/src/view/tooltip/DomTooltipManager.d.ts +7 -0
- package/src/view/tooltip/DomTooltipManager.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipManager.js +22 -0
- package/src/view/tooltip/DomTooltipObserver.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipObserver.js +13 -3
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.js +0 -45
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
* guard is not cosmetic: `1 << -1` is `1 << 31` under JavaScript's shift-count masking, which would
|
|
8
8
|
* silently produce garbage.
|
|
9
9
|
*
|
|
10
|
-
* `x` must fit in a signed 32-bit integer
|
|
11
|
-
*
|
|
10
|
+
* `x + 2^(n-1)` must fit in a signed 32-bit integer — the rounding term is added before the shift, so
|
|
11
|
+
* the bound is slightly tighter than `x` itself. Most intermediates the specification feeds this do;
|
|
12
|
+
* the self-guided restoration box filter's do not, and use {@link round2_wide} instead.
|
|
12
13
|
*
|
|
13
14
|
* @param {number} x
|
|
14
15
|
* @param {number} n number of bits to shift away, `>= 0`
|
|
@@ -19,4 +20,20 @@
|
|
|
19
20
|
* @copyright Company Named Limited (c) 2026
|
|
20
21
|
*/
|
|
21
22
|
export function round2(x: number, n: number): number;
|
|
23
|
+
/**
|
|
24
|
+
* {@link round2} for operands that run past a signed 32-bit integer.
|
|
25
|
+
*
|
|
26
|
+
* `>>` applies ToInt32 to its left operand, so the shifted form silently wraps above 2^31 and comes
|
|
27
|
+
* back negative — the self-guided restoration box filter's `p * s` reaches 3.8e9 on an ordinary
|
|
28
|
+
* black/white edge, where `round2` returned -484 against an exact 3612. Every JavaScript number is
|
|
29
|
+
* already a double, so the product itself is exact to 2^53; only the shift needs replacing with a
|
|
30
|
+
* floor division, which is what the specification's Round2 says in the first place. Same shape as
|
|
31
|
+
* `round2_12` in the inverse transform, which hit this earlier.
|
|
32
|
+
*
|
|
33
|
+
* @param {number} x
|
|
34
|
+
* @param {number} n number of bits to shift away, `>= 0`
|
|
35
|
+
* @returns {number}
|
|
36
|
+
* @see AV1 spec 4.7 "Mathematical functions"
|
|
37
|
+
*/
|
|
38
|
+
export function round2_wide(x: number, n: number): number;
|
|
22
39
|
//# sourceMappingURL=round2.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"round2.d.ts","sourceRoot":"","sources":["../../../../../../../src/format/image/avif/av1/util/round2.js"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"round2.d.ts","sourceRoot":"","sources":["../../../../../../../src/format/image/avif/av1/util/round2.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,0BARW,MAAM,KACN,MAAM,GACJ,MAAM,CAYlB;AAED;;;;;;;;;;;;;;GAcG;AACH,+BALW,MAAM,KACN,MAAM,GACJ,MAAM,CASlB"}
|
|
@@ -1,27 +1,51 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `Round2( x, n )` from the AV1 specification: divide by `2^n` and round half up, rounding towards
|
|
3
|
-
* negative infinity on the halfway case for negative inputs.
|
|
4
|
-
*
|
|
5
|
-
* The specification defines this with real division and a floor; JavaScript's `>>` is an arithmetic
|
|
6
|
-
* shift, which is exactly that floor, so the integer form transliterates directly. The `n === 0`
|
|
7
|
-
* guard is not cosmetic: `1 << -1` is `1 << 31` under JavaScript's shift-count masking, which would
|
|
8
|
-
* silently produce garbage.
|
|
9
|
-
*
|
|
10
|
-
* `x` must fit in a signed 32-bit integer
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @param {number}
|
|
15
|
-
* @
|
|
16
|
-
* @
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `Round2( x, n )` from the AV1 specification: divide by `2^n` and round half up, rounding towards
|
|
3
|
+
* negative infinity on the halfway case for negative inputs.
|
|
4
|
+
*
|
|
5
|
+
* The specification defines this with real division and a floor; JavaScript's `>>` is an arithmetic
|
|
6
|
+
* shift, which is exactly that floor, so the integer form transliterates directly. The `n === 0`
|
|
7
|
+
* guard is not cosmetic: `1 << -1` is `1 << 31` under JavaScript's shift-count masking, which would
|
|
8
|
+
* silently produce garbage.
|
|
9
|
+
*
|
|
10
|
+
* `x + 2^(n-1)` must fit in a signed 32-bit integer — the rounding term is added before the shift, so
|
|
11
|
+
* the bound is slightly tighter than `x` itself. Most intermediates the specification feeds this do;
|
|
12
|
+
* the self-guided restoration box filter's do not, and use {@link round2_wide} instead.
|
|
13
|
+
*
|
|
14
|
+
* @param {number} x
|
|
15
|
+
* @param {number} n number of bits to shift away, `>= 0`
|
|
16
|
+
* @returns {number}
|
|
17
|
+
* @see AV1 spec 4.7 "Mathematical functions"
|
|
18
|
+
*
|
|
19
|
+
* @author Alex Goldring
|
|
20
|
+
* @copyright Company Named Limited (c) 2026
|
|
21
|
+
*/
|
|
22
|
+
export function round2(x, n) {
|
|
23
|
+
if (n === 0) {
|
|
24
|
+
return x;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (x + (1 << (n - 1))) >> n;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* {@link round2} for operands that run past a signed 32-bit integer.
|
|
32
|
+
*
|
|
33
|
+
* `>>` applies ToInt32 to its left operand, so the shifted form silently wraps above 2^31 and comes
|
|
34
|
+
* back negative — the self-guided restoration box filter's `p * s` reaches 3.8e9 on an ordinary
|
|
35
|
+
* black/white edge, where `round2` returned -484 against an exact 3612. Every JavaScript number is
|
|
36
|
+
* already a double, so the product itself is exact to 2^53; only the shift needs replacing with a
|
|
37
|
+
* floor division, which is what the specification's Round2 says in the first place. Same shape as
|
|
38
|
+
* `round2_12` in the inverse transform, which hit this earlier.
|
|
39
|
+
*
|
|
40
|
+
* @param {number} x
|
|
41
|
+
* @param {number} n number of bits to shift away, `>= 0`
|
|
42
|
+
* @returns {number}
|
|
43
|
+
* @see AV1 spec 4.7 "Mathematical functions"
|
|
44
|
+
*/
|
|
45
|
+
export function round2_wide(x, n) {
|
|
46
|
+
if (n === 0) {
|
|
47
|
+
return x;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return Math.floor((x + 2 ** (n - 1)) / 2 ** n);
|
|
51
|
+
}
|
|
@@ -170,6 +170,22 @@ function read_iloc(file, cursor) {
|
|
|
170
170
|
|
|
171
171
|
check_count(item_count, "iloc");
|
|
172
172
|
|
|
173
|
+
/**
|
|
174
|
+
* What one extent record costs in the file. `uint_of_size(0)` returns 0 without consuming a
|
|
175
|
+
* byte, so with all three widths at zero an extent is free in the file and an `ItemExtent` in
|
|
176
|
+
* memory — 644 bytes asked for 6.5 million of them, and a full `item_count` asks for 4.3
|
|
177
|
+
* billion, which is an OOM. Every other width is self-limiting, because the cursor throws when
|
|
178
|
+
* it runs out; this one is not, so it is refused outright. An extent that carries neither an
|
|
179
|
+
* offset nor a length describes nothing anyway.
|
|
180
|
+
*/
|
|
181
|
+
const extent_record_bytes = index_size + offset_size + length_size;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Across the whole box, not per item. `check_count` bounds each `extent_count` on its own, and
|
|
185
|
+
* nothing bounded the product — which is the other half of the same arithmetic.
|
|
186
|
+
*/
|
|
187
|
+
let total_extent_count = 0;
|
|
188
|
+
|
|
173
189
|
for (let i = 0; i < item_count; i++) {
|
|
174
190
|
const id = version < 2 ? cursor.u16() : cursor.u32();
|
|
175
191
|
|
|
@@ -186,6 +202,14 @@ function read_iloc(file, cursor) {
|
|
|
186
202
|
|
|
187
203
|
check_count(extent_count, "iloc extents");
|
|
188
204
|
|
|
205
|
+
if (extent_count > 0 && extent_record_bytes === 0) {
|
|
206
|
+
throw new Error(`iloc declares ${extent_count} extents of zero width, which cannot be represented`);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
total_extent_count += extent_count;
|
|
210
|
+
|
|
211
|
+
check_count(total_extent_count, "iloc extents in total");
|
|
212
|
+
|
|
189
213
|
for (let j = 0; j < extent_count; j++) {
|
|
190
214
|
if (index_size > 0) {
|
|
191
215
|
cursor.uint_of_size(index_size);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GPUTypedTable.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/buffer/table/GPUTypedTable.js"],"names":[],"mappings":"AAwEA;;;GAGG;AACH;IAyKI;;;OAGG;IACH,wBAFW,uBAAuB,EASjC;IAlLD;;OAEG;IACH,YAFU,uBAAuB,CAEtB;IAEX;;;;OAIG;IACH,OAFU,IAAI,MAAM,EAAC,eAAe,CAAC,CAEnB;IAElB;;;;OAIG;IACH,uBAFU,YAAY,CAE6D;IAEnF;;;;;;;;;;;OAWG;IACH,4BAFU,YAAY,CAE6B;IAEnD;;;;;OAKG;IACH,qBAFU,YAAY,CAEsB;IAiF5C;;;;;OAKG;IACH,iBAFU,MAAM,CAEe;IAE/B;;;;OAIG;IACH,WAFU,MAAM,CAES;IAmBzB;;;;;;OAMG;IACH,oBAFU,MAAM,CAEkB;IAElC;;;OAGG;IACH,kBAFU,cAAc,GAAC,SAAS,CAEjB;IAejB;;;;;OAKG;IACH,WAHW,CAAC,GACC,MAAM,CAQlB;IAED;;;;;;;OAOG;IACH,kBAJW,CAAC,UACD,eAAe,GACb,MAAM,CAQlB;IAED;;;;;OAKG;IACH,sBAFW,MAAM,QAsChB;IAED;;;;OAIG;IACH,0BAIC;IAED;;;;;;OAMG;IACH,mBAHW,MAAM,GACJ,MAAM,CAUlB;IAsBD;;;;;;;;;;OAUG;IACH,cAuBC;IAmGD;;;;;;OAMG;IACH,mBAJW,MAAM,GACJ,CAAC,GAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"GPUTypedTable.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/buffer/table/GPUTypedTable.js"],"names":[],"mappings":"AAwEA;;;GAGG;AACH;IAyKI;;;OAGG;IACH,wBAFW,uBAAuB,EASjC;IAlLD;;OAEG;IACH,YAFU,uBAAuB,CAEtB;IAEX;;;;OAIG;IACH,OAFU,IAAI,MAAM,EAAC,eAAe,CAAC,CAEnB;IAElB;;;;OAIG;IACH,uBAFU,YAAY,CAE6D;IAEnF;;;;;;;;;;;OAWG;IACH,4BAFU,YAAY,CAE6B;IAEnD;;;;;OAKG;IACH,qBAFU,YAAY,CAEsB;IAiF5C;;;;;OAKG;IACH,iBAFU,MAAM,CAEe;IAE/B;;;;OAIG;IACH,WAFU,MAAM,CAES;IAmBzB;;;;;;OAMG;IACH,oBAFU,MAAM,CAEkB;IAElC;;;OAGG;IACH,kBAFU,cAAc,GAAC,SAAS,CAEjB;IAejB;;;;;OAKG;IACH,WAHW,CAAC,GACC,MAAM,CAQlB;IAED;;;;;;;OAOG;IACH,kBAJW,CAAC,UACD,eAAe,GACb,MAAM,CAQlB;IAED;;;;;OAKG;IACH,sBAFW,MAAM,QAsChB;IAED;;;;OAIG;IACH,0BAIC;IAED;;;;;;OAMG;IACH,mBAHW,MAAM,GACJ,MAAM,CAUlB;IAsBD;;;;;;;;;;OAUG;IACH,cAuBC;IAmGD;;;;;;OAMG;IACH,mBAJW,MAAM,GACJ,CAAC,GAAC,SAAS,CA0CvB;IAgDD;;;OAGG;IACH,cAsBC;IA+BD;;;;OAIG;IACH,mBAHW,MAAM,SACN,CAAC,QAyEX;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,0BAJW,MAAM,SACN,CAAC,UACD,eAAe,QA4DzB;IAED;;;;;;;;;;;;;OAaG;IACH,yBALW,MAAM,eACN,MAAM,oBAEN,UAAU,QAqBpB;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8CG;IACH,yBANW,MAAM,eACN,MAAM,UACN,WAAW,GAAC,eAAe,kBAC3B,MAAM,gBACN,MAAM,QA+DhB;IAED;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,0BAJW,MAAM,SACN,CAAC,UACD,eAAe,QA6GzB;IA0KD;;;OAGG;IACH,8BASC;IAED;;;OAGG;IACH,2BAYC;IAED;;OAEG;IACH,oBAEC;IAED;;;;;;;;;;OAUG;IACH,+BAEC;IAED;;;;;;;;;;OAUG;IACH,mCAJW,WAAW,UACX,MAAM,GACL,MAAM,CAoBjB;IAED;;;;;;;;;;;;OAYG;IACH,kCAMC;IAED;;;;;;;;;;;;;;OAcG;IACH,mCAHW,MAAM,GACL,MAAM,CAKjB;IAED,mBAEC;;CACJ;sCAl2CY,OAAO,8BAA8B,EAAE,uBAAuB;6BAC9D,OAAO,qBAAqB,EAAE,cAAc;yBAC5C,OAAO,iCAAiC,EAAE,UAAU;8BACpD,OAAO,mCAAmC,EAAE,eAAe;gCAPxC,sBAAsB;6BAhBzB,yCAAyC;uBAC/C,mCAAmC"}
|
|
@@ -519,6 +519,20 @@ export class GPUTypedTable {
|
|
|
519
519
|
* @throws {Error} if the element is not CPU-resident and not in the upload buffer
|
|
520
520
|
*/
|
|
521
521
|
get(element_index) {
|
|
522
|
+
if (!this.occupancy.get(element_index)) {
|
|
523
|
+
/**
|
|
524
|
+
* A freed row is not a record. {@link remove} zero-fills the shadow bytes and clears the
|
|
525
|
+
* bit but leaves the page allocated, so reading the bytes back gave a fully-formed
|
|
526
|
+
* record of zeros — against the `@returns {T|undefined}` one line above, which callers
|
|
527
|
+
* have been written to. Zero is a valid row index, so a caller walking a linked chain
|
|
528
|
+
* out of such a record walks to row 0 and back to row 0, forever.
|
|
529
|
+
*
|
|
530
|
+
* The occupancy bit is already the authority `#resolve` and `debug_table_read_all` read;
|
|
531
|
+
* the marshalling paths that deliberately ignore it do not come through here.
|
|
532
|
+
*/
|
|
533
|
+
return undefined;
|
|
534
|
+
}
|
|
535
|
+
|
|
522
536
|
const page_index = Math.floor(element_index / this.descriptor.elements_per_page);
|
|
523
537
|
const page = this.pages.get(page_index);
|
|
524
538
|
|
|
@@ -223,9 +223,7 @@ Distilled from the pixel-error musings
|
|
|
223
223
|
Pinned:
|
|
224
224
|
|
|
225
225
|
- **Error is an object-space distance from the *source* surface**, not a density heuristic
|
|
226
|
-
and not a sum of per-step deviations.
|
|
227
|
-
away, so that a patch consumed whole — which leaves nothing behind to be measured — still
|
|
228
|
-
costs what it cost. Vertex quadrics are built once from the source
|
|
226
|
+
and not a sum of per-step deviations. Vertex quadrics are built once from the source
|
|
229
227
|
triangles and carried through the entire build: a survivor absorbs its victim's quadric at
|
|
230
228
|
every collapse, at every round, so a vertex many rounds up still holds the planes of every
|
|
231
229
|
source triangle folded into it, and evaluating that quadric at its current position
|
|
@@ -234,6 +232,51 @@ Pinned:
|
|
|
234
232
|
`evaluate` is a sum of squared distances whose scale grows with the number of planes in the
|
|
235
233
|
quadric, and its root is not a length. It remains a calibrated measure rather than a proven
|
|
236
234
|
Hausdorff bound (blind to tangential drift), hence the sampled-Hausdorff gate in §3.
|
|
235
|
+
- **It is read at the collapses, per endpoint, and kept as a running maximum** — not as one
|
|
236
|
+
sweep of the surviving vertices at the end of a pass. The weight that makes the number a
|
|
237
|
+
length is also a divisor that grows every time a vertex absorbs another, so a vertex that
|
|
238
|
+
destroyed a feature and then spent the rest of the pass swallowing surface it sits exactly
|
|
239
|
+
on has that feature divided by all of it. The dilution therefore deepens with the DAG, and
|
|
240
|
+
understates most at the coarse levels where the cut spends its budget: measured on a unit
|
|
241
|
+
spike at the centre of a pinned grid, the same spike came back at `0.64` on a 7-vertex grid
|
|
242
|
+
and at `0.040` on a 33-vertex one. Read at each collapse the same spike reads `0.65`–`0.71`
|
|
243
|
+
at every size. Reading the two endpoints apart rather than summed is the same argument one
|
|
244
|
+
collapse at a time — the sum's reading is the weighted mean of the two, which averages a
|
|
245
|
+
small victim's residual into a large survivor's untouched history.
|
|
246
|
+
|
|
247
|
+
Nothing is given up by no longer sweeping the survivors, and it is a domination rather than
|
|
248
|
+
a coincidence. What the sweep reads off a survivor is its *merged* quadric at the placement
|
|
249
|
+
its last collapse chose, and a merged quadric's reading is the weight-weighted mean of its two
|
|
250
|
+
parts' readings at the same point — so it can never exceed the larger of the two already taken
|
|
251
|
+
there. Every value the sweep could report is one this maximum has seen or beaten, and the
|
|
252
|
+
maximum holds the earlier and sharper readings besides. A patch consumed whole, which leaves
|
|
253
|
+
behind a faceless vertex the cleanup then sweeps away, is likewise read at the collapse that
|
|
254
|
+
consumed it.
|
|
255
|
+
|
|
256
|
+
Each pass therefore reports what *its own* collapses cost, and a caller carrying quadrics
|
|
257
|
+
across passes carries the maximum across them too (`vgeo_build_group_step` across its
|
|
258
|
+
attempts, and the child floor below across levels). A vertex that arrives already deviating
|
|
259
|
+
needs no re-reading: that reading is what the pass which placed it there already returned.
|
|
260
|
+
|
|
261
|
+
Superseded: measuring after the pass, "before faceless vertices are cleaned away, so that a
|
|
262
|
+
patch consumed whole still costs what it cost". The measurement point was right about the
|
|
263
|
+
faceless vertex and wrong about everything the sweep threw away to get there.
|
|
264
|
+
- **A plane weighs the surface behind it, as a multiple of the mesh's mean triangle.** The
|
|
265
|
+
mean the error is read as has to be an average over the *surface*; over a plane count it is
|
|
266
|
+
an average over how the surface was cut, and a finely tessellated patch outvotes a coarse
|
|
267
|
+
one many times its size. Cutting one face in two along its own plane is the clean statement
|
|
268
|
+
of the defect — it adds no surface, and the metric heard the same plane twice. Weights are
|
|
269
|
+
ratios rather than areas because everything they are stated against is a ratio (the boundary
|
|
270
|
+
constraint is three *faces*; the attribute quadric summed with these weighs one per
|
|
271
|
+
triangle), and a slot holding square metres would make all of it depend on whether the asset
|
|
272
|
+
was authored in millimetres or kilometres. The reported error is a mean, which divides the
|
|
273
|
+
weights out again, so normalizing costs nothing there; it buys back every calibration.
|
|
274
|
+
|
|
275
|
+
This changes the quadric **matrix**, so it changes the placement solve and not only the
|
|
276
|
+
number — a behavioural change to simplification, landed on its own so it can be attributed.
|
|
277
|
+
`VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS` was calibrated against the diluted reading and is
|
|
278
|
+
**not** re-tuned here; it needs re-tuning against this one, separately.
|
|
279
|
+
|
|
237
280
|
- **Composition across levels does not happen**, and that is the point of carrying quadrics.
|
|
238
281
|
The measured value is already deviation from the source; a step takes `max(measured, max(e
|
|
239
282
|
of child groups))`, where the floor exists only to impose monotonicity — the accumulated
|
|
@@ -1,4 +1,94 @@
|
|
|
1
|
-
# Wedges — plan, 2026-09-18
|
|
1
|
+
# Wedges — plan, 2026-09-18 — **HALF OF IT REVERTED 2026-09-19**
|
|
2
|
+
|
|
3
|
+
> **The partition stayed. The crease angle went.** This document was written as one idea and it is
|
|
4
|
+
> two, and only one of them survived being measured in pixels.
|
|
5
|
+
>
|
|
6
|
+
> **What went: inferring a hard edge from an angle.** `VGEO_CREASE_ANGLE`, 45 degrees, applied
|
|
7
|
+
> where the builder has to *synthesize* a normal because the source authored none. It made a
|
|
8
|
+
> POSITION-only cube ship three normals at each corner instead of one that is 54.7 degrees wrong for
|
|
9
|
+
> every face using it, which is a real improvement to look at. Measured against a true LOD 0
|
|
10
|
+
> reference it bought nothing on any object tested, and on high-frequency relief it *cost*: the
|
|
11
|
+
> attribute quadric's least-squares fit lands near the neighbourhood's mean normal, which is the
|
|
12
|
+
> right filtered answer for a Lambertian surface, and bucketing each tile face on its own returns
|
|
13
|
+
> that one face's normal exactly instead. It was also most of the price — on the pebble-scatter
|
|
14
|
+
> geometry the wedge build cost +3.37% of asset bytes over pre-attribute with the threshold in and
|
|
15
|
+
> +0.97% without it.
|
|
16
|
+
>
|
|
17
|
+
> **What stayed: carrying the shading frame a source actually authored.** `BtWedgeSet`,
|
|
18
|
+
> `vgeo_mesh_wedges`, and the simplifier's wedge bookkeeping. The partition is decided by
|
|
19
|
+
> `loop_data.record_equal()` — byte equality of what the source gave — so it needs no threshold and
|
|
20
|
+
> makes no judgement about content. On a UE5 courtyard gate arch (188,180 triangles, authored
|
|
21
|
+
> normals and UVs), taking it out costs, at **equal drawn cluster count**, mean luminance against
|
|
22
|
+
> that build's own LOD 0:
|
|
23
|
+
>
|
|
24
|
+
> | ue_arch | τ=0.5 | τ=1 | τ=2 | τ=4 |
|
|
25
|
+
> |---|---|---|---|---|
|
|
26
|
+
> | without the partition | +1.18 | +6.50 | +6.91 | +8.82 |
|
|
27
|
+
> | *same build, second page load* | −0.06 | +0.07 | +0.06 | +0.06 |
|
|
28
|
+
>
|
|
29
|
+
> That is 20–27% more error against a noise floor of 0.07, and it reproduces. At τ=0.5, 1 and 2 the
|
|
30
|
+
> build without the partition is not even trading: it draws **more** clusters *and* errs more. Only
|
|
31
|
+
> τ=4 is a real trade (−20% clusters for +27% error), and interpolated it sits on the same curve.
|
|
32
|
+
>
|
|
33
|
+
> **It is a normals result, not a UV one.** The playground binds one untextured grey
|
|
34
|
+
> `StandardShadeMaterial` and samples no maps, so nothing in that table can come from texture
|
|
35
|
+
> coordinates. Seams are carried by the same mechanism and that is worth having, but it is a
|
|
36
|
+
> different question and it is not what was measured here.
|
|
37
|
+
>
|
|
38
|
+
> **And it helps where the frame is synthesized too**, now that the threshold is gone. Corners still
|
|
39
|
+
> group, by connectivity rather than by angle: at a mesh boundary or a non-manifold fin there is no
|
|
40
|
+
> second face to average with, so each side keeps its own normal instead of inventing a join the
|
|
41
|
+
> mesh does not make. On the pebble scatter that costs +0.45% of bytes over having no partition at
|
|
42
|
+
> all, and buys — again at equal drawn clusters, against pre-attribute —
|
|
43
|
+
>
|
|
44
|
+
> | mesh 1400 | τ=0.5 | τ=1 | τ=2 | τ=4 |
|
|
45
|
+
> |---|---|---|---|---|
|
|
46
|
+
> | no partition | +1.55 | +4.87 | +5.42 | +7.08 |
|
|
47
|
+
> | partition, no threshold | +4.95 | **+4.03** | **−2.51** | **−5.30** |
|
|
48
|
+
>
|
|
49
|
+
> Pareto-dominant at τ=1, 2 and 4 — fewer clusters *and* less error — and at the two coarse cuts it
|
|
50
|
+
> beats pre-attribute outright. The finest cut is worse, and that is the honest caveat.
|
|
51
|
+
>
|
|
52
|
+
> **The split is proved by byte identity, not only by pixels.** Built with the threshold removed,
|
|
53
|
+
> the gate arch is byte-identical to the full wedge build (the whole win preserved, nothing else
|
|
54
|
+
> changed), and a UE5 throne-room floor is byte-identical to a build with no wedge code at all.
|
|
55
|
+
>
|
|
56
|
+
> **What this does *not* claim.** Not that the N-dimensional attribute quadrics are themselves a
|
|
57
|
+
> pixel win — measured the same way they are a wash-to-worse on three of five objects, and that
|
|
58
|
+
> deserves its own investigation. Not that Zorah's normals are fine: on a POSITION-only source every
|
|
59
|
+
> normal is synthesized by `vgeo_normalize_source`, area-weighted, after the weld, nothing pinned,
|
|
60
|
+
> so a hard edge cannot exist at *any* level including the finest — that is the flat-looking tiled
|
|
61
|
+
> surface, it is upstream of everything here, and the UE5 rebuild is what fixes it. And not that the
|
|
62
|
+
> cut is free: on that floor, pre-attribute draws 80 clusters where both attribute builds draw 513
|
|
63
|
+
> at the same τ, a 6x difference nobody asked for.
|
|
64
|
+
>
|
|
65
|
+
> **The pixel harness is the other thing worth keeping** (`container_diff.mjs`, scratchpad pattern).
|
|
66
|
+
> Four ways it lied before it worked, each of which had already produced a confident wrong answer:
|
|
67
|
+
>
|
|
68
|
+
> 1. **TAA.** Two captures of one static camera differ by mean 4.0 with *not one pixel identical*.
|
|
69
|
+
> Pinning the jitter is necessary and insufficient — the resolve un-jitters against its own copy,
|
|
70
|
+
> so one run settles to 0.004 and an identical one plateaus at 0.153 forever. Average 16 frames.
|
|
71
|
+
> 2. **Dilution.** The object covered 1–2% of the viewport, so every mean read 0.2–0.7 with p95 of
|
|
72
|
+
> exactly 0.0. Mask to lit pixels and print the coverage.
|
|
73
|
+
> 3. **The stats panel**, which prints the file name and byte counts and so differs per build by
|
|
74
|
+
> construction — and the crop keeping it out was slicing through the object.
|
|
75
|
+
> 4. **Cross-run image diffs are worthless.** The same build in two page loads, with identical
|
|
76
|
+
> `drawn` counts, differs by mean 15–17. Only a build's *own* LOD-0 curve is comparable.
|
|
77
|
+
>
|
|
78
|
+
> A whole scene has no reachable LOD 0 either: below about τ=0.25 the residency budget picks the cut
|
|
79
|
+
> and at τ→0 the renderer stops producing frames, so single containers are the only honest reference.
|
|
80
|
+
>
|
|
81
|
+
> **Compare at equal drawn clusters, never at equal τ**, which is a request and not a price — the
|
|
82
|
+
> wedge build drew 1,085 where pre-attribute drew 772 at the same number on the slider.
|
|
83
|
+
>
|
|
84
|
+
> **Choosing what to measure was half the work.** Three rounds of picking objects out of
|
|
85
|
+
> `object_bounds` gave a pebble scatter, a bare tree and a set of beams, all nearly pure silhouette,
|
|
86
|
+
> and the difference image is then an outline with black interiors — which says nothing about
|
|
87
|
+
> shading, since attribute quadrics trade geometric accuracy for attribute accuracy. Manifest rows
|
|
88
|
+
> are `(mesh, primitive)`; carry the primitive or you build a different object, as a row claiming
|
|
89
|
+
> 289k triangles did when it built 2.04M. The UE5 rebuild's meshes have *names*, which is worth more
|
|
90
|
+
> than any heuristic over bounds.
|
|
91
|
+
|
|
2
92
|
|
|
3
93
|
`ATTRIBUTE_PLAN_2026_09_18.md` §7, taken up. That plan fixed *how a coarse vertex is given its
|
|
4
94
|
shading values*; this one fixes the fact that a vertex can only hold **one set of them**, so every
|
|
@@ -81,19 +81,6 @@ export class VGeoBuildOptions {
|
|
|
81
81
|
* @type {number}
|
|
82
82
|
*/
|
|
83
83
|
weld_ratio: number;
|
|
84
|
-
/**
|
|
85
|
-
* How far two triangles may turn across a shared edge before a **synthesized** normal is split
|
|
86
|
-
* there rather than averaged, in degrees. See {@link VGEO_CREASE_ANGLE}, which is where the
|
|
87
|
-
* default and the measurement behind it live.
|
|
88
|
-
*
|
|
89
|
-
* A build option rather than only a constant because it is the one number in this work that is a
|
|
90
|
-
* judgement about content rather than a consequence of arithmetic: a source of hard-surface
|
|
91
|
-
* props and a source of organic scans want different answers, and a conversion should be able to
|
|
92
|
-
* say which it has.
|
|
93
|
-
*
|
|
94
|
-
* @type {number}
|
|
95
|
-
*/
|
|
96
|
-
crease_angle: number;
|
|
97
84
|
/**
|
|
98
85
|
* Decoded bytes per page, as a **hard cap**: no page of the asset exceeds it, and the container
|
|
99
86
|
* says so with a feature bit a runtime can require (`VGEO_FORMAT.md` §11.14). That is what makes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VGeoBuildOptions.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VGeoBuildOptions.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH;IACI;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,OAFU,MAAM,CAEW;IAE3B;;;;;;;;;;;;;;;;;;OAkBG;IACH,aAFU,MAAM,CAEmB;IAEnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,YAFU,MAAM,CAEE;IAElB;;;;;;;;;;;;;;OAcG;IACH,mBAFU,MAAM,CAE2B;IAE3C;;;;;;;;;;;;;;;;;;;OAmBG;IACH,yBAFU,MAAM,EAAE,CAEqD;IAEvE;;OAEG;IACH,eAFU,gBAAgB,CAEa;CAC1C;iCAnIgC,6BAA6B"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { VGEO_CREASE_ANGLE } from "./mesh/VGEO_CREASE_ANGLE.js";
|
|
2
1
|
import { LZ4_LEVEL } from "../../../../../core/binary/lz4/LZ4_LEVEL.js";
|
|
3
2
|
import { VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS } from "./mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js";
|
|
4
3
|
import { VGEO_CODEC_DEFLATE } from "../format/frame/VGEO_CODEC_DEFLATE.js";
|
|
@@ -91,20 +90,6 @@ export class VGeoBuildOptions {
|
|
|
91
90
|
*/
|
|
92
91
|
weld_ratio = 1e-5;
|
|
93
92
|
|
|
94
|
-
/**
|
|
95
|
-
* How far two triangles may turn across a shared edge before a **synthesized** normal is split
|
|
96
|
-
* there rather than averaged, in degrees. See {@link VGEO_CREASE_ANGLE}, which is where the
|
|
97
|
-
* default and the measurement behind it live.
|
|
98
|
-
*
|
|
99
|
-
* A build option rather than only a constant because it is the one number in this work that is a
|
|
100
|
-
* judgement about content rather than a consequence of arithmetic: a source of hard-surface
|
|
101
|
-
* props and a source of organic scans want different answers, and a conversion should be able to
|
|
102
|
-
* say which it has.
|
|
103
|
-
*
|
|
104
|
-
* @type {number}
|
|
105
|
-
*/
|
|
106
|
-
crease_angle = VGEO_CREASE_ANGLE;
|
|
107
|
-
|
|
108
93
|
/**
|
|
109
94
|
* Decoded bytes per page, as a **hard cap**: no page of the asset exceeds it, and the container
|
|
110
95
|
* says so with a feature bit a runtime can require (`VGEO_FORMAT.md` §11.14). That is what makes
|
|
@@ -248,11 +248,11 @@ export function vgeo_build_group_step(
|
|
|
248
248
|
/**
|
|
249
249
|
* Largest deviation any attempt measured, rather than the last one's.
|
|
250
250
|
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
251
|
+
* Each call reports what *its own* collapses cost ({@link bt_mesh_simplify_with_quadrics}), and
|
|
252
|
+
* the attempts below are one simplification continued rather than several, so no single call's
|
|
253
|
+
* answer is the step's. Carrying the maximum across them is what makes it one. The surface only
|
|
254
|
+
* ever moves further from the source as this loop tightens, so a maximum is also the whole of
|
|
255
|
+
* what is needed — no attempt can undo what an earlier one charged for.
|
|
256
256
|
* @type {number}
|
|
257
257
|
*/
|
|
258
258
|
let deviation = 0;
|
package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts
CHANGED
|
@@ -13,12 +13,22 @@
|
|
|
13
13
|
* A collapse that would smear a crease is charged for it, in units of length, at exactly the rate
|
|
14
14
|
* this names.
|
|
15
15
|
*
|
|
16
|
-
* ## How it was chosen
|
|
16
|
+
* ## How it was chosen — and why that needs doing again
|
|
17
17
|
*
|
|
18
18
|
* Swept from `1e-9` — the term effectively off — to `1/2`, measuring how far the shipped normal field
|
|
19
19
|
* sits from the source's and what happened to `self_error`, which is the number the runtime's cut is
|
|
20
20
|
* driven by.
|
|
21
21
|
*
|
|
22
|
+
* **The `self_error` column below is a reading this metric no longer takes.** It was swept when the
|
|
23
|
+
* error was one post-hoc sweep of the surviving vertices, over quadrics that weighed a plane count —
|
|
24
|
+
* a mean that diluted with DAG depth and tracked tessellation rather than surface. Both are fixed
|
|
25
|
+
* (`VIRTUAL_GEOMETRY_DESIGN.md` §4), which moved the number the sweep was reading and changed the
|
|
26
|
+
* matrix that decides where a collapse puts the vertex, which is what this ratio trades against. The
|
|
27
|
+
* *shape* of the finding is unlikely to have moved — above `1/64` it was not a trade on smooth
|
|
28
|
+
* content by an order of magnitude — but the cliff's position is not known any more, and `1/1024`
|
|
29
|
+
* stands here because it was left deliberately untouched rather than because it has been re-measured
|
|
30
|
+
* against the metric that now ships. Re-sweeping it is its own work.
|
|
31
|
+
*
|
|
22
32
|
* On a 31,874-triangle Zorah primitive, the content the defect was found on:
|
|
23
33
|
*
|
|
24
34
|
* ```
|
package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,mDALU,MAAM,EAAE,CAOhB"}
|
package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js
CHANGED
|
@@ -16,12 +16,22 @@ import { VGEO_ATTRIBUTES } from "../../format/attribute/VGEO_ATTRIBUTES.js";
|
|
|
16
16
|
* A collapse that would smear a crease is charged for it, in units of length, at exactly the rate
|
|
17
17
|
* this names.
|
|
18
18
|
*
|
|
19
|
-
* ## How it was chosen
|
|
19
|
+
* ## How it was chosen — and why that needs doing again
|
|
20
20
|
*
|
|
21
21
|
* Swept from `1e-9` — the term effectively off — to `1/2`, measuring how far the shipped normal field
|
|
22
22
|
* sits from the source's and what happened to `self_error`, which is the number the runtime's cut is
|
|
23
23
|
* driven by.
|
|
24
24
|
*
|
|
25
|
+
* **The `self_error` column below is a reading this metric no longer takes.** It was swept when the
|
|
26
|
+
* error was one post-hoc sweep of the surviving vertices, over quadrics that weighed a plane count —
|
|
27
|
+
* a mean that diluted with DAG depth and tracked tessellation rather than surface. Both are fixed
|
|
28
|
+
* (`VIRTUAL_GEOMETRY_DESIGN.md` §4), which moved the number the sweep was reading and changed the
|
|
29
|
+
* matrix that decides where a collapse puts the vertex, which is what this ratio trades against. The
|
|
30
|
+
* *shape* of the finding is unlikely to have moved — above `1/64` it was not a trade on smooth
|
|
31
|
+
* content by an order of magnitude — but the cliff's position is not known any more, and `1/1024`
|
|
32
|
+
* stands here because it was left deliberately untouched rather than because it has been re-measured
|
|
33
|
+
* against the metric that now ships. Re-sweeping it is its own work.
|
|
34
|
+
*
|
|
25
35
|
* On a 31,874-triangle Zorah primitive, the content the defect was found on:
|
|
26
36
|
*
|
|
27
37
|
* ```
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Area-weighted normals of a mesh,
|
|
2
|
+
* Area-weighted normals of a mesh, written into its normal channel, one per corner.
|
|
3
3
|
*
|
|
4
4
|
* The geometry a mesh actually has is the answer for that mesh: carrying a surviving vertex's
|
|
5
5
|
* original normal through a dozen collapses shades a coarse level by whichever vertices happened to
|
|
6
6
|
* win, which is visibly wrong.
|
|
7
7
|
*
|
|
8
|
-
* **
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* and
|
|
12
|
-
*
|
|
13
|
-
*
|
|
8
|
+
* **It does not invent a crease.** An earlier version of this split a vertex wherever the surface
|
|
9
|
+
* turned more than a threshold, so that a synthesized cube got three normals at each corner instead
|
|
10
|
+
* of one that is ninety degrees wrong for every face using it. That is a real improvement to look
|
|
11
|
+
* at and it did not survive measurement: against a true LOD 0 reference in pixels it bought nothing
|
|
12
|
+
* on any object tested, and on high-frequency relief it *cost*, because the attribute quadric's
|
|
13
|
+
* least-squares fit lands near the neighbourhood's mean normal -- the right filtered answer for a
|
|
14
|
+
* Lambertian surface -- and bucketing each tile face on its own returns that one face's normal
|
|
15
|
+
* exactly instead. So the threshold is gone, and with it the one number in this work that was a
|
|
16
|
+
* judgement about content rather than a consequence of arithmetic.
|
|
17
|
+
*
|
|
18
|
+
* **Corners still group, by connectivity rather than by angle.** Two corners join when a manifold
|
|
19
|
+
* edge joins their faces, so a manifold vertex has exactly one group and this is the pass it has
|
|
20
|
+
* always been, arithmetic included. What the per-corner shape is *for* is the case this pass is not
|
|
21
|
+
* reached in at all: a source that authored its own shading frame, whose distinct corner values the
|
|
22
|
+
* weld would otherwise destroy. That is where wedges are worth their bytes, and it needs no
|
|
23
|
+
* threshold to decide anything.
|
|
14
24
|
*
|
|
15
25
|
* Area weighting falls out of the arithmetic rather than being applied: Newell's normal *is* the
|
|
16
26
|
* face normal scaled by twice the area, so summing the raw face normals is the area-weighted sum.
|
|
@@ -36,10 +46,9 @@
|
|
|
36
46
|
* slot for every live corner by construction
|
|
37
47
|
* @param {Set<number>} pinned vertex ids to leave exactly as they are; empty for a mesh nothing has
|
|
38
48
|
* locked yet
|
|
39
|
-
* @param {number} [crease_angle] degrees; see {@link VGEO_CREASE_ANGLE}
|
|
40
49
|
*
|
|
41
50
|
* @author Alex Goldring
|
|
42
51
|
* @copyright Company Named Limited (c) 2026
|
|
43
52
|
*/
|
|
44
|
-
export function vgeo_compute_vertex_normals(mesh: VirtualGeometryMesh, pinned: Set<number
|
|
53
|
+
export function vgeo_compute_vertex_normals(mesh: VirtualGeometryMesh, pinned: Set<number>): void;
|
|
45
54
|
//# sourceMappingURL=vgeo_compute_vertex_normals.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vgeo_compute_vertex_normals.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"vgeo_compute_vertex_normals.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js"],"names":[],"mappings":"AAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,+EANW,IAAI,MAAM,CAAC,QA+LrB"}
|