@woosh/meep-engine 3.41.0 → 3.42.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/editor/selection/editor_pick.d.ts.map +1 -1
- package/editor/selection/editor_pick.js +2 -1
- package/editor/tools/TransformToolV2.d.ts.map +1 -1
- package/editor/tools/TransformToolV2.js +7 -1
- package/editor/tools/engine/ToolEngine.d.ts.map +1 -1
- package/editor/tools/engine/ToolEngine.js +10 -0
- package/editor/tools/v2/TransformControls.d.ts.map +1 -1
- package/editor/tools/v2/TransformControls.js +7 -20
- package/editor/tools/v2/handle/gizmo_drag_plane.d.ts.map +1 -1
- package/editor/tools/v2/handle/gizmo_drag_plane.js +4 -0
- package/editor/view/ecs/EntityEditor.d.ts.map +1 -1
- package/editor/view/ecs/EntityEditor.js +3 -1
- package/editor/view/node-graph/NodeGraphView.d.ts.map +1 -1
- package/editor/view/node-graph/NodeGraphView.js +28 -12
- package/package.json +1 -1
- package/samples/engine/first-scene/index.html +4 -1
- package/samples/engine/first-scene/main.js +14 -9
- package/src/core/binary/utf8/utf8_decode.js +3 -3
- package/src/core/bvh2/binary/2/bvh32_query_user_data_ray.d.ts.map +1 -1
- package/src/core/bvh2/binary/2/bvh32_query_user_data_ray.js +112 -113
- package/src/core/bvh2/bvh3/ebvh_nodes_sort_sah_local4.js +2 -2
- package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +14 -14
- package/src/core/collection/RingBuffer.d.ts.map +1 -1
- package/src/core/collection/RingBuffer.js +4 -0
- package/src/core/collection/array/array_contains_duplicates.d.ts.map +1 -1
- package/src/core/collection/array/array_contains_duplicates.js +2 -1
- package/src/core/collection/array/array_copy.d.ts.map +1 -1
- package/src/core/collection/array/array_copy.js +23 -0
- package/src/core/collection/array/typed/sparse_typed_array_hash.d.ts +2 -2
- package/src/core/collection/array/typed/sparse_typed_array_hash.d.ts.map +1 -1
- package/src/core/collection/array/typed/sparse_typed_array_hash.js +9 -8
- package/src/core/collection/array/typed/uint16_array_hash.d.ts +2 -2
- package/src/core/collection/array/typed/uint16_array_hash.js +4 -4
- package/src/core/collection/array/typed/uint8_array_hash.d.ts +2 -2
- package/src/core/collection/array/typed/uint8_array_hash.js +4 -4
- package/src/core/collection/array/weightedRandomFromArray.d.ts +1 -0
- package/src/core/collection/array/weightedRandomFromArray.d.ts.map +1 -1
- package/src/core/collection/array/weightedRandomFromArray.js +9 -1
- package/src/core/collection/heap/BinaryHeap.d.ts.map +1 -1
- package/src/core/collection/heap/BinaryHeap.js +4 -0
- package/src/core/collection/list/List.d.ts.map +1 -1
- package/src/core/collection/list/List.js +4 -2
- package/src/core/collection/set/ArraySet.js +1 -1
- package/src/core/collection/set/HashSet.d.ts +1 -1
- package/src/core/collection/set/HashSet.d.ts.map +1 -1
- package/src/core/collection/set/HashSet.js +4 -2
- package/src/core/debug/matchers/IsEqual.js +1 -1
- package/src/core/debug/matchers/IsIterableContaining.d.ts.map +1 -1
- package/src/core/debug/matchers/IsIterableContaining.js +61 -74
- package/src/core/events/signal/SignalBinding.js +101 -101
- package/src/core/function/extractFunctionBody.js +13 -13
- package/src/core/function/objectsEqual.d.ts.map +1 -1
- package/src/core/function/objectsEqual.js +15 -14
- package/src/core/geom/3d/frustum/frustum3_compute_closest_point.d.ts.map +1 -1
- package/src/core/geom/3d/frustum/frustum3_compute_closest_point.js +207 -172
- package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -1
- package/src/core/geom/3d/gjk/gjk_epa_penetration.js +5 -4
- package/src/core/geom/3d/line/line3_compute_segment_point_distance_eikonal.d.ts.map +1 -1
- package/src/core/geom/3d/line/line3_compute_segment_point_distance_eikonal.js +8 -2
- package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts +20 -0
- package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
- package/src/core/geom/3d/triangle/tri3_ray_intersection.js +182 -0
- package/src/core/math/noise/curl_noise_3dt.d.ts.map +1 -1
- package/src/core/math/noise/curl_noise_3dt.js +20 -10
- package/src/core/math/noise/sdnoise.d.ts +16 -5
- package/src/core/math/noise/sdnoise.d.ts.map +1 -1
- package/src/core/math/noise/sdnoise.js +43 -9
- package/src/core/math/spline/spline3_hermite_nearest_point.d.ts +16 -1
- package/src/core/math/spline/spline3_hermite_nearest_point.d.ts.map +1 -1
- package/src/core/math/spline/spline3_hermite_nearest_point.js +44 -3
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +6 -2
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +9 -0
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +26 -0
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +2 -0
- package/src/engine/control/first-person/abilities/AbilitySet.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/AbilitySet.js +9 -0
- package/src/engine/control/first-person/abilities/LedgeGrab.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/LedgeGrab.js +6 -0
- package/src/engine/control/first-person/abilities/Slide.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/Slide.js +1 -0
- package/src/engine/control/first-person/abilities/WallRun.d.ts +4 -1
- package/src/engine/control/first-person/abilities/WallRun.d.ts.map +1 -1
- package/src/engine/control/first-person/abilities/WallRun.js +13 -1
- package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts +1 -1
- package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.d.ts.map +1 -1
- package/src/engine/control/first-person/mastery/SlideInitiationTimingEvaluator.js +6 -5
- package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts +3 -3
- package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.d.ts.map +1 -1
- package/src/engine/control/first-person/mastery/StrideTimingJumpEvaluator.js +9 -8
- package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.d.ts.map +1 -1
- package/src/engine/control/first-person/sensors/FirstPersonSensorsSystem.js +13 -4
- package/src/engine/ecs/EntityManager.d.ts.map +1 -1
- package/src/engine/ecs/EntityManager.js +18 -15
- package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescription.d.ts.map +1 -1
- package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescription.js +2 -1
- package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescriptionTable.d.ts.map +1 -1
- package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescriptionTable.js +1 -0
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +3 -0
- package/src/engine/ecs/parent/EntityNode.js +3 -3
- package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
- package/src/engine/ecs/speaker/VoiceSystem.js +4 -0
- package/src/engine/ecs/storage/BinaryBufferDeSerializer.js +5 -5
- package/src/engine/ecs/storage/binary/BinarySerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/binary/BinarySerializationRegistry.js +3 -2
- package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter2.js +1 -1
- package/src/engine/ecs/storage/binary/object-v2/BinaryObjectDeSerializer.d.ts.map +1 -1
- package/src/engine/ecs/storage/binary/object-v2/BinaryObjectDeSerializer.js +8 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +8 -0
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +5 -2
- package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.js +3 -0
- package/src/engine/ecs/terrain/ecs/splat/SplatMapping.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +1 -0
- package/src/engine/ecs/terrain/overlay/TerrainOverlay.js +1 -1
- package/src/engine/ecs/terrain/tiles/TerrainTile.d.ts.map +1 -1
- package/src/engine/ecs/terrain/tiles/TerrainTile.js +13 -1
- package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts.map +1 -1
- package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +1 -0
- package/src/engine/graphics/ecs/light/LightSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/ecs/light/LightSerializationAdapter.js +13 -1
- package/src/engine/graphics/ecs/light/LightSerializationUpgrader_0_1.d.ts +5 -0
- package/src/engine/graphics/ecs/light/LightSerializationUpgrader_0_1.d.ts.map +1 -0
- package/src/engine/graphics/ecs/light/LightSerializationUpgrader_0_1.js +27 -0
- package/src/engine/graphics/ecs/water/Water.d.ts +11 -0
- package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/Water.js +17 -0
- package/src/engine/graphics/ecs/water/WaterSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/WaterSerializationAdapter.js +3 -1
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_4_5.d.ts +9 -0
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_4_5.d.ts.map +1 -0
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_4_5.js +24 -0
- package/src/engine/graphics/ecs/water/WaterWaves.d.ts +30 -9
- package/src/engine/graphics/ecs/water/WaterWaves.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/WaterWaves.js +41 -9
- package/src/engine/graphics/ecs/water/WaterWavesSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/WaterWavesSerializationAdapter.js +30 -26
- package/src/engine/graphics/ecs/water/WaterWavesSerializationUpgrader_0_1.d.ts +6 -0
- package/src/engine/graphics/ecs/water/WaterWavesSerializationUpgrader_0_1.d.ts.map +1 -0
- package/src/engine/graphics/ecs/water/WaterWavesSerializationUpgrader_0_1.js +22 -0
- package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_raycast.d.ts.map +1 -1
- package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_raycast.js +3 -5
- package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts +20 -0
- package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts.map +1 -1
- package/src/engine/graphics/texture/3d/scs3d_sample_linear3.js +36 -0
- package/src/engine/graphics3/WaterSystem.d.ts +12 -3
- package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/WaterSystem.js +78 -46
- package/src/engine/input/devices/PointerDevice.d.ts.map +1 -1
- package/src/engine/input/devices/PointerDevice.js +29 -4
- package/src/engine/intelligence/behavior/selector/WeightedRandomBehavior.d.ts +1 -0
- package/src/engine/intelligence/behavior/selector/WeightedRandomBehavior.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/selector/WeightedRandomBehavior.js +14 -3
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +12 -3
- package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +8 -2
- package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.d.ts +19 -0
- package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.js +41 -2
- package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.js +9 -3
- package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.js +26 -10
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +3 -6
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +22 -9
- package/src/engine/ui/DraggableAspect.d.ts +5 -1
- package/src/engine/ui/DraggableAspect.d.ts.map +1 -1
- package/src/engine/ui/DraggableAspect.js +61 -4
- package/src/format/image/avif/heif/ItemProperty.d.ts +1 -1
- package/src/format/image/avif/heif/ItemProperty.js +1 -1
- package/src/format/image/png/chunk/png_chunk_decode_iTXt.d.ts.map +1 -1
- package/src/format/image/png/chunk/png_chunk_decode_iTXt.js +17 -6
- package/src/shade/device/mock/SoftwareGPUDevice.d.ts +2 -4
- package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUDevice.js +20 -13
- package/src/shade/playground/skinned_blas_refit/sweep_views.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/sweep_views.js +2 -1
- package/src/shade/playground/water_refraction/README.md +10 -11
- package/src/shade/playground/water_refraction/main.js +9 -8
- package/src/shade/playground/water_refraction/world.js +1 -1
- package/src/shade/playground/water_surface/README.md +43 -0
- package/src/shade/playground/water_surface/index.html +30 -0
- package/src/shade/playground/water_surface/main.d.ts +2 -0
- package/src/shade/playground/water_surface/main.d.ts.map +1 -0
- package/src/shade/playground/water_surface/main.js +154 -0
- package/src/shade/playground/water_surface/world.d.ts +44 -0
- package/src/shade/playground/water_surface/world.d.ts.map +1 -0
- package/src/shade/playground/water_surface/world.js +160 -0
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +5 -0
- package/src/shade/renderer/binding/BufferBinding.js +2 -2
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +5 -3
- package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.d.ts +10 -3
- package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.js +17 -9
- package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +3 -0
- package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +1 -1
- package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +16 -0
- package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +2 -0
- package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +1 -1
- package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +11 -0
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts +1 -1
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +9 -3
- package/src/shade/renderer/geometry/util/geometry_simplify_redundant_topology.d.ts.map +1 -1
- package/src/shade/renderer/geometry/util/geometry_simplify_redundant_topology.js +2 -2
- 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 +85 -0
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +12 -6
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +7 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +3 -1
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +2 -1
- package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128_inverse.d.ts +13 -0
- package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128_inverse.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128_inverse.js +42 -0
- package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128x4_inverse_workgroup.d.ts +15 -0
- package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128x4_inverse_workgroup.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/math/fft/chunk_fft128x4_inverse_workgroup.js +39 -0
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +2 -0
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts +15 -0
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
- package/src/shade/renderer/water/GPUWaterRenderer.js +110 -30
- package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +16 -8
- package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
- package/src/shade/renderer/water/medium/GPUWaterBodies.js +31 -26
- package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts +0 -1
- package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts.map +1 -1
- package/src/shade/renderer/water/medium/shader_water_meshlets.js +1 -39
- package/src/shade/renderer/water/shader_water.d.ts +0 -1
- package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
- package/src/shade/renderer/water/shader_water.js +201 -72
- package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts +70 -0
- package/src/shade/renderer/water/surface/GPUWaterSurface.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/GPUWaterSurface.js +199 -0
- package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts +5 -2
- package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.js +32 -12
- package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +22 -0
- package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +217 -0
- package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +65 -11
- package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/graph_water_tessellation.js +163 -28
- package/src/shade/renderer/water/surface/lod/WATER_LOD.d.ts +51 -0
- package/src/shade/renderer/water/surface/lod/WATER_LOD.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/lod/WATER_LOD.js +95 -0
- package/src/shade/renderer/water/surface/lod/chunk_water_lod.d.ts +10 -0
- package/src/shade/renderer/water/surface/lod/chunk_water_lod.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/lod/chunk_water_lod.js +127 -0
- package/src/shade/renderer/water/surface/lod/chunk_water_lod_cell.d.ts +17 -0
- package/src/shade/renderer/water/surface/lod/chunk_water_lod_cell.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/lod/chunk_water_lod_cell.js +246 -0
- package/src/shade/renderer/water/surface/lod/shader_water_lod.d.ts +118 -0
- package/src/shade/renderer/water/surface/lod/shader_water_lod.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/lod/shader_water_lod.js +727 -0
- package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts +60 -0
- package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +228 -0
- package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts +17 -0
- package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +49 -0
- package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +22 -0
- package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +143 -0
- package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +15 -0
- package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +121 -0
- package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +83 -0
- package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/particles/shader_water_particles.js +502 -0
- package/src/shade/renderer/water/surface/shader_water_cull.d.ts +42 -0
- package/src/shade/renderer/water/surface/shader_water_cull.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/shader_water_cull.js +269 -0
- package/src/shade/renderer/water/surface/shader_water_waves_combine.d.ts +15 -0
- package/src/shade/renderer/water/surface/shader_water_waves_combine.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/shader_water_waves_combine.js +73 -0
- package/src/shade/renderer/water/surface/shader_water_waves_derive.d.ts +11 -0
- package/src/shade/renderer/water/surface/shader_water_waves_derive.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/shader_water_waves_derive.js +78 -0
- package/src/shade/renderer/water/surface/spectrum/GPUWaterSpectrum.d.ts +35 -0
- package/src/shade/renderer/water/surface/spectrum/GPUWaterSpectrum.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/spectrum/GPUWaterSpectrum.js +103 -0
- package/src/shade/renderer/water/surface/spectrum/WATER_BAND_STATE.d.ts +22 -0
- package/src/shade/renderer/water/surface/spectrum/WATER_BAND_STATE.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/spectrum/WATER_BAND_STATE.js +57 -0
- package/src/shade/renderer/water/surface/spectrum/WATER_SPECTRUM.d.ts +22 -0
- package/src/shade/renderer/water/surface/spectrum/WATER_SPECTRUM.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/spectrum/WATER_SPECTRUM.js +25 -0
- package/src/shade/renderer/water/surface/spectrum/chunk_water_jonswap.d.ts +14 -0
- package/src/shade/renderer/water/surface/spectrum/chunk_water_jonswap.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/spectrum/chunk_water_jonswap.js +48 -0
- package/src/shade/renderer/water/surface/spectrum/chunk_water_spectrum.d.ts +23 -0
- package/src/shade/renderer/water/surface/spectrum/chunk_water_spectrum.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/spectrum/chunk_water_spectrum.js +169 -0
- package/src/shade/renderer/water/surface/spectrum/shader_water_spectrum.d.ts +26 -0
- package/src/shade/renderer/water/surface/spectrum/shader_water_spectrum.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/spectrum/shader_water_spectrum.js +161 -0
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +18 -6
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +11 -3
- package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.d.ts +0 -28
- package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.d.ts.map +0 -1
- package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.js +0 -86
- package/src/engine/ecs/storage/binary/object-v2/serializerTestHarness.d.ts +0 -29
- package/src/engine/ecs/storage/binary/object-v2/serializerTestHarness.d.ts.map +0 -1
- package/src/engine/ecs/storage/binary/object-v2/serializerTestHarness.js +0 -44
- package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts +0 -4
- package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts.map +0 -1
- package/src/shade/renderer/water/medium/shader_water_bodies_derive.js +0 -32
- package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts +0 -25
- package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.js +0 -128
- package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts +0 -9
- package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/chunk_water_tessellation.js +0 -144
- package/src/shade/renderer/water/surface/chunk_water_wave.d.ts +0 -13
- package/src/shade/renderer/water/surface/chunk_water_wave.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/chunk_water_wave.js +0 -40
- package/src/shade/renderer/water/surface/shader_water_tiles.d.ts +0 -4
- package/src/shade/renderer/water/surface/shader_water_tiles.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/shader_water_tiles.js +0 -123
- package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts +0 -6
- package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/shader_water_wave_batch.js +0 -85
- package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts +0 -6
- package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/shader_water_wave_domain.js +0 -83
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
|
|
2
|
+
import { atomic_u32, u32 } from "../../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
3
|
+
import { WebGPUArray } from "../../../shader/type/WebGPUArray.js";
|
|
4
|
+
import { WebGPUStruct } from "../../../shader/type/WebGPUStruct.js";
|
|
5
|
+
import { chunk_water_spectrum } from "./chunk_water_spectrum.js";
|
|
6
|
+
import { WATER_SPECTRUM_BAND_COUNT } from "./WATER_SPECTRUM.js";
|
|
7
|
+
|
|
8
|
+
/** The bits of every band. */
|
|
9
|
+
export const WATER_SPECTRUM_ALL_BANDS = (1 << WATER_SPECTRUM_BAND_COUNT) - 1;
|
|
10
|
+
|
|
11
|
+
const fields = (word) => ({
|
|
12
|
+
/** Bands whose tiles hold the time of the last evaluation. */
|
|
13
|
+
valid: word,
|
|
14
|
+
/** Bands the frame's spectrum passes evaluate: asked for and not valid. */
|
|
15
|
+
todo: word,
|
|
16
|
+
reserved_a: word,
|
|
17
|
+
reserved_b: word,
|
|
18
|
+
/**
|
|
19
|
+
* Per band, the largest |h| and |(Dx, Dz)| it has shown at any time evaluated on this device (f32 bits).
|
|
20
|
+
* Never cleared: a band is one fixed realisation, so this is a property of the band.
|
|
21
|
+
*/
|
|
22
|
+
envelope: WebGPUArray.from(word, 2 * WATER_SPECTRUM_BAND_COUNT),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* What the device's band spectrum knows about its bands, persistent across frames
|
|
27
|
+
* (WATER_SURFACE_DISTANCE_LOD_PROPOSAL_2026_10_06.md §3.1). Read with plain loads by the passes that only read it —
|
|
28
|
+
* the culling pass reads every envelope for every body — and atomically by the passes that write it.
|
|
29
|
+
*/
|
|
30
|
+
export const WATER_BAND_STATE_STRUCT = WebGPUStruct.from(fields(u32), 'WaterBandState');
|
|
31
|
+
|
|
32
|
+
/** The same state where the passes that write it take it, every word atomic. */
|
|
33
|
+
export const WATER_BAND_STATE_ATOMIC_STRUCT = WebGPUStruct.from(fields(atomic_u32), 'WaterBandStateAtomic');
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The bands the frame's visible bodies can draw, ORed in by the culling pass and taken by its finalize: apart from the
|
|
37
|
+
* band state, so that the culling pass reads that with plain loads.
|
|
38
|
+
*/
|
|
39
|
+
export const WATER_BAND_REQUESTS_STRUCT = WebGPUStruct.from({
|
|
40
|
+
needed: atomic_u32, reserved_a: u32, reserved_b: u32, reserved_c: u32,
|
|
41
|
+
}, 'WaterBandRequests');
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @type {CodeChunk}
|
|
45
|
+
*/
|
|
46
|
+
export const chunk_water_band_state = CodeChunk.from(/* language=WGSL */ `
|
|
47
|
+
// The n-th band set in mask, counting from band 0; WATER_SPECTRUM_BANDS when it has fewer.
|
|
48
|
+
fn water_band_nth(mask: u32, n: u32) -> u32 {
|
|
49
|
+
var remaining = n;
|
|
50
|
+
for (var band = 0u; band < WATER_SPECTRUM_BANDS; band++) {
|
|
51
|
+
if ((mask & (1u << band)) == 0u) { continue; }
|
|
52
|
+
if (remaining == 0u) { return band; }
|
|
53
|
+
remaining--;
|
|
54
|
+
}
|
|
55
|
+
return WATER_SPECTRUM_BANDS;
|
|
56
|
+
}
|
|
57
|
+
`, [chunk_water_spectrum]);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Octave bands of the shared ambient-wave basis (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §4.1).
|
|
3
|
+
*
|
|
4
|
+
* Band j holds waves of wavelength λⱼ/2 … 2λⱼ around its node λⱼ = SHORTEST · 2ʲ, on a periodic tile of
|
|
5
|
+
* 16 node wavelengths. Every water body's ambient waves are a weighted sum of the same bands.
|
|
6
|
+
*/
|
|
7
|
+
export const WATER_SPECTRUM_BAND_COUNT: 18;
|
|
8
|
+
/** Node wavelength of band 0, metres: 7.8 mm, capillary ripples. Band 17 is 1,024 m swell. */
|
|
9
|
+
export const WATER_SPECTRUM_SHORTEST_WAVELENGTH: number;
|
|
10
|
+
/**
|
|
11
|
+
* Texels per side of a band's tile. Its content sits at mode indices 8 … 32, so the band's shortest waves keep four
|
|
12
|
+
* texels a wavelength under bilinear sampling.
|
|
13
|
+
*/
|
|
14
|
+
export const WATER_SPECTRUM_TILE_SIZE: 128;
|
|
15
|
+
/** A band's tile period in node wavelengths: the node sits at mode index 16. */
|
|
16
|
+
export const WATER_SPECTRUM_TILE_WAVELENGTHS: 16;
|
|
17
|
+
/**
|
|
18
|
+
* Angular frequencies are quantized to multiples of 2π / this many seconds, so every wave repeats
|
|
19
|
+
* after it and the phase can be taken from `time mod LOOP` at full f32 precision (Tessendorf 2001 §3.3).
|
|
20
|
+
*/
|
|
21
|
+
export const WATER_SPECTRUM_LOOP_SECONDS: 1024;
|
|
22
|
+
//# sourceMappingURL=WATER_SPECTRUM.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WATER_SPECTRUM.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/water/surface/spectrum/WATER_SPECTRUM.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,2CAA4C;AAE5C,8FAA8F;AAC9F,wDAA0D;AAE1D;;;GAGG;AACH,2CAA4C;AAE5C,gFAAgF;AAChF,iDAAkD;AAElD;;;GAGG;AACH,+CAAgD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Octave bands of the shared ambient-wave basis (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §4.1).
|
|
3
|
+
*
|
|
4
|
+
* Band j holds waves of wavelength λⱼ/2 … 2λⱼ around its node λⱼ = SHORTEST · 2ʲ, on a periodic tile of
|
|
5
|
+
* 16 node wavelengths. Every water body's ambient waves are a weighted sum of the same bands.
|
|
6
|
+
*/
|
|
7
|
+
export const WATER_SPECTRUM_BAND_COUNT = 18;
|
|
8
|
+
|
|
9
|
+
/** Node wavelength of band 0, metres: 7.8 mm, capillary ripples. Band 17 is 1,024 m swell. */
|
|
10
|
+
export const WATER_SPECTRUM_SHORTEST_WAVELENGTH = 1 / 128;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Texels per side of a band's tile. Its content sits at mode indices 8 … 32, so the band's shortest waves keep four
|
|
14
|
+
* texels a wavelength under bilinear sampling.
|
|
15
|
+
*/
|
|
16
|
+
export const WATER_SPECTRUM_TILE_SIZE = 128;
|
|
17
|
+
|
|
18
|
+
/** A band's tile period in node wavelengths: the node sits at mode index 16. */
|
|
19
|
+
export const WATER_SPECTRUM_TILE_WAVELENGTHS = 16;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Angular frequencies are quantized to multiples of 2π / this many seconds, so every wave repeats
|
|
23
|
+
* after it and the phase can be taken from `time mod LOOP` at full f32 precision (Tessendorf 2001 §3.3).
|
|
24
|
+
*/
|
|
25
|
+
export const WATER_SPECTRUM_LOOP_SECONDS = 1024;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A wind sea's spectrum from its wind and fetch: JONSWAP (Hasselmann et al. 1973) with the fetch relations
|
|
3
|
+
* as Horvath 2015 restates them, clamped at the fully developed (Pierson–Moskowitz) sea, and turned into a
|
|
4
|
+
* wavenumber spectrum through the gravity–capillary dispersion relation the band basis uses
|
|
5
|
+
* (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §4.2).
|
|
6
|
+
*
|
|
7
|
+
* Above the peak the saturation k³F(k) is α/2 for gravity waves, so the band weights carry measured
|
|
8
|
+
* sea-surface slopes without a fitted term.
|
|
9
|
+
*
|
|
10
|
+
* @type {CodeChunk}
|
|
11
|
+
*/
|
|
12
|
+
export const chunk_water_jonswap: CodeChunk;
|
|
13
|
+
import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
|
|
14
|
+
//# sourceMappingURL=chunk_water_jonswap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk_water_jonswap.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/water/surface/spectrum/chunk_water_jonswap.js"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,kCAFU,SAAS,CAmCQ;0BA/CD,uCAAuC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
|
|
2
|
+
import { chunk_water_spectrum } from "./chunk_water_spectrum.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A wind sea's spectrum from its wind and fetch: JONSWAP (Hasselmann et al. 1973) with the fetch relations
|
|
6
|
+
* as Horvath 2015 restates them, clamped at the fully developed (Pierson–Moskowitz) sea, and turned into a
|
|
7
|
+
* wavenumber spectrum through the gravity–capillary dispersion relation the band basis uses
|
|
8
|
+
* (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §4.2).
|
|
9
|
+
*
|
|
10
|
+
* Above the peak the saturation k³F(k) is α/2 for gravity waves, so the band weights carry measured
|
|
11
|
+
* sea-surface slopes without a fitted term.
|
|
12
|
+
*
|
|
13
|
+
* @type {CodeChunk}
|
|
14
|
+
*/
|
|
15
|
+
export const chunk_water_jonswap = CodeChunk.from(/* language=WGSL */ `
|
|
16
|
+
struct WaterJonswap {
|
|
17
|
+
// peak angular frequency, rad/s
|
|
18
|
+
peak: f32,
|
|
19
|
+
// Phillips' constant
|
|
20
|
+
alpha: f32,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Wind speed U at 10 m (m/s) and fetch F (m). Dimensionless fetch X = gF/U²: the peak and α fall with
|
|
24
|
+
// fetch until the sea is fully developed near X ≈ 2·10⁴ (ω_p = 0.855 g/U, α = 0.0081).
|
|
25
|
+
fn water_jonswap(wind_speed: f32, fetch: f32) -> WaterJonswap {
|
|
26
|
+
let x = max(WATER_GRAVITY * fetch / max(wind_speed * wind_speed, 1e-12), 1e-6);
|
|
27
|
+
let peak = max(22.0 * WATER_GRAVITY / max(wind_speed, 1e-6) * pow(x, -1.0 / 3.0), 0.855 * WATER_GRAVITY / max(wind_speed, 1e-6));
|
|
28
|
+
let alpha = clamp(0.076 * pow(x, -0.22), 0.0081, 0.1);
|
|
29
|
+
return WaterJonswap(peak, alpha);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Saturation B(k) = k³ F(k) of the sea at wavenumber k, F(k) = S(ω) dω/dk.
|
|
33
|
+
fn water_jonswap_saturation(sea: WaterJonswap, k: f32) -> f32 {
|
|
34
|
+
let omega = water_dispersion(k);
|
|
35
|
+
let ratio = sea.peak / omega;
|
|
36
|
+
let sigma = select(0.09, 0.07, omega <= sea.peak);
|
|
37
|
+
let deviation = (omega - sea.peak) / (sigma * sea.peak);
|
|
38
|
+
let enhancement = pow(3.3, exp(-0.5 * deviation * deviation));
|
|
39
|
+
let r2 = ratio * ratio;
|
|
40
|
+
// S(ω) ω⁵ / (α g²): exp(−5/4 (ω_p/ω)⁴) γ^r
|
|
41
|
+
let shape = exp(-1.25 * r2 * r2) * enhancement;
|
|
42
|
+
// k³ · α g² ω⁻⁵ · shape · dω/dk with dω/dk = (g + 3τk²) / 2ω, written through q = gk/ω² (1 for
|
|
43
|
+
// gravity waves, below 1 where surface tension stiffens them) so no power of ω leaves f32
|
|
44
|
+
let w2 = omega * omega;
|
|
45
|
+
let q = WATER_GRAVITY * k / w2;
|
|
46
|
+
return sea.alpha * shape * q * q * k * (WATER_GRAVITY + 3.0 * WATER_SURFACE_TENSION * k * k) / (2.0 * w2);
|
|
47
|
+
}
|
|
48
|
+
`, [chunk_water_spectrum]);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exponent s of the directional spreading cos^2s(θ/2) shared by every band. Hasselmann's s is ~10 at a
|
|
3
|
+
* sea's peak and falls towards 1 far above it; a basis shared by every body cannot follow each body's
|
|
4
|
+
* peak, so one value between the two is used (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §4.1).
|
|
5
|
+
*/
|
|
6
|
+
export const WATER_SPECTRUM_SPREADING: 6;
|
|
7
|
+
/**
|
|
8
|
+
* The band basis of the ambient waves: where each band sits in wavelength, how its waves move, and the
|
|
9
|
+
* statistics of its unit-saturation spectrum (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §4).
|
|
10
|
+
*
|
|
11
|
+
* Band j's tile is periodic over `water_band_period(j)` metres. Its waves travel, on average, towards
|
|
12
|
+
* `water_band_wind_angle(j)` in the tile's own frame: every band is turned by a further golden angle,
|
|
13
|
+
* so no two bands repeat in step. A sampler turns the tile so that angle points along a body's wind.
|
|
14
|
+
*
|
|
15
|
+
* The band's variance spectrum is the saturation spectrum B(k) = k³F(k) = 1 times φⱼ(k)², a hat in
|
|
16
|
+
* log₂ k over the two octaves around the node, so neighbouring bands' weights sum to one and a body's
|
|
17
|
+
* spectrum, Σ wⱼ² φⱼ², is its saturation spectrum interpolated linearly in log k between nodes.
|
|
18
|
+
*
|
|
19
|
+
* @type {CodeChunk}
|
|
20
|
+
*/
|
|
21
|
+
export const chunk_water_spectrum: CodeChunk;
|
|
22
|
+
import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
|
|
23
|
+
//# sourceMappingURL=chunk_water_spectrum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk_water_spectrum.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/water/surface/spectrum/chunk_water_spectrum.js"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,yCAA0C;AAc1C;;;;;;;;;;;;;GAaG;AACH,mCAFU,SAAS,CA8HyB;0BAxKlB,uCAAuC"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
|
|
2
|
+
import { GOLDEN_ANGLE_DECLARATION } from "../../../shader/chunk/math/GOLDEN_ANGLE_DECLARATION.js";
|
|
3
|
+
import { chunk_pcg3d } from "../../../shader/chunk/random/pcg/chunk_pcg3d.js";
|
|
4
|
+
import {
|
|
5
|
+
WATER_SPECTRUM_BAND_COUNT,
|
|
6
|
+
WATER_SPECTRUM_LOOP_SECONDS,
|
|
7
|
+
WATER_SPECTRUM_SHORTEST_WAVELENGTH,
|
|
8
|
+
WATER_SPECTRUM_TILE_SIZE,
|
|
9
|
+
WATER_SPECTRUM_TILE_WAVELENGTHS
|
|
10
|
+
} from "./WATER_SPECTRUM.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Exponent s of the directional spreading cos^2s(θ/2) shared by every band. Hasselmann's s is ~10 at a
|
|
14
|
+
* sea's peak and falls towards 1 far above it; a basis shared by every body cannot follow each body's
|
|
15
|
+
* peak, so one value between the two is used (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §4.1).
|
|
16
|
+
*/
|
|
17
|
+
export const WATER_SPECTRUM_SPREADING = 6;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 1 / ∫ cos^2s(θ/2) dθ over a full turn, = (4^s (s!)²) / (2π (2s)!) for integer s.
|
|
21
|
+
* @param {number} s
|
|
22
|
+
* @returns {number}
|
|
23
|
+
*/
|
|
24
|
+
function spreading_normalization(s) {
|
|
25
|
+
let factorial = 1, double_factorial = 1;
|
|
26
|
+
for (let i = 2; i <= s; i++) { factorial *= i; }
|
|
27
|
+
for (let i = 2; i <= 2 * s; i++) { double_factorial *= i; }
|
|
28
|
+
return (4 ** s) * factorial * factorial / (2 * Math.PI * double_factorial);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The band basis of the ambient waves: where each band sits in wavelength, how its waves move, and the
|
|
33
|
+
* statistics of its unit-saturation spectrum (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §4).
|
|
34
|
+
*
|
|
35
|
+
* Band j's tile is periodic over `water_band_period(j)` metres. Its waves travel, on average, towards
|
|
36
|
+
* `water_band_wind_angle(j)` in the tile's own frame: every band is turned by a further golden angle,
|
|
37
|
+
* so no two bands repeat in step. A sampler turns the tile so that angle points along a body's wind.
|
|
38
|
+
*
|
|
39
|
+
* The band's variance spectrum is the saturation spectrum B(k) = k³F(k) = 1 times φⱼ(k)², a hat in
|
|
40
|
+
* log₂ k over the two octaves around the node, so neighbouring bands' weights sum to one and a body's
|
|
41
|
+
* spectrum, Σ wⱼ² φⱼ², is its saturation spectrum interpolated linearly in log k between nodes.
|
|
42
|
+
*
|
|
43
|
+
* @type {CodeChunk}
|
|
44
|
+
*/
|
|
45
|
+
export const chunk_water_spectrum = CodeChunk.from(/* language=WGSL */ `
|
|
46
|
+
const WATER_SPECTRUM_BANDS: u32 = ${WATER_SPECTRUM_BAND_COUNT}u;
|
|
47
|
+
const WATER_SPECTRUM_TILE: u32 = ${WATER_SPECTRUM_TILE_SIZE}u;
|
|
48
|
+
const WATER_SPECTRUM_SHORTEST: f32 = ${WATER_SPECTRUM_SHORTEST_WAVELENGTH};
|
|
49
|
+
const WATER_SPECTRUM_TILE_WAVELENGTHS: f32 = ${WATER_SPECTRUM_TILE_WAVELENGTHS}.0;
|
|
50
|
+
const WATER_SPECTRUM_LOOP: f32 = ${WATER_SPECTRUM_LOOP_SECONDS}.0;
|
|
51
|
+
const WATER_SPECTRUM_SPREADING: f32 = ${WATER_SPECTRUM_SPREADING}.0;
|
|
52
|
+
const WATER_SPECTRUM_SPREADING_NORMALIZATION: f32 = ${spreading_normalization(WATER_SPECTRUM_SPREADING)};
|
|
53
|
+
const WATER_GRAVITY: f32 = 9.81;
|
|
54
|
+
// surface tension over density, m³/s²
|
|
55
|
+
const WATER_SURFACE_TENSION: f32 = 7.28e-5;
|
|
56
|
+
const WATER_TAU: f32 = 6.28318530717958;
|
|
57
|
+
|
|
58
|
+
fn water_band_wavelength(band: u32) -> f32 {
|
|
59
|
+
return WATER_SPECTRUM_SHORTEST * exp2(f32(band));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
fn water_band_period(band: u32) -> f32 {
|
|
63
|
+
return WATER_SPECTRUM_TILE_WAVELENGTHS * water_band_wavelength(band);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
fn water_band_wind_angle(band: u32) -> f32 {
|
|
67
|
+
return f32(band) * GOLDEN_ANGLE;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Deep-water gravity–capillary angular frequency of wavenumber k (rad/m).
|
|
71
|
+
fn water_dispersion(k: f32) -> f32 {
|
|
72
|
+
return sqrt(WATER_GRAVITY * k + WATER_SURFACE_TENSION * k * k * k);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// The band's share of a saturation spectrum at wavenumber k: a hat in log₂ k, one at the node,
|
|
76
|
+
// zero an octave either side.
|
|
77
|
+
fn water_band_hat(band: u32, k: f32) -> f32 {
|
|
78
|
+
let node = WATER_TAU / water_band_wavelength(band);
|
|
79
|
+
return max(1.0 - abs(log2(k / node)), 0.0);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Directional spreading about the band's wind, normalized over a full turn.
|
|
83
|
+
fn water_band_spreading(band: u32, direction: vec2<f32>) -> f32 {
|
|
84
|
+
let wind = water_band_wind_angle(band);
|
|
85
|
+
let c = clamp(dot(direction, vec2<f32>(cos(wind), sin(wind))), -1.0, 1.0);
|
|
86
|
+
// cos²(θ/2) = (1 + cos θ) / 2
|
|
87
|
+
return WATER_SPECTRUM_SPREADING_NORMALIZATION * pow(0.5 * (1.0 + c), WATER_SPECTRUM_SPREADING);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// The mode at tile index (x, z), signed: indices 32..63 are the negative wavenumbers.
|
|
91
|
+
fn water_band_mode(index: vec2<u32>) -> vec2<i32> {
|
|
92
|
+
return vec2<i32>(index) - select(vec2<i32>(0), vec2<i32>(i32(WATER_SPECTRUM_TILE)), index >= vec2<u32>(WATER_SPECTRUM_TILE / 2u));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Real amplitude of a mode, for a complex standard normal of E|ξ|² = 2: the square root of the band's
|
|
96
|
+
// directional variance spectrum Ψ(k) = φ² k⁻⁴ D(θ) over the mode's cell, Δk².
|
|
97
|
+
fn water_band_mode_amplitude(band: u32, mode: vec2<i32>) -> f32 {
|
|
98
|
+
if (all(mode == vec2<i32>(0))) { return 0.0; }
|
|
99
|
+
let dk = WATER_TAU / water_band_period(band);
|
|
100
|
+
let k = vec2<f32>(mode) * dk;
|
|
101
|
+
let magnitude = length(k);
|
|
102
|
+
let hat = water_band_hat(band, magnitude);
|
|
103
|
+
if (hat <= 0.0) { return 0.0; }
|
|
104
|
+
return sqrt(hat * water_band_spreading(band, k / magnitude)) * dk / (magnitude * magnitude);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// A complex standard normal for the mode, E|ξ|² = 2, the same every frame and on every device.
|
|
108
|
+
fn water_band_gaussian(band: u32, mode: vec2<i32>) -> vec2<f32> {
|
|
109
|
+
let bits = pcg3d(vec3<u32>(band, bitcast<u32>(mode.x), bitcast<u32>(mode.y)));
|
|
110
|
+
let u1 = (f32(bits.x >> 8u) + 0.5) * (1.0 / 16777216.0);
|
|
111
|
+
let u2 = f32(bits.y >> 8u) * (1.0 / 16777216.0);
|
|
112
|
+
let radius = sqrt(-2.0 * log(u1));
|
|
113
|
+
return radius * vec2<f32>(cos(WATER_TAU * u2), sin(WATER_TAU * u2));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// The mode's phase ωt with ω quantized to whole turns per loop, so the phase can come from the time
|
|
117
|
+
// within the loop, given as a fraction of it.
|
|
118
|
+
fn water_band_mode_phase(k: f32, loop_fraction: f32) -> f32 {
|
|
119
|
+
let turns = round(water_dispersion(k) * WATER_SPECTRUM_LOOP / WATER_TAU);
|
|
120
|
+
return WATER_TAU * fract(turns * loop_fraction);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// The height spectrum h̃(k, t) of a mode, Hermitian in k so the field is real:
|
|
124
|
+
// ½ [ξ(k) A(k) e^{−iωt} + conj(ξ(−k) A(−k)) e^{iωt}]. Under the transform's e^{ik·x}, the first term is
|
|
125
|
+
// e^{i(k·x − ωt)}, a wave travelling towards k, so the energy A(k) puts along the wind travels downwind; the
|
|
126
|
+
// second is the partner that makes the field real, and travels downwind too.
|
|
127
|
+
fn water_band_height(band: u32, mode: vec2<i32>, loop_fraction: f32) -> vec2<f32> {
|
|
128
|
+
let a = water_band_gaussian(band, mode) * water_band_mode_amplitude(band, mode);
|
|
129
|
+
let b = water_band_gaussian(band, -mode) * water_band_mode_amplitude(band, -mode);
|
|
130
|
+
let dk = WATER_TAU / water_band_period(band);
|
|
131
|
+
let phase = water_band_mode_phase(length(vec2<f32>(mode)) * dk, loop_fraction);
|
|
132
|
+
let rotation = vec2<f32>(cos(phase), -sin(phase));
|
|
133
|
+
// a · e^{−iφ}
|
|
134
|
+
let forward = vec2<f32>(a.x * rotation.x - a.y * rotation.y, a.x * rotation.y + a.y * rotation.x);
|
|
135
|
+
// conj(b) · e^{iφ} = conj(b · e^{−iφ})
|
|
136
|
+
let backward = vec2<f32>(b.x * rotation.x - b.y * rotation.y, -(b.x * rotation.y + b.y * rotation.x));
|
|
137
|
+
return 0.5 * (forward + backward);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// A mode's four complex spectra, each two real fields as A + iB so one inverse transform yields both:
|
|
141
|
+
// (h, Dx), (Dz, ∂h/∂x), (∂h/∂z, ∂Dx/∂x), (∂Dz/∂z, ∂Dx/∂z) — height, horizontal displacement and the
|
|
142
|
+
// derivatives a normal and a Jacobian need.
|
|
143
|
+
struct WaterBandFields {
|
|
144
|
+
a: vec2<f32>,
|
|
145
|
+
b: vec2<f32>,
|
|
146
|
+
c: vec2<f32>,
|
|
147
|
+
d: vec2<f32>,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
fn water_band_fields(band: u32, mode: vec2<i32>, loop_fraction: f32) -> WaterBandFields {
|
|
151
|
+
let h = water_band_height(band, mode, loop_fraction);
|
|
152
|
+
let k = vec2<f32>(mode) * (WATER_TAU / water_band_period(band));
|
|
153
|
+
let magnitude = max(length(k), 1e-30);
|
|
154
|
+
// Horizontal displacement D̃ = i (k/k) h̃: for h = cos(k·x), D = −sin(k·x) k/k, so points slide towards a
|
|
155
|
+
// crest and away from a trough — a Gerstner wave's pinched crests, and the wave particles' sign.
|
|
156
|
+
var fields: WaterBandFields;
|
|
157
|
+
// h̃ + i·D̃x = h̃ (1 − kx/k)
|
|
158
|
+
fields.a = h * (1.0 - k.x / magnitude);
|
|
159
|
+
// D̃z + i·(∂h/∂x)~ = h̃ · (−kx + i kz/k)
|
|
160
|
+
fields.b = vec2<f32>(-k.x * h.x - k.y / magnitude * h.y, -k.x * h.y + k.y / magnitude * h.x);
|
|
161
|
+
// (∂h/∂z)~ + i·(∂Dx/∂x)~ = h̃ · i (kz − kx²/k)
|
|
162
|
+
let s = k.y - k.x * k.x / magnitude;
|
|
163
|
+
fields.c = vec2<f32>(-s * h.y, s * h.x);
|
|
164
|
+
// (∂Dz/∂z)~ + i·(∂Dx/∂z)~ = h̃ · −(kz²/k + i kx kz/k)
|
|
165
|
+
let c = -vec2<f32>(k.y * k.y, k.x * k.y) / magnitude;
|
|
166
|
+
fields.d = vec2<f32>(c.x * h.x - c.y * h.y, c.x * h.y + c.y * h.x);
|
|
167
|
+
return fields;
|
|
168
|
+
}
|
|
169
|
+
`, [GOLDEN_ANGLE_DECLARATION, chunk_pcg3d]);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rows and columns of a band's modes that can hold content: mode indices −32 … 31 on either axis.
|
|
3
|
+
*/
|
|
4
|
+
export const WATER_SPECTRUM_CONTENT: 64;
|
|
5
|
+
/** vec4s in the working buffer: bands × content rows × columns × two (four complex fields a texel). */
|
|
6
|
+
export const WATER_SPECTRUM_ROW_VALUE_COUNT: number;
|
|
7
|
+
/** Workgroups of the row pass a band: one a content row. */
|
|
8
|
+
export const WATER_SPECTRUM_ROW_GROUPS_PER_BAND: 64;
|
|
9
|
+
/** Workgroups of the column pass a band: one a column. */
|
|
10
|
+
export const WATER_SPECTRUM_COLUMN_GROUPS_PER_BAND: 128;
|
|
11
|
+
/**
|
|
12
|
+
* Each content row of every band in `band_state.todo` at the frame's time, transformed along x. The modes come from hashed Gaussians, so
|
|
13
|
+
* the tiles need no state and are the same on every device and every frame.
|
|
14
|
+
*/
|
|
15
|
+
export const shader_water_spectrum_rows: ComputeShader;
|
|
16
|
+
/**
|
|
17
|
+
* Each column of every band in `band_state.todo` transformed along z, packed into the two band textures, and each
|
|
18
|
+
* band's largest |h| and |(Dx, Dz)| raised into its envelope (f32 bits, atomic max, never cleared): the largest the
|
|
19
|
+
* band has shown at any time evaluated. Bilinear sampling cannot leave the texel range, so a body's weighted sum of
|
|
20
|
+
* the envelopes bounds its displacement at every time evaluated.
|
|
21
|
+
*
|
|
22
|
+
* displacement = (Dx, h, Dz, ∂Dx/∂z), derivatives = (∂h/∂x, ∂h/∂z, ∂Dx/∂x, ∂Dz/∂z).
|
|
23
|
+
*/
|
|
24
|
+
export const shader_water_spectrum_columns: ComputeShader;
|
|
25
|
+
import { ComputeShader } from "../../../shader/ComputeShader.js";
|
|
26
|
+
//# sourceMappingURL=shader_water_spectrum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shader_water_spectrum.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/water/surface/spectrum/shader_water_spectrum.js"],"names":[],"mappings":"AA6BA;;GAEG;AACH,wCAAyC;AAEzC,uGAAuG;AACvG,oDAAgI;AAEhI,4DAA4D;AAC5D,oDAAyE;AAEzE,0DAA0D;AAC1D,wDAA8E;AAO9E;;;GAGG;AACH,uDA8BsH;AAqEtH;;;;;;;GAOG;AACH,0DAC0B;8BA/JI,kCAAkC"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { WebGPUExtensionType } from "../../../../descriptor/WebGPUExtensionType.js";
|
|
2
|
+
import { ComputeShader } from "../../../shader/ComputeShader.js";
|
|
3
|
+
import { CodeChunk } from "../../../shader/compiler/CodeChunk.js";
|
|
4
|
+
import { ShaderResourceSetDescriptor } from "../../../shader/resource/ShaderResourceSetDescriptor.js";
|
|
5
|
+
import { f32, vec4f } from "../../../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
6
|
+
import { WebGPUArray } from "../../../shader/type/WebGPUArray.js";
|
|
7
|
+
import { chunk_folded_workgroup_index } from "../../../shader/chunk/grid/chunk_folded_workgroup_index.js";
|
|
8
|
+
import { chunk_fft128x4_inverse_workgroup } from "../../../shader/chunk/math/fft/chunk_fft128x4_inverse_workgroup.js";
|
|
9
|
+
import { chunk_water_spectrum } from "./chunk_water_spectrum.js";
|
|
10
|
+
import { WATER_SPECTRUM_BAND_COUNT, WATER_SPECTRUM_TILE_SIZE } from "./WATER_SPECTRUM.js";
|
|
11
|
+
import { chunk_water_band_state, WATER_BAND_STATE_ATOMIC_STRUCT, WATER_BAND_STATE_STRUCT } from "./WATER_BAND_STATE.js";
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
Two passes animate the bands the frame asked for (the band state's `todo` mask), dispatched indirectly with a
|
|
15
|
+
band's worth of workgroups for each, each one workgroup a line of all four of a band's complex fields (`water_band_fields`),
|
|
16
|
+
transformed together in 4 KiB of workgroup memory (`chunk_fft128x4_inverse_workgroup`):
|
|
17
|
+
|
|
18
|
+
- rows: a band's modes only reach index ±32 (its hat ends at twice its node, index 16), so only 64 of the 128 rows can
|
|
19
|
+
hold content. One workgroup a content row makes the row's modes and transforms them along x;
|
|
20
|
+
- columns: one workgroup a column of every band reads the content rows, zero elsewhere, transforms along z and packs
|
|
21
|
+
the texels into the band textures, with each band's extrema.
|
|
22
|
+
|
|
23
|
+
Between them a working buffer holds the four fields of one texel in one 32-byte cell, a memory sector, so the rows
|
|
24
|
+
write whole rows and the columns read whole sectors. Measured on an RTX 4090 against separate modes, row, column and
|
|
25
|
+
pack passes, each invocation running a 128-point line in private memory: it reproduces them to the f16 bit and takes
|
|
26
|
+
~21 µs a frame instead of ~147 (WATER_SURFACE_SIMULATION_PLAN_2026_10_06.md §8). A subgroup-shuffle variant of the
|
|
27
|
+
transform, with no barriers, measured no faster on the columns and 35% slower on the rows.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Rows and columns of a band's modes that can hold content: mode indices −32 … 31 on either axis.
|
|
32
|
+
*/
|
|
33
|
+
export const WATER_SPECTRUM_CONTENT = 64;
|
|
34
|
+
|
|
35
|
+
/** vec4s in the working buffer: bands × content rows × columns × two (four complex fields a texel). */
|
|
36
|
+
export const WATER_SPECTRUM_ROW_VALUE_COUNT = WATER_SPECTRUM_BAND_COUNT * WATER_SPECTRUM_CONTENT * WATER_SPECTRUM_TILE_SIZE * 2;
|
|
37
|
+
|
|
38
|
+
/** Workgroups of the row pass a band: one a content row. */
|
|
39
|
+
export const WATER_SPECTRUM_ROW_GROUPS_PER_BAND = WATER_SPECTRUM_CONTENT;
|
|
40
|
+
|
|
41
|
+
/** Workgroups of the column pass a band: one a column. */
|
|
42
|
+
export const WATER_SPECTRUM_COLUMN_GROUPS_PER_BAND = WATER_SPECTRUM_TILE_SIZE;
|
|
43
|
+
|
|
44
|
+
const rows_resources = new ShaderResourceSetDescriptor();
|
|
45
|
+
rows_resources.setImmediate('loop_fraction', f32);
|
|
46
|
+
rows_resources.createGroup().addStorageBuffer('rows', WebGPUArray.from(vec4f), true)
|
|
47
|
+
.addStorageBuffer('band_state', WATER_BAND_STATE_STRUCT);
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Each content row of every band in `band_state.todo` at the frame's time, transformed along x. The modes come from hashed Gaussians, so
|
|
51
|
+
* the tiles need no state and are the same on every device and every frame.
|
|
52
|
+
*/
|
|
53
|
+
export const shader_water_spectrum_rows = ComputeShader.from({ label: 'Water / spectrum rows', resources: rows_resources,
|
|
54
|
+
body: CodeChunk.from(/* language=WGSL */ `
|
|
55
|
+
const WATER_SPECTRUM_CONTENT: u32 = ${WATER_SPECTRUM_CONTENT}u;
|
|
56
|
+
|
|
57
|
+
@compute @workgroup_size(256)
|
|
58
|
+
fn main(@builtin(workgroup_id) group: vec3u, @builtin(local_invocation_index) lane: u32) {
|
|
59
|
+
let index = folded_workgroup_index(group);
|
|
60
|
+
let band = water_band_nth(band_state.todo, index / WATER_SPECTRUM_CONTENT);
|
|
61
|
+
if (band >= WATER_SPECTRUM_BANDS) { return; }
|
|
62
|
+
let row = band * WATER_SPECTRUM_CONTENT + index % WATER_SPECTRUM_CONTENT;
|
|
63
|
+
let mode_z = i32(row % WATER_SPECTRUM_CONTENT) - i32(WATER_SPECTRUM_CONTENT / 2u);
|
|
64
|
+
if (lane < WATER_SPECTRUM_TILE) {
|
|
65
|
+
var fields: WaterBandFields;
|
|
66
|
+
// x modes −32 … 31: the first and last quarter of the line
|
|
67
|
+
if (lane < WATER_SPECTRUM_CONTENT / 2u || lane >= WATER_SPECTRUM_TILE - WATER_SPECTRUM_CONTENT / 2u) {
|
|
68
|
+
fields = water_band_fields(band, vec2<i32>(water_band_mode(vec2<u32>(lane, 0u)).x, mode_z), loop_fraction);
|
|
69
|
+
}
|
|
70
|
+
let at = reverseBits(lane) >> 25u;
|
|
71
|
+
fft128x4_lines[at] = fields.a;
|
|
72
|
+
fft128x4_lines[128u + at] = fields.b;
|
|
73
|
+
fft128x4_lines[256u + at] = fields.c;
|
|
74
|
+
fft128x4_lines[384u + at] = fields.d;
|
|
75
|
+
}
|
|
76
|
+
fft128x4_inverse(lane);
|
|
77
|
+
if (lane < WATER_SPECTRUM_TILE) {
|
|
78
|
+
let cell = (row * WATER_SPECTRUM_TILE + lane) * 2u;
|
|
79
|
+
rows[cell] = vec4<f32>(fft128x4_lines[lane], fft128x4_lines[128u + lane]);
|
|
80
|
+
rows[cell + 1u] = vec4<f32>(fft128x4_lines[256u + lane], fft128x4_lines[384u + lane]);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
`, [chunk_water_spectrum, chunk_fft128x4_inverse_workgroup, chunk_folded_workgroup_index, chunk_water_band_state]) });
|
|
84
|
+
|
|
85
|
+
const columns_resources = new ShaderResourceSetDescriptor();
|
|
86
|
+
columns_resources.createGroup()
|
|
87
|
+
.addStorageBuffer('rows', WebGPUArray.from(vec4f))
|
|
88
|
+
.addStorageTexture('displacement', 'rgba16float', '2d-array', 'write-only')
|
|
89
|
+
.addStorageTexture('derivatives', 'rgba16float', '2d-array', 'write-only')
|
|
90
|
+
.addStorageBuffer('band_state', WATER_BAND_STATE_ATOMIC_STRUCT, true);
|
|
91
|
+
|
|
92
|
+
const columns_body = CodeChunk.from(/* language=WGSL */ `
|
|
93
|
+
const WATER_SPECTRUM_CONTENT: u32 = ${WATER_SPECTRUM_CONTENT}u;
|
|
94
|
+
|
|
95
|
+
// the column's largest |h| and |(Dx, Dz)|, gathered here first so a band's bound takes one atomic a column
|
|
96
|
+
var<workgroup> water_column_peaks: array<atomic<u32>, 2>;
|
|
97
|
+
// the frame's bands, read once: an atomic load is not uniform, a workgroup-uniform load of it is
|
|
98
|
+
var<workgroup> water_column_todo: u32;
|
|
99
|
+
|
|
100
|
+
@compute @workgroup_size(256)
|
|
101
|
+
fn main(@builtin(workgroup_id) group: vec3u, @builtin(local_invocation_index) lane: u32) {
|
|
102
|
+
let index = folded_workgroup_index(group);
|
|
103
|
+
if (lane == 0u) { water_column_todo = atomicLoad(&band_state.todo); }
|
|
104
|
+
let band = water_band_nth(workgroupUniformLoad(&water_column_todo), index / WATER_SPECTRUM_TILE);
|
|
105
|
+
if (band >= WATER_SPECTRUM_BANDS) { return; }
|
|
106
|
+
let x = index % WATER_SPECTRUM_TILE;
|
|
107
|
+
let rim = WATER_SPECTRUM_CONTENT / 2u;
|
|
108
|
+
if (lane < 2u) { atomicStore(&water_column_peaks[lane], 0u); }
|
|
109
|
+
if (lane < WATER_SPECTRUM_TILE) {
|
|
110
|
+
// z modes −32 … 31 are the content rows 0 … 63; the rest of the column is zero
|
|
111
|
+
var first = vec4<f32>(0.0);
|
|
112
|
+
var second = vec4<f32>(0.0);
|
|
113
|
+
if (lane < rim || lane >= WATER_SPECTRUM_TILE - rim) {
|
|
114
|
+
let row = select(lane + rim, lane - (WATER_SPECTRUM_TILE - rim), lane >= WATER_SPECTRUM_TILE - rim);
|
|
115
|
+
let cell = ((band * WATER_SPECTRUM_CONTENT + row) * WATER_SPECTRUM_TILE + x) * 2u;
|
|
116
|
+
first = rows[cell];
|
|
117
|
+
second = rows[cell + 1u];
|
|
118
|
+
}
|
|
119
|
+
let at = reverseBits(lane) >> 25u;
|
|
120
|
+
fft128x4_lines[at] = first.xy;
|
|
121
|
+
fft128x4_lines[128u + at] = first.zw;
|
|
122
|
+
fft128x4_lines[256u + at] = second.xy;
|
|
123
|
+
fft128x4_lines[384u + at] = second.zw;
|
|
124
|
+
}
|
|
125
|
+
fft128x4_inverse(lane);
|
|
126
|
+
var height = 0.0;
|
|
127
|
+
var horizontal = 0.0;
|
|
128
|
+
if (lane < WATER_SPECTRUM_TILE) {
|
|
129
|
+
let a = fft128x4_lines[lane];
|
|
130
|
+
let b = fft128x4_lines[128u + lane];
|
|
131
|
+
let c = fft128x4_lines[256u + lane];
|
|
132
|
+
let d = fft128x4_lines[384u + lane];
|
|
133
|
+
let coordinate = vec2<u32>(x, lane);
|
|
134
|
+
textureStore(displacement, coordinate, band, vec4<f32>(a.y, a.x, b.x, d.y));
|
|
135
|
+
textureStore(derivatives, coordinate, band, vec4<f32>(b.y, c.x, c.y, d.x));
|
|
136
|
+
height = abs(a.x);
|
|
137
|
+
horizontal = length(vec2<f32>(a.y, b.x));
|
|
138
|
+
}
|
|
139
|
+
// non-negative floats order as their bits do; subgroup operations stay in uniform control flow
|
|
140
|
+
let group_height = subgroupMax(height);
|
|
141
|
+
let group_horizontal = subgroupMax(horizontal);
|
|
142
|
+
if (subgroupElect()) {
|
|
143
|
+
atomicMax(&water_column_peaks[0], bitcast<u32>(group_height));
|
|
144
|
+
atomicMax(&water_column_peaks[1], bitcast<u32>(group_horizontal));
|
|
145
|
+
}
|
|
146
|
+
workgroupBarrier();
|
|
147
|
+
if (lane < 2u) { atomicMax(&band_state.envelope[2u * band + lane], atomicLoad(&water_column_peaks[lane])); }
|
|
148
|
+
}
|
|
149
|
+
`, [chunk_water_spectrum, chunk_fft128x4_inverse_workgroup, chunk_folded_workgroup_index, chunk_water_band_state]);
|
|
150
|
+
columns_body.addExtension(WebGPUExtensionType.Subgroups);
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Each column of every band in `band_state.todo` transformed along z, packed into the two band textures, and each
|
|
154
|
+
* band's largest |h| and |(Dx, Dz)| raised into its envelope (f32 bits, atomic max, never cleared): the largest the
|
|
155
|
+
* band has shown at any time evaluated. Bilinear sampling cannot leave the texel range, so a body's weighted sum of
|
|
156
|
+
* the envelopes bounds its displacement at every time evaluated.
|
|
157
|
+
*
|
|
158
|
+
* displacement = (Dx, h, Dz, ∂Dx/∂z), derivatives = (∂h/∂x, ∂h/∂z, ∂Dx/∂x, ∂Dz/∂z).
|
|
159
|
+
*/
|
|
160
|
+
export const shader_water_spectrum_columns = ComputeShader.from({ label: 'Water / spectrum columns', resources: columns_resources,
|
|
161
|
+
body: columns_body });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WGSLJavaScriptCompiler.d.ts","sourceRoot":"","sources":["../../../../../src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WGSLJavaScriptCompiler.d.ts","sourceRoot":"","sources":["../../../../../src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js"],"names":[],"mappings":"AAsmBA;IAEI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,oBAFa,MAAM,CAMlB;CACJ;;UAloBa,WAAW,GAAG,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS;WAC/G,MAAM;WACN,MAAM;WACN,MAAM;WACN,MAAM;aACN,MAAM;cACN,QAAQ;YACR,MAAM"}
|
|
@@ -302,6 +302,8 @@ function classifyType(ident, args, template_list_node) {
|
|
|
302
302
|
// template arg 0 is the element type (sub-template), arg 1 is the count
|
|
303
303
|
let element = T_UNKNOWN;
|
|
304
304
|
let count = -1;
|
|
305
|
+
// a count named by a module constant is read from that constant when a value is made
|
|
306
|
+
let count_name = null;
|
|
305
307
|
if (template_list_node !== null) {
|
|
306
308
|
const comma_list = namedChildByType(template_list_node, 'template_arg_comma_list');
|
|
307
309
|
if (comma_list !== null) {
|
|
@@ -312,12 +314,14 @@ function classifyType(ident, args, template_list_node) {
|
|
|
312
314
|
element = parseTypeSpecifier(inner_expr);
|
|
313
315
|
}
|
|
314
316
|
if (arg_nodes.length > 1) {
|
|
315
|
-
const
|
|
317
|
+
const text = arg_nodes[1].text.trim();
|
|
318
|
+
const c = parseInt(text);
|
|
316
319
|
if (!isNaN(c)) count = c;
|
|
320
|
+
else if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(text)) count_name = text;
|
|
317
321
|
}
|
|
318
322
|
}
|
|
319
323
|
}
|
|
320
|
-
return { kind: 'array', element, count };
|
|
324
|
+
return count_name === null ? { kind: 'array', element, count } : { kind: 'array', element, count, count_name };
|
|
321
325
|
}
|
|
322
326
|
if (ident === 'atomic') {
|
|
323
327
|
const inner = args.length > 0 ? args[0] : 'i32';
|
|
@@ -843,14 +847,16 @@ function defaultValueForType(type) {
|
|
|
843
847
|
case 'mat':
|
|
844
848
|
return `new Float32Array(${type.cols * type.rows})`;
|
|
845
849
|
case 'array': {
|
|
846
|
-
|
|
850
|
+
const length = type.count > 0 ? String(type.count)
|
|
851
|
+
: type.count_name !== undefined ? `Number(${identToJs(type.count_name)})` : null;
|
|
852
|
+
if (length !== null) {
|
|
847
853
|
if (type.element.kind === 'primitive') {
|
|
848
854
|
const ctor = arrayCtorForScalar(type.element.name);
|
|
849
|
-
return `new ${ctor}(${
|
|
855
|
+
return `new ${ctor}(${length})`;
|
|
850
856
|
}
|
|
851
857
|
// For non-primitive elements (vec / mat / struct / nested array) build the
|
|
852
858
|
// array eagerly so `out[i]` is a fresh, mutable element rather than `undefined`.
|
|
853
|
-
return `Array.from({ length: ${
|
|
859
|
+
return `Array.from({ length: ${length} }, () => ${defaultValueForType(type.element)})`;
|
|
854
860
|
}
|
|
855
861
|
return '[]';
|
|
856
862
|
}
|
|
@@ -2727,7 +2733,13 @@ function compileCallPhraseTyped(c, node) {
|
|
|
2727
2733
|
|
|
2728
2734
|
// 6) array / array<T, N> constructor.
|
|
2729
2735
|
if (callee_name === 'array') {
|
|
2730
|
-
|
|
2736
|
+
// The element type is what makes a member or swizzle on an element read compile; without
|
|
2737
|
+
// a template, it is the first argument's, as WGSL infers it.
|
|
2738
|
+
let type = parseTypeSpecifier(ident_node);
|
|
2739
|
+
if ((type.kind !== 'array' || type.element === T_UNKNOWN) && arg_results.length > 0 && !isAbstractType(arg_results[0].type)) {
|
|
2740
|
+
type = { kind: 'array', element: arg_results[0].type, count: arg_results.length };
|
|
2741
|
+
}
|
|
2742
|
+
return { code: `[${stored_args.join(', ')}]`, type };
|
|
2731
2743
|
}
|
|
2732
2744
|
|
|
2733
2745
|
// 7) Struct constructor.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WGSLLanguageCore.d.ts","sourceRoot":"","sources":["../../../../../src/shade/wgsl/emulator/WGSLLanguageCore.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"WGSLLanguageCore.d.ts","sourceRoot":"","sources":["../../../../../src/shade/wgsl/emulator/WGSLLanguageCore.js"],"names":[],"mappings":";IAs/CA;;;;;;;;;;;;;;OAcG;IACH,+DAmDC"}
|