@zephyr3d/scene 0.9.27 → 0.10.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/README.md +60 -27
- package/dist/animation/animation_bank.js +634 -0
- package/dist/animation/animation_bank.js.map +1 -0
- package/dist/animation/animation_bank_gpu.js +256 -0
- package/dist/animation/animation_bank_gpu.js.map +1 -0
- package/dist/animation/animationset.js +54 -0
- package/dist/animation/animationset.js.map +1 -1
- package/dist/animation/cloth/gpu_cloth_component.js +406 -0
- package/dist/animation/cloth/gpu_cloth_component.js.map +1 -0
- package/dist/animation/cloth/gpu_cloth_system.js +332 -202
- package/dist/animation/cloth/gpu_cloth_system.js.map +1 -1
- package/dist/animation/gpu_animation_driver.js +289 -0
- package/dist/animation/gpu_animation_driver.js.map +1 -0
- package/dist/animation/joint_dynamics/collision.js +112 -1
- package/dist/animation/joint_dynamics/collision.js.map +1 -1
- package/dist/animation/joint_dynamics/controller.js +6 -0
- package/dist/animation/joint_dynamics/controller.js.map +1 -1
- package/dist/animation/joint_dynamics/joint_dynamics_system.js +11 -0
- package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
- package/dist/animation/joint_dynamics/solver.js +50 -12
- package/dist/animation/joint_dynamics/solver.js.map +1 -1
- package/dist/animation/joint_dynamics/types.js.map +1 -1
- package/dist/animation/skeleton.js +279 -55
- package/dist/animation/skeleton.js.map +1 -1
- package/dist/animation/skin_palette_atlas.js +252 -0
- package/dist/animation/skin_palette_atlas.js.map +1 -0
- package/dist/animation/spring/multi_chain_spring_system.js +298 -38
- package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
- package/dist/animation/spring/spring_chain.js +2 -0
- package/dist/animation/spring/spring_chain.js.map +1 -1
- package/dist/animation/spring/spring_collider.js +159 -21
- package/dist/animation/spring/spring_collider.js.map +1 -1
- package/dist/animation/spring/spring_particle.js +1 -0
- package/dist/animation/spring/spring_particle.js.map +1 -1
- package/dist/animation/spring/spring_solver.js +173 -0
- package/dist/animation/spring/spring_solver.js.map +1 -0
- package/dist/animation/spring/spring_system.js +249 -24
- package/dist/animation/spring/spring_system.js.map +1 -1
- package/dist/animation/spring_modifier.js +32 -1
- package/dist/animation/spring_modifier.js.map +1 -1
- package/dist/app/app.js +26 -0
- package/dist/app/app.js.map +1 -1
- package/dist/app/engine.js +86 -15
- package/dist/app/engine.js.map +1 -1
- package/dist/app/gamepad.js +191 -0
- package/dist/app/gamepad.js.map +1 -0
- package/dist/app/inputactions.js +271 -0
- package/dist/app/inputactions.js.map +1 -0
- package/dist/app/inputmgr.js +331 -22
- package/dist/app/inputmgr.js.map +1 -1
- package/dist/app/loading.js +138 -0
- package/dist/app/loading.js.map +1 -0
- package/dist/app/pipelinecache.js +209 -0
- package/dist/app/pipelinecache.js.map +1 -0
- package/dist/app/runtimescript.js +25 -0
- package/dist/app/runtimescript.js.map +1 -1
- package/dist/app/scriptingsystem.js +54 -0
- package/dist/app/scriptingsystem.js.map +1 -1
- package/dist/app/scriptregistry.js +7 -2
- package/dist/app/scriptregistry.js.map +1 -1
- package/dist/asset/asset_manifest.js +59 -0
- package/dist/asset/asset_manifest.js.map +1 -0
- package/dist/asset/asset_preload.js +258 -0
- package/dist/asset/asset_preload.js.map +1 -0
- package/dist/asset/assetmanager.js +117 -65
- package/dist/asset/assetmanager.js.map +1 -1
- package/dist/asset/loaders/ktx2/basis/LICENSE +201 -0
- package/dist/asset/loaders/ktx2/basis/basis_transcoder.js +2 -0
- package/dist/asset/loaders/ktx2/basis/basis_transcoder.wasm +0 -0
- package/dist/asset/loaders/ktx2/basis_location.js +17 -0
- package/dist/asset/loaders/ktx2/basis_location.js.map +1 -0
- package/dist/asset/loaders/ktx2/ktx2_loader.js +88 -0
- package/dist/asset/loaders/ktx2/ktx2_loader.js.map +1 -0
- package/dist/asset/loaders/ktx2/ktx2_targets.js +118 -0
- package/dist/asset/loaders/ktx2/ktx2_targets.js.map +1 -0
- package/dist/asset/loaders/ktx2/transcoder_pool.js +259 -0
- package/dist/asset/loaders/ktx2/transcoder_pool.js.map +1 -0
- package/dist/asset/mesh_lod_builder.js +104 -0
- package/dist/asset/mesh_lod_builder.js.map +1 -0
- package/dist/asset/mesh_settings.js +111 -0
- package/dist/asset/mesh_settings.js.map +1 -0
- package/dist/asset/meshopt_decoder.js +18 -0
- package/dist/asset/meshopt_decoder.js.map +1 -0
- package/dist/asset/meshopt_simplifier.js +26 -0
- package/dist/asset/meshopt_simplifier.js.map +1 -0
- package/dist/asset/model.js +171 -1
- package/dist/asset/model.js.map +1 -1
- package/dist/asset/texture_settings.js +231 -0
- package/dist/asset/texture_settings.js.map +1 -0
- package/dist/asset/zmsh_binary.js +131 -0
- package/dist/asset/zmsh_binary.js.map +1 -0
- package/dist/asset/zsdf_binary.js +111 -0
- package/dist/asset/zsdf_binary.js.map +1 -0
- package/dist/blitter/bilateralblur.js +1 -2
- package/dist/blitter/bilateralblur.js.map +1 -1
- package/dist/blitter/gaussianblur.js +1 -6
- package/dist/blitter/gaussianblur.js.map +1 -1
- package/dist/camera/base.js +31 -10
- package/dist/camera/base.js.map +1 -1
- package/dist/camera/camera.js +104 -178
- package/dist/camera/camera.js.map +1 -1
- package/dist/camera/follow.js +342 -0
- package/dist/camera/follow.js.map +1 -0
- package/dist/camera/fps.js +9 -7
- package/dist/camera/fps.js.map +1 -1
- package/dist/camera/orbit.js +46 -19
- package/dist/camera/orbit.js.map +1 -1
- package/dist/index.d.ts +25436 -15990
- package/dist/index.js +65 -11
- package/dist/index.js.map +1 -1
- package/dist/material/blinn.js +3 -0
- package/dist/material/blinn.js.map +1 -1
- package/dist/material/eye.js +1 -1
- package/dist/material/eye.js.map +1 -1
- package/dist/material/hair.js +2 -3
- package/dist/material/hair.js.map +1 -1
- package/dist/material/lambert.js +4 -1
- package/dist/material/lambert.js.map +1 -1
- package/dist/material/material.js +66 -4
- package/dist/material/material.js.map +1 -1
- package/dist/material/meshmaterial.js +118 -45
- package/dist/material/meshmaterial.js.map +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
- package/dist/material/mixins/lightmodel/lambert.js +1 -1
- package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +34 -61
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +16 -2
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js +2 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
- package/dist/material/mixins/lit.js +191 -83
- package/dist/material/mixins/lit.js.map +1 -1
- package/dist/material/mixins/pbr/common.js +31 -206
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/mtoon.js +1 -1
- package/dist/material/mtoon.js.map +1 -1
- package/dist/material/pbrmr.js +3 -0
- package/dist/material/pbrmr.js.map +1 -1
- package/dist/material/pbrsg.js +3 -0
- package/dist/material/pbrsg.js.map +1 -1
- package/dist/material/sdf_debug.js +78 -0
- package/dist/material/sdf_debug.js.map +1 -0
- package/dist/material/shader/helper.js +333 -191
- package/dist/material/shader/helper.js.map +1 -1
- package/dist/material/shader/terrain_blend.js +204 -43
- package/dist/material/shader/terrain_blend.js.map +1 -1
- package/dist/material/skin.js +331 -297
- package/dist/material/skin.js.map +1 -1
- package/dist/material/skinprofile.js +1058 -0
- package/dist/material/skinprofile.js.map +1 -0
- package/dist/material/sss.js +353 -0
- package/dist/material/sss.js.map +1 -0
- package/dist/material/sss_kernel.js +265 -0
- package/dist/material/sss_kernel.js.map +1 -0
- package/dist/material/sssprofile.js +879 -0
- package/dist/material/sssprofile.js.map +1 -0
- package/dist/material/subsurfaceprofile.js +4 -8
- package/dist/material/subsurfaceprofile.js.map +1 -1
- package/dist/material/terrain-cm.js +464 -188
- package/dist/material/terrain-cm.js.map +1 -1
- package/dist/material/unlit.js +3 -0
- package/dist/material/unlit.js.map +1 -1
- package/dist/material/water.js +1261 -1438
- package/dist/material/water.js.map +1 -1
- package/dist/node_modules/meshoptimizer/LICENSE +21 -0
- package/dist/node_modules/meshoptimizer/meshopt_decoder.js +197 -0
- package/dist/node_modules/meshoptimizer/meshopt_decoder.js.map +1 -0
- package/dist/node_modules/meshoptimizer/meshopt_simplifier.js +677 -0
- package/dist/node_modules/meshoptimizer/meshopt_simplifier.js.map +1 -0
- package/dist/physics/character.js +226 -0
- package/dist/physics/character.js.map +1 -0
- package/dist/physics/collider.js +209 -0
- package/dist/physics/collider.js.map +1 -0
- package/dist/physics/events.js +79 -0
- package/dist/physics/events.js.map +1 -0
- package/dist/physics/joint.js +272 -0
- package/dist/physics/joint.js.map +1 -0
- package/dist/physics/node_physics.js +234 -0
- package/dist/physics/node_physics.js.map +1 -0
- package/dist/physics/part.js +91 -0
- package/dist/physics/part.js.map +1 -0
- package/dist/physics/rigid_body.js +379 -0
- package/dist/physics/rigid_body.js.map +1 -0
- package/dist/physics/vehicle.js +335 -0
- package/dist/physics/vehicle.js.map +1 -0
- package/dist/physics/world.js +25 -0
- package/dist/physics/world.js.map +1 -0
- package/dist/posteffect/bloom.js +49 -14
- package/dist/posteffect/bloom.js.map +1 -1
- package/dist/posteffect/motionblur.js +106 -106
- package/dist/posteffect/motionblur.js.map +1 -1
- package/dist/posteffect/postsss.js +572 -0
- package/dist/posteffect/postsss.js.map +1 -0
- package/dist/posteffect/sao.js +2 -6
- package/dist/posteffect/sao.js.map +1 -1
- package/dist/posteffect/skinsss.js +605 -355
- package/dist/posteffect/skinsss.js.map +1 -1
- package/dist/posteffect/ssgi.js +91 -162
- package/dist/posteffect/ssgi.js.map +1 -1
- package/dist/posteffect/ssr.js +3 -11
- package/dist/posteffect/ssr.js.map +1 -1
- package/dist/posteffect/sss.js +4 -13
- package/dist/posteffect/sss.js.map +1 -1
- package/dist/posteffect/taa.js +1 -0
- package/dist/posteffect/taa.js.map +1 -1
- package/dist/render/abuffer_oit.js +3 -2
- package/dist/render/abuffer_oit.js.map +1 -1
- package/dist/render/clipmap.js +179 -64
- package/dist/render/clipmap.js.map +1 -1
- package/dist/render/cluster_light.js +958 -224
- package/dist/render/cluster_light.js.map +1 -1
- package/dist/render/cull_visitor.js +25 -5
- package/dist/render/cull_visitor.js.map +1 -1
- package/dist/render/debug_views.js +37 -0
- package/dist/render/debug_views.js.map +1 -0
- package/dist/render/depthpass.js +5 -1
- package/dist/render/depthpass.js.map +1 -1
- package/dist/render/drawable_mixin.js +53 -6
- package/dist/render/drawable_mixin.js.map +1 -1
- package/dist/render/dualdepthpeeling_oit.js +5 -5
- package/dist/render/dualdepthpeeling_oit.js.map +1 -1
- package/dist/render/envlight.js +196 -113
- package/dist/render/envlight.js.map +1 -1
- package/dist/render/fbm_wavegenerator.js +5 -10
- package/dist/render/fbm_wavegenerator.js.map +1 -1
- package/dist/render/fft_wavegenerator.js +247 -157
- package/dist/render/fft_wavegenerator.js.map +1 -1
- package/dist/render/gerstner_wavegenerator.js +16 -38
- package/dist/render/gerstner_wavegenerator.js.map +1 -1
- package/dist/render/gi/probe_volume.js +1334 -0
- package/dist/render/gi/probe_volume.js.map +1 -0
- package/dist/render/gi/scene_gi.js +282 -0
- package/dist/render/gi/scene_gi.js.map +1 -0
- package/dist/render/gi/voxel_atlas.js +198 -0
- package/dist/render/gi/voxel_atlas.js.map +1 -0
- package/dist/render/gi/voxel_lighting.js +652 -0
- package/dist/render/gi/voxel_lighting.js.map +1 -0
- package/dist/render/gi/voxel_scene.js +642 -0
- package/dist/render/gi/voxel_scene.js.map +1 -0
- package/dist/render/gi/voxelize_pass.js +223 -0
- package/dist/render/gi/voxelize_pass.js.map +1 -0
- package/dist/render/globalbindgroup_allocator.js +3 -2
- package/dist/render/globalbindgroup_allocator.js.map +1 -1
- package/dist/render/gpu_picking.js +9 -36
- package/dist/render/gpu_picking.js.map +1 -1
- package/dist/render/instance_culling.js +499 -0
- package/dist/render/instance_culling.js.map +1 -0
- package/dist/render/lightpass.js +19 -8
- package/dist/render/lightpass.js.map +1 -1
- package/dist/render/lod.js +46 -0
- package/dist/render/lod.js.map +1 -0
- package/dist/render/primitive.js +301 -9
- package/dist/render/primitive.js.map +1 -1
- package/dist/render/primitive_readback.js +209 -0
- package/dist/render/primitive_readback.js.map +1 -0
- package/dist/render/render_queue.js +162 -11
- package/dist/render/render_queue.js.map +1 -1
- package/dist/render/renderer.js +10 -7
- package/dist/render/renderer.js.map +1 -1
- package/dist/render/rendergraph/blackboard.js +14 -1
- package/dist/render/rendergraph/blackboard.js.map +1 -1
- package/dist/render/rendergraph/executor.js +136 -0
- package/dist/render/rendergraph/executor.js.map +1 -1
- package/dist/render/rendergraph/forward_plus_builder.js +272 -55
- package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
- package/dist/render/rendergraph/frame_graph_context.js +41 -0
- package/dist/render/rendergraph/frame_graph_context.js.map +1 -0
- package/dist/render/rendergraph/scene_render_context.js +31 -2
- package/dist/render/rendergraph/scene_render_context.js.map +1 -1
- package/dist/render/rendergraph/types.js.map +1 -1
- package/dist/render/renderpass.js +28 -5
- package/dist/render/renderpass.js.map +1 -1
- package/dist/render/sdf/box_allocator.js +98 -0
- package/dist/render/sdf/box_allocator.js.map +1 -0
- package/dist/render/sdf/global_sdf.js +865 -0
- package/dist/render/sdf/global_sdf.js.map +1 -0
- package/dist/render/sdf/scene_sdf.js +562 -0
- package/dist/render/sdf/scene_sdf.js.map +1 -0
- package/dist/render/sdf/sdf_atlas.js +227 -0
- package/dist/render/sdf/sdf_atlas.js.map +1 -0
- package/dist/render/sdf/sdf_programs.js +42 -0
- package/dist/render/sdf/sdf_programs.js.map +1 -0
- package/dist/render/sdf/sdf_view.js +199 -0
- package/dist/render/sdf/sdf_view.js.map +1 -0
- package/dist/render/sdf/waterline.js +610 -0
- package/dist/render/sdf/waterline.js.map +1 -0
- package/dist/render/shadow_mask_pass.js +142 -25
- package/dist/render/shadow_mask_pass.js.map +1 -1
- package/dist/render/shore_wave_generator.js +1193 -0
- package/dist/render/shore_wave_generator.js.map +1 -0
- package/dist/render/sky.js +516 -86
- package/dist/render/sky.js.map +1 -1
- package/dist/render/transmission_thickness_pass.js +477 -0
- package/dist/render/transmission_thickness_pass.js.map +1 -0
- package/dist/render/underwater.js +58 -158
- package/dist/render/underwater.js.map +1 -1
- package/dist/render/virtualtexture/virtual_texture.js +1214 -0
- package/dist/render/virtualtexture/virtual_texture.js.map +1 -0
- package/dist/render/volumetric_cloud/cloud_common.js +472 -0
- package/dist/render/volumetric_cloud/cloud_common.js.map +1 -0
- package/dist/render/volumetric_cloud/cloud_noise.js +189 -0
- package/dist/render/volumetric_cloud/cloud_noise.js.map +1 -0
- package/dist/render/volumetric_cloud/debug_view.js +131 -0
- package/dist/render/volumetric_cloud/debug_view.js.map +1 -0
- package/dist/render/volumetric_cloud/resources.js +380 -0
- package/dist/render/volumetric_cloud/resources.js.map +1 -0
- package/dist/render/volumetric_cloud/sky_cache.js +380 -0
- package/dist/render/volumetric_cloud/sky_cache.js.map +1 -0
- package/dist/render/volumetric_cloud/volumetric_cloud.js +318 -0
- package/dist/render/volumetric_cloud/volumetric_cloud.js.map +1 -0
- package/dist/render/water_caustics.js +134 -319
- package/dist/render/water_caustics.js.map +1 -1
- package/dist/render/water_foam.js +627 -0
- package/dist/render/water_foam.js.map +1 -0
- package/dist/render/water_interaction.js +1795 -0
- package/dist/render/water_interaction.js.map +1 -0
- package/dist/render/weightedblended_oit.js +3 -3
- package/dist/render/weightedblended_oit.js.map +1 -1
- package/dist/scene/basesprite.js +9 -4
- package/dist/scene/basesprite.js.map +1 -1
- package/dist/scene/batchgroup.js +108 -12
- package/dist/scene/batchgroup.js.map +1 -1
- package/dist/scene/environment.js +28 -7
- package/dist/scene/environment.js.map +1 -1
- package/dist/scene/foliage.js +1020 -0
- package/dist/scene/foliage.js.map +1 -0
- package/dist/scene/foliage_buckets.js +147 -0
- package/dist/scene/foliage_buckets.js.map +1 -0
- package/dist/scene/foliage_mask.js +358 -0
- package/dist/scene/foliage_mask.js.map +1 -0
- package/dist/scene/hair.js +15 -4
- package/dist/scene/hair.js.map +1 -1
- package/dist/scene/light.js +179 -13
- package/dist/scene/light.js.map +1 -1
- package/dist/scene/mesh.js +327 -45
- package/dist/scene/mesh.js.map +1 -1
- package/dist/scene/meshdrawable.js +6 -0
- package/dist/scene/meshdrawable.js.map +1 -1
- package/dist/scene/msdftext.js +9 -3
- package/dist/scene/msdftext.js.map +1 -1
- package/dist/scene/msdftextsprite.js +9 -3
- package/dist/scene/msdftextsprite.js.map +1 -1
- package/dist/scene/particlesys.js +8 -2
- package/dist/scene/particlesys.js.map +1 -1
- package/dist/scene/physics_settings.js +157 -0
- package/dist/scene/physics_settings.js.map +1 -0
- package/dist/scene/scene.js +190 -44
- package/dist/scene/scene.js.map +1 -1
- package/dist/scene/scene_node.js +147 -6
- package/dist/scene/scene_node.js.map +1 -1
- package/dist/scene/terrain-cm/bladegrassmaterial.js +735 -0
- package/dist/scene/terrain-cm/bladegrassmaterial.js.map +1 -0
- package/dist/scene/terrain-cm/grass.js +881 -42
- package/dist/scene/terrain-cm/grass.js.map +1 -1
- package/dist/scene/terrain-cm/grass_gpu.js +929 -0
- package/dist/scene/terrain-cm/grass_gpu.js.map +1 -0
- package/dist/scene/terrain-cm/grassmaterial.js +180 -9
- package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
- package/dist/scene/terrain-cm/terrain-cm.js +465 -36
- package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
- package/dist/scene/terrain-cm/terrain_gi_albedo.js +257 -0
- package/dist/scene/terrain-cm/terrain_gi_albedo.js.map +1 -0
- package/dist/scene/terrain-cm/terrain_rvt.js +395 -0
- package/dist/scene/terrain-cm/terrain_rvt.js.map +1 -0
- package/dist/scene/update_queue.js +54 -0
- package/dist/scene/update_queue.js.map +1 -0
- package/dist/scene/water.js +633 -268
- package/dist/scene/water.js.map +1 -1
- package/dist/scene/water_surface_sampler.js +324 -0
- package/dist/scene/water_surface_sampler.js.map +1 -0
- package/dist/scene/wind.js +317 -0
- package/dist/scene/wind.js.map +1 -0
- package/dist/shaders/atmosphere.js +388 -166
- package/dist/shaders/atmosphere.js.map +1 -1
- package/dist/shaders/fog.js +100 -32
- package/dist/shaders/fog.js.map +1 -1
- package/dist/shaders/gi.js +365 -0
- package/dist/shaders/gi.js.map +1 -0
- package/dist/shaders/ltc_rect.js +202 -0
- package/dist/shaders/ltc_rect.js.map +1 -0
- package/dist/shaders/misc.js +1 -10
- package/dist/shaders/misc.js.map +1 -1
- package/dist/shaders/noise.js +5 -1
- package/dist/shaders/noise.js.map +1 -1
- package/dist/shaders/probes.js +309 -0
- package/dist/shaders/probes.js.map +1 -0
- package/dist/shaders/sdf.js +537 -0
- package/dist/shaders/sdf.js.map +1 -0
- package/dist/shaders/shadow.js +104 -70
- package/dist/shaders/shadow.js.map +1 -1
- package/dist/shaders/skin_brdf.js +243 -0
- package/dist/shaders/skin_brdf.js.map +1 -0
- package/dist/shaders/ssgi.js +63 -0
- package/dist/shaders/ssgi.js.map +1 -0
- package/dist/shaders/ssgi_reprojection.js +118 -0
- package/dist/shaders/ssgi_reprojection.js.map +1 -0
- package/dist/shaders/ssr.js +6 -159
- package/dist/shaders/ssr.js.map +1 -1
- package/dist/shaders/temporal.js +38 -27
- package/dist/shaders/temporal.js.map +1 -1
- package/dist/shaders/water.js +32 -82
- package/dist/shaders/water.js.map +1 -1
- package/dist/shaders/water_medium.js +7 -21
- package/dist/shaders/water_medium.js.map +1 -1
- package/dist/shadow/dom.js +110 -19
- package/dist/shadow/dom.js.map +1 -1
- package/dist/shadow/esm.js +3 -3
- package/dist/shadow/esm.js.map +1 -1
- package/dist/shadow/pcf_opt.js +15 -48
- package/dist/shadow/pcf_opt.js.map +1 -1
- package/dist/shadow/pcf_pd.js +15 -53
- package/dist/shadow/pcf_pd.js.map +1 -1
- package/dist/shadow/pcss.js +34 -9
- package/dist/shadow/pcss.js.map +1 -1
- package/dist/shadow/shadow_impl.js +3 -8
- package/dist/shadow/shadow_impl.js.map +1 -1
- package/dist/shadow/shadow_region.js +40 -2
- package/dist/shadow/shadow_region.js.map +1 -1
- package/dist/shadow/shadowmapper.js +93 -53
- package/dist/shadow/shadowmapper.js.map +1 -1
- package/dist/shadow/ssm.js +18 -72
- package/dist/shadow/ssm.js.map +1 -1
- package/dist/shadow/vsm.js +3 -3
- package/dist/shadow/vsm.js.map +1 -1
- package/dist/shapes/shape.js +44 -1
- package/dist/shapes/shape.js.map +1 -1
- package/dist/utility/buoyancy.js +287 -0
- package/dist/utility/buoyancy.js.map +1 -0
- package/dist/utility/physical.js +10 -1
- package/dist/utility/physical.js.map +1 -1
- package/dist/utility/pmrem.js +17 -43
- package/dist/utility/pmrem.js.map +1 -1
- package/dist/utility/sdf/bake.js +435 -0
- package/dist/utility/sdf/bake.js.map +1 -0
- package/dist/utility/sdf/bvh.js +576 -0
- package/dist/utility/sdf/bvh.js.map +1 -0
- package/dist/utility/serialization/manager.js +34 -6
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +46 -5
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/batch.js +11 -4
- package/dist/utility/serialization/scene/batch.js.map +1 -1
- package/dist/utility/serialization/scene/camera.js +87 -254
- package/dist/utility/serialization/scene/camera.js.map +1 -1
- package/dist/utility/serialization/scene/cloth.js +25 -0
- package/dist/utility/serialization/scene/cloth.js.map +1 -0
- package/dist/utility/serialization/scene/common.js +14 -6
- package/dist/utility/serialization/scene/common.js.map +1 -1
- package/dist/utility/serialization/scene/foliage.js +821 -0
- package/dist/utility/serialization/scene/foliage.js.map +1 -0
- package/dist/utility/serialization/scene/hair.js +11 -4
- package/dist/utility/serialization/scene/hair.js.map +1 -1
- package/dist/utility/serialization/scene/light.js +115 -7
- package/dist/utility/serialization/scene/light.js.map +1 -1
- package/dist/utility/serialization/scene/material.js +388 -220
- package/dist/utility/serialization/scene/material.js.map +1 -1
- package/dist/utility/serialization/scene/mesh.js +69 -4
- package/dist/utility/serialization/scene/mesh.js.map +1 -1
- package/dist/utility/serialization/scene/node.js +140 -5
- package/dist/utility/serialization/scene/node.js.map +1 -1
- package/dist/utility/serialization/scene/node_physics.js +1318 -0
- package/dist/utility/serialization/scene/node_physics.js.map +1 -0
- package/dist/utility/serialization/scene/particle.js +11 -4
- package/dist/utility/serialization/scene/particle.js.map +1 -1
- package/dist/utility/serialization/scene/physics.js +120 -0
- package/dist/utility/serialization/scene/physics.js.map +1 -0
- package/dist/utility/serialization/scene/primitive.js +124 -10
- package/dist/utility/serialization/scene/primitive.js.map +1 -1
- package/dist/utility/serialization/scene/scene.js +1687 -51
- package/dist/utility/serialization/scene/scene.js.map +1 -1
- package/dist/utility/serialization/scene/sprite.js +11 -4
- package/dist/utility/serialization/scene/sprite.js.map +1 -1
- package/dist/utility/serialization/scene/terrain.js +163 -33
- package/dist/utility/serialization/scene/terrain.js.map +1 -1
- package/dist/utility/serialization/scene/text.js +11 -4
- package/dist/utility/serialization/scene/text.js.map +1 -1
- package/dist/utility/serialization/scene/water.js +1543 -264
- package/dist/utility/serialization/scene/water.js.map +1 -1
- package/dist/utility/serialization/types.js.map +1 -1
- package/dist/utility/shprojector.js +10 -22
- package/dist/utility/shprojector.js.map +1 -1
- package/dist/utility/textures/foam.js +170 -0
- package/dist/utility/textures/foam.js.map +1 -0
- package/dist/utility/textures/ggxlut.js +17 -43
- package/dist/utility/textures/ggxlut.js.map +1 -1
- package/dist/utility/textures/ltcdata.js +4 -4
- package/dist/utility/textures/ltcdata.js.map +1 -1
- package/dist/utility/textures/ltclut.js +16 -6
- package/dist/utility/textures/ltclut.js.map +1 -1
- package/dist/utility/unsupported.js +24 -0
- package/dist/utility/unsupported.js.map +1 -0
- package/dist/values.js +13 -1
- package/dist/values.js.map +1 -1
- package/package.json +25 -12
- package/src/asset/loaders/ktx2/basis/LICENSE +201 -0
- package/src/asset/loaders/ktx2/basis/basis_transcoder.js +2 -0
- package/src/asset/loaders/ktx2/basis/basis_transcoder.wasm +0 -0
- package/src/asset/meshoptimizer/LICENSE +21 -0
- package/dist/animation/joint_dynamics/convex_collider.js +0 -320
- package/dist/animation/joint_dynamics/convex_collider.js.map +0 -1
package/dist/scene/water.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import { Vector4, applyMixins, DRef, Vector3 } from '@zephyr3d/base';
|
|
1
|
+
import { Vector4, applyMixins, DRef, Vector3, Vector2 } from '@zephyr3d/base';
|
|
2
2
|
import { GraphNode } from './graph_node.js';
|
|
3
3
|
import { mixinDrawable } from '../render/drawable_mixin.js';
|
|
4
4
|
import { QUEUE_OPAQUE } from '../values.js';
|
|
5
|
-
import '../render/render_queue.js';
|
|
6
5
|
import { getDevice } from '../app/api.js';
|
|
6
|
+
import '../render/render_queue.js';
|
|
7
7
|
import { Primitive } from '../render/primitive.js';
|
|
8
8
|
import '@zephyr3d/device';
|
|
9
|
-
import '../material/shader/helper.js';
|
|
9
|
+
import { ShaderHelper } from '../material/shader/helper.js';
|
|
10
10
|
import '../material/lambert.js';
|
|
11
11
|
import '../material/blinn.js';
|
|
12
12
|
import '../material/unlit.js';
|
|
13
|
+
import '../material/meshmaterial.js';
|
|
13
14
|
import '../material/particle.js';
|
|
14
15
|
import '../material/subsurfaceprofile.js';
|
|
15
|
-
import '../material/
|
|
16
|
+
import '../material/sssprofile.js';
|
|
17
|
+
import '../material/sss.js';
|
|
16
18
|
import '../material/eye.js';
|
|
17
|
-
import '../material/meshmaterial.js';
|
|
18
19
|
import '../material/hair.js';
|
|
19
20
|
import '../material/hairstrand.js';
|
|
20
21
|
import '../material/grassmaterial.js';
|
|
@@ -31,11 +32,18 @@ import '../render/lightpass.js';
|
|
|
31
32
|
import '../render/sky.js';
|
|
32
33
|
import { Clipmap } from '../render/clipmap.js';
|
|
33
34
|
import '../render/envlight.js';
|
|
35
|
+
import '../render/lod.js';
|
|
34
36
|
import '../render/dualdepthpeeling_oit.js';
|
|
35
37
|
import { setWaterSubmergence } from '../render/underwater.js';
|
|
36
38
|
import '../shaders/atmosphere.js';
|
|
37
39
|
import { FBMWaveGenerator } from '../render/fbm_wavegenerator.js';
|
|
40
|
+
import { InteractiveWaveGenerator } from '../render/water_interaction.js';
|
|
41
|
+
import { RenderGraphExecutor } from '../render/rendergraph/executor.js';
|
|
38
42
|
import '../render/rendergraph/scene_render_context.js';
|
|
43
|
+
import '../render/sdf/scene_sdf.js';
|
|
44
|
+
import '../render/sdf/global_sdf.js';
|
|
45
|
+
import { TerrainWaterlineSource, WaterlineField } from '../render/sdf/waterline.js';
|
|
46
|
+
import '../render/gi/voxelize_pass.js';
|
|
39
47
|
import { WaterMaterial } from '../material/water.js';
|
|
40
48
|
import { BoundingBox } from '../utility/bounding_volume.js';
|
|
41
49
|
|
|
@@ -43,17 +51,24 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
43
51
|
/** Floor on the eye height feeding the horizon distance, in meters. @internal */ const MIN_HORIZON_EYE_HEIGHT = 0.1;
|
|
44
52
|
/**
|
|
45
53
|
* How far past the tessellated surface the skirt's outer edge is placed, as a
|
|
46
|
-
* multiple of the view distance.
|
|
47
|
-
*
|
|
48
|
-
* Only has to be far enough that the ring reads as a horizon line rather than a
|
|
49
|
-
* visible band; it is depth-pinned to the far plane regardless of how far out
|
|
50
|
-
* it actually lands.
|
|
54
|
+
* multiple of the view distance. Its depth is pinned to the far plane.
|
|
51
55
|
* @internal
|
|
52
56
|
*/ const SKIRT_DISTANCE_FACTOR = 10;
|
|
53
57
|
/**
|
|
54
58
|
* Region rectangle standing in for "no bounds", matching the WaterMaterial
|
|
55
59
|
* default. @internal
|
|
56
60
|
*/ const WHOLE_DOMAIN = new Vector4(-99999, -99999, 99999, 99999);
|
|
61
|
+
/**
|
|
62
|
+
* The shore field's levels around the camera: cells along a side and the
|
|
63
|
+
* finest cell size in metres, each level twice the size of the one before,
|
|
64
|
+
* laid out as the foam field's are.
|
|
65
|
+
*/ const SHORE_FIELD_LEVELS = 4;
|
|
66
|
+
const SHORE_FIELD_CELLS = 256;
|
|
67
|
+
const SHORE_FIELD_CELL_SIZE = 0.5;
|
|
68
|
+
/** Shore field levels rebuilt in a frame at most, so the camera crossing every level's cell at once is no spike. */ const SHORE_FIELD_REBUILDS = 2;
|
|
69
|
+
/** No waterline grid: 0 cells. */ const NO_REGIONS = [
|
|
70
|
+
new Vector4(0, 0, 1, 0)
|
|
71
|
+
];
|
|
57
72
|
/**
|
|
58
73
|
* Water scene node
|
|
59
74
|
* @public
|
|
@@ -68,17 +83,30 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
68
83
|
/** Wave clock, in seconds. Advanced by `animationSpeed` per frame. */ _waveTime;
|
|
69
84
|
/** Elapsed time at the previous update, for the frame delta. */ _lastUpdateTime;
|
|
70
85
|
_feedbackProgram;
|
|
86
|
+
/** Hash of the wave generator the feedback program was built for. */ _feedbackHash;
|
|
71
87
|
_feedbackBindGroup;
|
|
72
88
|
_feedbackPrimitive;
|
|
73
89
|
_feedbackRenderTarget;
|
|
74
90
|
_feedbackRenderStates;
|
|
91
|
+
/**
|
|
92
|
+
* Tail of the surface-query queue. The feedback pass reuses one vertex buffer
|
|
93
|
+
* and render target, so requests are serialized in issue order.
|
|
94
|
+
*/ _feedbackQueue;
|
|
95
|
+
/**
|
|
96
|
+
* Frame numbers of the stages of the most recent surface-point query, for
|
|
97
|
+
* latency diagnostics: when it was requested, when its render was recorded,
|
|
98
|
+
* and when the readback resolved. All are `device.frameInfo.frameCounter`.
|
|
99
|
+
* @public
|
|
100
|
+
*/ lastFeedbackTiming = {
|
|
101
|
+
issued: 0,
|
|
102
|
+
recorded: 0,
|
|
103
|
+
mapped: 0
|
|
104
|
+
};
|
|
75
105
|
_material;
|
|
76
106
|
/**
|
|
77
|
-
* Whether each camera was inside this body of water on its previous update
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* which way it is crossing; per camera, because two views of one ocean can be
|
|
81
|
-
* on opposite sides of it.
|
|
107
|
+
* Whether each camera was inside this body of water on its previous update;
|
|
108
|
+
* the submerged test has a dead band around the surface, so it needs the
|
|
109
|
+
* crossing direction.
|
|
82
110
|
*/ _submerged;
|
|
83
111
|
/**
|
|
84
112
|
* Creates an instance of Water node
|
|
@@ -98,19 +126,25 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
98
126
|
this._lastUpdateTime = 0;
|
|
99
127
|
this._material = new DRef(new WaterMaterial());
|
|
100
128
|
this._material.get().region = new Vector4(-1, -1, 1, 1);
|
|
101
|
-
this._material.get().TAAStrength = 0.
|
|
129
|
+
this._material.get().TAAStrength = 0.2;
|
|
102
130
|
this.waveGenerator = new FBMWaveGenerator();
|
|
103
131
|
this._feedbackProgram = new DRef();
|
|
132
|
+
this._feedbackHash = '';
|
|
104
133
|
this._feedbackBindGroup = new DRef();
|
|
105
134
|
this._feedbackPrimitive = new DRef();
|
|
106
135
|
this._feedbackRenderTarget = new DRef();
|
|
107
136
|
this._feedbackRenderStates = null;
|
|
137
|
+
this._feedbackQueue = Promise.resolve();
|
|
108
138
|
this._submerged = new WeakMap();
|
|
109
139
|
scene.queuePerCameraUpdateNode(this);
|
|
110
140
|
}
|
|
111
141
|
/** Disposes the water node */ onDispose() {
|
|
112
142
|
super.onDispose();
|
|
113
143
|
this._clipmap.dispose();
|
|
144
|
+
this._shoreField?.dispose();
|
|
145
|
+
this._shoreSource?.dispose();
|
|
146
|
+
this._shoreField = null;
|
|
147
|
+
this._shoreSource = null;
|
|
114
148
|
this._renderData = null;
|
|
115
149
|
this._feedbackBindGroup.dispose();
|
|
116
150
|
this._feedbackPrimitive.dispose();
|
|
@@ -132,8 +166,14 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
132
166
|
/** Material of the water */ get material() {
|
|
133
167
|
return this._material.get();
|
|
134
168
|
}
|
|
135
|
-
/**
|
|
136
|
-
|
|
169
|
+
/**
|
|
170
|
+
* Wave generator object of the water: the source of the ambient surface.
|
|
171
|
+
*
|
|
172
|
+
* While an {@link interaction} is attached the surface actually drawn is
|
|
173
|
+
* this generator plus the interaction field; this still returns the
|
|
174
|
+
* generator on its own.
|
|
175
|
+
*/ get waveGenerator() {
|
|
176
|
+
return this.material.baseWaveGenerator;
|
|
137
177
|
}
|
|
138
178
|
set waveGenerator(waveGenerator) {
|
|
139
179
|
this.material.waveGenerator = waveGenerator;
|
|
@@ -142,16 +182,30 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
142
182
|
}
|
|
143
183
|
}
|
|
144
184
|
/**
|
|
185
|
+
* Dynamic height field layered over the surface, driven by things touching
|
|
186
|
+
* the water, or null for none. See {@link WaterInteraction}.
|
|
187
|
+
*
|
|
188
|
+
* The field is stepped on this water's own clock, so {@link animationSpeed}
|
|
189
|
+
* scales it too; it is added everywhere the surface is evaluated, so
|
|
190
|
+
* {@link getSurfacePoint} and the caustics see it as well.
|
|
191
|
+
*/ get interaction() {
|
|
192
|
+
return this.material.interaction;
|
|
193
|
+
}
|
|
194
|
+
set interaction(val) {
|
|
195
|
+
this.material.interaction = val;
|
|
196
|
+
if (this.material.needUpdate()) {
|
|
197
|
+
this.scene?.queueUpdateNode(this);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
145
201
|
* Whether the surface reads as an unbounded ocean reaching the horizon,
|
|
146
202
|
* rather than a body of water ending at the node's extent.
|
|
147
203
|
*
|
|
148
|
-
* Off by default.
|
|
149
|
-
* that draws it is skipped entirely while this is on.
|
|
204
|
+
* Off by default. The region test is skipped while this is on.
|
|
150
205
|
*
|
|
151
206
|
* The horizon is reached without touching the camera's far plane: the
|
|
152
207
|
* clipmap's outermost ring is drawn as a skirt whose outer vertices are
|
|
153
|
-
* pushed well past it with their depth pinned to the far value.
|
|
154
|
-
* sized for the near scene therefore keeps its depth precision.
|
|
208
|
+
* pushed well past it with their depth pinned to the far value.
|
|
155
209
|
*/ get infinite() {
|
|
156
210
|
return this.material.infinite;
|
|
157
211
|
}
|
|
@@ -166,12 +220,9 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
166
220
|
* on, in meters. 0 derives it from the true horizon distance for the camera's
|
|
167
221
|
* height above the water.
|
|
168
222
|
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
* water out further than the aerial perspective LUT reaches and the far water
|
|
173
|
-
* stops converging towards the sky colour, which puts back the hard band this
|
|
174
|
-
* setting exists to remove.
|
|
223
|
+
* Geometry cost grows only logarithmically. Keep it within the sky's
|
|
224
|
+
* {@link SkyRenderer.aerialPerspectiveDistance}, or the far water stops
|
|
225
|
+
* converging towards the sky colour and shows a hard band.
|
|
175
226
|
*/ get viewDistance() {
|
|
176
227
|
return this._viewDistance;
|
|
177
228
|
}
|
|
@@ -188,6 +239,17 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
188
239
|
set animationSpeed(val) {
|
|
189
240
|
this._animationSpeed = val;
|
|
190
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* The wave clock the surface is currently at, in seconds.
|
|
244
|
+
*
|
|
245
|
+
* The time the displaced surface was last evaluated with (the value
|
|
246
|
+
* {@link WaterMaterial.update} is handed), not the scene's elapsed time. CPU
|
|
247
|
+
* samplers of the surface should use this clock; it matches `elapsedInSeconds`
|
|
248
|
+
* from {@link SceneNode.update} only while {@link animationSpeed} is 1 and the
|
|
249
|
+
* water has not been paused.
|
|
250
|
+
*/ get waveTime() {
|
|
251
|
+
return this._waveTime;
|
|
252
|
+
}
|
|
191
253
|
/** TAA strength of the water */ get TAAStrength() {
|
|
192
254
|
return this.material.TAAStrength;
|
|
193
255
|
}
|
|
@@ -228,10 +290,8 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
228
290
|
this.material.causticsSceneDepth = val;
|
|
229
291
|
}
|
|
230
292
|
/**
|
|
231
|
-
* Furthest distance in meters from the camera the caustic map reaches
|
|
232
|
-
*
|
|
233
|
-
* A cap rather than a fixed extent: the map is fitted to the part of the water
|
|
234
|
-
* within this distance.
|
|
293
|
+
* Furthest distance in meters from the camera the caustic map reaches; the
|
|
294
|
+
* map is fitted to the part of the water within this distance.
|
|
235
295
|
*/ get causticsRange() {
|
|
236
296
|
return this.material.causticsRange;
|
|
237
297
|
}
|
|
@@ -257,18 +317,21 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
257
317
|
set causticsWarp(val) {
|
|
258
318
|
this.material.causticsWarp = val;
|
|
259
319
|
}
|
|
320
|
+
/** Water depth in metres below which no caustics show. */ get causticsMinDepth() {
|
|
321
|
+
return this.material.causticsMinDepth;
|
|
322
|
+
}
|
|
323
|
+
set causticsMinDepth(val) {
|
|
324
|
+
this.material.causticsMinDepth = val;
|
|
325
|
+
}
|
|
260
326
|
/**
|
|
261
327
|
* Whether a camera inside this body of water sees the water from the inside:
|
|
262
328
|
* the medium applied to the whole scene, the sky replaced by water, and the
|
|
263
329
|
* surface read from below with its Snell window.
|
|
264
330
|
*
|
|
265
331
|
* Uses the same medium coefficients the surface does ({@link absorption},
|
|
266
|
-
* {@link scattering} and their scales)
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
* Only reaches opaque geometry, like the atmospheric fog it replaces;
|
|
271
|
-
* transparent surfaces are not tinted by the column in front of them.
|
|
332
|
+
* {@link scattering} and their scales). Atmospheric fog is suppressed while
|
|
333
|
+
* submerged. Only reaches opaque geometry, like the atmospheric fog it
|
|
334
|
+
* replaces.
|
|
272
335
|
*/ get underwaterEnabled() {
|
|
273
336
|
return this.material.underwaterEnabled;
|
|
274
337
|
}
|
|
@@ -288,9 +351,8 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
288
351
|
/**
|
|
289
352
|
* Whether shafts of sunlight are marched through the water column.
|
|
290
353
|
*
|
|
291
|
-
* Reads the caustic map as the surface's transmittance
|
|
292
|
-
*
|
|
293
|
-
* and everything it needs; switches itself off wherever the map is
|
|
354
|
+
* Reads the caustic map as the surface's transmittance. Needs
|
|
355
|
+
* {@link causticsEnabled}; switches itself off wherever the map is
|
|
294
356
|
* unavailable.
|
|
295
357
|
*/ get underwaterGodRays() {
|
|
296
358
|
return this.material.underwaterGodRays;
|
|
@@ -306,8 +368,7 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
306
368
|
}
|
|
307
369
|
/**
|
|
308
370
|
* Samples taken along each view ray for the light shafts. Raise it when the
|
|
309
|
-
* shafts read as grain rather than as beams
|
|
310
|
-
* a sharp caustic pattern look like.
|
|
371
|
+
* shafts read as grain rather than as beams.
|
|
311
372
|
*/ get underwaterGodRaySteps() {
|
|
312
373
|
return this.material.underwaterGodRaySteps;
|
|
313
374
|
}
|
|
@@ -318,11 +379,8 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
318
379
|
* Whether geometry standing in the water breaks the light shafts. Off by
|
|
319
380
|
* default.
|
|
320
381
|
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
* shaft runs straight through a piling or a hull. Costs a shadow map lookup
|
|
324
|
-
* per march step, roughly doubling what the shafts cost. The sea bed's own
|
|
325
|
-
* shadows are unaffected either way.
|
|
382
|
+
* Without it a shaft runs straight through a piling or a hull. Costs a shadow
|
|
383
|
+
* map lookup per march step, roughly doubling the cost of the shafts.
|
|
326
384
|
*/ get underwaterGodRayShadow() {
|
|
327
385
|
return this.material.underwaterGodRayShadow;
|
|
328
386
|
}
|
|
@@ -340,11 +398,37 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
340
398
|
this.material.underwaterHysteresis = val;
|
|
341
399
|
}
|
|
342
400
|
/**
|
|
401
|
+
* Strength of the glow of a backlit wave crest, 0 to disable. Authored, not
|
|
402
|
+
* scaled by the light's intensity; {@link subsurfaceTint} supplies the hue.
|
|
403
|
+
*/ get subsurfaceIntensity() {
|
|
404
|
+
return this.material.subsurfaceIntensity;
|
|
405
|
+
}
|
|
406
|
+
set subsurfaceIntensity(val) {
|
|
407
|
+
this.material.subsurfaceIntensity = val;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Height above the still-water level, in meters, over which the lit wall of
|
|
411
|
+
* a crest thins by a factor of `e`. Lower for a calm sea, higher so only the
|
|
412
|
+
* tallest crests glow.
|
|
413
|
+
*/ get subsurfaceCrestHeight() {
|
|
414
|
+
return this.material.subsurfaceCrestHeight;
|
|
415
|
+
}
|
|
416
|
+
set subsurfaceCrestHeight(val) {
|
|
417
|
+
this.material.subsurfaceCrestHeight = val;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Colour of the crest glow, before the crest gate tints it with the medium's
|
|
421
|
+
* extinction.
|
|
422
|
+
*/ get subsurfaceTint() {
|
|
423
|
+
return this.material.subsurfaceTint;
|
|
424
|
+
}
|
|
425
|
+
set subsurfaceTint(val) {
|
|
426
|
+
this.material.subsurfaceTint = val;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
343
429
|
* Strength of the sunlight scattered out of the water column towards the eye,
|
|
344
|
-
* 1 for the value the medium coefficients imply.
|
|
345
|
-
*
|
|
346
|
-
* This is what makes a shadow falling on the water darken the water itself,
|
|
347
|
-
* and a low sun tint it. 0 leaves the body lit by the environment alone.
|
|
430
|
+
* 1 for the value the medium coefficients imply. Lets shadows darken the
|
|
431
|
+
* water body and a low sun tint it; 0 leaves it lit by the environment alone.
|
|
348
432
|
*/ get sunScatteringIntensity() {
|
|
349
433
|
return this.material.sunScatteringIntensity;
|
|
350
434
|
}
|
|
@@ -352,91 +436,160 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
352
436
|
this.material.sunScatteringIntensity = val;
|
|
353
437
|
}
|
|
354
438
|
/**
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
* to a piling or a hull - so one band covers both the shoreline and the contact
|
|
362
|
-
* line around anything standing in the water.
|
|
363
|
-
* {@link shoreFoamWashAmount} is what makes it run up and drain back rather
|
|
364
|
-
* than sit there as a rim.
|
|
365
|
-
*
|
|
366
|
-
* Estimated from the depth buffer, so it only knows about what the camera can
|
|
367
|
-
* see: water in front of something standing above the surface gets no foam
|
|
368
|
-
* rather than a guess. See {@link WaterMaterial.shoreFoamAmount}.
|
|
369
|
-
*/ get shoreFoamAmount() {
|
|
370
|
-
return this.material.shoreFoamAmount;
|
|
439
|
+
* Crest to trough height in metres of the waves rolling in to the shore,
|
|
440
|
+
* breaking and running up the beach, 0 for none. They come square on to the
|
|
441
|
+
* coast whatever its shape, and boats ride them. Needs the scene signed
|
|
442
|
+
* distance field (WebGPU, scene SDF enabled).
|
|
443
|
+
*/ get shoreWaveHeight() {
|
|
444
|
+
return this.material.shoreWaveHeight;
|
|
371
445
|
}
|
|
372
|
-
set
|
|
373
|
-
this.material.
|
|
446
|
+
set shoreWaveHeight(val) {
|
|
447
|
+
this.material.shoreWaveHeight = val;
|
|
374
448
|
}
|
|
375
|
-
/**
|
|
376
|
-
|
|
377
|
-
* of water over a bed, a horizontal distance against anything vertical. How
|
|
378
|
-
* wide that is on screen depends on the geometry: a thin line on a steep
|
|
379
|
-
* drop-off, a broad stretch on a flat shelf.
|
|
380
|
-
*/ get shoreFoamDepth() {
|
|
381
|
-
return this.material.shoreFoamDepth;
|
|
449
|
+
/** Thickness in metres over which a thin sheet of water fades in from the ground under it; 0 disables it. */ get edgeFadeWidth() {
|
|
450
|
+
return this.material.edgeFadeWidth;
|
|
382
451
|
}
|
|
383
|
-
set
|
|
384
|
-
this.material.
|
|
452
|
+
set edgeFadeWidth(val) {
|
|
453
|
+
this.material.edgeFadeWidth = val;
|
|
385
454
|
}
|
|
386
|
-
/**
|
|
387
|
-
|
|
388
|
-
* keeps the outer edge thin and broken.
|
|
389
|
-
*/ get shoreFoamFalloff() {
|
|
390
|
-
return this.material.shoreFoamFalloff;
|
|
455
|
+
/** Distance in metres between shore wave crests at the outer edge of their zone. */ get shoreWaveLength() {
|
|
456
|
+
return this.material.shoreWaveLength;
|
|
391
457
|
}
|
|
392
|
-
set
|
|
393
|
-
this.material.
|
|
458
|
+
set shoreWaveLength(val) {
|
|
459
|
+
this.material.shoreWaveLength = val;
|
|
394
460
|
}
|
|
395
|
-
/**
|
|
396
|
-
|
|
397
|
-
*
|
|
398
|
-
* Relative to {@link shoreFoamDepth} rather than in cycles per metre, so one
|
|
399
|
-
* setting reads the same on a shoreline metres across and on a collar a
|
|
400
|
-
* handspan wide around a piling.
|
|
401
|
-
*/ get shoreFoamScale() {
|
|
402
|
-
return this.material.shoreFoamScale;
|
|
461
|
+
/** Seconds between successive shore waves. */ get shoreWavePeriod() {
|
|
462
|
+
return this.material.shoreWavePeriod;
|
|
403
463
|
}
|
|
404
|
-
set
|
|
405
|
-
this.material.
|
|
464
|
+
set shoreWavePeriod(val) {
|
|
465
|
+
this.material.shoreWavePeriod = val;
|
|
406
466
|
}
|
|
407
|
-
/**
|
|
408
|
-
|
|
409
|
-
* {@link shoreFoamDepth}. 0 leaves a static band.
|
|
410
|
-
*/ get shoreFoamWashAmount() {
|
|
411
|
-
return this.material.shoreFoamWashAmount;
|
|
467
|
+
/** How far out from the waterline the shore waves rise, in metres. */ get shoreWaveZone() {
|
|
468
|
+
return this.material.shoreWaveZone;
|
|
412
469
|
}
|
|
413
|
-
set
|
|
414
|
-
this.material.
|
|
470
|
+
set shoreWaveZone(val) {
|
|
471
|
+
this.material.shoreWaveZone = val;
|
|
415
472
|
}
|
|
416
|
-
/**
|
|
417
|
-
return this.material.
|
|
473
|
+
/** How sharp the shore wave crests become at the shore, 0 for a sine and towards 1 for a cusp. */ get shoreWaveSharpness() {
|
|
474
|
+
return this.material.shoreWaveSharpness;
|
|
418
475
|
}
|
|
419
|
-
set
|
|
420
|
-
this.material.
|
|
476
|
+
set shoreWaveSharpness(val) {
|
|
477
|
+
this.material.shoreWaveSharpness = val;
|
|
421
478
|
}
|
|
422
|
-
/**
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
479
|
+
/** How far the shore wave crests lean towards the shore there, 0 for upright, 1 for a steep front face. */ get shoreWaveLean() {
|
|
480
|
+
return this.material.shoreWaveLean;
|
|
481
|
+
}
|
|
482
|
+
set shoreWaveLean(val) {
|
|
483
|
+
this.material.shoreWaveLean = val;
|
|
484
|
+
}
|
|
485
|
+
/** How irregular the shore waves are, 0..1: 0 for parallel crests a fixed wavelength apart, higher for each wave with a period and a bend of its own. */ get shoreWaveIrregularity() {
|
|
486
|
+
return this.material.shoreWaveIrregularity;
|
|
487
|
+
}
|
|
488
|
+
set shoreWaveIrregularity(val) {
|
|
489
|
+
this.material.shoreWaveIrregularity = val;
|
|
490
|
+
}
|
|
491
|
+
/** How fast the foam fades, per second (Crest's Foam Fade Rate): lower leaves longer trails behind breaking waves. */ get foamFadeRate() {
|
|
492
|
+
return this.material.foamFadeRate;
|
|
493
|
+
}
|
|
494
|
+
set foamFadeRate(val) {
|
|
495
|
+
this.material.foamFadeRate = val;
|
|
496
|
+
}
|
|
497
|
+
/** How much foam the open water's breaking crests leave behind to drift and fade; 0 keeps foam only while a crest breaks. */ get foamTrailStrength() {
|
|
498
|
+
return this.material.foamTrailStrength;
|
|
499
|
+
}
|
|
500
|
+
set foamTrailStrength(val) {
|
|
501
|
+
this.material.foamTrailStrength = val;
|
|
502
|
+
}
|
|
503
|
+
/** Share of the wind speed the foam drifts at, about 0.03 in nature. */ get foamDrift() {
|
|
504
|
+
return this.material.foamDrift;
|
|
505
|
+
}
|
|
506
|
+
set foamDrift(val) {
|
|
507
|
+
this.material.foamDrift = val;
|
|
508
|
+
}
|
|
509
|
+
/** Side in metres of the finest square of water around the view whose foam lingers, in the most detail; coarser squares reach eight times as far, beyond which foam shows only while crests break. */ get foamFieldSize() {
|
|
510
|
+
return this.material.foamFieldSize;
|
|
511
|
+
}
|
|
512
|
+
set foamFieldSize(val) {
|
|
513
|
+
this.material.foamFieldSize = val;
|
|
514
|
+
}
|
|
515
|
+
/** How much foam the breaking shore waves make (Crest's Wave Foam Strength). */ get shoreWaveFoamStrength() {
|
|
516
|
+
return this.material.shoreWaveFoamStrength;
|
|
517
|
+
}
|
|
518
|
+
set shoreWaveFoamStrength(val) {
|
|
519
|
+
this.material.shoreWaveFoamStrength = val;
|
|
520
|
+
}
|
|
521
|
+
/** How much of the shore waves makes foam, 0..1, higher for more (Crest's Wave Foam Coverage). */ get shoreWaveFoamCoverage() {
|
|
522
|
+
return this.material.shoreWaveFoamCoverage;
|
|
523
|
+
}
|
|
524
|
+
set shoreWaveFoamCoverage(val) {
|
|
525
|
+
this.material.shoreWaveFoamCoverage = val;
|
|
526
|
+
}
|
|
527
|
+
/** Water shallower than this many metres makes foam (Crest's Shoreline Foam Max Depth). */ get shoreWaveShallowFoamDepth() {
|
|
528
|
+
return this.material.shoreWaveShallowFoamDepth;
|
|
529
|
+
}
|
|
530
|
+
set shoreWaveShallowFoamDepth(val) {
|
|
531
|
+
this.material.shoreWaveShallowFoamDepth = val;
|
|
428
532
|
}
|
|
429
|
-
|
|
430
|
-
this.material.
|
|
533
|
+
/** How much foam shallow water makes (Crest's Shoreline Foam Strength). */ get shoreWaveShallowFoamStrength() {
|
|
534
|
+
return this.material.shoreWaveShallowFoamStrength;
|
|
535
|
+
}
|
|
536
|
+
set shoreWaveShallowFoamStrength(val) {
|
|
537
|
+
this.material.shoreWaveShallowFoamStrength = val;
|
|
538
|
+
}
|
|
539
|
+
/** How opaque the foam is that the water makes against walls, rocks and piers standing in it, 0..1; it always rings them whole. */ get wallFoamStrength() {
|
|
540
|
+
return this.material.wallFoamStrength;
|
|
541
|
+
}
|
|
542
|
+
set wallFoamStrength(val) {
|
|
543
|
+
this.material.wallFoamStrength = val;
|
|
544
|
+
}
|
|
545
|
+
/** Speed in metres per second the water has to hit a wall at before it makes any foam there. */ get wallFoamMinSpeed() {
|
|
546
|
+
return this.material.wallFoamMinSpeed;
|
|
547
|
+
}
|
|
548
|
+
set wallFoamMinSpeed(val) {
|
|
549
|
+
this.material.wallFoamMinSpeed = val;
|
|
550
|
+
}
|
|
551
|
+
/** Speed in metres per second at which water hitting a wall makes the most foam. */ get wallFoamMaxSpeed() {
|
|
552
|
+
return this.material.wallFoamMaxSpeed;
|
|
553
|
+
}
|
|
554
|
+
set wallFoamMaxSpeed(val) {
|
|
555
|
+
this.material.wallFoamMaxSpeed = val;
|
|
556
|
+
}
|
|
557
|
+
/** Speed in metres per second the foam drifts out from walls, rocks and piers at: higher for a wider ring of foam around them. */ get wallFoamDrift() {
|
|
558
|
+
return this.material.wallFoamDrift;
|
|
559
|
+
}
|
|
560
|
+
set wallFoamDrift(val) {
|
|
561
|
+
this.material.wallFoamDrift = val;
|
|
562
|
+
}
|
|
563
|
+
/** Seconds the foam each breaking wave brings in lasts, behind the crest and up the beach. */ get surfFoamDuration() {
|
|
564
|
+
return this.material.surfFoamDuration;
|
|
565
|
+
}
|
|
566
|
+
set surfFoamDuration(val) {
|
|
567
|
+
this.material.surfFoamDuration = val;
|
|
568
|
+
}
|
|
569
|
+
/** Water depth in metres at and below which foam stops drifting and stays where it is. */ get foamSettleDepth() {
|
|
570
|
+
return this.material.foamSettleDepth;
|
|
571
|
+
}
|
|
572
|
+
set foamSettleDepth(val) {
|
|
573
|
+
this.material.foamSettleDepth = val;
|
|
574
|
+
}
|
|
575
|
+
/** Water depth in metres at and beyond which foam drifts freely. */ get foamDriftDepth() {
|
|
576
|
+
return this.material.foamDriftDepth;
|
|
577
|
+
}
|
|
578
|
+
set foamDriftDepth(val) {
|
|
579
|
+
this.material.foamDriftDepth = val;
|
|
580
|
+
}
|
|
581
|
+
/** How fast foam settled in shallow water and on the sand fades, as a share of the foam's fade. */ get settledFoamFade() {
|
|
582
|
+
return this.material.settledFoamFade;
|
|
583
|
+
}
|
|
584
|
+
set settledFoamFade(val) {
|
|
585
|
+
this.material.settledFoamFade = val;
|
|
431
586
|
}
|
|
432
587
|
/**
|
|
433
588
|
* How the refracted view sample is located. Defaults to `march`.
|
|
434
589
|
*
|
|
435
|
-
* `offset`
|
|
436
|
-
*
|
|
437
|
-
*
|
|
438
|
-
* smears rather than holding still. Set it on hardware that cannot afford the
|
|
439
|
-
* search.
|
|
590
|
+
* `offset` skips the depth-buffer search and displaces the screen UV by the
|
|
591
|
+
* wave normal instead: cheaper, but submerged silhouettes smear. For hardware
|
|
592
|
+
* that cannot afford the search.
|
|
440
593
|
*/ get refractionMode() {
|
|
441
594
|
return this.material.refractionMode;
|
|
442
595
|
}
|
|
@@ -457,9 +610,8 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
457
610
|
* Depth in meters the cheap refraction mode assumes the water is, used only
|
|
458
611
|
* when {@link refractionMode} is `offset`.
|
|
459
612
|
*
|
|
460
|
-
* Sets how strong the cheap distortion looks. A constant
|
|
461
|
-
*
|
|
462
|
-
* second copy of anything breaking the surface.
|
|
613
|
+
* Sets how strong the cheap distortion looks. A constant, because an offset
|
|
614
|
+
* scaled by the real depth paints a second copy of anything breaking the surface.
|
|
463
615
|
*/ get cheapRefractionDepth() {
|
|
464
616
|
return this.material.cheapRefractionDepth;
|
|
465
617
|
}
|
|
@@ -514,15 +666,10 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
514
666
|
/**
|
|
515
667
|
* Artistic scale on the refracted view offset. 1 is physical, 0 disables it.
|
|
516
668
|
*
|
|
517
|
-
* The offset
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
* only to dial the result back for a stylised look - not to make it correct.
|
|
522
|
-
*
|
|
523
|
-
* Values above 1 exaggerate; the surface stays continuous, but the sample can
|
|
524
|
-
* wander far enough from the true hit point that the medium tint stops
|
|
525
|
-
* matching what is visible through it.
|
|
669
|
+
* The offset comes from refracting the view ray by Snell's law and projecting
|
|
670
|
+
* its hit point back to the screen; this only dials it for a stylised look.
|
|
671
|
+
* Values above 1 exaggerate, and the medium tint may stop matching what is
|
|
672
|
+
* visible through the water.
|
|
526
673
|
*/ get refractionScale() {
|
|
527
674
|
return this.material.refractionScale;
|
|
528
675
|
}
|
|
@@ -532,11 +679,8 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
532
679
|
/**
|
|
533
680
|
* Scale on the Fresnel reflectance, 1 for the physical value.
|
|
534
681
|
*
|
|
535
|
-
* Below 1 the surface reflects less
|
|
536
|
-
*
|
|
537
|
-
* physically right but can bury a sea bed the shot is about; this is the knob
|
|
538
|
-
* that trades that reflection away. The F0 floor is scaled with it, so 0 gives
|
|
539
|
-
* a surface with no specular response at all.
|
|
682
|
+
* Below 1 the surface reflects less and shows more of what is beneath it. The
|
|
683
|
+
* F0 floor is scaled with it, so 0 gives no specular response at all.
|
|
540
684
|
*/ get reflectionStrength() {
|
|
541
685
|
return this.material.reflectionStrength;
|
|
542
686
|
}
|
|
@@ -546,9 +690,8 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
546
690
|
/**
|
|
547
691
|
* How much of a folded texel reads as foam.
|
|
548
692
|
*
|
|
549
|
-
*
|
|
550
|
-
*
|
|
551
|
-
* coverage fraction. 0 disables foam.
|
|
693
|
+
* Scales the wave generator's fold measure into a coverage fraction. 0
|
|
694
|
+
* disables foam.
|
|
552
695
|
*/ get foamAmount() {
|
|
553
696
|
return this.material.foamAmount;
|
|
554
697
|
}
|
|
@@ -558,9 +701,8 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
558
701
|
/**
|
|
559
702
|
* Falloff applied to foam coverage before it is scaled.
|
|
560
703
|
*
|
|
561
|
-
* Above 1 this pushes light folding towards no foam
|
|
562
|
-
*
|
|
563
|
-
* turning uniformly white.
|
|
704
|
+
* Above 1 this pushes light folding towards no foam, so only broken crests
|
|
705
|
+
* show any.
|
|
564
706
|
*/ get foamFalloff() {
|
|
565
707
|
return this.material.foamFalloff;
|
|
566
708
|
}
|
|
@@ -576,38 +718,46 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
576
718
|
/** {@inheritDoc SceneNode.update} */ update(frameId, elapsedInSeconds) {
|
|
577
719
|
if (this.material.needUpdate()) {
|
|
578
720
|
this.scene?.queueUpdateNode(this);
|
|
721
|
+
if (this.hidden) {
|
|
722
|
+
// Nothing shows the waves, the interaction or the foam: leave them be, and
|
|
723
|
+
// pick the phase up from here once the water shows again
|
|
724
|
+
this._lastUpdateTime = elapsedInSeconds;
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
579
727
|
if (this._timeStart === 0) {
|
|
580
728
|
this._timeStart = elapsedInSeconds;
|
|
581
729
|
}
|
|
582
|
-
//
|
|
583
|
-
// elapsed time by the speed makes a speed of zero freeze the surface at
|
|
584
|
-
// the origin of the timeline instead of where it is, so pausing snapped
|
|
585
|
-
// the waves back to their first frame. Accumulating the delta keeps the
|
|
586
|
-
// phase where it was, and a speed of zero simply stops advancing it.
|
|
730
|
+
// Accumulate the scaled delta so a speed of zero freezes the phase in place.
|
|
587
731
|
this._waveTime += Math.max(0, elapsedInSeconds - Math.max(this._timeStart, this._lastUpdateTime)) * this._animationSpeed;
|
|
588
732
|
this._lastUpdateTime = elapsedInSeconds;
|
|
733
|
+
const interaction = this.material.interaction;
|
|
734
|
+
if (interaction) {
|
|
735
|
+
interaction.resolveNodes(this.scene);
|
|
736
|
+
interaction.setWaterLevel(this.worldMatrix.m13);
|
|
737
|
+
}
|
|
589
738
|
this.material.update(frameId, this._waveTime);
|
|
590
739
|
this.invalidateWorldBoundingVolume(false);
|
|
591
740
|
}
|
|
592
741
|
}
|
|
593
742
|
/** {@inheritDoc SceneNode.updatePerCamera} */ updatePerCamera(camera, _elapsedInSeconds, _deltaInSeconds) {
|
|
594
743
|
const mat = this._material.get();
|
|
744
|
+
if (mat && this.hidden) {
|
|
745
|
+
// Not drawn: no surface to gather, no shore or foam field to step
|
|
746
|
+
this.scene?.queuePerCameraUpdateNode(this);
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
595
749
|
if (mat) {
|
|
596
750
|
const that = this;
|
|
597
751
|
const infinite = mat.infinite;
|
|
598
752
|
let viewDistance = 0;
|
|
599
753
|
if (infinite) {
|
|
600
754
|
viewDistance = this._viewDistance > 0 ? this._viewDistance : this.horizonDistance(camera);
|
|
601
|
-
// The skirt's outer edge sits beyond
|
|
602
|
-
// so the band between them is what hides the last ring of geometry.
|
|
755
|
+
// The skirt's outer edge sits beyond the tessellated surface to hide its last ring.
|
|
603
756
|
mat.setSkirtDistance(viewDistance * SKIRT_DISTANCE_FACTOR);
|
|
604
757
|
}
|
|
605
758
|
this._renderData = this._clipmap.gather({
|
|
606
759
|
camera,
|
|
607
|
-
// An unbounded surface is not clipped to the node's
|
|
608
|
-
// region rectangle is what the clipmap would otherwise reject tiles
|
|
609
|
-
// against. The material's own default is already this whole-domain
|
|
610
|
-
// value; passing it keeps the two agreeing.
|
|
760
|
+
// An unbounded surface is not clipped to the node's region.
|
|
611
761
|
minMaxWorldPos: infinite ? WHOLE_DOMAIN : mat.region,
|
|
612
762
|
gridScale: Math.max(0.01, this._gridScale),
|
|
613
763
|
userData: this,
|
|
@@ -616,8 +766,8 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
616
766
|
skirt: infinite,
|
|
617
767
|
calcAABB (userData, minX, maxX, minZ, maxZ, outAABB) {
|
|
618
768
|
const p = that.worldMatrix.transformPointAffine(Vector3.zero());
|
|
619
|
-
if (
|
|
620
|
-
|
|
769
|
+
if (mat.waveGenerator) {
|
|
770
|
+
mat.waveGenerator.calcClipmapTileAABB(minX, maxX, minZ, maxZ, p.y, outAABB);
|
|
621
771
|
} else {
|
|
622
772
|
outAABB.minPoint.setXYZ(minX, p.y, minZ);
|
|
623
773
|
outAABB.maxPoint.setXYZ(maxX, p.y + 1, maxZ);
|
|
@@ -625,25 +775,135 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
625
775
|
}
|
|
626
776
|
});
|
|
627
777
|
this.updateSubmergence(camera, mat);
|
|
778
|
+
const interaction = mat.interaction;
|
|
779
|
+
const wantsDepth = !!interaction && interaction.shallowDepth > 0;
|
|
780
|
+
if ((mat.shoreWaveHeight > 0 || wantsDepth) && this.scene?.sdf.enabled) {
|
|
781
|
+
// The interaction field and the shore waves read the waterline at the rest level
|
|
782
|
+
this.scene.sdf.global?.waterline.request(this.worldMatrix.m13);
|
|
783
|
+
}
|
|
784
|
+
if (mat.shoreWaveHeight > 0) {
|
|
785
|
+
// The waves and the beach's foam follow the terrain alone, in levels
|
|
786
|
+
// out to the foam field's reach; the foam against walls, rocks and
|
|
787
|
+
// piers the scene field's single level. Without a terrain the scene
|
|
788
|
+
// field shapes the waves too.
|
|
789
|
+
const terrainField = this.updateShoreField(camera);
|
|
790
|
+
const waterline = this.scene?.sdf.enabled ? this.scene.sdf.global?.waterline : null;
|
|
791
|
+
const wall = waterline?.ready ? waterline : null;
|
|
792
|
+
const shore = terrainField?.ready ? terrainField : terrainField ? null : wall;
|
|
793
|
+
mat.setShoreWaveFrame(shore?.smoothTexture ?? null, shore?.regions ?? NO_REGIONS, wall?.smoothTexture ?? null, wall?.region ?? NO_REGIONS[0], this.worldMatrix.m13);
|
|
794
|
+
}
|
|
795
|
+
if (interaction) {
|
|
796
|
+
interaction.setBathymetry(wantsDepth ? this.findBathymetry() : null);
|
|
797
|
+
}
|
|
798
|
+
if (interaction && interaction.followMode === 'camera') {
|
|
799
|
+
const focus = this.viewFocus(camera, interaction.windowSize * 0.5);
|
|
800
|
+
interaction.setFocus(focus.x, focus.y);
|
|
801
|
+
}
|
|
802
|
+
// After the shore waves' frame, which the foam field's sources read
|
|
803
|
+
const foamFocus = this.viewFocus(camera, mat.foamFieldSize * 0.5);
|
|
804
|
+
RenderGraphExecutor.profileScope('WaterFoamField', ()=>mat.updateFoamField(foamFocus.x, foamFocus.y));
|
|
628
805
|
this.scene?.queuePerCameraUpdateNode(this);
|
|
629
806
|
}
|
|
630
807
|
}
|
|
631
808
|
/**
|
|
809
|
+
* Where the interaction field reads the depth of the water: the scene
|
|
810
|
+
* field's waterline grid when there is one, else the first terrain's height
|
|
811
|
+
* map, else nothing.
|
|
812
|
+
* @internal
|
|
813
|
+
*/ findBathymetry() {
|
|
814
|
+
const level = this.worldMatrix.m13;
|
|
815
|
+
const waterline = this.scene?.sdf.enabled ? this.scene.sdf.global?.waterline : null;
|
|
816
|
+
if (waterline?.ready && waterline.texture) {
|
|
817
|
+
const r = waterline.region;
|
|
818
|
+
return {
|
|
819
|
+
kind: 'field',
|
|
820
|
+
texture: waterline.texture,
|
|
821
|
+
region: [
|
|
822
|
+
r.x,
|
|
823
|
+
r.y,
|
|
824
|
+
r.z * r.w,
|
|
825
|
+
r.z * r.w
|
|
826
|
+
],
|
|
827
|
+
level
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
let terrain = this.findTerrain();
|
|
831
|
+
const heightMap = terrain?.heightMap;
|
|
832
|
+
if (!terrain || !heightMap) {
|
|
833
|
+
return null;
|
|
834
|
+
}
|
|
835
|
+
const region = terrain.worldRegion;
|
|
836
|
+
return {
|
|
837
|
+
kind: 'height',
|
|
838
|
+
texture: heightMap,
|
|
839
|
+
region: [
|
|
840
|
+
region.x,
|
|
841
|
+
region.y,
|
|
842
|
+
region.z - region.x,
|
|
843
|
+
region.w - region.y
|
|
844
|
+
],
|
|
845
|
+
level,
|
|
846
|
+
heightScale: Math.abs(terrain.scale.y),
|
|
847
|
+
heightOffset: terrain.worldMatrix.m13
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
/** The first terrain in the scene, cached while it stays in it. @internal */ findTerrain() {
|
|
851
|
+
let terrain = this._bathyTerrain?.attached && this._bathyTerrain.scene === this.scene ? this._bathyTerrain : null;
|
|
852
|
+
if (!terrain && this.scene) {
|
|
853
|
+
this.scene.rootNode.iterate((node)=>{
|
|
854
|
+
if (node.isClipmapTerrain()) {
|
|
855
|
+
terrain = node;
|
|
856
|
+
return true;
|
|
857
|
+
}
|
|
858
|
+
return false;
|
|
859
|
+
});
|
|
860
|
+
this._bathyTerrain = terrain;
|
|
861
|
+
}
|
|
862
|
+
return terrain;
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Rebuilds the shore field, the waterline of the terrain alone in levels
|
|
866
|
+
* around the camera, which the shore waves read, and returns it. Null
|
|
867
|
+
* without a terrain or off WebGPU.
|
|
868
|
+
* @internal
|
|
869
|
+
*/ updateShoreField(camera) {
|
|
870
|
+
const terrain = this.findTerrain();
|
|
871
|
+
const device = getDevice();
|
|
872
|
+
if (!terrain?.heightMap || device.type !== 'webgpu') {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
if (!this._shoreField) {
|
|
876
|
+
this._shoreSource = new TerrainWaterlineSource();
|
|
877
|
+
this._shoreField = new WaterlineField(this._shoreSource, {
|
|
878
|
+
levels: SHORE_FIELD_LEVELS,
|
|
879
|
+
resolution: SHORE_FIELD_CELLS,
|
|
880
|
+
cellSize: SHORE_FIELD_CELL_SIZE,
|
|
881
|
+
maxRebuilds: SHORE_FIELD_REBUILDS
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
this._shoreSource.setTerrain(terrain);
|
|
885
|
+
this._shoreField.request(this.worldMatrix.m13);
|
|
886
|
+
device.pushDeviceStates();
|
|
887
|
+
try {
|
|
888
|
+
RenderGraphExecutor.profileScope('WaterShoreField', ()=>this._shoreField.update(camera.getWorldPosition()));
|
|
889
|
+
} finally{
|
|
890
|
+
device.popDeviceStates();
|
|
891
|
+
}
|
|
892
|
+
return this._shoreField;
|
|
893
|
+
}
|
|
894
|
+
/** @internal */ _shoreSource = null;
|
|
895
|
+
/** @internal */ _shoreField = null;
|
|
896
|
+
/** @internal */ _bathyTerrain = null;
|
|
897
|
+
/**
|
|
632
898
|
* Decide whether `camera` is inside this body of water and publish the result.
|
|
633
899
|
*
|
|
634
|
-
* Run from `updatePerCamera`, which
|
|
635
|
-
*
|
|
636
|
-
* is exactly what a camera on the sea bed looking down does to it.
|
|
637
|
-
*
|
|
638
|
-
* The test is against the rest plane rather than the displaced surface. Reading
|
|
639
|
-
* the real wave height means a GPU readback ({@link Water.getSurfacePoint}) and
|
|
640
|
-
* the frame or two of latency that comes with it; against that, the plane is
|
|
641
|
-
* wrong only while the eye is within a wave height of the surface, which is
|
|
642
|
-
* also the one case this feature deliberately does not try to render.
|
|
900
|
+
* Run from `updatePerCamera`, which runs every frame regardless of culling, so
|
|
901
|
+
* the state survives the surface leaving the frustum.
|
|
643
902
|
*
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
*
|
|
903
|
+
* The test is against the rest plane rather than the displaced surface, which
|
|
904
|
+
* would need a GPU readback. A dead band of
|
|
905
|
+
* {@link WaterMaterial.underwaterHysteresis} around the plane keeps an eye at
|
|
906
|
+
* water level from flipping state every frame.
|
|
647
907
|
* @internal
|
|
648
908
|
*/ updateSubmergence(camera, mat) {
|
|
649
909
|
const surfaceY = this.worldMatrix.transformPointAffine(Vector3.zero()).y;
|
|
@@ -651,9 +911,7 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
651
911
|
if (!this.hidden && this.attached) {
|
|
652
912
|
const camPos = camera.getWorldPosition();
|
|
653
913
|
const region = mat.region;
|
|
654
|
-
//
|
|
655
|
-
// only entered from within its own footprint, so a camera beside a pool at
|
|
656
|
-
// the height of its water is not in it.
|
|
914
|
+
// A bounded surface is only entered from within its own footprint.
|
|
657
915
|
const inside = mat.infinite || camPos.x >= region.x && camPos.x <= region.z && camPos.z >= region.y && camPos.z <= region.w;
|
|
658
916
|
if (inside) {
|
|
659
917
|
const band = mat.underwaterHysteresis;
|
|
@@ -664,19 +922,44 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
664
922
|
setWaterSubmergence(camera, this, submerged, surfaceY);
|
|
665
923
|
}
|
|
666
924
|
/**
|
|
925
|
+
* The water the camera is looking at, on which a window that follows the
|
|
926
|
+
* view (the interaction field, the foam field) is centred.
|
|
927
|
+
*
|
|
928
|
+
* Where the view direction meets the rest plane, no further ahead than
|
|
929
|
+
* `reach` (half a window), so the window covers the visible water rather
|
|
930
|
+
* than putting it in the sponge band at its edge.
|
|
931
|
+
* @internal
|
|
932
|
+
*/ viewFocus(camera, reach) {
|
|
933
|
+
const camPos = camera.getWorldPosition();
|
|
934
|
+
const m = camera.worldMatrix;
|
|
935
|
+
// The camera looks down its local -Z.
|
|
936
|
+
const fx = -m.m02;
|
|
937
|
+
const fy = -m.m12;
|
|
938
|
+
const fz = -m.m22;
|
|
939
|
+
const horizontal = Math.hypot(fx, fz);
|
|
940
|
+
let ahead = reach;
|
|
941
|
+
if (fy < -1e-4) {
|
|
942
|
+
const t = (this.worldMatrix.m13 - camPos.y) / fy;
|
|
943
|
+
if (t > 0) {
|
|
944
|
+
ahead = Math.min(reach, t * horizontal);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
if (horizontal < 1e-6) {
|
|
948
|
+
return new Vector2(camPos.x, camPos.z);
|
|
949
|
+
}
|
|
950
|
+
return new Vector2(camPos.x + fx / horizontal * ahead, camPos.z + fz / horizontal * ahead);
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
667
953
|
* Distance to the true horizon for the camera's height above this water, in
|
|
668
954
|
* meters.
|
|
669
955
|
*
|
|
670
956
|
* `sqrt(2 * R * h)` for earth's radius: about 5km from an eye 2m up, 25km
|
|
671
|
-
* from 50m.
|
|
672
|
-
* horizon move correctly as the camera climbs, which is most of what sells
|
|
673
|
-
* the scale of an ocean.
|
|
957
|
+
* from 50m.
|
|
674
958
|
* @internal
|
|
675
959
|
*/ horizonDistance(camera) {
|
|
676
960
|
const camPos = camera.getWorldPosition();
|
|
677
961
|
const waterLevel = this.worldMatrix.transformPointAffine(Vector3.zero()).y;
|
|
678
|
-
//
|
|
679
|
-
// also keeps the sqrt away from zero when the eye is exactly at water level.
|
|
962
|
+
// Floored for cameras at or below the surface.
|
|
680
963
|
const height = Math.max(camPos.y - waterLevel, MIN_HORIZON_EYE_HEIGHT);
|
|
681
964
|
return Math.sqrt(2 * EARTH_RADIUS * height);
|
|
682
965
|
}
|
|
@@ -719,11 +1002,6 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
719
1002
|
return this._material.get()?.needSceneDepth() ?? false;
|
|
720
1003
|
}
|
|
721
1004
|
/**
|
|
722
|
-
* {@inheritDoc Drawable.needHiZNearest}
|
|
723
|
-
*/ needHiZNearest() {
|
|
724
|
-
return this._material.get()?.needHiZNearest() ?? false;
|
|
725
|
-
}
|
|
726
|
-
/**
|
|
727
1005
|
* {@inheritDoc Drawable.getMaterial}
|
|
728
1006
|
*/ getMaterial() {
|
|
729
1007
|
return this._material.get();
|
|
@@ -749,10 +1027,8 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
749
1027
|
const p = this.worldMatrix.transformPointAffine(Vector3.zero());
|
|
750
1028
|
const mat = this._material?.get();
|
|
751
1029
|
if (mat) {
|
|
752
|
-
//
|
|
753
|
-
//
|
|
754
|
-
// decision to the clipmap's per-tile culling - the only place that can
|
|
755
|
-
// decide it, since the surface is built around wherever the camera is.
|
|
1030
|
+
// Null keeps an unbounded surface in the queue (ClipState.CLIPPED) and
|
|
1031
|
+
// leaves culling to the clipmap's per-tile test.
|
|
756
1032
|
if (mat.infinite) {
|
|
757
1033
|
return null;
|
|
758
1034
|
}
|
|
@@ -803,7 +1079,7 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
803
1079
|
const mat = this._material?.get();
|
|
804
1080
|
if (mat) {
|
|
805
1081
|
this.bind(ctx, renderQueue);
|
|
806
|
-
mat.setClipmapGridInfo(this._gridScale, this.worldMatrix.m03, this.worldMatrix.m23);
|
|
1082
|
+
mat.setClipmapGridInfo(this._gridScale, this.worldMatrix.m03, this.worldMatrix.m23, this._clipmap.tileResolution);
|
|
807
1083
|
mat.apply(ctx);
|
|
808
1084
|
for (const info of this._renderData){
|
|
809
1085
|
mat.draw(info.primitive, ctx, info.numInstances);
|
|
@@ -811,99 +1087,185 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
811
1087
|
}
|
|
812
1088
|
}
|
|
813
1089
|
/**
|
|
814
|
-
*
|
|
815
|
-
|
|
1090
|
+
* Retrieve the disturbed world position and normal at water surface.
|
|
1091
|
+
* Set includeDisturbers to false for buoyancy: retain ambient waves and
|
|
1092
|
+
* external impulses, but exclude waves generated by moving disturbers.
|
|
1093
|
+
*/ async getSurfacePoint(points, outPos, outNorm, includeDisturbers = true) {
|
|
1094
|
+
if (!outPos && !outNorm) {
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
const hits = await this._evaluateSurfacePoints(points, !!outNorm, includeDisturbers);
|
|
1098
|
+
if (!hits) {
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
for(let i = 0; i < points.length; i++){
|
|
1102
|
+
outPos && outPos[i].setXYZ(hits[i].x, hits[i].y, hits[i].z);
|
|
1103
|
+
outNorm && outNorm[i].setXYZ(hits[i].nx, hits[i].ny, hits[i].nz);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Evaluate the disturbed surface over a set of world XZ positions.
|
|
1108
|
+
*
|
|
1109
|
+
* Evaluated by the same wave generator the material draws with, so it is
|
|
1110
|
+
* exact by construction. Costs one point-list draw plus one readback per call.
|
|
1111
|
+
* Requests are serialized because the vertex buffer and render target are
|
|
1112
|
+
* shared.
|
|
1113
|
+
*
|
|
1114
|
+
* @param points - World XZ positions to evaluate. Y is ignored.
|
|
1115
|
+
* @param withNormal - Whether to also read the surface normal back, which
|
|
1116
|
+
* costs a second readback of the same size.
|
|
1117
|
+
* @returns One hit per input point, or null if `points` was empty.
|
|
1118
|
+
* @internal
|
|
1119
|
+
*/ async _evaluateSurfacePoints(points, withNormal, includeDisturbers = true) {
|
|
816
1120
|
const device = getDevice();
|
|
817
1121
|
if (!points || points.length === 0) {
|
|
818
|
-
return;
|
|
1122
|
+
return null;
|
|
819
1123
|
}
|
|
820
1124
|
points = points.map((v)=>v.clone());
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
vb.bufferSubData(0, vertices);
|
|
851
|
-
}
|
|
852
|
-
const fb = this._feedbackRenderTarget.get();
|
|
853
|
-
if (!fb || fb.getColorAttachment(0).width < points.length) {
|
|
854
|
-
const rt0 = device.createTexture2D('rgba32f', points.length, 1, {
|
|
855
|
-
mipmapping: false
|
|
856
|
-
});
|
|
857
|
-
const rt1 = device.createTexture2D('rgba32f', points.length, 1, {
|
|
858
|
-
mipmapping: false
|
|
859
|
-
});
|
|
860
|
-
if (fb) {
|
|
861
|
-
fb.getColorAttachment(0).dispose();
|
|
862
|
-
fb.getColorAttachment(1).dispose();
|
|
863
|
-
this._feedbackRenderTarget.dispose();
|
|
1125
|
+
const timing = {
|
|
1126
|
+
issued: device.frameInfo.frameCounter,
|
|
1127
|
+
recorded: 0,
|
|
1128
|
+
mapped: 0
|
|
1129
|
+
};
|
|
1130
|
+
// Take and replace the queue's tail in one synchronous step before awaiting,
|
|
1131
|
+
// so two callers arriving together cannot both pass the same settled tail.
|
|
1132
|
+
const previous = this._feedbackQueue;
|
|
1133
|
+
let release = ()=>{};
|
|
1134
|
+
this._feedbackQueue = new Promise((resolve)=>release = resolve);
|
|
1135
|
+
await previous;
|
|
1136
|
+
const hits = points.map(()=>({
|
|
1137
|
+
x: 0,
|
|
1138
|
+
y: 0,
|
|
1139
|
+
z: 0,
|
|
1140
|
+
nx: 0,
|
|
1141
|
+
ny: 1,
|
|
1142
|
+
nz: 0
|
|
1143
|
+
}));
|
|
1144
|
+
try {
|
|
1145
|
+
await device.runNextFrameAsync(async ()=>{
|
|
1146
|
+
timing.recorded = device.frameInfo.frameCounter;
|
|
1147
|
+
const renderedGenerator = this.material.waveGenerator;
|
|
1148
|
+
const waveGenerator = !includeDisturbers && renderedGenerator instanceof InteractiveWaveGenerator ? new InteractiveWaveGenerator(renderedGenerator.base, renderedGenerator.interaction, false) : renderedGenerator;
|
|
1149
|
+
const feedbackHash = waveGenerator?.getHash() ?? '';
|
|
1150
|
+
if (this._feedbackProgram.get() && this._feedbackHash !== feedbackHash) {
|
|
1151
|
+
// The wave generator changed; rebuild the program for it.
|
|
1152
|
+
this._feedbackBindGroup.dispose();
|
|
1153
|
+
this._feedbackProgram.dispose();
|
|
864
1154
|
}
|
|
865
|
-
this.
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
}
|
|
870
|
-
primitive.indexCount = points.length;
|
|
871
|
-
const bindGroup = this._feedbackBindGroup.get();
|
|
872
|
-
bindGroup.setValue('textureWidth', this._feedbackRenderTarget.get().getWidth());
|
|
873
|
-
this.waveGenerator.applyWaterBindGroup(bindGroup);
|
|
874
|
-
device.pushDeviceStates();
|
|
875
|
-
device.setProgram(this._feedbackProgram.get());
|
|
876
|
-
device.setBindGroup(0, this._feedbackBindGroup.get());
|
|
877
|
-
device.setFramebuffer(this._feedbackRenderTarget.get());
|
|
878
|
-
this._feedbackPrimitive.get().draw();
|
|
879
|
-
device.popDeviceStates();
|
|
880
|
-
const pos = new Float32Array(points.length * 4);
|
|
881
|
-
const norm = new Float32Array(points.length * 4);
|
|
882
|
-
await Promise.all([
|
|
883
|
-
this._feedbackRenderTarget.get().getColorAttachment(0).readPixels(0, 0, points.length, 1, 0, 0, pos),
|
|
884
|
-
this._feedbackRenderTarget.get().getColorAttachment(1).readPixels(0, 0, points.length, 1, 0, 0, norm)
|
|
885
|
-
]);
|
|
886
|
-
for(let i = 0; i < points.length; i++){
|
|
887
|
-
if (outPos) {
|
|
888
|
-
outPos[i].setXYZ(pos[i * 4 + 0], pos[i * 4 + 1], pos[i * 4 + 2]);
|
|
1155
|
+
if (!this._feedbackProgram.get()) {
|
|
1156
|
+
this._feedbackHash = feedbackHash;
|
|
1157
|
+
this._feedbackProgram.set(this._createFeedbackProgram(device, waveGenerator));
|
|
1158
|
+
this._feedbackBindGroup.set(device.createBindGroup(this._feedbackProgram.get().bindGroupLayouts[0]));
|
|
889
1159
|
}
|
|
890
|
-
if (
|
|
891
|
-
|
|
1160
|
+
if (!this._feedbackPrimitive.get()) {
|
|
1161
|
+
this._feedbackPrimitive.set(new Primitive());
|
|
1162
|
+
this._feedbackPrimitive.get().primitiveType = 'point-list';
|
|
892
1163
|
}
|
|
893
|
-
|
|
894
|
-
|
|
1164
|
+
if (!this._feedbackRenderStates) {
|
|
1165
|
+
this._feedbackRenderStates = device.createRenderStateSet();
|
|
1166
|
+
this._feedbackRenderStates.useDepthState().enableTest(false).enableWrite(false);
|
|
1167
|
+
this._feedbackRenderStates.useRasterizerState().setCullMode('none');
|
|
1168
|
+
}
|
|
1169
|
+
const primitive = this._feedbackPrimitive.get();
|
|
1170
|
+
const vertices = new Float32Array(points.length * 4);
|
|
1171
|
+
// The generators displace from the still-water level, so it replaces the caller's Y.
|
|
1172
|
+
const level = this.worldMatrix.m13;
|
|
1173
|
+
for(let i = 0; i < points.length; i++){
|
|
1174
|
+
vertices[i * 4 + 0] = points[i].x;
|
|
1175
|
+
vertices[i * 4 + 1] = level;
|
|
1176
|
+
vertices[i * 4 + 2] = points[i].z;
|
|
1177
|
+
vertices[i * 4 + 3] = i;
|
|
1178
|
+
}
|
|
1179
|
+
let vb = primitive.getVertexBuffer('position');
|
|
1180
|
+
if (!vb || vb.byteLength !== vertices.byteLength) {
|
|
1181
|
+
vb = device.createVertexBuffer('position_f32x4', vertices, {
|
|
1182
|
+
dynamic: true
|
|
1183
|
+
});
|
|
1184
|
+
primitive.setVertexBuffer(vb);
|
|
1185
|
+
} else {
|
|
1186
|
+
vb.bufferSubData(0, vertices);
|
|
1187
|
+
}
|
|
1188
|
+
const fb = this._feedbackRenderTarget.get();
|
|
1189
|
+
if (!fb || fb.getColorAttachment(0).width < points.length) {
|
|
1190
|
+
const rt0 = device.createTexture2D('rgba32f', points.length, 1, {
|
|
1191
|
+
mipmapping: false
|
|
1192
|
+
});
|
|
1193
|
+
const rt1 = device.createTexture2D('rgba32f', points.length, 1, {
|
|
1194
|
+
mipmapping: false
|
|
1195
|
+
});
|
|
1196
|
+
if (fb) {
|
|
1197
|
+
fb.getColorAttachment(0).dispose();
|
|
1198
|
+
fb.getColorAttachment(1).dispose();
|
|
1199
|
+
this._feedbackRenderTarget.dispose();
|
|
1200
|
+
}
|
|
1201
|
+
this._feedbackRenderTarget.set(device.createFrameBuffer([
|
|
1202
|
+
rt0,
|
|
1203
|
+
rt1
|
|
1204
|
+
], null));
|
|
1205
|
+
}
|
|
1206
|
+
primitive.indexCount = points.length;
|
|
1207
|
+
const bindGroup = this._feedbackBindGroup.get();
|
|
1208
|
+
bindGroup.setValue('textureWidth', this._feedbackRenderTarget.get().getWidth());
|
|
1209
|
+
if (waveGenerator) {
|
|
1210
|
+
waveGenerator.applyWaterBindGroup(bindGroup);
|
|
1211
|
+
ShaderHelper.setStandaloneCameraTime(bindGroup);
|
|
1212
|
+
}
|
|
1213
|
+
device.pushDeviceStates();
|
|
1214
|
+
device.setProgram(this._feedbackProgram.get());
|
|
1215
|
+
device.setBindGroup(0, this._feedbackBindGroup.get());
|
|
1216
|
+
device.setFramebuffer(this._feedbackRenderTarget.get());
|
|
1217
|
+
this._feedbackPrimitive.get().draw();
|
|
1218
|
+
device.popDeviceStates();
|
|
1219
|
+
const pos = new Float32Array(points.length * 4);
|
|
1220
|
+
// The normal attachment is only read when wanted, halving the readback otherwise.
|
|
1221
|
+
const norm = withNormal ? new Float32Array(points.length * 4) : null;
|
|
1222
|
+
// readPixels records its copy synchronously; flushing right after lets the
|
|
1223
|
+
// readback start before this frame's main render is recorded. This runs from
|
|
1224
|
+
// beginFrame, so the submit carries only the feedback work.
|
|
1225
|
+
const readPos = this._feedbackRenderTarget.get().getColorAttachment(0).readPixels(0, 0, points.length, 1, 0, 0, pos);
|
|
1226
|
+
const readNorm = norm ? this._feedbackRenderTarget.get().getColorAttachment(1).readPixels(0, 0, points.length, 1, 0, 0, norm) : Promise.resolve();
|
|
1227
|
+
device.flush();
|
|
1228
|
+
await Promise.all([
|
|
1229
|
+
readPos,
|
|
1230
|
+
readNorm
|
|
1231
|
+
]);
|
|
1232
|
+
timing.mapped = device.frameInfo.frameCounter;
|
|
1233
|
+
this.lastFeedbackTiming = timing;
|
|
1234
|
+
for(let i = 0; i < points.length; i++){
|
|
1235
|
+
hits[i].x = pos[i * 4 + 0];
|
|
1236
|
+
hits[i].y = pos[i * 4 + 1];
|
|
1237
|
+
hits[i].z = pos[i * 4 + 2];
|
|
1238
|
+
if (norm) {
|
|
1239
|
+
hits[i].nx = norm[i * 4 + 0];
|
|
1240
|
+
hits[i].ny = norm[i * 4 + 1];
|
|
1241
|
+
hits[i].nz = norm[i * 4 + 2];
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
});
|
|
1245
|
+
} finally{
|
|
1246
|
+
release();
|
|
1247
|
+
}
|
|
1248
|
+
return hits;
|
|
895
1249
|
}
|
|
896
|
-
/** @internal */ _createFeedbackProgram(device) {
|
|
897
|
-
const that = this;
|
|
1250
|
+
/** @internal */ _createFeedbackProgram(device, waveGenerator) {
|
|
898
1251
|
const program = device.buildRenderProgram({
|
|
899
1252
|
vertex (pb) {
|
|
900
1253
|
this.$inputs.position = pb.vec4().attrib('position');
|
|
901
1254
|
this.textureWidth = pb.float().uniform(0);
|
|
902
|
-
|
|
1255
|
+
if (waveGenerator) {
|
|
1256
|
+
waveGenerator.setupUniforms(this, 0);
|
|
1257
|
+
// Wave generators animate from camera.elapsedTime, declared standalone here
|
|
1258
|
+
ShaderHelper.declareStandaloneCameraTime(this, 0);
|
|
1259
|
+
}
|
|
903
1260
|
pb.main(function() {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1261
|
+
if (waveGenerator) {
|
|
1262
|
+
this.$l.worldPos = pb.vec3();
|
|
1263
|
+
this.$l.worldNorm = pb.vec3();
|
|
1264
|
+
waveGenerator.calcVertexPositionAndNormal(this, this.$inputs.position.xyz, this.worldPos, this.worldNorm);
|
|
1265
|
+
} else {
|
|
1266
|
+
this.$l.worldPos = this.$inputs.position.xyz;
|
|
1267
|
+
this.$l.worldNorm = pb.vec3(0, 1, 0);
|
|
1268
|
+
}
|
|
907
1269
|
this.$outputs.worldPos = this.worldPos;
|
|
908
1270
|
this.$outputs.worldNorm = this.worldNorm;
|
|
909
1271
|
this.$outputs.xz = this.$inputs.position.xz;
|
|
@@ -917,10 +1279,13 @@ import { BoundingBox } from '../utility/bounding_volume.js';
|
|
|
917
1279
|
fragment (pb) {
|
|
918
1280
|
this.$outputs.worldPos = pb.vec4();
|
|
919
1281
|
this.$outputs.worldNorm = pb.vec4();
|
|
920
|
-
|
|
1282
|
+
if (waveGenerator) {
|
|
1283
|
+
waveGenerator.setupUniforms(this, 0);
|
|
1284
|
+
ShaderHelper.declareStandaloneCameraTime(this, 0);
|
|
1285
|
+
}
|
|
921
1286
|
pb.main(function() {
|
|
922
1287
|
this.$outputs.worldPos = pb.vec4(this.$inputs.worldPos, 1);
|
|
923
|
-
this.$outputs.worldNorm = pb.vec4(
|
|
1288
|
+
this.$outputs.worldNorm = waveGenerator ? pb.vec4(waveGenerator.calcFragmentNormal(this, this.$inputs.xz, this.$inputs.worldNorm), 1) : pb.vec4(0, 1, 0, 1);
|
|
924
1289
|
});
|
|
925
1290
|
}
|
|
926
1291
|
});
|