@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
|
@@ -9,6 +9,7 @@ import '../render/primitive.js';
|
|
|
9
9
|
import '@zephyr3d/device';
|
|
10
10
|
import { getDevice } from '../app/api.js';
|
|
11
11
|
import { CopyBlitter } from '../blitter/copy.js';
|
|
12
|
+
import { blendTerrainDetailNormal, terrainSplatMaskCount, blendTerrainRoughness, blendTerrainAlbedo } from './shader/terrain_blend.js';
|
|
12
13
|
|
|
13
14
|
const MAX_DETAIL_MAPS = 8;
|
|
14
15
|
/**
|
|
@@ -17,6 +18,8 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
17
18
|
*/ class ClipmapTerrainMaterial extends applyMaterialMixins(MeshMaterial, mixinLight, mixinPBRMetallicRoughness) {
|
|
18
19
|
static FEATURE_DETAIL_MAP = this.defineFeature();
|
|
19
20
|
static FEATURE_DEBUG_MODE = this.defineFeature();
|
|
21
|
+
static FEATURE_VIRTUAL_TEXTURE = this.defineFeature();
|
|
22
|
+
/** Bit i: detail layer i uses hex tiling */ static FEATURE_HEX_TILING = this.defineFeature();
|
|
20
23
|
static _defaultDetailMap = new DRef();
|
|
21
24
|
static _defaultNormalMap = new DRef();
|
|
22
25
|
_region;
|
|
@@ -28,6 +31,8 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
28
31
|
_splatMapSize;
|
|
29
32
|
_heightMapSize;
|
|
30
33
|
_levelDataBuffer;
|
|
34
|
+
_virtualTexture;
|
|
35
|
+
_contentVersion;
|
|
31
36
|
constructor(heightMap){
|
|
32
37
|
super();
|
|
33
38
|
this.metallic = 0;
|
|
@@ -47,6 +52,10 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
47
52
|
this._heightMapSize = new Vector4(this.heightMap.width, this.heightMap.height, 1 / this.heightMap.width, 1 / this.heightMap.height);
|
|
48
53
|
this.useFeature(ClipmapTerrainMaterial.FEATURE_DETAIL_MAP, 0);
|
|
49
54
|
this.useFeature(ClipmapTerrainMaterial.FEATURE_DEBUG_MODE, 'none');
|
|
55
|
+
this.useFeature(ClipmapTerrainMaterial.FEATURE_VIRTUAL_TEXTURE, '');
|
|
56
|
+
this.useFeature(ClipmapTerrainMaterial.FEATURE_HEX_TILING, 0);
|
|
57
|
+
this._virtualTexture = null;
|
|
58
|
+
this._contentVersion = 0;
|
|
50
59
|
}
|
|
51
60
|
static get MAX_DETAIL_MAP_COUNT() {
|
|
52
61
|
return MAX_DETAIL_MAPS;
|
|
@@ -57,6 +66,111 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
57
66
|
set debugMode(mode) {
|
|
58
67
|
this.useFeature(ClipmapTerrainMaterial.FEATURE_DEBUG_MODE, mode);
|
|
59
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Bumped whenever a splat or detail texture is replaced. The detail parameters, the layer
|
|
71
|
+
* count and the roughness are uniforms, compared directly by the virtual texture owner.
|
|
72
|
+
* @internal
|
|
73
|
+
*/ get contentVersion() {
|
|
74
|
+
return this._contentVersion;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The runtime virtual texture holding the blended layers, null to blend them per pixel.
|
|
78
|
+
* Only used on WebGPU with at least one detail layer.
|
|
79
|
+
* @internal
|
|
80
|
+
*/ get virtualTexture() {
|
|
81
|
+
return this._virtualTexture;
|
|
82
|
+
}
|
|
83
|
+
set virtualTexture(vt) {
|
|
84
|
+
this._virtualTexture = vt;
|
|
85
|
+
this.updateVirtualTextureFeature();
|
|
86
|
+
}
|
|
87
|
+
/** Whether shading reads the runtime virtual texture instead of blending the layers @internal */ get virtualTextureUsed() {
|
|
88
|
+
return !!this.featureUsed(ClipmapTerrainMaterial.FEATURE_VIRTUAL_TEXTURE);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The feature value is the layout of the virtual texture, which the shader bakes in (level
|
|
92
|
+
* count and sizes, page and atlas geometry), so a rebuilt texture gets its own program.
|
|
93
|
+
*/ updateVirtualTextureFeature() {
|
|
94
|
+
const vt = this._virtualTexture;
|
|
95
|
+
const used = !!vt && getDevice().type === 'webgpu' && this._detailMapInfo.numDetailMaps > 0;
|
|
96
|
+
this.useFeature(ClipmapTerrainMaterial.FEATURE_VIRTUAL_TEXTURE, used ? `${vt.levels[0].pagesX}x${vt.levels[0].pagesY}:${vt.pageSize}:${vt.border}:${vt.atlasSize}` : '');
|
|
97
|
+
}
|
|
98
|
+
/** @internal */ get detailMapParams() {
|
|
99
|
+
return this._detailMapInfo.detailMapParams;
|
|
100
|
+
}
|
|
101
|
+
/** @internal */ get detailHexParams() {
|
|
102
|
+
return this._detailMapInfo.detailHexParams;
|
|
103
|
+
}
|
|
104
|
+
/** Bit i set: detail layer i is hex tiled. @internal */ get hexTilingMask() {
|
|
105
|
+
return this.featureUsed(ClipmapTerrainMaterial.FEATURE_HEX_TILING);
|
|
106
|
+
}
|
|
107
|
+
updateHexTilingFeature() {
|
|
108
|
+
let mask = 0;
|
|
109
|
+
for(let i = 0; i < this._detailMapInfo.numDetailMaps; i++){
|
|
110
|
+
if (this._detailMapInfo.detailHexParams[i * 4 + 3] !== 0) {
|
|
111
|
+
mask |= 1 << i;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
this.useFeature(ClipmapTerrainMaterial.FEATURE_HEX_TILING, mask);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Whether a detail layer is hex tiled to break up its repetition (Mikkelsen, Practical
|
|
118
|
+
* Real-Time Hex-Tiling, 2022). Costs three texture samples per layer instead of one, only
|
|
119
|
+
* when the layers are blended: once per page with the runtime virtual texture.
|
|
120
|
+
*/ getDetailMapHexTiling(index) {
|
|
121
|
+
if (index >= this._detailMapInfo.numDetailMaps || index < 0 || !Number.isInteger(index)) {
|
|
122
|
+
console.error('Invalid detail map index');
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
return this._detailMapInfo.detailHexParams[index * 4 + 3] !== 0;
|
|
126
|
+
}
|
|
127
|
+
setDetailMapHexTiling(index, enabled) {
|
|
128
|
+
if (index >= this._detailMapInfo.numDetailMaps || index < 0 || !Number.isInteger(index)) {
|
|
129
|
+
console.error('Invalid detail map index');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
this._detailMapInfo.detailHexParams[index * 4 + 3] = enabled ? 1 : 0;
|
|
133
|
+
this.updateHexTilingFeature();
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Hex tiling parameters of a detail layer as [rotation, scale, contrast], MaterialX
|
|
137
|
+
* hextiledimage inputs:
|
|
138
|
+
* - rotation: 0 to 1, how much each tile is turned at random, 1 for any angle
|
|
139
|
+
* - scale: 0 to 1, how much each tile is resized at random, 1 for 0.5 to 2 times
|
|
140
|
+
* - contrast: 0 to 1, how much brighter tiles win at the seams between tiles
|
|
141
|
+
*/ getDetailMapHexParams(index) {
|
|
142
|
+
if (index >= this._detailMapInfo.numDetailMaps || index < 0 || !Number.isInteger(index)) {
|
|
143
|
+
console.error('Invalid detail map index');
|
|
144
|
+
return [
|
|
145
|
+
1,
|
|
146
|
+
1,
|
|
147
|
+
0.5
|
|
148
|
+
];
|
|
149
|
+
}
|
|
150
|
+
const p = this._detailMapInfo.detailHexParams;
|
|
151
|
+
return [
|
|
152
|
+
p[index * 4],
|
|
153
|
+
p[index * 4 + 1],
|
|
154
|
+
p[index * 4 + 2]
|
|
155
|
+
];
|
|
156
|
+
}
|
|
157
|
+
setDetailMapHexParams(index, rotation, scale, contrast) {
|
|
158
|
+
if (index >= this._detailMapInfo.numDetailMaps || index < 0 || !Number.isInteger(index)) {
|
|
159
|
+
console.error('Invalid detail map index');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const p = this._detailMapInfo.detailHexParams;
|
|
163
|
+
p[index * 4] = rotation;
|
|
164
|
+
p[index * 4 + 1] = scale;
|
|
165
|
+
p[index * 4 + 2] = contrast;
|
|
166
|
+
this.uniformChanged();
|
|
167
|
+
}
|
|
168
|
+
/** @internal */ get detailMapArray() {
|
|
169
|
+
return this._detailMapInfo.detailMap.get();
|
|
170
|
+
}
|
|
171
|
+
/** @internal */ get detailNormalMapArray() {
|
|
172
|
+
return this._detailMapInfo.detailNormalMap?.get() ?? null;
|
|
173
|
+
}
|
|
60
174
|
/** @internal */ setLevelData(data, length) {
|
|
61
175
|
this._levelDataBuffer.get().bufferSubData(0, data, 0, length);
|
|
62
176
|
}
|
|
@@ -92,10 +206,6 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
92
206
|
console.error('Invalid number of detail maps');
|
|
93
207
|
return;
|
|
94
208
|
}
|
|
95
|
-
if (getDevice().type === 'webgl' && val > 4) {
|
|
96
|
-
console.error('Only 4 detail map layers is supported for WebGL1');
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
209
|
const n = this._detailMapInfo.numDetailMaps;
|
|
100
210
|
const defaultDetailMap = ClipmapTerrainMaterial.getDefaultDetailMap();
|
|
101
211
|
const defaultNormalMap = ClipmapTerrainMaterial.getDefaultNormalMap();
|
|
@@ -106,6 +216,12 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
106
216
|
this.setDetailNormalMap(i, defaultNormalMap);
|
|
107
217
|
this.setDetailMapUVScale(i, 80);
|
|
108
218
|
this.setDetailMapRoughness(i, 1);
|
|
219
|
+
this._detailMapInfo.detailHexParams.set([
|
|
220
|
+
1,
|
|
221
|
+
1,
|
|
222
|
+
0.5,
|
|
223
|
+
0
|
|
224
|
+
], i * 4);
|
|
109
225
|
this._detailMapInfo.detailMapList[i].dispose();
|
|
110
226
|
this._detailMapInfo.detailNormalMapList[i].dispose();
|
|
111
227
|
}
|
|
@@ -115,12 +231,20 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
115
231
|
this.setDetailNormalMap(i, defaultNormalMap);
|
|
116
232
|
this.setDetailMapUVScale(i, 80);
|
|
117
233
|
this.setDetailMapRoughness(i, 1);
|
|
234
|
+
this._detailMapInfo.detailHexParams.set([
|
|
235
|
+
1,
|
|
236
|
+
1,
|
|
237
|
+
0.5,
|
|
238
|
+
0
|
|
239
|
+
], i * 4);
|
|
118
240
|
this._detailMapInfo.detailMapList[i].dispose();
|
|
119
241
|
this._detailMapInfo.detailNormalMapList[i].dispose();
|
|
120
242
|
}
|
|
121
243
|
this._detailMapInfo.numDetailMaps = val;
|
|
122
244
|
}
|
|
123
245
|
this.useFeature(ClipmapTerrainMaterial.FEATURE_DETAIL_MAP, this._detailMapInfo.numDetailMaps);
|
|
246
|
+
this.updateVirtualTextureFeature();
|
|
247
|
+
this.updateHexTilingFeature();
|
|
124
248
|
}
|
|
125
249
|
getSplatMap() {
|
|
126
250
|
return this._detailMapInfo.splatMap?.get() ?? null;
|
|
@@ -132,6 +256,7 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
132
256
|
return;
|
|
133
257
|
}
|
|
134
258
|
this._detailMapInfo.splatMap.set(tex);
|
|
259
|
+
this._contentVersion++;
|
|
135
260
|
this.uniformChanged();
|
|
136
261
|
}
|
|
137
262
|
}
|
|
@@ -186,14 +311,13 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
186
311
|
this._detailMapInfo.detailMapList[index] = new DRef();
|
|
187
312
|
}
|
|
188
313
|
this._detailMapInfo.detailMapList[index].set(albedoMap === ClipmapTerrainMaterial.getDefaultDetailMap() ? null : albedoMap);
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
314
|
+
this._contentVersion++;
|
|
315
|
+
const blitter = new CopyBlitter();
|
|
316
|
+
const fb = getDevice().createFrameBuffer([
|
|
317
|
+
this._detailMapInfo.detailMap.get()
|
|
318
|
+
], null);
|
|
319
|
+
blitter.blit(albedoMap, fb, index, albedoMap.width === this._detailMapSize && albedoMap.height === this._detailMapSize ? fetchSampler('clamp_nearest_nomip') : fetchSampler('clamp_linear_nomip'));
|
|
320
|
+
fb.dispose();
|
|
197
321
|
}
|
|
198
322
|
getDetailNormalMap(index) {
|
|
199
323
|
if (index >= this._detailMapInfo.numDetailMaps || index < 0 || !Number.isInteger(index)) {
|
|
@@ -212,14 +336,13 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
212
336
|
this._detailMapInfo.detailNormalMapList[index] = new DRef();
|
|
213
337
|
}
|
|
214
338
|
this._detailMapInfo.detailNormalMapList[index].set(normalMap === ClipmapTerrainMaterial.getDefaultNormalMap() ? null : normalMap);
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
339
|
+
this._contentVersion++;
|
|
340
|
+
const blitter = new CopyBlitter();
|
|
341
|
+
const fb = getDevice().createFrameBuffer([
|
|
342
|
+
this._detailMapInfo.detailNormalMap.get()
|
|
343
|
+
], null);
|
|
344
|
+
blitter.blit(normalMap, fb, index, normalMap.width === this._detailMapSize && normalMap.height === this._detailMapSize ? fetchSampler('clamp_nearest_nomip') : fetchSampler('clamp_linear_nomip'));
|
|
345
|
+
fb.dispose();
|
|
223
346
|
}
|
|
224
347
|
/** @internal */ update(region, terrainScale) {
|
|
225
348
|
if (!region.equalsTo(this._region) || !terrainScale.equalsTo(this._terrainScale)) {
|
|
@@ -234,6 +357,7 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
234
357
|
set heightMap(val) {
|
|
235
358
|
if (val !== this._heightMap.get()) {
|
|
236
359
|
this._heightMap.set(val);
|
|
360
|
+
this._contentVersion++;
|
|
237
361
|
this._heightMapSize.setXYZW(this.heightMap.width, this.heightMap.height, 1 / this.heightMap.width, 1 / this.heightMap.height);
|
|
238
362
|
this.uniformChanged();
|
|
239
363
|
}
|
|
@@ -253,41 +377,104 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
253
377
|
getMetallicRoughnessTexCoord = function(scope) {
|
|
254
378
|
return scope.$inputs.uv;
|
|
255
379
|
};
|
|
256
|
-
sampleDetailNormalMap(scope, index, texCoord) {
|
|
380
|
+
/** Raw rgb of a detail normal map, see blendTerrainDetailNormal */ sampleDetailNormalMap(scope, index, texCoord, ddx = null, ddy = null) {
|
|
257
381
|
const pb = scope.$builder;
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
382
|
+
return ddx && ddy ? pb.textureArraySampleGrad(scope.detailNormalMap, texCoord, index, ddx, ddy).rgb : pb.textureArraySample(scope.detailNormalMap, texCoord, index).rgb;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Gradients of the terrain uv and the hex tiled layers, for the blend functions; null when no
|
|
386
|
+
* layer is hex tiled, so the others keep sampling with implicit derivatives.
|
|
387
|
+
*/ hexTilingInputs(scope) {
|
|
388
|
+
const mask = this.hexTilingMask;
|
|
389
|
+
if (!mask) {
|
|
390
|
+
return [
|
|
391
|
+
null,
|
|
392
|
+
null
|
|
393
|
+
];
|
|
394
|
+
}
|
|
395
|
+
const pb = scope.$builder;
|
|
396
|
+
return [
|
|
397
|
+
{
|
|
398
|
+
ddx: pb.dpdx(scope.$inputs.uv),
|
|
399
|
+
ddy: pb.dpdy(scope.$inputs.uv)
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
mask,
|
|
403
|
+
params: scope.detailHexParams
|
|
404
|
+
}
|
|
405
|
+
];
|
|
261
406
|
}
|
|
262
407
|
calculateDetailNormal(scope, TBN) {
|
|
263
408
|
const that = this;
|
|
264
409
|
const pb = scope.$builder;
|
|
265
410
|
const funcName = 'getTerrainNormal';
|
|
411
|
+
const numDetailMaps = that.featureUsed(ClipmapTerrainMaterial.FEATURE_DETAIL_MAP);
|
|
266
412
|
pb.func(funcName, [
|
|
267
|
-
pb.mat3('TBN')
|
|
413
|
+
pb.mat3('TBN'),
|
|
414
|
+
...this.splatMaskParams(scope, numDetailMaps)
|
|
268
415
|
], function() {
|
|
269
|
-
|
|
270
|
-
this.$l.detailNormal = pb.vec3(0);
|
|
271
|
-
for(let i = 0; i < numDetailMaps + 3 >> 2; i++){
|
|
272
|
-
this.$l[`mask${i}`] = that.drawContext.device.type === 'webgl' ? pb.textureSample(this.splatMap, this.$inputs.uv) : pb.textureArraySample(this.splatMap, this.$inputs.uv, i);
|
|
273
|
-
}
|
|
274
|
-
for(let i = 0; i < numDetailMaps; i++){
|
|
275
|
-
const uv = pb.mul(this.$inputs.uv, this.detailParams[i].x);
|
|
276
|
-
this.detailNormal = pb.add(this.detailNormal, pb.mul(that.sampleDetailNormalMap(this, i, uv), this[`mask${i >> 2}`][i & 3]));
|
|
277
|
-
}
|
|
416
|
+
this.$l.detailNormal = blendTerrainDetailNormal(this, numDetailMaps, that.splatMaskLocals(this, numDetailMaps), this.$inputs.uv, this.detailParams, (scope, i, uv, ddx, ddy)=>that.sampleDetailNormalMap(scope, i, uv, ddx, ddy), ...that.hexTilingInputs(this));
|
|
278
417
|
this.$return(pb.normalize(pb.mul(this.TBN, this.detailNormal)));
|
|
279
418
|
});
|
|
280
|
-
return pb.getGlobalScope()[funcName](TBN);
|
|
419
|
+
return pb.getGlobalScope()[funcName](TBN, ...this.splatMaskArgs(scope, numDetailMaps));
|
|
420
|
+
}
|
|
421
|
+
/** Parameter declarations for passing the splat masks sampled in the main scope */ splatMaskParams(scope, numDetailMaps) {
|
|
422
|
+
const pb = scope.$builder;
|
|
423
|
+
return Array.from({
|
|
424
|
+
length: terrainSplatMaskCount(numDetailMaps)
|
|
425
|
+
}, (_, i)=>pb.vec4(`mask${i}`));
|
|
426
|
+
}
|
|
427
|
+
/** The splat mask parameters inside a function declared with splatMaskParams() */ splatMaskLocals(scope, numDetailMaps) {
|
|
428
|
+
return Array.from({
|
|
429
|
+
length: terrainSplatMaskCount(numDetailMaps)
|
|
430
|
+
}, (_, i)=>scope[`mask${i}`]);
|
|
431
|
+
}
|
|
432
|
+
/** The splat masks sampled once in the main scope, see fragmentShader() */ splatMaskArgs(scope, numDetailMaps) {
|
|
433
|
+
return Array.from({
|
|
434
|
+
length: terrainSplatMaskCount(numDetailMaps)
|
|
435
|
+
}, (_, i)=>scope[`terrainSplatMask${i}`]);
|
|
281
436
|
}
|
|
282
437
|
getNormalTexCoord = function(scope) {
|
|
283
438
|
return scope.$inputs.uv;
|
|
284
439
|
};
|
|
440
|
+
/** Samples the splat weights of detail layers [4 * index, 4 * index + 3] */ sampleSplatMask(scope, index) {
|
|
441
|
+
const pb = scope.$builder;
|
|
442
|
+
return pb.textureArraySample(scope.splatMap, scope.$inputs.uv, index);
|
|
443
|
+
}
|
|
444
|
+
calculateRoughness(scope, albedo, normal) {
|
|
445
|
+
const base = super.calculateRoughness(scope, albedo, normal);
|
|
446
|
+
const numDetailMaps = this.featureUsed(ClipmapTerrainMaterial.FEATURE_DETAIL_MAP);
|
|
447
|
+
if (numDetailMaps === 0) {
|
|
448
|
+
return base;
|
|
449
|
+
}
|
|
450
|
+
if (this.virtualTextureUsed) {
|
|
451
|
+
// This runs inside PBRLight's own function, so the roughness read from the virtual texture
|
|
452
|
+
// comes in through albedo.a (see sampleVirtualTexture); nothing reads the terrain albedo
|
|
453
|
+
// alpha otherwise (opaque, no subsurface outputs). The page fill already blended in the
|
|
454
|
+
// material roughness.
|
|
455
|
+
return albedo.a;
|
|
456
|
+
}
|
|
457
|
+
const that = this;
|
|
458
|
+
const pb = scope.$builder;
|
|
459
|
+
const funcName = 'getTerrainRoughness';
|
|
460
|
+
pb.func(funcName, [
|
|
461
|
+
pb.float('base')
|
|
462
|
+
], function() {
|
|
463
|
+
const masks = [];
|
|
464
|
+
for(let i = 0; i < terrainSplatMaskCount(numDetailMaps); i++){
|
|
465
|
+
this.$l[`mask${i}`] = that.sampleSplatMask(this, i);
|
|
466
|
+
masks.push(this[`mask${i}`]);
|
|
467
|
+
}
|
|
468
|
+
this.$return(blendTerrainRoughness(this, numDetailMaps, masks, this.detailParams, this.base));
|
|
469
|
+
});
|
|
470
|
+
return pb.getGlobalScope()[funcName](base);
|
|
471
|
+
}
|
|
285
472
|
calculateAlbedoColor(scope) {
|
|
286
473
|
const that = this;
|
|
287
474
|
const pb = scope.$builder;
|
|
288
475
|
const funcName = 'getTerrainAlbedo';
|
|
289
|
-
|
|
290
|
-
|
|
476
|
+
const numDetailMaps = that.featureUsed(ClipmapTerrainMaterial.FEATURE_DETAIL_MAP);
|
|
477
|
+
pb.func(funcName, this.splatMaskParams(scope, numDetailMaps), function() {
|
|
291
478
|
if (numDetailMaps === 0) {
|
|
292
479
|
this.$l.checkerPos = pb.mul(this.$inputs.uv, pb.sub(this.region.zw, this.region.xy));
|
|
293
480
|
this.$l.ddx = pb.dpdx(this.checkerPos);
|
|
@@ -302,74 +489,129 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
302
489
|
this.$l.checkerColor = pb.mix(pb.vec3(0.4), pb.vec3(1), pb.vec3(this.checker));
|
|
303
490
|
this.$return(pb.vec4(this.checkerColor, 1));
|
|
304
491
|
} else {
|
|
305
|
-
this.$l.color = pb.
|
|
306
|
-
for(let i = 0; i < numDetailMaps + 3 >> 2; i++){
|
|
307
|
-
this.$l[`mask${i}`] = that.drawContext.device.type === 'webgl' ? pb.textureSample(this.splatMap, this.$inputs.uv) : pb.textureArraySample(this.splatMap, this.$inputs.uv, i);
|
|
308
|
-
}
|
|
309
|
-
for(let i = 0; i < numDetailMaps; i++){
|
|
310
|
-
const uv = pb.mul(this.$inputs.uv, this.detailParams[i].x);
|
|
311
|
-
const sample = that.drawContext.device.type === 'webgl' ? pb.textureSample(this[`detailAlbedoMap${i}`], uv).rgb : pb.textureArraySample(this.detailAlbedoMap, uv, i).rgb;
|
|
312
|
-
this.color = pb.add(this.color, pb.mul(sample, this[`mask${i >> 2}`][i & 3]));
|
|
313
|
-
}
|
|
492
|
+
this.$l.color = blendTerrainAlbedo(this, numDetailMaps, that.splatMaskLocals(this, numDetailMaps), this.$inputs.uv, this.detailParams, (scope, i, uv, ddx, ddy)=>ddx && ddy ? pb.textureArraySampleGrad(scope.detailAlbedoMap, uv, i, ddx, ddy) : pb.textureArraySample(scope.detailAlbedoMap, uv, i), ...that.hexTilingInputs(this));
|
|
314
493
|
this.$return(pb.vec4(this.color, 1));
|
|
315
494
|
}
|
|
316
495
|
});
|
|
317
|
-
return pb.getGlobalScope()[funcName]();
|
|
496
|
+
return pb.getGlobalScope()[funcName](...this.splatMaskArgs(scope, numDetailMaps));
|
|
318
497
|
}
|
|
319
|
-
|
|
498
|
+
/**
|
|
499
|
+
* Reads the blended layers from the runtime virtual texture: (linear albedo, roughness) is
|
|
500
|
+
* returned, the world space normal written to `normal`.
|
|
501
|
+
*/ sampleVirtualTexture(scope, normal) {
|
|
502
|
+
const pb = scope.$builder;
|
|
503
|
+
const vt = this._virtualTexture;
|
|
504
|
+
const maxLevel = vt.levels.length - 1;
|
|
505
|
+
pb.func('zTerrainSampleRVT', [
|
|
506
|
+
pb.vec3('normal').out()
|
|
507
|
+
], function() {
|
|
508
|
+
this.$l.uv = this.$inputs.uv;
|
|
509
|
+
this.$l.level = vt.computeLevel(this, this.uv);
|
|
510
|
+
this.$l.level0 = pb.floor(this.level);
|
|
511
|
+
this.$l.level1 = pb.min(pb.add(this.level0, 1), maxLevel);
|
|
512
|
+
this.$l.loc0 = vt.resolve(this, pb.uint(this.level0), this.uv);
|
|
513
|
+
this.$l.loc1 = vt.resolve(this, pb.uint(this.level1), this.uv);
|
|
514
|
+
this.$l.t = pb.select(pb.float(0), pb.sub(this.level, this.level0), pb.equal(this.loc1.z, this.level1));
|
|
515
|
+
this.$l.baseColor = pb.mix(pb.textureSampleLevel(this.zTerrainRVT0, this.loc0.xy, 0), pb.textureSampleLevel(this.zTerrainRVT0, this.loc1.xy, 0), this.t);
|
|
516
|
+
this.$l.normalRoughness = pb.mix(pb.textureSampleLevel(this.zTerrainRVT1, this.loc0.xy, 0), pb.textureSampleLevel(this.zTerrainRVT1, this.loc1.xy, 0), this.t);
|
|
517
|
+
// VirtualTextureUnpackNormal
|
|
518
|
+
this.$l.nxz = pb.sub(pb.mul(this.normalRoughness.xz, 255 / 127), pb.vec2(1));
|
|
519
|
+
this.normal = pb.normalize(pb.vec3(this.nxz.x, pb.sqrt(pb.clamp(pb.sub(1, pb.dot(this.nxz, this.nxz)), 0, 1)), this.nxz.y));
|
|
520
|
+
// sRGB decode
|
|
521
|
+
this.$l.c = this.baseColor.rgb;
|
|
522
|
+
this.$l.linear = pb.mix(pb.pow(pb.div(pb.add(this.c, pb.vec3(0.055)), 1.055), pb.vec3(2.4)), pb.div(this.c, 12.92), pb.vec3(pb.lessThanEqual(this.c, pb.vec3(0.04045))));
|
|
523
|
+
this.$return(pb.vec4(this.linear, this.normalRoughness.y));
|
|
524
|
+
});
|
|
525
|
+
return scope.zTerrainSampleRVT(normal);
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Height of a clipmap vertex, blended towards the next coarser level across the outer part of
|
|
529
|
+
* its ring (the transition regions of Hoppe's GPU geometry clipmaps).
|
|
530
|
+
*
|
|
531
|
+
* The outer boundary of level L lies on grid lines of level L + 1, so its vertices already sit
|
|
532
|
+
* where the coarser ring's do; only their heights have to agree. hC is the height the coarser
|
|
533
|
+
* mesh has at the vertex: its own height where a coarse vertex coincides, the mean of the two
|
|
534
|
+
* coarse vertices around the edge midpoints, the mean of the four corners at cell centres
|
|
535
|
+
* (never on a boundary, only has to be continuous). With alpha reaching 1 before the boundary,
|
|
536
|
+
* boundary vertices lie exactly on the coarse edges and the rings meet without T-junction
|
|
537
|
+
* cracks. The inner boundary needs no blend: it is the finer level's outer one.
|
|
538
|
+
*
|
|
539
|
+
* @param uv - Height map coordinate of the vertex
|
|
540
|
+
* @param gridCoord - Global grid coordinate of the vertex, in grid cells
|
|
541
|
+
* @param pos - World XZ of the vertex
|
|
542
|
+
*/ sampleHeightMap(scope, uv, gridCoord, pos, levelStart, levelDiff) {
|
|
320
543
|
const pb = scope.$builder;
|
|
321
|
-
|
|
544
|
+
// Blend over the outer 40% of the ring, fully coarse over its last 5% so boundary vertices
|
|
545
|
+
// are unaffected by rounding in the ring ratio.
|
|
546
|
+
const transitionStart = 0.6;
|
|
547
|
+
const transitionEnd = 0.95;
|
|
322
548
|
pb.func('sampleHeightMap', [
|
|
323
549
|
pb.vec2('uv'),
|
|
550
|
+
pb.vec2('gridCoord'),
|
|
324
551
|
pb.vec2('pos'),
|
|
325
552
|
pb.vec4('levelStart'),
|
|
326
553
|
pb.vec4('levelDiff')
|
|
327
554
|
], function() {
|
|
328
|
-
this.$l.
|
|
555
|
+
this.$l.h = pb.textureSampleLevel(this.heightMap, this.uv, this.$inputs.miplevel).r;
|
|
329
556
|
this.$l.ratio = pb.mul(pb.sub(this.pos.xyxy, this.levelStart), this.levelDiff);
|
|
330
|
-
this.$l.maxVal = pb.
|
|
331
|
-
this.$l.
|
|
332
|
-
this.$if(pb.greaterThan(this.
|
|
333
|
-
this.$l.
|
|
334
|
-
|
|
335
|
-
this.
|
|
557
|
+
this.$l.maxVal = pb.max(pb.max(this.ratio.x, this.ratio.y), pb.max(this.ratio.z, this.ratio.w));
|
|
558
|
+
this.$l.alpha = pb.clamp(pb.div(pb.sub(this.maxVal, transitionStart), transitionEnd - transitionStart), 0, 1);
|
|
559
|
+
this.$if(pb.greaterThan(this.alpha, 0), function() {
|
|
560
|
+
this.$l.levelScale = pb.exp2(this.$inputs.miplevel);
|
|
561
|
+
// Vertex index in this level; the coarser level's vertices are its even ones
|
|
562
|
+
this.$l.index = pb.div(this.gridCoord, this.levelScale);
|
|
563
|
+
this.$l.odd = pb.sub(this.index, pb.mul(pb.floor(pb.mul(this.index, 0.5)), 2));
|
|
564
|
+
// Height map distance to the neighbouring coarse vertices along the odd axes
|
|
565
|
+
this.$l.d = pb.div(pb.mul(this.odd, pb.mul(this.levelScale, this.clipmapGridInfo.x)), pb.sub(this.region.zw, this.region.xy));
|
|
566
|
+
this.$l.coarseLevel = pb.add(this.$inputs.miplevel, 1);
|
|
567
|
+
this.$l.hc = pb.mul(pb.add(pb.add(pb.textureSampleLevel(this.heightMap, pb.sub(this.uv, this.d), this.coarseLevel).r, pb.textureSampleLevel(this.heightMap, pb.add(this.uv, this.d), this.coarseLevel).r), pb.add(pb.textureSampleLevel(this.heightMap, pb.add(this.uv, pb.vec2(this.d.x, pb.neg(this.d.y))), this.coarseLevel).r, pb.textureSampleLevel(this.heightMap, pb.add(this.uv, pb.vec2(pb.neg(this.d.x), this.d.y)), this.coarseLevel).r)), 0.25);
|
|
568
|
+
this.h = pb.mix(this.h, this.hc, this.alpha);
|
|
336
569
|
});
|
|
337
|
-
this.$
|
|
338
|
-
this.$l.h2 = pb.textureSampleLevel(this.heightMap, this.uv, pb.max(pb.sub(this.$inputs.miplevel, 1), 0)).r;
|
|
339
|
-
this.morphFactor = pb.mul(pb.add(pb.div(this.maxVal, morphRange), 1), 0.5);
|
|
340
|
-
this.h1 = pb.mix(this.h1, this.h2, this.morphFactor);
|
|
341
|
-
});
|
|
342
|
-
this.$return(this.h1);
|
|
570
|
+
this.$return(this.h);
|
|
343
571
|
});
|
|
344
|
-
return scope.sampleHeightMap(uv, pos, levelStart, levelDiff);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
|
|
572
|
+
return scope.sampleHeightMap(uv, gridCoord, pos, levelStart, levelDiff);
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Terrain tangent frame at the fragment, differentiated from the height map itself.
|
|
576
|
+
*
|
|
577
|
+
* Per-vertex normals only see the mesh resolution and blur slopes: a one-texel peak gets an
|
|
578
|
+
* upward normal at its tip and half the real slope around it. Differentiating the bilinear
|
|
579
|
+
* height field per pixel gives the slopes the geometry actually has, and keeps height map
|
|
580
|
+
* detail on the coarse outer rings.
|
|
581
|
+
*/ calculateTerrainTBN(scope, tangent, bitangent, normal) {
|
|
348
582
|
const pb = scope.$builder;
|
|
583
|
+
const textureLod = this.drawContext.device.getDeviceCaps().shaderCaps.supportShaderTextureLod;
|
|
349
584
|
pb.func('calcTerrainTBN', [
|
|
350
|
-
pb.vec2('clipmapPos'),
|
|
351
|
-
pb.vec2('uv'),
|
|
352
|
-
pb.vec4('texSize'),
|
|
353
|
-
pb.vec3('scale'),
|
|
354
|
-
pb.vec4('levelStart'),
|
|
355
|
-
pb.vec4('levelDiff'),
|
|
356
585
|
pb.vec3('t').out(),
|
|
357
586
|
pb.vec3('b').out(),
|
|
358
587
|
pb.vec3('n').out()
|
|
359
588
|
], function() {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
589
|
+
if (textureLod) {
|
|
590
|
+
// Differentiate on the mip whose texels match the pixel footprint, so distant terrain
|
|
591
|
+
// does not alias.
|
|
592
|
+
this.$l.texCoord = pb.mul(this.$inputs.uv, this.heightMapSize.xy);
|
|
593
|
+
this.$l.footprint = pb.max(pb.length(pb.dpdx(this.texCoord)), pb.length(pb.dpdy(this.texCoord)));
|
|
594
|
+
this.$l.lod = pb.max(pb.log2(pb.max(this.footprint, 0.0001)), 0);
|
|
595
|
+
} else {
|
|
596
|
+
this.$l.lod = pb.float(0);
|
|
597
|
+
}
|
|
598
|
+
// Half a texel either way: on a bilinear field that yields the full slope of each cell
|
|
599
|
+
// everywhere but within half a texel of a crest or foot.
|
|
600
|
+
this.$l.offset = pb.mul(this.heightMapSize.zw, pb.mul(pb.exp2(this.lod), 0.5));
|
|
601
|
+
const sample = (scope, uv)=>textureLod ? pb.textureSampleLevel(scope.heightMap, uv, scope.lod).r : pb.textureSample(scope.heightMap, uv).r;
|
|
602
|
+
this.$l.hL = sample(this, pb.sub(this.$inputs.uv, pb.vec2(this.offset.x, 0)));
|
|
603
|
+
this.$l.hR = sample(this, pb.add(this.$inputs.uv, pb.vec2(this.offset.x, 0)));
|
|
604
|
+
this.$l.hU = sample(this, pb.sub(this.$inputs.uv, pb.vec2(0, this.offset.y)));
|
|
605
|
+
this.$l.hD = sample(this, pb.add(this.$inputs.uv, pb.vec2(0, this.offset.y)));
|
|
606
|
+
// World-space distance between the two samples of each difference
|
|
607
|
+
this.$l.sampleDist = pb.mul(pb.sub(this.region.zw, this.region.xy), pb.mul(this.offset, 2));
|
|
608
|
+
this.$l.dHdU = pb.div(pb.mul(pb.sub(this.hR, this.hL), this.terrainScale.y), this.sampleDist.x);
|
|
609
|
+
this.$l.dHdV = pb.div(pb.mul(pb.sub(this.hD, this.hU), this.terrainScale.y), this.sampleDist.y);
|
|
368
610
|
this.t = pb.normalize(pb.vec3(1, this.dHdU, 0));
|
|
369
611
|
this.b = pb.normalize(pb.vec3(0, this.dHdV, 1));
|
|
370
612
|
this.n = pb.normalize(pb.cross(this.b, this.t));
|
|
371
613
|
});
|
|
372
|
-
return scope.calcTerrainTBN(
|
|
614
|
+
return scope.calcTerrainTBN(tangent, bitangent, normal);
|
|
373
615
|
}
|
|
374
616
|
vertexShader(scope) {
|
|
375
617
|
super.vertexShader(scope);
|
|
@@ -387,34 +629,45 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
387
629
|
scope.$l.c = pb.cos(scope.$inputs.clipmapInfo.x);
|
|
388
630
|
scope.$l.scale2 = pb.mul(scope.$inputs.clipmapInfo.y, scope.clipmapGridInfo.x);
|
|
389
631
|
scope.$l.clipmapMatrix = pb.mat4(pb.mul(scope.c, scope.scale2), pb.mul(scope.s, scope.scale2), 0, 0, pb.neg(pb.mul(scope.s, scope.scale2)), pb.mul(scope.c, scope.scale2), 0, 0, 0, 0, 1, 0, pb.sub(pb.mul(scope.$inputs.clipmapInfo.z, scope.clipmapGridInfo.x), scope.clipmapGridInfo.y), pb.sub(pb.mul(scope.$inputs.clipmapInfo.w, scope.clipmapGridInfo.x), scope.clipmapGridInfo.z), 0, 1);
|
|
390
|
-
scope.$l.
|
|
632
|
+
scope.$l.localPos = scope.$inputs.position.xy;
|
|
633
|
+
// position.z = -side flags a seam midpoint (see Clipmap.generateSeamMesh). When the seam edge
|
|
634
|
+
// lies outside the region, clamping would line its flaps up along the border as vertical
|
|
635
|
+
// curtains, so the midpoint takes its neighbour's local position instead: both then run the
|
|
636
|
+
// exact same math below, land on the same point, and the flap degenerates.
|
|
637
|
+
scope.$l.seamSide = pb.neg(scope.$inputs.position.z);
|
|
638
|
+
scope.$if(pb.greaterThan(scope.seamSide, 0.5), function() {
|
|
639
|
+
this.$l.probeLocal = pb.mul(this.clipmapMatrix, pb.vec4(this.localPos, 0, 1)).xy;
|
|
640
|
+
this.$l.probe = pb.mul(ShaderHelper.getWorldMatrix(this), pb.vec4(this.probeLocal.x, 0, this.probeLocal.y, 1)).xz;
|
|
641
|
+
// Sides 1 and 3 run along local x (world x, seams are never rotated), so the border they
|
|
642
|
+
// can lie beyond is a z one; sides 2 and 4 run along z.
|
|
643
|
+
this.$l.alongX = pb.greaterThan(pb.mod(this.seamSide, 2), 0.5);
|
|
644
|
+
this.$l.outside = pb.or(pb.and(this.alongX, pb.or(pb.lessThan(this.probe.y, this.region.y), pb.greaterThan(this.probe.y, this.region.w))), pb.and(pb.not(this.alongX), pb.or(pb.lessThan(this.probe.x, this.region.x), pb.greaterThan(this.probe.x, this.region.z))));
|
|
645
|
+
this.$if(this.outside, function() {
|
|
646
|
+
// The previous seam vertex sits one unit back along the side: -x, -y, +x, +y for sides 1..4
|
|
647
|
+
this.$l.dir = pb.sub(pb.mul(pb.float(pb.greaterThan(this.seamSide, 2.5)), 2), 1);
|
|
648
|
+
this.localPos = pb.add(this.localPos, pb.mul(pb.vec2(pb.float(this.alongX), pb.float(pb.not(this.alongX))), this.dir));
|
|
649
|
+
});
|
|
650
|
+
});
|
|
651
|
+
scope.$l.clipmapPos = pb.mul(scope.clipmapMatrix, pb.vec4(scope.localPos, 0, 1)).xy;
|
|
391
652
|
scope.$l.clipmapWorldPos = pb.mul(ShaderHelper.getWorldMatrix(scope), pb.vec4(scope.clipmapPos.x, 0, scope.clipmapPos.y, 1)).xyz;
|
|
653
|
+
// Heights are evaluated at the unclamped grid point: every level computes the same function
|
|
654
|
+
// of its own grid, which keeps the rings matching. Beyond the region the sampler clamps to
|
|
655
|
+
// the edge texels, the same heights the clamped position would get.
|
|
656
|
+
scope.$l.gridPos = scope.clipmapWorldPos.xz;
|
|
657
|
+
scope.$l.gridUV = pb.div(pb.sub(scope.gridPos, scope.region.xy), pb.sub(scope.region.zw, scope.region.xy));
|
|
658
|
+
// Global grid coordinate in cells, see ClipmapGatherContext.gridOriginX
|
|
659
|
+
scope.$l.gridCoord = pb.floor(pb.add(pb.div(pb.add(scope.clipmapPos, scope.clipmapGridInfo.yz), scope.clipmapGridInfo.x), 0.5));
|
|
660
|
+
// Keep the grid inside the terrain region instead of discarding fragments outside of it,
|
|
661
|
+
// which would cost early-Z on the largest occluder in the scene. The clipmap grid is
|
|
662
|
+
// axis-aligned, so clamping collapses triangles lying outside into zero-area ones and snaps
|
|
663
|
+
// the ones crossing the border exactly onto it.
|
|
664
|
+
scope.clipmapWorldPos = pb.vec3(pb.clamp(scope.clipmapWorldPos.x, scope.region.x, scope.region.z), scope.clipmapWorldPos.y, pb.clamp(scope.clipmapWorldPos.z, scope.region.y, scope.region.w));
|
|
392
665
|
scope.$outputs.uv = pb.div(pb.sub(scope.clipmapWorldPos.xz, scope.region.xy), pb.sub(scope.region.zw, scope.region.xy));
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
scope.$l.index = pb.mul(pb.int(scope.$inputs.miplevel), 2);
|
|
397
|
-
scope.$for(pb.int('i'), 0, 32, function() {
|
|
398
|
-
this.$if(pb.equal(this.i, this.index), function() {
|
|
399
|
-
this.levelStart = this.levelData.at(this.i);
|
|
400
|
-
this.levelDiff = this.levelData.at(pb.add(this.i, 1));
|
|
401
|
-
this.$break();
|
|
402
|
-
});
|
|
403
|
-
});
|
|
404
|
-
} else {
|
|
405
|
-
scope.$l.levelStart = scope.levelData.at(pb.mul(pb.int(scope.$inputs.miplevel), 2));
|
|
406
|
-
scope.$l.levelDiff = scope.levelData.at(pb.add(pb.mul(pb.int(scope.$inputs.miplevel), 2), 1));
|
|
407
|
-
}
|
|
408
|
-
scope.$l.height = this.sampleHeightMap(scope, scope.$outputs.uv, scope.clipmapWorldPos.xz, scope.levelStart, scope.levelDiff);
|
|
666
|
+
scope.$l.levelStart = scope.levelData.at(pb.mul(pb.int(scope.$inputs.miplevel), 2));
|
|
667
|
+
scope.$l.levelDiff = scope.levelData.at(pb.add(pb.mul(pb.int(scope.$inputs.miplevel), 2), 1));
|
|
668
|
+
scope.$l.height = this.sampleHeightMap(scope, scope.gridUV, scope.gridCoord, scope.gridPos, scope.levelStart, scope.levelDiff);
|
|
409
669
|
scope.$outputs.worldPos = pb.add(scope.clipmapWorldPos, pb.vec3(0, pb.mul(scope.height, scope.terrainScale.y), 0));
|
|
410
|
-
scope.$l.t = pb.vec3();
|
|
411
|
-
scope.$l.b = pb.vec3();
|
|
412
|
-
scope.$l.n = pb.vec3();
|
|
413
|
-
this.calculateTerrainTBN(scope, scope.clipmapWorldPos.xz, scope.$outputs.uv, scope.heightMapSize, scope.terrainScale, scope.levelStart, scope.levelDiff, scope.t, scope.b, scope.n);
|
|
414
670
|
scope.$outputs.clipmapPos = scope.clipmapWorldPos;
|
|
415
|
-
scope.$outputs.worldTangent = scope.t;
|
|
416
|
-
scope.$outputs.worldBinormal = scope.b;
|
|
417
|
-
scope.$outputs.worldNormal = scope.n;
|
|
418
671
|
ShaderHelper.setClipSpacePosition(scope, pb.mul(ShaderHelper.getViewProjectionMatrix(scope), pb.vec4(scope.$outputs.worldPos, 1)));
|
|
419
672
|
ShaderHelper.resolveMotionVector(scope, scope.$outputs.worldPos, scope.$outputs.worldPos);
|
|
420
673
|
}
|
|
@@ -422,120 +675,142 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
422
675
|
super.fragmentShader(scope);
|
|
423
676
|
const pb = scope.$builder;
|
|
424
677
|
scope.region = pb.vec4().uniform(2);
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
678
|
+
if (this.needFragmentColor() && this.virtualTextureUsed) {
|
|
679
|
+
const globals = pb.getGlobalScope();
|
|
680
|
+
this._virtualTexture.declareBindings(globals, 2, false);
|
|
681
|
+
globals.zTerrainRVT0 = pb.tex2D().uniform(2);
|
|
682
|
+
globals.zTerrainRVT1 = pb.tex2D().uniform(2);
|
|
683
|
+
scope.$l.terrainN = pb.vec3();
|
|
684
|
+
scope.$l.albedo = this.sampleVirtualTexture(scope, scope.terrainN);
|
|
685
|
+
// The normal read back already carries the height map slopes and the detail layers; the
|
|
686
|
+
// frame around it only orients anisotropic and clear coat terms
|
|
687
|
+
scope.$l.terrainT = pb.normalize(pb.sub(pb.vec3(1, 0, 0), pb.mul(scope.terrainN, scope.terrainN.x)));
|
|
688
|
+
scope.$l.terrainB = pb.cross(scope.terrainT, scope.terrainN);
|
|
689
|
+
scope.$l.normalInfo = this.calculateNormalAndTBN(scope, scope.$inputs.worldPos, scope.terrainN, scope.terrainT, scope.terrainB);
|
|
690
|
+
this.shadeTerrain(scope);
|
|
691
|
+
} else if (this.needFragmentColor()) {
|
|
430
692
|
scope.heightMap = pb.tex2D().uniform(2);
|
|
693
|
+
scope.heightMapSize = pb.vec4().uniform(2);
|
|
694
|
+
scope.terrainScale = pb.vec3().uniform(2);
|
|
431
695
|
const numDetailMaps = this.featureUsed(ClipmapTerrainMaterial.FEATURE_DETAIL_MAP);
|
|
432
696
|
if (numDetailMaps > 0) {
|
|
433
697
|
scope.detailParams = pb.vec4[numDetailMaps]().uniform(2);
|
|
434
|
-
if (this.
|
|
435
|
-
scope.
|
|
436
|
-
for(let i = 0; i < numDetailMaps; i++){
|
|
437
|
-
scope[`detailAlbedoMap${i}`] = pb.tex2D().uniform(2);
|
|
438
|
-
scope[`detailNormalMap${i}`] = pb.tex2D().uniform(2);
|
|
439
|
-
}
|
|
440
|
-
} else {
|
|
441
|
-
scope.splatMap = pb.tex2DArray().uniform(2);
|
|
442
|
-
scope.detailAlbedoMap = pb.tex2DArray().uniform(2);
|
|
443
|
-
scope.detailNormalMap = pb.tex2DArray().uniform(2);
|
|
698
|
+
if (this.hexTilingMask) {
|
|
699
|
+
scope.detailHexParams = pb.vec4[numDetailMaps]().uniform(2);
|
|
444
700
|
}
|
|
701
|
+
scope.splatMap = pb.tex2DArray().uniform(2);
|
|
702
|
+
scope.detailAlbedoMap = pb.tex2DArray().uniform(2);
|
|
703
|
+
scope.detailNormalMap = pb.tex2DArray().uniform(2);
|
|
704
|
+
}
|
|
705
|
+
// Sampled once here and shared by the albedo and detail normal blends
|
|
706
|
+
for(let i = 0; i < numDetailMaps + 3 >> 2; i++){
|
|
707
|
+
scope.$l[`terrainSplatMask${i}`] = this.sampleSplatMask(scope, i);
|
|
445
708
|
}
|
|
446
709
|
scope.$l.albedo = this.calculateAlbedoColor(scope);
|
|
447
|
-
scope.$l.
|
|
448
|
-
scope.$l.
|
|
710
|
+
scope.$l.terrainT = pb.vec3();
|
|
711
|
+
scope.$l.terrainB = pb.vec3();
|
|
712
|
+
scope.$l.terrainN = pb.vec3();
|
|
713
|
+
this.calculateTerrainTBN(scope, scope.terrainT, scope.terrainB, scope.terrainN);
|
|
714
|
+
scope.$l.normalInfo = this.calculateNormalAndTBN(scope, scope.$inputs.worldPos, scope.terrainN, scope.terrainT, scope.terrainB);
|
|
449
715
|
if (this.featureUsed(ClipmapTerrainMaterial.FEATURE_DETAIL_MAP) > 0) {
|
|
450
716
|
scope.normalInfo.normal = this.calculateDetailNormal(scope, scope.normalInfo.TBN);
|
|
451
717
|
}
|
|
452
|
-
|
|
453
|
-
scope.$l.litColor = this.PBRLight(scope, scope.$inputs.worldPos, scope.normalInfo.normal, scope.viewVec, scope.albedo, scope.normalInfo.TBN);
|
|
454
|
-
switch(this.featureUsed(ClipmapTerrainMaterial.FEATURE_DEBUG_MODE)){
|
|
455
|
-
case 'albedo':
|
|
456
|
-
scope.$l.outColor = scope.albedo;
|
|
457
|
-
break;
|
|
458
|
-
case 'vertex_normal':
|
|
459
|
-
scope.$l.outColor = pb.vec4(pb.add(pb.mul(scope.normalInfo.TBN[2], 0.5), pb.vec3(0.5)), 1);
|
|
460
|
-
break;
|
|
461
|
-
case 'detail_normal':
|
|
462
|
-
scope.$l.outColor = pb.vec4(pb.add(pb.mul(scope.normalInfo.normal, 0.5), pb.vec3(0.5)), 1);
|
|
463
|
-
break;
|
|
464
|
-
case 'tangent':
|
|
465
|
-
scope.$l.outColor = pb.vec4(pb.add(pb.mul(scope.normalInfo.TBN[0], 0.5), pb.vec3(0.5)), 1);
|
|
466
|
-
break;
|
|
467
|
-
case 'bitangent':
|
|
468
|
-
scope.$l.outColor = pb.vec4(pb.add(pb.mul(scope.normalInfo.TBN[1], 0.5), pb.vec3(0.5)), 1);
|
|
469
|
-
break;
|
|
470
|
-
case 'uv':
|
|
471
|
-
scope.$l.outColor = pb.vec4(scope.$inputs.uv, 0, 1);
|
|
472
|
-
break;
|
|
473
|
-
default:
|
|
474
|
-
scope.$l.outColor = pb.vec4(scope.litColor, 1);
|
|
475
|
-
break;
|
|
476
|
-
}
|
|
477
|
-
//scope.$l.outColor = pb.vec4(scope.litColor, 1);
|
|
478
|
-
if (this.drawContext.materialFlags & (MaterialVaryingFlags.SCENE_STORE_ROUGHNESS | MaterialVaryingFlags.SCENE_STORE_NORMAL)) {
|
|
479
|
-
scope.$l.outRoughness = pb.vec4(0, 0, 0, 0);
|
|
480
|
-
this.outputFragmentColor(scope, scope.$inputs.worldPos, scope.outColor, scope.outRoughness, scope.outColor);
|
|
481
|
-
} else {
|
|
482
|
-
this.outputFragmentColor(scope, scope.$inputs.worldPos, scope.outColor);
|
|
483
|
-
}
|
|
718
|
+
this.shadeTerrain(scope);
|
|
484
719
|
} else {
|
|
485
720
|
this.outputFragmentColor(scope, scope.$inputs.worldPos, null);
|
|
486
721
|
}
|
|
487
722
|
}
|
|
723
|
+
/** Lights the terrain from the albedo and normalInfo locals of the fragment shader */ shadeTerrain(scope) {
|
|
724
|
+
const pb = scope.$builder;
|
|
725
|
+
scope.$l.viewVec = this.calculateViewVector(scope, scope.$inputs.worldPos);
|
|
726
|
+
const storeSceneData = !!(this.drawContext.materialFlags & (MaterialVaryingFlags.SCENE_STORE_ROUGHNESS | MaterialVaryingFlags.SCENE_STORE_NORMAL));
|
|
727
|
+
if (storeSceneData) {
|
|
728
|
+
// Filled by PBRLight with (specular color, roughness) for SSR/SSGI
|
|
729
|
+
scope.$l.outRoughness = pb.vec4();
|
|
730
|
+
}
|
|
731
|
+
scope.$l.litColor = this.PBRLight(scope, scope.$inputs.worldPos, scope.normalInfo.normal, scope.viewVec, scope.albedo, scope.normalInfo.TBN, storeSceneData ? scope.outRoughness : undefined);
|
|
732
|
+
switch(this.featureUsed(ClipmapTerrainMaterial.FEATURE_DEBUG_MODE)){
|
|
733
|
+
case 'albedo':
|
|
734
|
+
scope.$l.outColor = pb.vec4(scope.albedo.rgb, 1);
|
|
735
|
+
break;
|
|
736
|
+
case 'vertex_normal':
|
|
737
|
+
scope.$l.outColor = pb.vec4(pb.add(pb.mul(scope.normalInfo.TBN[2], 0.5), pb.vec3(0.5)), 1);
|
|
738
|
+
break;
|
|
739
|
+
case 'detail_normal':
|
|
740
|
+
scope.$l.outColor = pb.vec4(pb.add(pb.mul(scope.normalInfo.normal, 0.5), pb.vec3(0.5)), 1);
|
|
741
|
+
break;
|
|
742
|
+
case 'tangent':
|
|
743
|
+
scope.$l.outColor = pb.vec4(pb.add(pb.mul(scope.normalInfo.TBN[0], 0.5), pb.vec3(0.5)), 1);
|
|
744
|
+
break;
|
|
745
|
+
case 'bitangent':
|
|
746
|
+
scope.$l.outColor = pb.vec4(pb.add(pb.mul(scope.normalInfo.TBN[1], 0.5), pb.vec3(0.5)), 1);
|
|
747
|
+
break;
|
|
748
|
+
case 'uv':
|
|
749
|
+
scope.$l.outColor = pb.vec4(scope.$inputs.uv, 0, 1);
|
|
750
|
+
break;
|
|
751
|
+
default:
|
|
752
|
+
scope.$l.outColor = pb.vec4(scope.litColor, 1);
|
|
753
|
+
break;
|
|
754
|
+
}
|
|
755
|
+
if (storeSceneData) {
|
|
756
|
+
this.outputFragmentColor(scope, scope.$inputs.worldPos, scope.outColor, scope.outRoughness, pb.vec4(pb.add(pb.mul(scope.normalInfo.normal, 0.5), pb.vec3(0.5)), 1));
|
|
757
|
+
} else {
|
|
758
|
+
this.outputFragmentColor(scope, scope.$inputs.worldPos, scope.outColor);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
488
761
|
applyUniformValues(bindGroup, ctx, pass) {
|
|
489
762
|
super.applyUniformValues(bindGroup, ctx, pass);
|
|
490
763
|
bindGroup.setValue('clipmapGridInfo', this._clipmapGridInfo);
|
|
491
764
|
bindGroup.setValue('region', this._region);
|
|
492
765
|
bindGroup.setValue('terrainScale', this._terrainScale);
|
|
493
|
-
|
|
766
|
+
const heightMap = this._heightMap.get();
|
|
767
|
+
// The vertex shader samples explicit mip levels per clipmap ring. WebGL ignores the LOD of
|
|
768
|
+
// textureLod() under a non-mipmapped min filter, so the sampler has to be mipmapped whenever
|
|
769
|
+
// the texture has a mip chain.
|
|
770
|
+
bindGroup.setTexture('heightMap', heightMap, fetchSampler(heightMap.mipLevelCount > 1 ? 'clamp_linear' : 'clamp_linear_nomip'));
|
|
494
771
|
bindGroup.setValue('heightMapSize', this._heightMapSize);
|
|
495
772
|
bindGroup.setBuffer('levelData', this._levelDataBuffer.get());
|
|
496
|
-
if (this.needFragmentColor(ctx)) {
|
|
773
|
+
if (this.needFragmentColor(ctx) && this.virtualTextureUsed) {
|
|
774
|
+
const vt = this._virtualTexture;
|
|
775
|
+
vt.applyBindings(bindGroup, false);
|
|
776
|
+
bindGroup.setTexture('zTerrainRVT0', vt.getPlaneTexture('baseColor'), fetchSampler('clamp_linear_nomip'));
|
|
777
|
+
bindGroup.setTexture('zTerrainRVT1', vt.getPlaneTexture('normalRoughness'), fetchSampler('clamp_linear_nomip'));
|
|
778
|
+
} else if (this.needFragmentColor(ctx)) {
|
|
497
779
|
if (this._detailMapInfo.numDetailMaps > 0) {
|
|
498
780
|
bindGroup.setTexture('splatMap', this._detailMapInfo.splatMap.get());
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
bindGroup.setTexture(`detailAlbedoMap${i}`, this._detailMapInfo.detailMapList[i]?.get() ?? ClipmapTerrainMaterial.getDefaultDetailMap(), fetchSampler('repeat_linear'));
|
|
502
|
-
bindGroup.setTexture(`detailNormalMap${i}`, this._detailMapInfo.detailNormalMapList[i]?.get() ?? ClipmapTerrainMaterial.getDefaultNormalMap(), fetchSampler('repeat_linear'));
|
|
503
|
-
}
|
|
504
|
-
} else {
|
|
505
|
-
bindGroup.setTexture('detailAlbedoMap', this._detailMapInfo.detailMap.get(), fetchSampler('repeat_linear'));
|
|
506
|
-
bindGroup.setTexture('detailNormalMap', this._detailMapInfo.detailNormalMap.get(), fetchSampler('repeat_linear'));
|
|
507
|
-
}
|
|
781
|
+
bindGroup.setTexture('detailAlbedoMap', this._detailMapInfo.detailMap.get(), fetchSampler('repeat_linear'));
|
|
782
|
+
bindGroup.setTexture('detailNormalMap', this._detailMapInfo.detailNormalMap.get(), fetchSampler('repeat_linear'));
|
|
508
783
|
bindGroup.setValue('detailParams', this._detailMapInfo.detailMapParams);
|
|
784
|
+
if (this.hexTilingMask) {
|
|
785
|
+
bindGroup.setValue('detailHexParams', this._detailMapInfo.detailHexParams);
|
|
786
|
+
}
|
|
509
787
|
}
|
|
510
788
|
}
|
|
511
789
|
}
|
|
512
790
|
createDetailMapInfo() {
|
|
513
791
|
const device = getDevice();
|
|
514
|
-
const
|
|
515
|
-
const
|
|
516
|
-
const
|
|
517
|
-
const splatMap = isWebGL1 ? device.createTexture2D('rgba8unorm', this._splatMapSize, this._splatMapSize) : device.createTexture2DArray('rgba8unorm', this._splatMapSize, this._splatMapSize, MAX_DETAIL_MAPS >> 2);
|
|
792
|
+
const detailMap = device.createTexture2DArray('rgba8unorm', this._detailMapSize, this._detailMapSize, MAX_DETAIL_MAPS);
|
|
793
|
+
const detailNormalMap = device.createTexture2DArray('rgba8unorm', this._detailMapSize, this._detailMapSize, MAX_DETAIL_MAPS);
|
|
794
|
+
const splatMap = device.createTexture2DArray('rgba8unorm', this._splatMapSize, this._splatMapSize, MAX_DETAIL_MAPS >> 2);
|
|
518
795
|
device.pushDeviceStates();
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
device.clearFrameBuffer(new Vector4(0.5, 0.5, 1, 1), DEPTH_CLEAR_VALUE, 0);
|
|
536
|
-
}
|
|
537
|
-
fbNormal.dispose();
|
|
796
|
+
const fbDetail = device.createFrameBuffer([
|
|
797
|
+
detailMap
|
|
798
|
+
], null);
|
|
799
|
+
device.setFramebuffer(fbDetail);
|
|
800
|
+
for(let i = 0; i < detailMap.depth; i++){
|
|
801
|
+
fbDetail.setColorAttachmentLayer(0, i);
|
|
802
|
+
device.clearFrameBuffer(Vector4.zero(), DEPTH_CLEAR_VALUE, 0);
|
|
803
|
+
}
|
|
804
|
+
fbDetail.dispose();
|
|
805
|
+
const fbNormal = device.createFrameBuffer([
|
|
806
|
+
detailNormalMap
|
|
807
|
+
], null);
|
|
808
|
+
device.setFramebuffer(fbNormal);
|
|
809
|
+
for(let i = 0; i < detailNormalMap.depth; i++){
|
|
810
|
+
fbNormal.setColorAttachmentLayer(0, i);
|
|
811
|
+
device.clearFrameBuffer(new Vector4(0.5, 0.5, 1, 1), DEPTH_CLEAR_VALUE, 0);
|
|
538
812
|
}
|
|
813
|
+
fbNormal.dispose();
|
|
539
814
|
const fbSplat = device.createFrameBuffer([
|
|
540
815
|
splatMap
|
|
541
816
|
], null);
|
|
@@ -553,6 +828,7 @@ const MAX_DETAIL_MAPS = 8;
|
|
|
553
828
|
detailNormalMapList: [],
|
|
554
829
|
splatMap: new DRef(splatMap),
|
|
555
830
|
detailMapParams: new Float32Array(MAX_DETAIL_MAPS * 4),
|
|
831
|
+
detailHexParams: new Float32Array(MAX_DETAIL_MAPS * 4),
|
|
556
832
|
numDetailMaps: 0
|
|
557
833
|
};
|
|
558
834
|
}
|