@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
|
@@ -76,6 +76,12 @@ import { getEngine } from '../app/api.js';
|
|
|
76
76
|
* @internal
|
|
77
77
|
*/ _optionTag;
|
|
78
78
|
/**
|
|
79
|
+
* Incremented by every option change that can alter how the material looks,
|
|
80
|
+
* which leaves out per-object values of utility passes (the object color of
|
|
81
|
+
* GPU picking).
|
|
82
|
+
* @internal
|
|
83
|
+
*/ _appearanceTag;
|
|
84
|
+
/**
|
|
79
85
|
* Unique runtime instance ID.
|
|
80
86
|
* @internal
|
|
81
87
|
*/ _id;
|
|
@@ -108,6 +114,7 @@ import { getEngine } from '../app/api.js';
|
|
|
108
114
|
null
|
|
109
115
|
];
|
|
110
116
|
this._optionTag = 0;
|
|
117
|
+
this._appearanceTag = 0;
|
|
111
118
|
this._changeTag = 0;
|
|
112
119
|
this._currentHash = [];
|
|
113
120
|
}
|
|
@@ -146,6 +153,21 @@ import { getEngine } from '../app/api.js';
|
|
|
146
153
|
return this._id;
|
|
147
154
|
}
|
|
148
155
|
/**
|
|
156
|
+
* Incremented on every option or uniform change (see `optionChanged()`),
|
|
157
|
+
* including value edits that leave the programs alone, which
|
|
158
|
+
* {@link Material.changeTag} does not count.
|
|
159
|
+
*/ get optionTag() {
|
|
160
|
+
return this._optionTag;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Like {@link Material.optionTag}, but not advanced by values that do not
|
|
164
|
+
* change how the material looks, such as the object color GPU picking sets
|
|
165
|
+
* every frame it picks. For caches of the material's appearance, like the
|
|
166
|
+
* voxelized materials of the global illumination.
|
|
167
|
+
*/ get appearanceTag() {
|
|
168
|
+
return this._appearanceTag;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
149
171
|
* Number of rendering passes this material uses.
|
|
150
172
|
*
|
|
151
173
|
* Increasing this will expand the per-pass hash cache; make sure to implement
|
|
@@ -385,6 +407,26 @@ import { getEngine } from '../app/api.js';
|
|
|
385
407
|
}
|
|
386
408
|
}
|
|
387
409
|
/**
|
|
410
|
+
* Draw a primitive in all passes with arguments read from a GPU buffer (WebGPU only).
|
|
411
|
+
*
|
|
412
|
+
* The indirect counterpart of {@link Material.draw}, see {@link Primitive.drawIndirect} for the
|
|
413
|
+
* buffer layout. The instance count comes from the buffer, so instanced shaders fed by
|
|
414
|
+
* `ctx.instanceData` do not apply; the vertex shader reads per-instance data from instance
|
|
415
|
+
* vertex buffers instead.
|
|
416
|
+
*
|
|
417
|
+
* @param primitive - Geometry to draw.
|
|
418
|
+
* @param ctx - Draw context.
|
|
419
|
+
* @param indirectBuffer - Buffer holding the draw arguments.
|
|
420
|
+
* @param indirectOffset - Byte offset of the arguments, a multiple of 4.
|
|
421
|
+
* @internal
|
|
422
|
+
*/ drawIndirect(primitive, ctx, indirectBuffer, indirectOffset = 0) {
|
|
423
|
+
const numPasses = this.getNumPassesForRender(ctx);
|
|
424
|
+
for(let pass = 0; pass < numPasses; pass++){
|
|
425
|
+
this.bind(ctx.device, pass);
|
|
426
|
+
primitive.drawIndirect(indirectBuffer, indirectOffset);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
388
430
|
* Conditionally update uniforms/resources into the material bind group.
|
|
389
431
|
*
|
|
390
432
|
* Delegates to `_applyUniforms()` when `needUpdate` is true (based on `_optionTag` check).
|
|
@@ -406,9 +448,14 @@ import { getEngine } from '../app/api.js';
|
|
|
406
448
|
* increments `_changeTag`, and notifies `RenderBundleWrapper` to regenerate recorded bundles.
|
|
407
449
|
*
|
|
408
450
|
* @param changeHash - Set true if the change affects shader compilation or render states.
|
|
451
|
+
* @param appearance - Set false for a value that does not change how the material looks
|
|
452
|
+
* (see {@link Material.appearanceTag}); defaults to true.
|
|
409
453
|
* @internal
|
|
410
|
-
*/ optionChanged(changeHash) {
|
|
454
|
+
*/ optionChanged(changeHash, appearance = true) {
|
|
411
455
|
this._optionTag++;
|
|
456
|
+
if (appearance || changeHash) {
|
|
457
|
+
this._appearanceTag++;
|
|
458
|
+
}
|
|
412
459
|
if (changeHash) {
|
|
413
460
|
for(let i = 0; i < this._numPasses; i++){
|
|
414
461
|
this._hash[i] = null;
|
|
@@ -466,17 +513,32 @@ import { getEngine } from '../app/api.js';
|
|
|
466
513
|
* - Else uses `ctx.instanceData.numInstances` if available.
|
|
467
514
|
* - Else issues a non-instanced draw.
|
|
468
515
|
*
|
|
516
|
+
* The primitive is drawn at the level of detail in `ctx.primitiveLod`.
|
|
517
|
+
*
|
|
469
518
|
* @param pass - Pass number.
|
|
470
519
|
* @param primitive - Primitive to draw.
|
|
471
520
|
* @param ctx - Draw context.
|
|
472
521
|
* @param numInstances - Explicit instance count (0 = auto).
|
|
473
522
|
*/ drawPrimitive(pass, primitive, ctx, numInstances) {
|
|
523
|
+
const lod = ctx.primitiveLod ?? 0;
|
|
474
524
|
if (numInstances > 0) {
|
|
475
|
-
primitive.drawInstanced(numInstances);
|
|
525
|
+
primitive.drawInstanced(numInstances, lod);
|
|
476
526
|
} else if (ctx.instanceData) {
|
|
477
|
-
|
|
527
|
+
const culled = ctx.instanceData.culled;
|
|
528
|
+
if (culled && culled.primitive === primitive) {
|
|
529
|
+
// One draw per level of detail culling spread the instances over, empty ones included
|
|
530
|
+
for(let i = 0; i < culled.lodCount; i++){
|
|
531
|
+
primitive.drawIndirect(culled.argsBuffer, culled.argsOffset + i * 20, culled.edgeArgsOffset >= 0 ? culled.edgeArgsOffset + i * 20 : -1);
|
|
532
|
+
}
|
|
533
|
+
} else {
|
|
534
|
+
if (culled) {
|
|
535
|
+
// Culled for another primitive: draw all instances
|
|
536
|
+
ctx.device.setBindGroup(3, ctx.instanceData.bindGroup.bindGroup);
|
|
537
|
+
}
|
|
538
|
+
primitive.drawInstanced(ctx.instanceData.numInstances, lod);
|
|
539
|
+
}
|
|
478
540
|
} else {
|
|
479
|
-
primitive.draw();
|
|
541
|
+
primitive.draw(lod);
|
|
480
542
|
}
|
|
481
543
|
}
|
|
482
544
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"material.js","sources":["../../src/material/material.ts"],"sourcesContent":["import type { AbstractDevice, BindGroup, GPUProgram, RenderStateSet } from '@zephyr3d/device';\r\nimport { ProgramBuilder } from '@zephyr3d/device';\r\nimport type { Primitive } from '../render/primitive';\r\nimport type { DrawContext } from '../render/drawable';\r\nimport { QUEUE_OPAQUE } from '../values';\r\nimport { RenderBundleWrapper } from '../render/renderbundle_wrapper';\r\nimport { Disposable } from '@zephyr3d/base';\r\nimport type { Clonable, IDisposable, Nullable } from '@zephyr3d/base';\r\nimport { getEngine } from '../app/api';\r\nimport type { OIT } from '../render';\r\n\r\ntype MaterialState = {\r\n program: Nullable<GPUProgram>;\r\n bindGroup: Nullable<BindGroup>;\r\n bindGroupTag: string;\r\n renderStateSet: RenderStateSet;\r\n materialTag: number;\r\n OIT: Nullable<OIT>;\r\n oitUniformTag: number;\r\n};\r\n\r\ntype ProgramCacheEntry = {\r\n program: GPUProgram;\r\n refCount: number;\r\n};\r\n\r\n/**\r\n * Base class for all materials.\r\n *\r\n * Responsibilities:\r\n * - Defines a multi-pass rendering interface (`numPasses`, `apply`, `bind`, `draw`, `drawPrimitive`).\r\n * - Builds and caches GPU shader programs per pass and per-render-context hash.\r\n * - Manages a per-material bind group (typically at index 2) for uniforms and resources.\r\n * - Updates render states per pass (`updateRenderStates`) and uploads uniforms (`_applyUniforms`).\r\n * - Tracks \"option\" changes that affect shader variant hashing and render bundles.\r\n *\r\n * Caching and hashing:\r\n * - `createHash(pass)` produces a stable hash representing shader variant options for a pass.\r\n * Override `_createHash()` in subclasses to encode feature toggles (defines, keywords, macros).\r\n * - The global hash used to key `MaterialState` also includes `ctx.materialFlags` and\r\n * `ctx.shaderVariantHash` when provided, allowing context-sensitive variants without\r\n * coupling shader programs to runtime texture identities.\r\n * - GPU programs are additionally memoized in a global static `_programCache` across materials\r\n * by `constructor.name` + hash, to avoid recompilation of identical variants.\r\n *\r\n * Bind groups and uniforms:\r\n * - If a program declares a bind group layout at index 2 (i.e., `bindGroupLayouts.length > 2`),\r\n * `apply()` will allocate the group and keep it in the state. Subclasses should fill it in\r\n * `_applyUniforms()`.\r\n * - `applyUniforms()` only calls `_applyUniforms()` when `needUpdate` is true, based on\r\n * `_optionTag` changes (see `optionChanged()`).\r\n *\r\n * Lifecycle:\r\n * - Constructed materials register a persistent ID into a global registry for serialization.\r\n * - `apply(ctx)` prepares all passes: creates/gets state, programs, bind groups, render states,\r\n * and uploads uniforms as needed.\r\n * - `bind(device, pass)` binds the program, bind group (index 2), and render states.\r\n * - `draw(primitive, ctx, numInstances)` runs all passes, calling `bind()` and `drawPrimitive()`.\r\n * - `onDispose()` releases bind groups and registry entries.\r\n *\r\n * Extending:\r\n * - Override `_createProgram(pb, ctx, pass)` to build a shader.\r\n * - Override `_applyUniforms(bindGroup, ctx, pass)` to upload uniforms and resources.\r\n * - Override `updateRenderStates(pass, renderStates, ctx)` to set depth, blend, cull, etc.\r\n * - Override `_createHash()` to encode options that affect program compilation.\r\n * - Override `supportLighting`, `supportInstancing`, `isTransparentPass`, `getQueueType`, etc.\r\n *\r\n * Thread-safety:\r\n * - Intended for main-thread use in a renderer driving WebGPU/WebGL-like devices.\r\n *\r\n * @public\r\n */\r\nexport class Material extends Disposable implements Clonable<Material>, IDisposable {\r\n /**\r\n * Monotonic instance ID counter.\r\n * @internal\r\n */\r\n private static _nextId = 0;\r\n /**\r\n * Global program cache keyed by global hash\r\n */\r\n private static _programCache: { [hash: string]: ProgramCacheEntry } = {};\r\n /**\r\n * Per-material state cache keyed by global hash (material + context + pass).\r\n * @internal\r\n */\r\n private _states: { [hash: string]: MaterialState };\r\n /**\r\n * Number of rendering passes.\r\n * Subclasses can increase this to implement multi-pass rendering.\r\n * @internal\r\n */\r\n protected _numPasses: number;\r\n /**\r\n * Per-pass hash cached results. Length scales with `numPasses`.\r\n * @internal\r\n */\r\n protected _hash: Nullable<string>[];\r\n /**\r\n * Incremented each time options change (via `optionChanged`), used to decide whether\r\n * uniforms need update on next `apply()`.\r\n * @internal\r\n */\r\n private _optionTag: number;\r\n /**\r\n * Unique runtime instance ID.\r\n * @internal\r\n */\r\n protected readonly _id: number;\r\n /**\r\n * Latest computed global hash per pass, set during `apply()`, read in `bind()`.\r\n * @internal\r\n */\r\n private _currentHash: string[];\r\n /**\r\n * Incremented when material states affecting render bundles change (e.g., bind group id changes\r\n * or `optionChanged(true)`), used to trigger re-recording of render bundles.\r\n * @internal\r\n */\r\n private _changeTag: number;\r\n /**\r\n * Unique program id counter for naming compiled programs.\r\n * @internal\r\n */\r\n private _nextProgramId = 0;\r\n /**\r\n * Create a new material instance.\r\n *\r\n * - Initializes one pass by default.\r\n * - Prepares per-pass hash storage and change tracking.\r\n * - Registers a persistent ID in the global registry.\r\n */\r\n constructor() {\r\n super();\r\n this._id = ++Material._nextId;\r\n this._nextProgramId = 0;\r\n this._states = {};\r\n this._numPasses = 1;\r\n this._hash = [null];\r\n this._optionTag = 0;\r\n this._changeTag = 0;\r\n this._currentHash = [];\r\n }\r\n /**\r\n * Create a shallow clone of this material.\r\n *\r\n * Note: The base implementation returns a base `Material`. Subclasses should\r\n * override to return their own type and copy custom fields.\r\n */\r\n clone() {\r\n const other = new Material();\r\n other.copyFrom(this);\r\n return other;\r\n }\r\n /**\r\n * Copy basic properties from another material.\r\n *\r\n * Disposes existing bind groups/states, copies `numPasses`. Subclasses should\r\n * extend this to copy their own fields and call `optionChanged(true)` if\r\n * shader-affecting options differ.\r\n *\r\n * @param other - Source material.\r\n */\r\n copyFrom(other: this) {\r\n this.clearCache();\r\n this._numPasses = other._numPasses;\r\n getEngine().resourceManager.setAssetId(this, getEngine().resourceManager.getAssetId(other.coreMaterial));\r\n }\r\n /**\r\n * Incremented when the material’s GPU-relevant state changes and render bundles\r\n * may need to be rebuilt.\r\n */\r\n get changeTag() {\r\n return this._changeTag;\r\n }\r\n /**\r\n * Runtime-unique numeric identifier for the material instance.\r\n */\r\n get instanceId() {\r\n return this._id;\r\n }\r\n /**\r\n * Number of rendering passes this material uses.\r\n *\r\n * Increasing this will expand the per-pass hash cache; make sure to implement\r\n * `createHash(pass)`, `_createProgram(pb, ctx, pass)`, and `updateRenderStates(pass, ...)`\r\n * accordingly for each pass.\r\n */\r\n get numPasses() {\r\n return this._numPasses;\r\n }\r\n set numPasses(val) {\r\n while (this._hash.length < val) {\r\n this._hash.push(null);\r\n }\r\n this._numPasses = val;\r\n }\r\n /**\r\n * Get the number of passes this material will render for the given draw context.\r\n *\r\n * Default returns `numPasses`. Subclasses may override to skip passes based on context flags.\r\n * @param _ctx - Draw context (device, flags, pass hash, instance data, etc.).\r\n * @returns Number of passes to render for this context.\r\n */\r\n protected getNumPassesForRender(_ctx: DrawContext) {\r\n return this._numPasses;\r\n }\r\n /**\r\n * Get or compute the per-pass shader hash used for program caching.\r\n *\r\n * Calls `createHash(pass)` lazily and caches the result.\r\n * @internal\r\n */\r\n protected getHash(pass: number) {\r\n if (this._hash[pass] === null) {\r\n this._hash[pass] = this.createHash(pass);\r\n }\r\n return this._hash[pass];\r\n }\r\n /**\r\n * Return the queue type to which this material belongs.\r\n *\r\n * Override this in transparent or special materials (e.g., post-process).\r\n */\r\n getQueueType(): number {\r\n return QUEUE_OPAQUE;\r\n }\r\n /**\r\n * Whether the given pass is transparent.\r\n *\r\n * Used to place draw calls into appropriate render queues and set blending states.\r\n */\r\n isTransparentPass(_pass: number): boolean {\r\n return false;\r\n }\r\n /**\r\n * Whether this material's shading is affected by scene lights.\r\n *\r\n * Override and return `false` for unlit materials.\r\n */\r\n supportLighting(): boolean {\r\n return true;\r\n }\r\n /**\r\n * Whether this material supports hardware instancing.\r\n *\r\n * Override and return `false` if per-instance data is not supported in the shader.\r\n */\r\n supportInstancing(): boolean {\r\n return true;\r\n }\r\n /** Returns true if this is a instance of material */\r\n isBatchable(): boolean {\r\n return false;\r\n }\r\n\r\n /**\r\n * Whether this material requires the scene color texture (e.g., for refraction).\r\n */\r\n needSceneColor(): boolean {\r\n return false;\r\n }\r\n /**\r\n * Whether this material requires the linear scene depth texture (e.g., for depth-aware effects).\r\n */\r\n needSceneDepth(): boolean {\r\n return false;\r\n }\r\n /**\r\n * Create a material instance (instance-uniform-driven variant).\r\n *\r\n * Base returns `null`. Subclasses that support instancing can return a lightweight instance.\r\n */\r\n createInstance(): this {\r\n throw new Error('Abstract function call');\r\n }\r\n /**\r\n * Returns the core material that owns GPU state.\r\n *\r\n * Instances may delegate to a shared core to reuse compiled programs and caches.\r\n * @public\r\n */\r\n get coreMaterial(): this {\r\n return this;\r\n }\r\n /**\r\n * Prepare the material for drawing across all passes for the given draw context.\r\n *\r\n * Steps per pass:\r\n * - Compute global hash (material variant + context).\r\n * - Retrieve or build the GPU program, cache in `_programCache`.\r\n * - Create per-material bind group (index 2) if the program exposes it.\r\n * - Update uniforms if `_optionTag` indicates changes since last apply.\r\n * - Update and cache render states for the pass.\r\n * - Detect bind group GPU ID changes to bump `changeTag` and notify `RenderBundleWrapper`.\r\n *\r\n * @param ctx - Draw context (device, flags, pass hash, instance data, etc.).\r\n * @returns `true` if successful; `false` if any pass lacks a valid program.\r\n */\r\n apply(ctx: DrawContext) {\r\n const numPasses = this.getNumPassesForRender(ctx);\r\n for (let pass = 0; pass < numPasses; pass++) {\r\n const hash = this.calcGlobalHash(ctx, pass);\r\n let state = this._states[hash];\r\n if (!state) {\r\n let programEntry = Material._programCache[hash];\r\n let program = programEntry?.program;\r\n if (!program) {\r\n program = this.createProgram(ctx, pass) ?? null;\r\n if (!program) {\r\n console.error('[Material.apply] program build failed', {\r\n material: this.constructor.name,\r\n pass,\r\n renderPassType: ctx.renderPass?.type ?? null,\r\n materialFlags: ctx.materialFlags,\r\n queue: ctx.queue,\r\n lightBlending: ctx.lightBlending,\r\n hasOIT: !!ctx.oit,\r\n hasShadowLight: !!ctx.currentShadowLight,\r\n renderPassHash: ctx.renderPassHash\r\n });\r\n state = {\r\n program: null,\r\n bindGroup: null,\r\n bindGroupTag: '',\r\n renderStateSet: ctx.device.createRenderStateSet(),\r\n materialTag: -1,\r\n OIT: null,\r\n oitUniformTag: -1\r\n };\r\n this._states[hash] = state;\r\n return false;\r\n }\r\n program.name = `@${this.constructor.name}_program_${this._nextProgramId++}`;\r\n programEntry = { program, refCount: 0 };\r\n Material._programCache[hash] = programEntry;\r\n }\r\n programEntry!.refCount++;\r\n const bindGroup =\r\n program.bindGroupLayouts.length > 2\r\n ? ctx.device.createBindGroup(program.bindGroupLayouts[2])\r\n : null;\r\n state = {\r\n program,\r\n bindGroup,\r\n bindGroupTag: bindGroup?.getVersion() ?? '',\r\n renderStateSet: ctx.device.createRenderStateSet(),\r\n materialTag: -1,\r\n OIT: null,\r\n oitUniformTag: -1\r\n };\r\n this._states[hash] = state;\r\n }\r\n if (!state.program) {\r\n return false;\r\n }\r\n if (state.bindGroup) {\r\n if (ctx.oit && (state.OIT !== ctx.oit || state.oitUniformTag !== ctx.oit.uniformTag)) {\r\n state.OIT = ctx.oit;\r\n state.oitUniformTag = ctx.oit.uniformTag;\r\n ctx.oit.applyUniforms(ctx, state.bindGroup);\r\n }\r\n this.applyUniforms(state.bindGroup, ctx, state.materialTag !== this._optionTag, pass);\r\n }\r\n state.materialTag = this._optionTag;\r\n this.updateRenderStates(pass, state.renderStateSet, ctx);\r\n this._currentHash[pass] = hash;\r\n if (state.bindGroup) {\r\n const id = state.bindGroup.getVersion();\r\n if (id !== state.bindGroupTag) {\r\n state.bindGroupTag = id;\r\n this._changeTag++;\r\n RenderBundleWrapper.materialChanged(this.coreMaterial);\r\n }\r\n }\r\n }\r\n return true;\r\n }\r\n /**\r\n * Bind the program, bind group, and render states for the specified pass.\r\n *\r\n * Must be called after `apply(ctx)` for the same pass.\r\n *\r\n * @param device - Rendering device.\r\n * @param pass - Pass index to bind.\r\n * @returns `true` on success; `false` if state or program missing.\r\n * @internal\r\n */\r\n bind(device: AbstractDevice, pass: number) {\r\n const hash = this._currentHash[pass];\r\n const state = this._states[hash];\r\n if (!state) {\r\n console.error('Material.bind() failed: state not found');\r\n return false;\r\n }\r\n if (!state.program) {\r\n return false;\r\n }\r\n device.setProgram(state.program);\r\n if (state.bindGroup) {\r\n device.setBindGroup(2, state.bindGroup);\r\n }\r\n device.setRenderStates(state.renderStateSet);\r\n return true;\r\n }\r\n /**\r\n * Compute the global hash for the given pass and draw context.\r\n *\r\n * Includes:\r\n * - Per-pass material hash from `getHash(pass)`.\r\n * - `ctx.materialFlags` for context-dependent toggles.\r\n * - `ctx.shaderVariantHash` for shader layout/feature variants, falling back\r\n * to `ctx.renderPassHash` for passes without a shader-only hash.\r\n * @internal\r\n */\r\n private calcGlobalHash(ctx: DrawContext, pass: number) {\r\n const shaderVariantHash = ctx.shaderVariantHash ?? ctx.renderPassHash;\r\n return `${this.getHash(pass)}:${ctx.materialFlags}:${shaderVariantHash}:${\r\n ctx.drawEnvLight ? 1 : 0\r\n }:${ctx.currentShadowLight ? 1 : 0}:${ctx.lightBlending ? 1 : 0}`;\r\n }\r\n /**\r\n * Draw a primitive for all passes using this material.\r\n *\r\n * Calls `bind()` then `drawPrimitive()` per pass. If `numInstances` is zero,\r\n * and `ctx.instanceData` exists, uses `ctx.instanceData.numInstances`.\r\n *\r\n * @param primitive - Geometry to draw.\r\n * @param ctx - Draw context.\r\n * @param numInstances - Instance count; 0 means auto-detect from context.\r\n * @internal\r\n */\r\n draw(primitive: Primitive, ctx: DrawContext, numInstances = 0) {\r\n const numPasses = this.getNumPassesForRender(ctx);\r\n for (let pass = 0; pass < numPasses; pass++) {\r\n this.bind(ctx.device, pass);\r\n this.drawPrimitive(pass, primitive, ctx, numInstances);\r\n }\r\n }\r\n /**\r\n * Conditionally update uniforms/resources into the material bind group.\r\n *\r\n * Delegates to `_applyUniforms()` when `needUpdate` is true (based on `_optionTag` check).\r\n *\r\n * @param bindGroup - Material bind group at index 2 (may be `null` if program has no layout).\r\n * @param ctx - Draw context.\r\n * @param needUpdate - Whether uniforms need to be refreshed.\r\n * @param pass - Pass index.\r\n */\r\n applyUniforms(bindGroup: BindGroup, ctx: DrawContext, needUpdate: boolean, pass: number) {\r\n if (needUpdate) {\r\n this._applyUniforms(bindGroup, ctx, pass);\r\n }\r\n }\r\n /**\r\n * Notify the material that some option changed.\r\n *\r\n * - Always increments `_optionTag`. This will trigger uniforms update on next `apply()`.\r\n * - If `changeHash` is true, clears per-pass hashes so programs/states will be rebuilt,\r\n * increments `_changeTag`, and notifies `RenderBundleWrapper` to regenerate recorded bundles.\r\n *\r\n * @param changeHash - Set true if the change affects shader compilation or render states.\r\n * @internal\r\n */\r\n optionChanged(changeHash: boolean) {\r\n this._optionTag++;\r\n if (changeHash) {\r\n for (let i = 0; i < this._numPasses; i++) {\r\n this._hash[i] = null;\r\n }\r\n this._changeTag++;\r\n RenderBundleWrapper.materialChanged(this.coreMaterial);\r\n }\r\n }\r\n clearCache() {\r\n const hashes = Object.keys(this._states);\r\n if (hashes.length > 0) {\r\n this._changeTag++;\r\n RenderBundleWrapper.materialChanged(this.coreMaterial);\r\n }\r\n for (const k of hashes) {\r\n const state = this._states[k];\r\n state?.bindGroup?.dispose();\r\n const programEntry = Material._programCache[k];\r\n if (state?.program && programEntry?.program === state.program) {\r\n programEntry.refCount--;\r\n if (programEntry.refCount <= 0) {\r\n programEntry.program.dispose();\r\n delete Material._programCache[k];\r\n }\r\n }\r\n }\r\n this._states = {};\r\n }\r\n /**\r\n * Convert a pass index to a hash seed string.\r\n *\r\n * Subclasses may override to encode per-pass role (e.g., \"depth\", \"forward\", \"shadow\").\r\n *\r\n * @param pass - Pass number.\r\n * @returns String used when building full hash.\r\n */\r\n passToHash(pass: number) {\r\n return String(pass);\r\n }\r\n /**\r\n * Build the material hash for a pass (excluding context-dependent parts).\r\n *\r\n * Default formula: `${constructor.name}|${pass}|${_createHash()}`\r\n *\r\n * @param pass - Pass number.\r\n * @returns Hash string used in program caching.\r\n * @internal\r\n */\r\n createHash(pass: number) {\r\n return `${this.constructor.name}|${this.passToHash(pass)}|${this._createHash()}`;\r\n }\r\n /**\r\n * Issue the actual draw call for a pass.\r\n *\r\n * Override for custom per-pass draw behavior if necessary. The default implementation:\r\n * - Draws instanced if `numInstances > 0`.\r\n * - Else uses `ctx.instanceData.numInstances` if available.\r\n * - Else issues a non-instanced draw.\r\n *\r\n * @param pass - Pass number.\r\n * @param primitive - Primitive to draw.\r\n * @param ctx - Draw context.\r\n * @param numInstances - Explicit instance count (0 = auto).\r\n */\r\n drawPrimitive(pass: number, primitive: Primitive, ctx: DrawContext, numInstances: number) {\r\n if (numInstances > 0) {\r\n primitive.drawInstanced(numInstances);\r\n } else if (ctx.instanceData) {\r\n primitive.drawInstanced(ctx.instanceData.numInstances);\r\n } else {\r\n primitive.draw();\r\n }\r\n }\r\n /**\r\n * Dispose the material and release GPU-side resource references.\r\n *\r\n * - Unregisters from the global registry.\r\n * - Disposes the per-material bind groups kept in `_states`.\r\n */\r\n protected onDispose() {\r\n super.onDispose();\r\n this.clearCache();\r\n }\r\n /**\r\n * Build the GPU program for a pass.\r\n *\r\n * Default creates a `ProgramBuilder` and calls `_createProgram(pb, ctx, pass)`.\r\n * Subclasses should override `_createProgram` instead of this method unless\r\n * they need to replace builder instantiation.\r\n *\r\n * @param ctx - Draw context.\r\n * @param pass - Pass number.\r\n * @returns The compiled `GPUProgram`, or `null` on failure.\r\n * @internal\r\n */\r\n protected createProgram(ctx: DrawContext, pass: number) {\r\n const pb = new ProgramBuilder(ctx.device);\r\n return this._createProgram(pb, ctx, pass);\r\n }\r\n /**\r\n * Create and compile the shader program for this material/pass.\r\n *\r\n * Implement in subclasses:\r\n * - Define shader stages, entry points, macros/defines, and resource layouts.\r\n * - Return a compiled `GPUProgram`.\r\n *\r\n * @param pb - Program builder.\r\n * @param ctx - Draw context.\r\n * @param _pass - Pass number.\r\n * @returns The created program, or `null` on failure.\r\n */\r\n protected _createProgram(_pb: ProgramBuilder, _ctx: DrawContext, _pass: number): GPUProgram {\r\n throw new Error('Abstract function call');\r\n }\r\n /**\r\n * Upload uniforms and bind resources to the per-material bind group (index 2).\r\n *\r\n * Implement in subclasses to:\r\n * - Write uniform buffers/textures/samplers to the `bindGroup`.\r\n * - Respect the current `pass` and `ctx`.\r\n *\r\n * @param _bindGroup - The bind group to populate.\r\n * @param _ctx - Draw context.\r\n * @param _pass - Pass number.\r\n */\r\n protected _applyUniforms(_bindGroup: BindGroup, _ctx: DrawContext, _pass: number) {}\r\n /**\r\n * Update render states (depth/stencil, blending, rasterization) for the pass.\r\n *\r\n * Implement in subclasses based on transparency, double-sidedness, depth writes/tests,\r\n * color mask, stencil ops, etc., and any context flags in `ctx`.\r\n *\r\n * @param _pass - Current pass index.\r\n * @param _renderStates - Render state set to mutate.\r\n * @param _ctx - Draw context.\r\n */\r\n protected updateRenderStates(_pass: number, _renderStates: RenderStateSet, _ctx: DrawContext) {}\r\n /**\r\n * Compute the material-specific portion of the shader hash for the current options.\r\n *\r\n * Subclasses should override to include macro/define sets that influence program compilation.\r\n * Example return: `\"USE_NORMALMAP=1;ALPHA_MODE=BLEND;RECEIVE_SHADOWS=1\"`.\r\n *\r\n * @returns Hash fragment string (no context/pass info).\r\n */\r\n protected _createHash() {\r\n return '';\r\n }\r\n /**\r\n * Whether this is a lightweight instance of a core material.\r\n *\r\n * Instances typically share GPU programs with a core and only override instance uniforms.\r\n * @internal\r\n */\r\n get $isInstance(): boolean {\r\n return false;\r\n }\r\n /**\r\n * Instance-uniform buffer for material instances, if supported.\r\n *\r\n * Returned as a typed Float32 view over a backing ArrayBuffer.\r\n * @internal\r\n */\r\n get $instanceUniforms(): Float32Array<ArrayBuffer> {\r\n throw new Error('Abstract function call');\r\n }\r\n}\r\n"],"names":["Material","Disposable","_nextId","_programCache","_nextProgramId","_id","_states","_numPasses","_hash","_optionTag","_changeTag","_currentHash","clone","other","copyFrom","clearCache","getEngine","resourceManager","setAssetId","getAssetId","coreMaterial","changeTag","instanceId","numPasses","val","length","push","getNumPassesForRender","_ctx","getHash","pass","createHash","getQueueType","QUEUE_OPAQUE","isTransparentPass","_pass","supportLighting","supportInstancing","isBatchable","needSceneColor","needSceneDepth","createInstance","Error","apply","ctx","hash","calcGlobalHash","state","programEntry","program","createProgram","console","error","material","name","renderPassType","renderPass","type","materialFlags","queue","lightBlending","hasOIT","oit","hasShadowLight","currentShadowLight","renderPassHash","bindGroup","bindGroupTag","renderStateSet","device","createRenderStateSet","materialTag","OIT","oitUniformTag","refCount","bindGroupLayouts","createBindGroup","getVersion","uniformTag","applyUniforms","updateRenderStates","id","RenderBundleWrapper","materialChanged","bind","setProgram","setBindGroup","setRenderStates","shaderVariantHash","drawEnvLight","draw","primitive","numInstances","drawPrimitive","needUpdate","_applyUniforms","optionChanged","changeHash","i","hashes","Object","keys","k","dispose","passToHash","String","_createHash","drawInstanced","instanceData","onDispose","pb","ProgramBuilder","_createProgram","_pb","_bindGroup","_renderStates","$isInstance","$instanceUniforms"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"material.js","sources":["../../src/material/material.ts"],"sourcesContent":["import type { AbstractDevice, BindGroup, GPUDataBuffer, GPUProgram, RenderStateSet } from '@zephyr3d/device';\r\nimport { ProgramBuilder } from '@zephyr3d/device';\r\nimport type { Primitive } from '../render/primitive';\r\nimport type { DrawContext } from '../render/drawable';\r\nimport { QUEUE_OPAQUE } from '../values';\r\nimport { RenderBundleWrapper } from '../render/renderbundle_wrapper';\r\nimport { Disposable } from '@zephyr3d/base';\r\nimport type { Clonable, IDisposable, Nullable } from '@zephyr3d/base';\r\nimport { getEngine } from '../app/api';\r\nimport type { OIT } from '../render';\r\n\r\ntype MaterialState = {\r\n program: Nullable<GPUProgram>;\r\n bindGroup: Nullable<BindGroup>;\r\n bindGroupTag: string;\r\n renderStateSet: RenderStateSet;\r\n materialTag: number;\r\n OIT: Nullable<OIT>;\r\n oitUniformTag: number;\r\n};\r\n\r\ntype ProgramCacheEntry = {\r\n program: GPUProgram;\r\n refCount: number;\r\n};\r\n\r\n/**\r\n * Base class for all materials.\r\n *\r\n * Responsibilities:\r\n * - Defines a multi-pass rendering interface (`numPasses`, `apply`, `bind`, `draw`, `drawPrimitive`).\r\n * - Builds and caches GPU shader programs per pass and per-render-context hash.\r\n * - Manages a per-material bind group (typically at index 2) for uniforms and resources.\r\n * - Updates render states per pass (`updateRenderStates`) and uploads uniforms (`_applyUniforms`).\r\n * - Tracks \"option\" changes that affect shader variant hashing and render bundles.\r\n *\r\n * Caching and hashing:\r\n * - `createHash(pass)` produces a stable hash representing shader variant options for a pass.\r\n * Override `_createHash()` in subclasses to encode feature toggles (defines, keywords, macros).\r\n * - The global hash used to key `MaterialState` also includes `ctx.materialFlags` and\r\n * `ctx.shaderVariantHash` when provided, allowing context-sensitive variants without\r\n * coupling shader programs to runtime texture identities.\r\n * - GPU programs are additionally memoized in a global static `_programCache` across materials\r\n * by `constructor.name` + hash, to avoid recompilation of identical variants.\r\n *\r\n * Bind groups and uniforms:\r\n * - If a program declares a bind group layout at index 2 (i.e., `bindGroupLayouts.length > 2`),\r\n * `apply()` will allocate the group and keep it in the state. Subclasses should fill it in\r\n * `_applyUniforms()`.\r\n * - `applyUniforms()` only calls `_applyUniforms()` when `needUpdate` is true, based on\r\n * `_optionTag` changes (see `optionChanged()`).\r\n *\r\n * Lifecycle:\r\n * - Constructed materials register a persistent ID into a global registry for serialization.\r\n * - `apply(ctx)` prepares all passes: creates/gets state, programs, bind groups, render states,\r\n * and uploads uniforms as needed.\r\n * - `bind(device, pass)` binds the program, bind group (index 2), and render states.\r\n * - `draw(primitive, ctx, numInstances)` runs all passes, calling `bind()` and `drawPrimitive()`.\r\n * - `onDispose()` releases bind groups and registry entries.\r\n *\r\n * Extending:\r\n * - Override `_createProgram(pb, ctx, pass)` to build a shader.\r\n * - Override `_applyUniforms(bindGroup, ctx, pass)` to upload uniforms and resources.\r\n * - Override `updateRenderStates(pass, renderStates, ctx)` to set depth, blend, cull, etc.\r\n * - Override `_createHash()` to encode options that affect program compilation.\r\n * - Override `supportLighting`, `supportInstancing`, `isTransparentPass`, `getQueueType`, etc.\r\n *\r\n * Thread-safety:\r\n * - Intended for main-thread use in a renderer driving WebGPU/WebGL-like devices.\r\n *\r\n * @public\r\n */\r\nexport class Material extends Disposable implements Clonable<Material>, IDisposable {\r\n /**\r\n * Monotonic instance ID counter.\r\n * @internal\r\n */\r\n private static _nextId = 0;\r\n /**\r\n * Global program cache keyed by global hash\r\n */\r\n private static _programCache: { [hash: string]: ProgramCacheEntry } = {};\r\n /**\r\n * Per-material state cache keyed by global hash (material + context + pass).\r\n * @internal\r\n */\r\n private _states: { [hash: string]: MaterialState };\r\n /**\r\n * Number of rendering passes.\r\n * Subclasses can increase this to implement multi-pass rendering.\r\n * @internal\r\n */\r\n protected _numPasses: number;\r\n /**\r\n * Per-pass hash cached results. Length scales with `numPasses`.\r\n * @internal\r\n */\r\n protected _hash: Nullable<string>[];\r\n /**\r\n * Incremented each time options change (via `optionChanged`), used to decide whether\r\n * uniforms need update on next `apply()`.\r\n * @internal\r\n */\r\n private _optionTag: number;\r\n /**\r\n * Incremented by every option change that can alter how the material looks,\r\n * which leaves out per-object values of utility passes (the object color of\r\n * GPU picking).\r\n * @internal\r\n */\r\n private _appearanceTag: number;\r\n /**\r\n * Unique runtime instance ID.\r\n * @internal\r\n */\r\n protected readonly _id: number;\r\n /**\r\n * Latest computed global hash per pass, set during `apply()`, read in `bind()`.\r\n * @internal\r\n */\r\n private _currentHash: string[];\r\n /**\r\n * Incremented when material states affecting render bundles change (e.g., bind group id changes\r\n * or `optionChanged(true)`), used to trigger re-recording of render bundles.\r\n * @internal\r\n */\r\n private _changeTag: number;\r\n /**\r\n * Unique program id counter for naming compiled programs.\r\n * @internal\r\n */\r\n private _nextProgramId = 0;\r\n /**\r\n * Create a new material instance.\r\n *\r\n * - Initializes one pass by default.\r\n * - Prepares per-pass hash storage and change tracking.\r\n * - Registers a persistent ID in the global registry.\r\n */\r\n constructor() {\r\n super();\r\n this._id = ++Material._nextId;\r\n this._nextProgramId = 0;\r\n this._states = {};\r\n this._numPasses = 1;\r\n this._hash = [null];\r\n this._optionTag = 0;\r\n this._appearanceTag = 0;\r\n this._changeTag = 0;\r\n this._currentHash = [];\r\n }\r\n /**\r\n * Create a shallow clone of this material.\r\n *\r\n * Note: The base implementation returns a base `Material`. Subclasses should\r\n * override to return their own type and copy custom fields.\r\n */\r\n clone() {\r\n const other = new Material();\r\n other.copyFrom(this);\r\n return other;\r\n }\r\n /**\r\n * Copy basic properties from another material.\r\n *\r\n * Disposes existing bind groups/states, copies `numPasses`. Subclasses should\r\n * extend this to copy their own fields and call `optionChanged(true)` if\r\n * shader-affecting options differ.\r\n *\r\n * @param other - Source material.\r\n */\r\n copyFrom(other: this) {\r\n this.clearCache();\r\n this._numPasses = other._numPasses;\r\n getEngine().resourceManager.setAssetId(this, getEngine().resourceManager.getAssetId(other.coreMaterial));\r\n }\r\n /**\r\n * Incremented when the material’s GPU-relevant state changes and render bundles\r\n * may need to be rebuilt.\r\n */\r\n get changeTag() {\r\n return this._changeTag;\r\n }\r\n /**\r\n * Runtime-unique numeric identifier for the material instance.\r\n */\r\n get instanceId() {\r\n return this._id;\r\n }\r\n /**\r\n * Incremented on every option or uniform change (see `optionChanged()`),\r\n * including value edits that leave the programs alone, which\r\n * {@link Material.changeTag} does not count.\r\n */\r\n get optionTag() {\r\n return this._optionTag;\r\n }\r\n /**\r\n * Like {@link Material.optionTag}, but not advanced by values that do not\r\n * change how the material looks, such as the object color GPU picking sets\r\n * every frame it picks. For caches of the material's appearance, like the\r\n * voxelized materials of the global illumination.\r\n */\r\n get appearanceTag() {\r\n return this._appearanceTag;\r\n }\r\n /**\r\n * Number of rendering passes this material uses.\r\n *\r\n * Increasing this will expand the per-pass hash cache; make sure to implement\r\n * `createHash(pass)`, `_createProgram(pb, ctx, pass)`, and `updateRenderStates(pass, ...)`\r\n * accordingly for each pass.\r\n */\r\n get numPasses() {\r\n return this._numPasses;\r\n }\r\n set numPasses(val) {\r\n while (this._hash.length < val) {\r\n this._hash.push(null);\r\n }\r\n this._numPasses = val;\r\n }\r\n /**\r\n * Get the number of passes this material will render for the given draw context.\r\n *\r\n * Default returns `numPasses`. Subclasses may override to skip passes based on context flags.\r\n * @param _ctx - Draw context (device, flags, pass hash, instance data, etc.).\r\n * @returns Number of passes to render for this context.\r\n */\r\n protected getNumPassesForRender(_ctx: DrawContext) {\r\n return this._numPasses;\r\n }\r\n /**\r\n * Get or compute the per-pass shader hash used for program caching.\r\n *\r\n * Calls `createHash(pass)` lazily and caches the result.\r\n * @internal\r\n */\r\n protected getHash(pass: number) {\r\n if (this._hash[pass] === null) {\r\n this._hash[pass] = this.createHash(pass);\r\n }\r\n return this._hash[pass];\r\n }\r\n /**\r\n * Return the queue type to which this material belongs.\r\n *\r\n * Override this in transparent or special materials (e.g., post-process).\r\n */\r\n getQueueType(): number {\r\n return QUEUE_OPAQUE;\r\n }\r\n /**\r\n * Whether the given pass is transparent.\r\n *\r\n * Used to place draw calls into appropriate render queues and set blending states.\r\n */\r\n isTransparentPass(_pass: number): boolean {\r\n return false;\r\n }\r\n /**\r\n * Whether this material's shading is affected by scene lights.\r\n *\r\n * Override and return `false` for unlit materials.\r\n */\r\n supportLighting(): boolean {\r\n return true;\r\n }\r\n /**\r\n * Whether this material supports hardware instancing.\r\n *\r\n * Override and return `false` if per-instance data is not supported in the shader.\r\n */\r\n supportInstancing(): boolean {\r\n return true;\r\n }\r\n /** Returns true if this is a instance of material */\r\n isBatchable(): boolean {\r\n return false;\r\n }\r\n\r\n /**\r\n * Whether this material requires the scene color texture (e.g., for refraction).\r\n */\r\n needSceneColor(): boolean {\r\n return false;\r\n }\r\n /**\r\n * Whether this material requires the linear scene depth texture (e.g., for depth-aware effects).\r\n */\r\n needSceneDepth(): boolean {\r\n return false;\r\n }\r\n /**\r\n * Create a material instance (instance-uniform-driven variant).\r\n *\r\n * Base returns `null`. Subclasses that support instancing can return a lightweight instance.\r\n */\r\n createInstance(): this {\r\n throw new Error('Abstract function call');\r\n }\r\n /**\r\n * Returns the core material that owns GPU state.\r\n *\r\n * Instances may delegate to a shared core to reuse compiled programs and caches.\r\n * @public\r\n */\r\n get coreMaterial(): this {\r\n return this;\r\n }\r\n /**\r\n * Prepare the material for drawing across all passes for the given draw context.\r\n *\r\n * Steps per pass:\r\n * - Compute global hash (material variant + context).\r\n * - Retrieve or build the GPU program, cache in `_programCache`.\r\n * - Create per-material bind group (index 2) if the program exposes it.\r\n * - Update uniforms if `_optionTag` indicates changes since last apply.\r\n * - Update and cache render states for the pass.\r\n * - Detect bind group GPU ID changes to bump `changeTag` and notify `RenderBundleWrapper`.\r\n *\r\n * @param ctx - Draw context (device, flags, pass hash, instance data, etc.).\r\n * @returns `true` if successful; `false` if any pass lacks a valid program.\r\n */\r\n apply(ctx: DrawContext) {\r\n const numPasses = this.getNumPassesForRender(ctx);\r\n for (let pass = 0; pass < numPasses; pass++) {\r\n const hash = this.calcGlobalHash(ctx, pass);\r\n let state = this._states[hash];\r\n if (!state) {\r\n let programEntry = Material._programCache[hash];\r\n let program = programEntry?.program;\r\n if (!program) {\r\n program = this.createProgram(ctx, pass) ?? null;\r\n if (!program) {\r\n console.error('[Material.apply] program build failed', {\r\n material: this.constructor.name,\r\n pass,\r\n renderPassType: ctx.renderPass?.type ?? null,\r\n materialFlags: ctx.materialFlags,\r\n queue: ctx.queue,\r\n lightBlending: ctx.lightBlending,\r\n hasOIT: !!ctx.oit,\r\n hasShadowLight: !!ctx.currentShadowLight,\r\n renderPassHash: ctx.renderPassHash\r\n });\r\n state = {\r\n program: null,\r\n bindGroup: null,\r\n bindGroupTag: '',\r\n renderStateSet: ctx.device.createRenderStateSet(),\r\n materialTag: -1,\r\n OIT: null,\r\n oitUniformTag: -1\r\n };\r\n this._states[hash] = state;\r\n return false;\r\n }\r\n program.name = `@${this.constructor.name}_program_${this._nextProgramId++}`;\r\n programEntry = { program, refCount: 0 };\r\n Material._programCache[hash] = programEntry;\r\n }\r\n programEntry!.refCount++;\r\n const bindGroup =\r\n program.bindGroupLayouts.length > 2\r\n ? ctx.device.createBindGroup(program.bindGroupLayouts[2])\r\n : null;\r\n state = {\r\n program,\r\n bindGroup,\r\n bindGroupTag: bindGroup?.getVersion() ?? '',\r\n renderStateSet: ctx.device.createRenderStateSet(),\r\n materialTag: -1,\r\n OIT: null,\r\n oitUniformTag: -1\r\n };\r\n this._states[hash] = state;\r\n }\r\n if (!state.program) {\r\n return false;\r\n }\r\n if (state.bindGroup) {\r\n if (ctx.oit && (state.OIT !== ctx.oit || state.oitUniformTag !== ctx.oit.uniformTag)) {\r\n state.OIT = ctx.oit;\r\n state.oitUniformTag = ctx.oit.uniformTag;\r\n ctx.oit.applyUniforms(ctx, state.bindGroup);\r\n }\r\n this.applyUniforms(state.bindGroup, ctx, state.materialTag !== this._optionTag, pass);\r\n }\r\n state.materialTag = this._optionTag;\r\n this.updateRenderStates(pass, state.renderStateSet, ctx);\r\n this._currentHash[pass] = hash;\r\n if (state.bindGroup) {\r\n const id = state.bindGroup.getVersion();\r\n if (id !== state.bindGroupTag) {\r\n state.bindGroupTag = id;\r\n this._changeTag++;\r\n RenderBundleWrapper.materialChanged(this.coreMaterial);\r\n }\r\n }\r\n }\r\n return true;\r\n }\r\n /**\r\n * Bind the program, bind group, and render states for the specified pass.\r\n *\r\n * Must be called after `apply(ctx)` for the same pass.\r\n *\r\n * @param device - Rendering device.\r\n * @param pass - Pass index to bind.\r\n * @returns `true` on success; `false` if state or program missing.\r\n * @internal\r\n */\r\n bind(device: AbstractDevice, pass: number) {\r\n const hash = this._currentHash[pass];\r\n const state = this._states[hash];\r\n if (!state) {\r\n console.error('Material.bind() failed: state not found');\r\n return false;\r\n }\r\n if (!state.program) {\r\n return false;\r\n }\r\n device.setProgram(state.program);\r\n if (state.bindGroup) {\r\n device.setBindGroup(2, state.bindGroup);\r\n }\r\n device.setRenderStates(state.renderStateSet);\r\n return true;\r\n }\r\n /**\r\n * Compute the global hash for the given pass and draw context.\r\n *\r\n * Includes:\r\n * - Per-pass material hash from `getHash(pass)`.\r\n * - `ctx.materialFlags` for context-dependent toggles.\r\n * - `ctx.shaderVariantHash` for shader layout/feature variants, falling back\r\n * to `ctx.renderPassHash` for passes without a shader-only hash.\r\n * @internal\r\n */\r\n private calcGlobalHash(ctx: DrawContext, pass: number) {\r\n const shaderVariantHash = ctx.shaderVariantHash ?? ctx.renderPassHash;\r\n return `${this.getHash(pass)}:${ctx.materialFlags}:${shaderVariantHash}:${\r\n ctx.drawEnvLight ? 1 : 0\r\n }:${ctx.currentShadowLight ? 1 : 0}:${ctx.lightBlending ? 1 : 0}`;\r\n }\r\n /**\r\n * Draw a primitive for all passes using this material.\r\n *\r\n * Calls `bind()` then `drawPrimitive()` per pass. If `numInstances` is zero,\r\n * and `ctx.instanceData` exists, uses `ctx.instanceData.numInstances`.\r\n *\r\n * @param primitive - Geometry to draw.\r\n * @param ctx - Draw context.\r\n * @param numInstances - Instance count; 0 means auto-detect from context.\r\n * @internal\r\n */\r\n draw(primitive: Primitive, ctx: DrawContext, numInstances = 0) {\r\n const numPasses = this.getNumPassesForRender(ctx);\r\n for (let pass = 0; pass < numPasses; pass++) {\r\n this.bind(ctx.device, pass);\r\n this.drawPrimitive(pass, primitive, ctx, numInstances);\r\n }\r\n }\r\n /**\r\n * Draw a primitive in all passes with arguments read from a GPU buffer (WebGPU only).\r\n *\r\n * The indirect counterpart of {@link Material.draw}, see {@link Primitive.drawIndirect} for the\r\n * buffer layout. The instance count comes from the buffer, so instanced shaders fed by\r\n * `ctx.instanceData` do not apply; the vertex shader reads per-instance data from instance\r\n * vertex buffers instead.\r\n *\r\n * @param primitive - Geometry to draw.\r\n * @param ctx - Draw context.\r\n * @param indirectBuffer - Buffer holding the draw arguments.\r\n * @param indirectOffset - Byte offset of the arguments, a multiple of 4.\r\n * @internal\r\n */\r\n drawIndirect(primitive: Primitive, ctx: DrawContext, indirectBuffer: GPUDataBuffer, indirectOffset = 0) {\r\n const numPasses = this.getNumPassesForRender(ctx);\r\n for (let pass = 0; pass < numPasses; pass++) {\r\n this.bind(ctx.device, pass);\r\n primitive.drawIndirect(indirectBuffer, indirectOffset);\r\n }\r\n }\r\n /**\r\n * Conditionally update uniforms/resources into the material bind group.\r\n *\r\n * Delegates to `_applyUniforms()` when `needUpdate` is true (based on `_optionTag` check).\r\n *\r\n * @param bindGroup - Material bind group at index 2 (may be `null` if program has no layout).\r\n * @param ctx - Draw context.\r\n * @param needUpdate - Whether uniforms need to be refreshed.\r\n * @param pass - Pass index.\r\n */\r\n applyUniforms(bindGroup: BindGroup, ctx: DrawContext, needUpdate: boolean, pass: number) {\r\n if (needUpdate) {\r\n this._applyUniforms(bindGroup, ctx, pass);\r\n }\r\n }\r\n /**\r\n * Notify the material that some option changed.\r\n *\r\n * - Always increments `_optionTag`. This will trigger uniforms update on next `apply()`.\r\n * - If `changeHash` is true, clears per-pass hashes so programs/states will be rebuilt,\r\n * increments `_changeTag`, and notifies `RenderBundleWrapper` to regenerate recorded bundles.\r\n *\r\n * @param changeHash - Set true if the change affects shader compilation or render states.\r\n * @param appearance - Set false for a value that does not change how the material looks\r\n * (see {@link Material.appearanceTag}); defaults to true.\r\n * @internal\r\n */\r\n optionChanged(changeHash: boolean, appearance = true) {\r\n this._optionTag++;\r\n if (appearance || changeHash) {\r\n this._appearanceTag++;\r\n }\r\n if (changeHash) {\r\n for (let i = 0; i < this._numPasses; i++) {\r\n this._hash[i] = null;\r\n }\r\n this._changeTag++;\r\n RenderBundleWrapper.materialChanged(this.coreMaterial);\r\n }\r\n }\r\n clearCache() {\r\n const hashes = Object.keys(this._states);\r\n if (hashes.length > 0) {\r\n this._changeTag++;\r\n RenderBundleWrapper.materialChanged(this.coreMaterial);\r\n }\r\n for (const k of hashes) {\r\n const state = this._states[k];\r\n state?.bindGroup?.dispose();\r\n const programEntry = Material._programCache[k];\r\n if (state?.program && programEntry?.program === state.program) {\r\n programEntry.refCount--;\r\n if (programEntry.refCount <= 0) {\r\n programEntry.program.dispose();\r\n delete Material._programCache[k];\r\n }\r\n }\r\n }\r\n this._states = {};\r\n }\r\n /**\r\n * Convert a pass index to a hash seed string.\r\n *\r\n * Subclasses may override to encode per-pass role (e.g., \"depth\", \"forward\", \"shadow\").\r\n *\r\n * @param pass - Pass number.\r\n * @returns String used when building full hash.\r\n */\r\n passToHash(pass: number) {\r\n return String(pass);\r\n }\r\n /**\r\n * Build the material hash for a pass (excluding context-dependent parts).\r\n *\r\n * Default formula: `${constructor.name}|${pass}|${_createHash()}`\r\n *\r\n * @param pass - Pass number.\r\n * @returns Hash string used in program caching.\r\n * @internal\r\n */\r\n createHash(pass: number) {\r\n return `${this.constructor.name}|${this.passToHash(pass)}|${this._createHash()}`;\r\n }\r\n /**\r\n * Issue the actual draw call for a pass.\r\n *\r\n * Override for custom per-pass draw behavior if necessary. The default implementation:\r\n * - Draws instanced if `numInstances > 0`.\r\n * - Else uses `ctx.instanceData.numInstances` if available.\r\n * - Else issues a non-instanced draw.\r\n *\r\n * The primitive is drawn at the level of detail in `ctx.primitiveLod`.\r\n *\r\n * @param pass - Pass number.\r\n * @param primitive - Primitive to draw.\r\n * @param ctx - Draw context.\r\n * @param numInstances - Explicit instance count (0 = auto).\r\n */\r\n drawPrimitive(pass: number, primitive: Primitive, ctx: DrawContext, numInstances: number) {\r\n const lod = ctx.primitiveLod ?? 0;\r\n if (numInstances > 0) {\r\n primitive.drawInstanced(numInstances, lod);\r\n } else if (ctx.instanceData) {\r\n const culled = ctx.instanceData.culled;\r\n if (culled && culled.primitive === primitive) {\r\n // One draw per level of detail culling spread the instances over, empty ones included\r\n for (let i = 0; i < culled.lodCount; i++) {\r\n primitive.drawIndirect(\r\n culled.argsBuffer,\r\n culled.argsOffset + i * 20,\r\n culled.edgeArgsOffset >= 0 ? culled.edgeArgsOffset + i * 20 : -1\r\n );\r\n }\r\n } else {\r\n if (culled) {\r\n // Culled for another primitive: draw all instances\r\n ctx.device.setBindGroup(3, ctx.instanceData.bindGroup.bindGroup);\r\n }\r\n primitive.drawInstanced(ctx.instanceData.numInstances, lod);\r\n }\r\n } else {\r\n primitive.draw(lod);\r\n }\r\n }\r\n /**\r\n * Dispose the material and release GPU-side resource references.\r\n *\r\n * - Unregisters from the global registry.\r\n * - Disposes the per-material bind groups kept in `_states`.\r\n */\r\n protected onDispose() {\r\n super.onDispose();\r\n this.clearCache();\r\n }\r\n /**\r\n * Build the GPU program for a pass.\r\n *\r\n * Default creates a `ProgramBuilder` and calls `_createProgram(pb, ctx, pass)`.\r\n * Subclasses should override `_createProgram` instead of this method unless\r\n * they need to replace builder instantiation.\r\n *\r\n * @param ctx - Draw context.\r\n * @param pass - Pass number.\r\n * @returns The compiled `GPUProgram`, or `null` on failure.\r\n * @internal\r\n */\r\n protected createProgram(ctx: DrawContext, pass: number) {\r\n const pb = new ProgramBuilder(ctx.device);\r\n return this._createProgram(pb, ctx, pass);\r\n }\r\n /**\r\n * Create and compile the shader program for this material/pass.\r\n *\r\n * Implement in subclasses:\r\n * - Define shader stages, entry points, macros/defines, and resource layouts.\r\n * - Return a compiled `GPUProgram`.\r\n *\r\n * @param pb - Program builder.\r\n * @param ctx - Draw context.\r\n * @param _pass - Pass number.\r\n * @returns The created program, or `null` on failure.\r\n */\r\n protected _createProgram(_pb: ProgramBuilder, _ctx: DrawContext, _pass: number): GPUProgram {\r\n throw new Error('Abstract function call');\r\n }\r\n /**\r\n * Upload uniforms and bind resources to the per-material bind group (index 2).\r\n *\r\n * Implement in subclasses to:\r\n * - Write uniform buffers/textures/samplers to the `bindGroup`.\r\n * - Respect the current `pass` and `ctx`.\r\n *\r\n * @param _bindGroup - The bind group to populate.\r\n * @param _ctx - Draw context.\r\n * @param _pass - Pass number.\r\n */\r\n protected _applyUniforms(_bindGroup: BindGroup, _ctx: DrawContext, _pass: number) {}\r\n /**\r\n * Update render states (depth/stencil, blending, rasterization) for the pass.\r\n *\r\n * Implement in subclasses based on transparency, double-sidedness, depth writes/tests,\r\n * color mask, stencil ops, etc., and any context flags in `ctx`.\r\n *\r\n * @param _pass - Current pass index.\r\n * @param _renderStates - Render state set to mutate.\r\n * @param _ctx - Draw context.\r\n */\r\n protected updateRenderStates(_pass: number, _renderStates: RenderStateSet, _ctx: DrawContext) {}\r\n /**\r\n * Compute the material-specific portion of the shader hash for the current options.\r\n *\r\n * Subclasses should override to include macro/define sets that influence program compilation.\r\n * Example return: `\"USE_NORMALMAP=1;ALPHA_MODE=BLEND;RECEIVE_SHADOWS=1\"`.\r\n *\r\n * @returns Hash fragment string (no context/pass info).\r\n */\r\n protected _createHash() {\r\n return '';\r\n }\r\n /**\r\n * Whether this is a lightweight instance of a core material.\r\n *\r\n * Instances typically share GPU programs with a core and only override instance uniforms.\r\n * @internal\r\n */\r\n get $isInstance(): boolean {\r\n return false;\r\n }\r\n /**\r\n * Instance-uniform buffer for material instances, if supported.\r\n *\r\n * Returned as a typed Float32 view over a backing ArrayBuffer.\r\n * @internal\r\n */\r\n get $instanceUniforms(): Float32Array<ArrayBuffer> {\r\n throw new Error('Abstract function call');\r\n }\r\n}\r\n"],"names":["Material","Disposable","_nextId","_programCache","_nextProgramId","_id","_states","_numPasses","_hash","_optionTag","_appearanceTag","_changeTag","_currentHash","clone","other","copyFrom","clearCache","getEngine","resourceManager","setAssetId","getAssetId","coreMaterial","changeTag","instanceId","optionTag","appearanceTag","numPasses","val","length","push","getNumPassesForRender","_ctx","getHash","pass","createHash","getQueueType","QUEUE_OPAQUE","isTransparentPass","_pass","supportLighting","supportInstancing","isBatchable","needSceneColor","needSceneDepth","createInstance","Error","apply","ctx","hash","calcGlobalHash","state","programEntry","program","createProgram","console","error","material","name","renderPassType","renderPass","type","materialFlags","queue","lightBlending","hasOIT","oit","hasShadowLight","currentShadowLight","renderPassHash","bindGroup","bindGroupTag","renderStateSet","device","createRenderStateSet","materialTag","OIT","oitUniformTag","refCount","bindGroupLayouts","createBindGroup","getVersion","uniformTag","applyUniforms","updateRenderStates","id","RenderBundleWrapper","materialChanged","bind","setProgram","setBindGroup","setRenderStates","shaderVariantHash","drawEnvLight","draw","primitive","numInstances","drawPrimitive","drawIndirect","indirectBuffer","indirectOffset","needUpdate","_applyUniforms","optionChanged","changeHash","appearance","i","hashes","Object","keys","k","dispose","passToHash","String","_createHash","lod","primitiveLod","drawInstanced","instanceData","culled","lodCount","argsBuffer","argsOffset","edgeArgsOffset","onDispose","pb","ProgramBuilder","_createProgram","_pb","_bindGroup","_renderStates","$isInstance","$instanceUniforms"],"mappings":";;;;;;AA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA8CO,MAAMA,QAAiBC,SAAAA,UAAAA,CAAAA;AAC5B;;;MAIA,OAAeC,UAAU,CAAE;AAC3B;;MAGA,OAAeC,aAAuD,GAAA,EAAG;AACzE;;;AAGC,MACD,OAAmD;AACnD;;;;AAIC,MACD,UAA6B;AAC7B;;;AAGC,MACD,KAAoC;AACpC;;;;AAIC,MACD,UAA2B;AAC3B;;;;;AAKC,MACD,cAA+B;AAC/B;;;AAGC,MACD,GAA+B;AAC/B;;;AAGC,MACD,YAA+B;AAC/B;;;;AAIC,MACD,UAA2B;AAC3B;;;MAIQC,iBAAiB,CAAE;AAC3B;;;;;;AAMC,MACD,WAAc,EAAA;QACZ,KAAK,EAAA;AACL,QAAA,IAAI,CAACC,GAAG,GAAG,EAAEL,SAASE,OAAO;QAC7B,IAAI,CAACE,cAAc,GAAG,CAAA;QACtB,IAAI,CAACE,OAAO,GAAG,EAAC;QAChB,IAAI,CAACC,UAAU,GAAG,CAAA;QAClB,IAAI,CAACC,KAAK,GAAG;AAAC,YAAA;AAAK,SAAA;QACnB,IAAI,CAACC,UAAU,GAAG,CAAA;QAClB,IAAI,CAACC,cAAc,GAAG,CAAA;QACtB,IAAI,CAACC,UAAU,GAAG,CAAA;QAClB,IAAI,CAACC,YAAY,GAAG,EAAE;AACxB;AACA;;;;;AAKC,MACDC,KAAQ,GAAA;AACN,QAAA,MAAMC,QAAQ,IAAId,QAAAA,EAAAA;QAClBc,KAAMC,CAAAA,QAAQ,CAAC,IAAI,CAAA;QACnB,OAAOD,KAAAA;AACT;AACA;;;;;;;;MASAC,QAAAA,CAASD,KAAW,EAAE;AACpB,QAAA,IAAI,CAACE,UAAU,EAAA;AACf,QAAA,IAAI,CAACT,UAAU,GAAGO,KAAAA,CAAMP,UAAU;AAClCU,QAAAA,SAAAA,EAAAA,CAAYC,eAAe,CAACC,UAAU,CAAC,IAAI,EAAEF,SAAYC,EAAAA,CAAAA,eAAe,CAACE,UAAU,CAACN,KAAAA,CAAMO,YAAY,CAAA,CAAA;AACxG;AACA;;;AAGC,MACD,IAAIC,SAAY,GAAA;QACd,OAAO,IAAI,CAACX,UAAU;AACxB;AACA;;AAEC,MACD,IAAIY,UAAa,GAAA;QACf,OAAO,IAAI,CAAClB,GAAG;AACjB;AACA;;;;AAIC,MACD,IAAImB,SAAY,GAAA;QACd,OAAO,IAAI,CAACf,UAAU;AACxB;AACA;;;;;AAKC,MACD,IAAIgB,aAAgB,GAAA;QAClB,OAAO,IAAI,CAACf,cAAc;AAC5B;AACA;;;;;;AAMC,MACD,IAAIgB,SAAY,GAAA;QACd,OAAO,IAAI,CAACnB,UAAU;AACxB;IACA,IAAImB,SAAAA,CAAUC,GAAG,EAAE;AACjB,QAAA,MAAO,IAAI,CAACnB,KAAK,CAACoB,MAAM,GAAGD,GAAK,CAAA;AAC9B,YAAA,IAAI,CAACnB,KAAK,CAACqB,IAAI,CAAC,IAAA,CAAA;AAClB;QACA,IAAI,CAACtB,UAAU,GAAGoB,GAAAA;AACpB;AACA;;;;;;MAOUG,qBAAsBC,CAAAA,IAAiB,EAAE;QACjD,OAAO,IAAI,CAACxB,UAAU;AACxB;AACA;;;;;MAMUyB,OAAQC,CAAAA,IAAY,EAAE;AAC9B,QAAA,IAAI,IAAI,CAACzB,KAAK,CAACyB,IAAAA,CAAK,KAAK,IAAM,EAAA;YAC7B,IAAI,CAACzB,KAAK,CAACyB,IAAAA,CAAK,GAAG,IAAI,CAACC,UAAU,CAACD,IAAAA,CAAAA;AACrC;AACA,QAAA,OAAO,IAAI,CAACzB,KAAK,CAACyB,IAAK,CAAA;AACzB;AACA;;;;AAIC,MACDE,YAAuB,GAAA;QACrB,OAAOC,YAAAA;AACT;AACA;;;;MAKAC,iBAAAA,CAAkBC,KAAa,EAAW;QACxC,OAAO,KAAA;AACT;AACA;;;;AAIC,MACDC,eAA2B,GAAA;QACzB,OAAO,IAAA;AACT;AACA;;;;AAIC,MACDC,iBAA6B,GAAA;QAC3B,OAAO,IAAA;AACT;AACA,0DACAC,WAAuB,GAAA;QACrB,OAAO,KAAA;AACT;AAEA;;AAEC,MACDC,cAA0B,GAAA;QACxB,OAAO,KAAA;AACT;AACA;;AAEC,MACDC,cAA0B,GAAA;QACxB,OAAO,KAAA;AACT;AACA;;;;AAIC,MACDC,cAAuB,GAAA;AACrB,QAAA,MAAM,IAAIC,KAAM,CAAA,wBAAA,CAAA;AAClB;AACA;;;;;AAKC,MACD,IAAIxB,YAAqB,GAAA;AACvB,QAAA,OAAO,IAAI;AACb;AACA;;;;;;;;;;;;;MAcAyB,KAAAA,CAAMC,GAAgB,EAAE;AACtB,QAAA,MAAMrB,SAAY,GAAA,IAAI,CAACI,qBAAqB,CAACiB,GAAAA,CAAAA;AAC7C,QAAA,IAAK,IAAId,IAAAA,GAAO,CAAGA,EAAAA,IAAAA,GAAOP,WAAWO,IAAQ,EAAA,CAAA;AAC3C,YAAA,MAAMe,IAAO,GAAA,IAAI,CAACC,cAAc,CAACF,GAAKd,EAAAA,IAAAA,CAAAA;AACtC,YAAA,IAAIiB,KAAQ,GAAA,IAAI,CAAC5C,OAAO,CAAC0C,IAAK,CAAA;AAC9B,YAAA,IAAI,CAACE,KAAO,EAAA;AACV,gBAAA,IAAIC,YAAenD,GAAAA,QAAAA,CAASG,aAAa,CAAC6C,IAAK,CAAA;AAC/C,gBAAA,IAAII,UAAUD,YAAcC,EAAAA,OAAAA;AAC5B,gBAAA,IAAI,CAACA,OAAS,EAAA;AACZA,oBAAAA,OAAAA,GAAU,IAAI,CAACC,aAAa,CAACN,KAAKd,IAAS,CAAA,IAAA,IAAA;AAC3C,oBAAA,IAAI,CAACmB,OAAS,EAAA;wBACZE,OAAQC,CAAAA,KAAK,CAAC,uCAAyC,EAAA;AACrDC,4BAAAA,QAAAA,EAAU,IAAI,CAAC,WAAW,CAACC,IAAI;AAC/BxB,4BAAAA,IAAAA;4BACAyB,cAAgBX,EAAAA,GAAAA,CAAIY,UAAU,EAAEC,IAAQ,IAAA,IAAA;AACxCC,4BAAAA,aAAAA,EAAed,IAAIc,aAAa;AAChCC,4BAAAA,KAAAA,EAAOf,IAAIe,KAAK;AAChBC,4BAAAA,aAAAA,EAAehB,IAAIgB,aAAa;4BAChCC,MAAQ,EAAA,CAAC,CAACjB,GAAAA,CAAIkB,GAAG;4BACjBC,cAAgB,EAAA,CAAC,CAACnB,GAAAA,CAAIoB,kBAAkB;AACxCC,4BAAAA,cAAAA,EAAgBrB,IAAIqB;AACtB,yBAAA,CAAA;wBACAlB,KAAQ,GAAA;4BACNE,OAAS,EAAA,IAAA;4BACTiB,SAAW,EAAA,IAAA;4BACXC,YAAc,EAAA,EAAA;4BACdC,cAAgBxB,EAAAA,GAAAA,CAAIyB,MAAM,CAACC,oBAAoB,EAAA;AAC/CC,4BAAAA,WAAAA,EAAa,EAAC;4BACdC,GAAK,EAAA,IAAA;AACLC,4BAAAA,aAAAA,EAAe;AACjB,yBAAA;AACA,wBAAA,IAAI,CAACtE,OAAO,CAAC0C,IAAAA,CAAK,GAAGE,KAAAA;wBACrB,OAAO,KAAA;AACT;AACAE,oBAAAA,OAAAA,CAAQK,IAAI,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,CAACA,IAAI,CAAC,SAAS,EAAE,IAAI,CAACrD,cAAc,EAAI,CAAA,CAAA;oBAC3E+C,YAAe,GAAA;AAAEC,wBAAAA,OAAAA;wBAASyB,QAAU,EAAA;AAAE,qBAAA;oBACtC7E,QAASG,CAAAA,aAAa,CAAC6C,IAAAA,CAAK,GAAGG,YAAAA;AACjC;AACAA,gBAAAA,YAAAA,CAAc0B,QAAQ,EAAA;AACtB,gBAAA,MAAMR,YACJjB,OAAQ0B,CAAAA,gBAAgB,CAAClD,MAAM,GAAG,CAC9BmB,GAAAA,GAAAA,CAAIyB,MAAM,CAACO,eAAe,CAAC3B,OAAAA,CAAQ0B,gBAAgB,CAAC,EAAE,CACtD,GAAA,IAAA;gBACN5B,KAAQ,GAAA;AACNE,oBAAAA,OAAAA;AACAiB,oBAAAA,SAAAA;AACAC,oBAAAA,YAAAA,EAAcD,WAAWW,UAAgB,EAAA,IAAA,EAAA;oBACzCT,cAAgBxB,EAAAA,GAAAA,CAAIyB,MAAM,CAACC,oBAAoB,EAAA;AAC/CC,oBAAAA,WAAAA,EAAa,EAAC;oBACdC,GAAK,EAAA,IAAA;AACLC,oBAAAA,aAAAA,EAAe;AACjB,iBAAA;AACA,gBAAA,IAAI,CAACtE,OAAO,CAAC0C,IAAAA,CAAK,GAAGE,KAAAA;AACvB;YACA,IAAI,CAACA,KAAME,CAAAA,OAAO,EAAE;gBAClB,OAAO,KAAA;AACT;YACA,IAAIF,KAAAA,CAAMmB,SAAS,EAAE;AACnB,gBAAA,IAAItB,IAAIkB,GAAG,KAAKf,KAAMyB,CAAAA,GAAG,KAAK5B,GAAIkB,CAAAA,GAAG,IAAIf,KAAAA,CAAM0B,aAAa,KAAK7B,GAAAA,CAAIkB,GAAG,CAACgB,UAAU,CAAG,EAAA;oBACpF/B,KAAMyB,CAAAA,GAAG,GAAG5B,GAAAA,CAAIkB,GAAG;AACnBf,oBAAAA,KAAAA,CAAM0B,aAAa,GAAG7B,GAAIkB,CAAAA,GAAG,CAACgB,UAAU;AACxClC,oBAAAA,GAAAA,CAAIkB,GAAG,CAACiB,aAAa,CAACnC,GAAAA,EAAKG,MAAMmB,SAAS,CAAA;AAC5C;AACA,gBAAA,IAAI,CAACa,aAAa,CAAChC,KAAAA,CAAMmB,SAAS,EAAEtB,GAAKG,EAAAA,KAAAA,CAAMwB,WAAW,KAAK,IAAI,CAACjE,UAAU,EAAEwB,IAAAA,CAAAA;AAClF;AACAiB,YAAAA,KAAAA,CAAMwB,WAAW,GAAG,IAAI,CAACjE,UAAU;AACnC,YAAA,IAAI,CAAC0E,kBAAkB,CAAClD,IAAMiB,EAAAA,KAAAA,CAAMqB,cAAc,EAAExB,GAAAA,CAAAA;AACpD,YAAA,IAAI,CAACnC,YAAY,CAACqB,IAAAA,CAAK,GAAGe,IAAAA;YAC1B,IAAIE,KAAAA,CAAMmB,SAAS,EAAE;AACnB,gBAAA,MAAMe,EAAKlC,GAAAA,KAAAA,CAAMmB,SAAS,CAACW,UAAU,EAAA;gBACrC,IAAII,EAAAA,KAAOlC,KAAMoB,CAAAA,YAAY,EAAE;AAC7BpB,oBAAAA,KAAAA,CAAMoB,YAAY,GAAGc,EAAAA;AACrB,oBAAA,IAAI,CAACzE,UAAU,EAAA;AACf0E,oBAAAA,mBAAAA,CAAoBC,eAAe,CAAC,IAAI,CAACjE,YAAY,CAAA;AACvD;AACF;AACF;QACA,OAAO,IAAA;AACT;AACA;;;;;;;;;AASC,MACDkE,IAAKf,CAAAA,MAAsB,EAAEvC,IAAY,EAAE;AACzC,QAAA,MAAMe,IAAO,GAAA,IAAI,CAACpC,YAAY,CAACqB,IAAK,CAAA;AACpC,QAAA,MAAMiB,KAAQ,GAAA,IAAI,CAAC5C,OAAO,CAAC0C,IAAK,CAAA;AAChC,QAAA,IAAI,CAACE,KAAO,EAAA;AACVI,YAAAA,OAAAA,CAAQC,KAAK,CAAC,yCAAA,CAAA;YACd,OAAO,KAAA;AACT;QACA,IAAI,CAACL,KAAME,CAAAA,OAAO,EAAE;YAClB,OAAO,KAAA;AACT;QACAoB,MAAOgB,CAAAA,UAAU,CAACtC,KAAAA,CAAME,OAAO,CAAA;QAC/B,IAAIF,KAAAA,CAAMmB,SAAS,EAAE;AACnBG,YAAAA,MAAAA,CAAOiB,YAAY,CAAC,CAAGvC,EAAAA,KAAAA,CAAMmB,SAAS,CAAA;AACxC;QACAG,MAAOkB,CAAAA,eAAe,CAACxC,KAAAA,CAAMqB,cAAc,CAAA;QAC3C,OAAO,IAAA;AACT;AACA;;;;;;;;;AASC,MACD,cAAQtB,CAAeF,GAAgB,EAAEd,IAAY,EAAE;AACrD,QAAA,MAAM0D,iBAAoB5C,GAAAA,GAAAA,CAAI4C,iBAAiB,IAAI5C,IAAIqB,cAAc;AACrE,QAAA,OAAO,CAAG,EAAA,IAAI,CAACpC,OAAO,CAACC,IAAM,CAAA,CAAA,CAAC,EAAEc,GAAAA,CAAIc,aAAa,CAAC,CAAC,EAAE8B,iBAAAA,CAAkB,CAAC,EACtE5C,GAAAA,CAAI6C,YAAY,GAAG,CAAI,GAAA,CAAA,CACxB,CAAC,EAAE7C,IAAIoB,kBAAkB,GAAG,CAAI,GAAA,CAAA,CAAE,CAAC,EAAEpB,GAAAA,CAAIgB,aAAa,GAAG,IAAI,CAAG,CAAA,CAAA;AACnE;AACA;;;;;;;;;;AAUC,MACD8B,KAAKC,SAAoB,EAAE/C,GAAgB,EAAEgD,YAAAA,GAAe,CAAC,EAAE;AAC7D,QAAA,MAAMrE,SAAY,GAAA,IAAI,CAACI,qBAAqB,CAACiB,GAAAA,CAAAA;AAC7C,QAAA,IAAK,IAAId,IAAAA,GAAO,CAAGA,EAAAA,IAAAA,GAAOP,WAAWO,IAAQ,EAAA,CAAA;AAC3C,YAAA,IAAI,CAACsD,IAAI,CAACxC,GAAAA,CAAIyB,MAAM,EAAEvC,IAAAA,CAAAA;AACtB,YAAA,IAAI,CAAC+D,aAAa,CAAC/D,IAAAA,EAAM6D,WAAW/C,GAAKgD,EAAAA,YAAAA,CAAAA;AAC3C;AACF;AACA;;;;;;;;;;;;;MAcAE,YAAAA,CAAaH,SAAoB,EAAE/C,GAAgB,EAAEmD,cAA6B,EAAEC,cAAiB,GAAA,CAAC,EAAE;AACtG,QAAA,MAAMzE,SAAY,GAAA,IAAI,CAACI,qBAAqB,CAACiB,GAAAA,CAAAA;AAC7C,QAAA,IAAK,IAAId,IAAAA,GAAO,CAAGA,EAAAA,IAAAA,GAAOP,WAAWO,IAAQ,EAAA,CAAA;AAC3C,YAAA,IAAI,CAACsD,IAAI,CAACxC,GAAAA,CAAIyB,MAAM,EAAEvC,IAAAA,CAAAA;YACtB6D,SAAUG,CAAAA,YAAY,CAACC,cAAgBC,EAAAA,cAAAA,CAAAA;AACzC;AACF;AACA;;;;;;;;;MAUAjB,aAAAA,CAAcb,SAAoB,EAAEtB,GAAgB,EAAEqD,UAAmB,EAAEnE,IAAY,EAAE;AACvF,QAAA,IAAImE,UAAY,EAAA;AACd,YAAA,IAAI,CAACC,cAAc,CAAChC,SAAAA,EAAWtB,GAAKd,EAAAA,IAAAA,CAAAA;AACtC;AACF;AACA;;;;;;;;;;;AAWC,MACDqE,aAAcC,CAAAA,UAAmB,EAAEC,UAAAA,GAAa,IAAI,EAAE;AACpD,QAAA,IAAI,CAAC/F,UAAU,EAAA;AACf,QAAA,IAAI+F,cAAcD,UAAY,EAAA;AAC5B,YAAA,IAAI,CAAC7F,cAAc,EAAA;AACrB;AACA,QAAA,IAAI6F,UAAY,EAAA;YACd,IAAK,IAAIE,IAAI,CAAGA,EAAAA,CAAAA,GAAI,IAAI,CAAClG,UAAU,EAAEkG,CAAK,EAAA,CAAA;AACxC,gBAAA,IAAI,CAACjG,KAAK,CAACiG,CAAAA,CAAE,GAAG,IAAA;AAClB;AACA,YAAA,IAAI,CAAC9F,UAAU,EAAA;AACf0E,YAAAA,mBAAAA,CAAoBC,eAAe,CAAC,IAAI,CAACjE,YAAY,CAAA;AACvD;AACF;IACAL,UAAa,GAAA;AACX,QAAA,MAAM0F,SAASC,MAAOC,CAAAA,IAAI,CAAC,IAAI,CAACtG,OAAO,CAAA;QACvC,IAAIoG,MAAAA,CAAO9E,MAAM,GAAG,CAAG,EAAA;AACrB,YAAA,IAAI,CAACjB,UAAU,EAAA;AACf0E,YAAAA,mBAAAA,CAAoBC,eAAe,CAAC,IAAI,CAACjE,YAAY,CAAA;AACvD;QACA,KAAK,MAAMwF,KAAKH,MAAQ,CAAA;AACtB,YAAA,MAAMxD,KAAQ,GAAA,IAAI,CAAC5C,OAAO,CAACuG,CAAE,CAAA;AAC7B3D,YAAAA,KAAAA,EAAOmB,SAAWyC,EAAAA,OAAAA,EAAAA;AAClB,YAAA,MAAM3D,YAAenD,GAAAA,QAAAA,CAASG,aAAa,CAAC0G,CAAE,CAAA;AAC9C,YAAA,IAAI3D,OAAOE,OAAWD,IAAAA,YAAAA,EAAcC,OAAYF,KAAAA,KAAAA,CAAME,OAAO,EAAE;AAC7DD,gBAAAA,YAAAA,CAAa0B,QAAQ,EAAA;gBACrB,IAAI1B,YAAAA,CAAa0B,QAAQ,IAAI,CAAG,EAAA;oBAC9B1B,YAAaC,CAAAA,OAAO,CAAC0D,OAAO,EAAA;oBAC5B,OAAO9G,QAAAA,CAASG,aAAa,CAAC0G,CAAE,CAAA;AAClC;AACF;AACF;QACA,IAAI,CAACvG,OAAO,GAAG,EAAC;AAClB;AACA;;;;;;;MAQAyG,UAAAA,CAAW9E,IAAY,EAAE;AACvB,QAAA,OAAO+E,MAAO/E,CAAAA,IAAAA,CAAAA;AAChB;AACA;;;;;;;;MASAC,UAAAA,CAAWD,IAAY,EAAE;AACvB,QAAA,OAAO,GAAG,IAAI,CAAC,WAAW,CAACwB,IAAI,CAAC,CAAC,EAAE,IAAI,CAACsD,UAAU,CAAC9E,IAAM,CAAA,CAAA,CAAC,EAAE,IAAI,CAACgF,WAAW,EAAI,CAAA,CAAA;AAClF;AACA;;;;;;;;;;;;;;MAeAjB,aAAAA,CAAc/D,IAAY,EAAE6D,SAAoB,EAAE/C,GAAgB,EAAEgD,YAAoB,EAAE;QACxF,MAAMmB,GAAAA,GAAMnE,GAAIoE,CAAAA,YAAY,IAAI,CAAA;AAChC,QAAA,IAAIpB,eAAe,CAAG,EAAA;YACpBD,SAAUsB,CAAAA,aAAa,CAACrB,YAAcmB,EAAAA,GAAAA,CAAAA;SACjC,MAAA,IAAInE,GAAIsE,CAAAA,YAAY,EAAE;AAC3B,YAAA,MAAMC,MAASvE,GAAAA,GAAAA,CAAIsE,YAAY,CAACC,MAAM;AACtC,YAAA,IAAIA,MAAUA,IAAAA,MAAAA,CAAOxB,SAAS,KAAKA,SAAW,EAAA;;AAE5C,gBAAA,IAAK,IAAIW,CAAI,GAAA,CAAA,EAAGA,IAAIa,MAAOC,CAAAA,QAAQ,EAAEd,CAAK,EAAA,CAAA;AACxCX,oBAAAA,SAAAA,CAAUG,YAAY,CACpBqB,MAAAA,CAAOE,UAAU,EACjBF,MAAAA,CAAOG,UAAU,GAAGhB,CAAAA,GAAI,IACxBa,MAAOI,CAAAA,cAAc,IAAI,CAAIJ,GAAAA,MAAAA,CAAOI,cAAc,GAAGjB,CAAAA,GAAI,KAAK,EAAC,CAAA;AAEnE;aACK,MAAA;AACL,gBAAA,IAAIa,MAAQ,EAAA;;oBAEVvE,GAAIyB,CAAAA,MAAM,CAACiB,YAAY,CAAC,CAAA,EAAG1C,IAAIsE,YAAY,CAAChD,SAAS,CAACA,SAAS,CAAA;AACjE;AACAyB,gBAAAA,SAAAA,CAAUsB,aAAa,CAACrE,GAAAA,CAAIsE,YAAY,CAACtB,YAAY,EAAEmB,GAAAA,CAAAA;AACzD;SACK,MAAA;AACLpB,YAAAA,SAAAA,CAAUD,IAAI,CAACqB,GAAAA,CAAAA;AACjB;AACF;AACA;;;;;AAKC,MACD,SAAsB,GAAA;AACpB,QAAA,KAAK,CAACS,SAAAA,EAAAA;AACN,QAAA,IAAI,CAAC3G,UAAU,EAAA;AACjB;AACA;;;;;;;;;;;AAWC,MACD,aAAUqC,CAAcN,GAAgB,EAAEd,IAAY,EAAE;AACtD,QAAA,MAAM2F,EAAK,GAAA,IAAIC,cAAe9E,CAAAA,GAAAA,CAAIyB,MAAM,CAAA;AACxC,QAAA,OAAO,IAAI,CAACsD,cAAc,CAACF,IAAI7E,GAAKd,EAAAA,IAAAA,CAAAA;AACtC;AACA;;;;;;;;;;;AAWC,MACD,cAAyB8F,CAAAA,GAAmB,EAAEhG,IAAiB,EAAEO,KAAa,EAAc;AAC1F,QAAA,MAAM,IAAIO,KAAM,CAAA,wBAAA,CAAA;AAClB;AACA;;;;;;;;;;MAWUwD,eAAe2B,UAAqB,EAAEjG,IAAiB,EAAEO,KAAa,EAAE;AAClF;;;;;;;;;MAUU6C,mBAAmB7C,KAAa,EAAE2F,aAA6B,EAAElG,IAAiB,EAAE;AAC9F;;;;;;;AAOC,MACD,WAAwB,GAAA;QACtB,OAAO,EAAA;AACT;AACA;;;;;AAKC,MACD,IAAImG,WAAuB,GAAA;QACzB,OAAO,KAAA;AACT;AACA;;;;;AAKC,MACD,IAAIC,iBAA+C,GAAA;AACjD,QAAA,MAAM,IAAItF,KAAM,CAAA,wBAAA,CAAA;AAClB;AACF;;;;"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ProgramBuilder } from '@zephyr3d/device';
|
|
2
|
-
import { RENDER_PASS_TYPE_DEPTH, RENDER_PASS_TYPE_SHADOWMAP, RENDER_PASS_TYPE_OBJECT_COLOR, RENDER_PASS_TYPE_LIGHT, QUEUE_OPAQUE, MaterialVaryingFlags, QUEUE_TRANSPARENT } from '../values.js';
|
|
2
|
+
import { RENDER_PASS_TYPE_DEPTH, RENDER_PASS_TYPE_SHADOWMAP, RENDER_PASS_TYPE_VOXELIZE, RENDER_PASS_TYPE_OBJECT_COLOR, RENDER_PASS_TYPE_LIGHT, QUEUE_OPAQUE, MaterialVaryingFlags, QUEUE_TRANSPARENT } from '../values.js';
|
|
3
3
|
import { Material } from './material.js';
|
|
4
4
|
import { encodeNormalizedFloatToRGBA } from '../shaders/misc.js';
|
|
5
5
|
import { interleavedGradientNoise } from '../shaders/noise.js';
|
|
6
|
+
import { storeVoxelMaterial } from '../shaders/gi.js';
|
|
6
7
|
import { ShaderHelper } from './shader/helper.js';
|
|
7
8
|
import { Vector4, DRef, Vector3, Vector2, applyMixins } from '@zephyr3d/base';
|
|
8
9
|
import { RenderBundleWrapper } from '../render/renderbundle_wrapper.js';
|
|
9
|
-
import {
|
|
10
|
+
import { getEngine } from '../app/api.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Apply material mixins to a target material class.
|
|
@@ -245,6 +246,28 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
245
246
|
return offset << 2 | numComponents - 1;
|
|
246
247
|
}
|
|
247
248
|
/**
|
|
249
|
+
* Fragment-stage hook for materials that know their own ambient occlusion without a texture,
|
|
250
|
+
* such as procedural grass darkening toward the root.
|
|
251
|
+
*
|
|
252
|
+
* Lit materials multiply it into the occlusion of the indirect (environment) lighting, on top of
|
|
253
|
+
* the occlusion texture when there is one. Called inside the lighting functions of the fragment
|
|
254
|
+
* shader, where varyings are readable.
|
|
255
|
+
*
|
|
256
|
+
* @param _scope - Current fragment shader scope
|
|
257
|
+
* @returns Occlusion factor in [0, 1] (float), or null for none
|
|
258
|
+
*/ getAmbientOcclusionFactor(_scope) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Fragment-stage hook for thin two-sided surfaces lit through from behind, such as leaves and
|
|
263
|
+
* grass blades.
|
|
264
|
+
*
|
|
265
|
+
* @param _scope - Current fragment shader scope
|
|
266
|
+
* @returns Subsurface color (vec3), or null for a surface that lets no light through
|
|
267
|
+
*/ getSubsurfaceColor(_scope) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
248
271
|
* Read an encoded per-instance uniform in shader code.
|
|
249
272
|
*
|
|
250
273
|
* Encoded index packs: vector index, component offset, and component count.
|
|
@@ -278,7 +301,7 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
278
301
|
/**
|
|
279
302
|
* Create a material instance (preferred for GPU instancing).
|
|
280
303
|
*
|
|
281
|
-
* -
|
|
304
|
+
* - When instancing is unsupported, falls back to cloning.
|
|
282
305
|
* - Otherwise, returns a proxy instance that shares GPU programs and
|
|
283
306
|
* stores per-instance uniforms in a compact Float32Array.
|
|
284
307
|
*
|
|
@@ -290,8 +313,7 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
290
313
|
if (this.$isInstance) {
|
|
291
314
|
return this.coreMaterial.createInstance();
|
|
292
315
|
}
|
|
293
|
-
|
|
294
|
-
if (isWebGL1 || !this.supportInstancing()) {
|
|
316
|
+
if (!this.supportInstancing()) {
|
|
295
317
|
return this.clone();
|
|
296
318
|
}
|
|
297
319
|
const instanceUniforms = this.getInstancedUniforms();
|
|
@@ -300,7 +322,7 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
300
322
|
const that = this;
|
|
301
323
|
const coreMaterial = new DRef(that);
|
|
302
324
|
let disposed = false;
|
|
303
|
-
instance.isBatchable = ()=>true;
|
|
325
|
+
instance.isBatchable = ()=>true;
|
|
304
326
|
instance.dispose = ()=>{
|
|
305
327
|
if (!disposed) {
|
|
306
328
|
disposed = true;
|
|
@@ -581,7 +603,8 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
581
603
|
set objectColor(val) {
|
|
582
604
|
if (val !== this._objectColor) {
|
|
583
605
|
this._objectColor = val;
|
|
584
|
-
|
|
606
|
+
// Uniforms only: the look is unchanged, so voxelized material caches stay valid
|
|
607
|
+
this.optionChanged(false, false);
|
|
585
608
|
}
|
|
586
609
|
}
|
|
587
610
|
/**
|
|
@@ -651,6 +674,15 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
651
674
|
* @param ctx - Current draw context.
|
|
652
675
|
* @returns void
|
|
653
676
|
*/ updateRenderStates(pass, stateSet, ctx) {
|
|
677
|
+
if (ctx.renderPass.type === RENDER_PASS_TYPE_VOXELIZE) {
|
|
678
|
+
// Every fragment of every face stores its voxel; the colour attachment is scratch
|
|
679
|
+
stateSet.defaultBlendingState();
|
|
680
|
+
stateSet.useDepthState().enableTest(false).enableWrite(false);
|
|
681
|
+
stateSet.useRasterizerState().setCullMode('none');
|
|
682
|
+
stateSet.useColorState().setColorMask(false, false, false, false);
|
|
683
|
+
stateSet.defaultStencilState();
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
654
686
|
const isObjectColorPass = ctx.renderPass.type === RENDER_PASS_TYPE_OBJECT_COLOR;
|
|
655
687
|
const blendMode = this.getEffectiveBlendMode(pass, ctx);
|
|
656
688
|
const blending = !isObjectColorPass && (blendMode !== 'none' || ctx.lightBlending);
|
|
@@ -760,7 +792,21 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
760
792
|
*
|
|
761
793
|
* @param pass - Material pass index.
|
|
762
794
|
* @returns True if the pass is transparent; otherwise false.
|
|
763
|
-
*/
|
|
795
|
+
*/ /**
|
|
796
|
+
* Whether an opaque light pass keeps the alpha this material computed.
|
|
797
|
+
*
|
|
798
|
+
* @remarks
|
|
799
|
+
* Opaque geometry normally forces `SceneColor.a` to 1, since nothing reads it.
|
|
800
|
+
* A material that encodes data there for a later screen-space pass — as
|
|
801
|
+
* {@link SSSMaterial} does with its diffuse luminance — overrides this to opt
|
|
802
|
+
* out. Only affects opaque passes; transparent alpha handling is unchanged.
|
|
803
|
+
*
|
|
804
|
+
* @param ctx - The current draw context.
|
|
805
|
+
* @returns `true` to keep the computed alpha. Defaults to `false`.
|
|
806
|
+
*/ preservesOpaqueAlpha(ctx) {
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
isTransparentPass(pass, ctx) {
|
|
764
810
|
return this.getEffectiveBlendMode(pass, ctx) !== 'none';
|
|
765
811
|
}
|
|
766
812
|
/**
|
|
@@ -837,7 +883,14 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
837
883
|
if (!drawContext?.renderPass) {
|
|
838
884
|
return this._alphaCutoff > 0 || this.alphaToCoverage;
|
|
839
885
|
}
|
|
840
|
-
return drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT || this._alphaCutoff > 0 || this.alphaToCoverage;
|
|
886
|
+
return drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT || drawContext.renderPass.type === RENDER_PASS_TYPE_VOXELIZE || this._alphaCutoff > 0 || this.alphaToCoverage;
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* Whether the material can be voxelized for global illumination: in the voxelize
|
|
890
|
+
* pass its fragment shader must hand {@link MeshMaterial.outputFragmentColor} its
|
|
891
|
+
* albedo (and alpha) as the colour. False by default.
|
|
892
|
+
*/ supportsVoxelization() {
|
|
893
|
+
return false;
|
|
841
894
|
}
|
|
842
895
|
/**
|
|
843
896
|
* Vertex shader hook.
|
|
@@ -854,9 +907,6 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
854
907
|
scope.$inputs.zBlendWeights = pb.vec4().attrib('blendWeights');
|
|
855
908
|
ShaderHelper.prepareSkinAnimation(scope);
|
|
856
909
|
}
|
|
857
|
-
if (this.drawContext.device.type === 'webgl' && this.drawContext.materialFlags & (MaterialVaryingFlags.SKIN_ANIMATION | MaterialVaryingFlags.MORPH_ANIMATION)) {
|
|
858
|
-
scope.$inputs.zFakeVertexID = pb.float().attrib('texCoord7');
|
|
859
|
-
}
|
|
860
910
|
if (this.drawContext.materialFlags & MaterialVaryingFlags.INSTANCING) {
|
|
861
911
|
if (this.drawContext.renderPass.type === RENDER_PASS_TYPE_OBJECT_COLOR) {
|
|
862
912
|
scope.$outputs.zObjectColor = this.getInstancedUniform(scope, MeshMaterial.OBJECT_COLOR_UNIFORM);
|
|
@@ -936,12 +986,18 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
936
986
|
this.$outputs.zSSSTransmission = pb.vec4();
|
|
937
987
|
}
|
|
938
988
|
if (ctx.materialFlags & MaterialVaryingFlags.SKIN_SSS_STORE) {
|
|
939
|
-
this.$outputs.
|
|
989
|
+
this.$outputs.zPostSSS = pb.vec4();
|
|
940
990
|
}
|
|
941
991
|
if (ctx.renderPass.type === RENDER_PASS_TYPE_DEPTH && ctx.motionVectors) {
|
|
942
992
|
this.$outputs.zMotionVector = pb.vec4();
|
|
943
993
|
this.zTAAStrength = pb.float().uniform(2);
|
|
944
994
|
}
|
|
995
|
+
// Declared after the motion vector, because the declaration order is
|
|
996
|
+
// the MRT order and the prepass framebuffer appends this attachment
|
|
997
|
+
// last (render/rendergraph/forward_plus_builder.ts, DepthPrepassModule).
|
|
998
|
+
if (ctx.renderPass.type === RENDER_PASS_TYPE_DEPTH && ctx.sssProfileId) {
|
|
999
|
+
this.$outputs.zSSSProfileId = pb.vec4();
|
|
1000
|
+
}
|
|
945
1001
|
if (ctx.renderPass.type === RENDER_PASS_TYPE_OBJECT_COLOR) {
|
|
946
1002
|
this.$outputs.zDistance = pb.vec4();
|
|
947
1003
|
}
|
|
@@ -954,6 +1010,22 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
954
1010
|
return program;
|
|
955
1011
|
}
|
|
956
1012
|
/**
|
|
1013
|
+
* Per-pixel subsurface profile id this material contributes to the depth prepass.
|
|
1014
|
+
*
|
|
1015
|
+
* @remarks
|
|
1016
|
+
* `null` (the default) means "not skin", which is what every material other than
|
|
1017
|
+
* {@link SSSMaterial} wants; otherwise the normalized `SSSProfile.encodedId`.
|
|
1018
|
+
*
|
|
1019
|
+
* It lives on the prepass rather than the light pass because the transmission
|
|
1020
|
+
* thickness pass needs it and runs earlier, and because that frees the skin mask
|
|
1021
|
+
* buffer's alpha to carry the subsurface opacity.
|
|
1022
|
+
*
|
|
1023
|
+
* @param scope - Inside-function shader scope.
|
|
1024
|
+
* @returns Normalized profile id expression, or `null` for non-skin materials.
|
|
1025
|
+
*/ getDepthPassProfileId(scope) {
|
|
1026
|
+
return null;
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
957
1029
|
* Centralized final color write and per-pass output composition.
|
|
958
1030
|
*
|
|
959
1031
|
* Behavior by pass:
|
|
@@ -975,7 +1047,7 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
975
1047
|
* @param sssDiffuse - Optional diffuse-only lighting color for SSS composition.
|
|
976
1048
|
* @param sssTransmission - Optional thin-shell transmission lighting color for SSS composition.
|
|
977
1049
|
* @returns void
|
|
978
|
-
*/ outputFragmentColor(scope, worldPos, color, ssrRoughness, ssrNormal, sssProfile, sssParams, sssDiffuse, sssTransmission, sssProfileEnabled = false,
|
|
1050
|
+
*/ outputFragmentColor(scope, worldPos, color, ssrRoughness, ssrNormal, sssProfile, sssParams, sssDiffuse, sssTransmission, sssProfileEnabled = false, postSSS) {
|
|
979
1051
|
const pb = scope.$builder;
|
|
980
1052
|
const that = this;
|
|
981
1053
|
const funcName = 'Z_outputFragmentColor';
|
|
@@ -985,7 +1057,7 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
985
1057
|
pb.float('cutoff')
|
|
986
1058
|
], function() {
|
|
987
1059
|
const shadowMaskedCaster = that.useTransparentShadowCaster(that.drawContext, that.pass);
|
|
988
|
-
const shadowAlphaClip =
|
|
1060
|
+
const shadowAlphaClip = that.drawContext.renderPass.type === RENDER_PASS_TYPE_SHADOWMAP && (shadowMaskedCaster || !that.isTransparentPass(that.pass, that.drawContext));
|
|
989
1061
|
if (shadowAlphaClip) {
|
|
990
1062
|
if (!pb.getGlobalScope().Z_shadowDither4x4) {
|
|
991
1063
|
pb.getGlobalScope().Z_shadowDither4x4 = [
|
|
@@ -1018,27 +1090,7 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
1018
1090
|
this.$l.noise = this.Z_shadowDither4x4.at(pb.uint(this.ditherIndex));
|
|
1019
1091
|
this.$return(pb.lessThan(this.coverage, this.noise));
|
|
1020
1092
|
} else if (that.featureUsed(FEATURE_ALPHADITHER) && !that.isTransparentPass(that.pass, that.drawContext)) {
|
|
1021
|
-
// Interleaved gradient noise rather than the fract(sin(dot(...)))
|
|
1022
|
-
// hash it replaced. That hash feeds its dot product straight into
|
|
1023
|
-
// sin(), and at 1080p the fragCoord term alone reaches ~1e5 - past
|
|
1024
|
-
// the range where GPU sin() stays accurate - so it degraded into a
|
|
1025
|
-
// fixed hatch pattern that TAA then faithfully preserved instead of
|
|
1026
|
-
// averaging away. IGN wraps its accumulator in fract() before the
|
|
1027
|
-
// magnifying multiply, so it stays well conditioned at any
|
|
1028
|
-
// resolution, and it is what UE5 uses for exactly this job.
|
|
1029
|
-
//
|
|
1030
|
-
// The frame index is wrapped for the same reason: it is unbounded
|
|
1031
|
-
// (device.frameInfo.frameCounter), and left raw it would walk the
|
|
1032
|
-
// noise input back out of that well-conditioned range within a
|
|
1033
|
-
// minute. 64 matches the wrap the eye material already applies.
|
|
1034
1093
|
this.$l.frameId = pb.mod(pb.float(ShaderHelper.getFramestamp(this)), 64);
|
|
1035
|
-
// Decorrelate overlapping layers by depth, for the same reason the
|
|
1036
|
-
// shadow dither above does it: the noise is a function of the pixel,
|
|
1037
|
-
// so without this every fragment stacked on one texel draws the same
|
|
1038
|
-
// value and they all pass or all fail together. That collapses the
|
|
1039
|
-
// visible coverage of N layers from 1-(1-a)^N down to a - on dense
|
|
1040
|
-
// hair seen from far enough that each strand is thin, an order of
|
|
1041
|
-
// magnitude too dark. The 131.37 scale matches the shadow path.
|
|
1042
1094
|
this.$l.layerJitter = pb.fract(pb.mul(this.$builtins.fragCoord.z, 131.37));
|
|
1043
1095
|
this.$l.phase = pb.add(this.$builtins.fragCoord.xy, pb.add(pb.mul(pb.vec2(47, 17), 0.695, this.frameId), pb.mul(pb.vec2(13.7, 29.3), this.layerJitter)));
|
|
1044
1096
|
this.$l.noise = interleavedGradientNoise(this, this.phase);
|
|
@@ -1057,12 +1109,14 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
1057
1109
|
this.$l.outColor = color ? this.color : pb.vec4();
|
|
1058
1110
|
if (that.drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT) {
|
|
1059
1111
|
let output = true;
|
|
1060
|
-
if (!that.isTransparentPass(that.pass, that.drawContext) && !that.alphaToCoverage) {
|
|
1112
|
+
if (!that.isTransparentPass(that.pass, that.drawContext) && !that.alphaToCoverage && !that.preservesOpaqueAlpha(that.drawContext)) {
|
|
1061
1113
|
this.outColor.a = 1;
|
|
1062
1114
|
} else if (that.isTransparentPass(that.pass, that.drawContext)) {
|
|
1063
1115
|
const opacity = that.drawContext.materialFlags & MaterialVaryingFlags.INSTANCING ? this.$inputs.zOpacity : this.zOpacity;
|
|
1064
1116
|
this.outColor.a = pb.mul(this.outColor.a, opacity);
|
|
1065
1117
|
}
|
|
1118
|
+
// Whether outColor.rgb is premultiplied by coverage when fog is applied.
|
|
1119
|
+
let premultiplied = true;
|
|
1066
1120
|
if (that.isTransparentPass(that.pass, that.drawContext)) {
|
|
1067
1121
|
if (this.zAlphaCutoff) {
|
|
1068
1122
|
this.$if(pb.getGlobalScope()[alphaClipFuncName](this.outColor.a, this.zAlphaCutoff), function() {
|
|
@@ -1075,11 +1129,16 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
1075
1129
|
this.outColor = pb.vec4(this.outColor.rgb, 0);
|
|
1076
1130
|
} else if (!that.drawContext.oit || that.drawContext.oit.wantsPremultipliedAlpha()) {
|
|
1077
1131
|
this.outColor = pb.vec4(pb.mul(this.outColor.rgb, this.outColor.a), that.featureUsed(FEATURE_ALPHABLEND) === 'additive' ? 0 : this.outColor.a);
|
|
1132
|
+
} else {
|
|
1133
|
+
premultiplied = false;
|
|
1078
1134
|
}
|
|
1135
|
+
// Fog before handing the fragment to OIT, which otherwise consumes it unfogged.
|
|
1136
|
+
ShaderHelper.applyFog(this, this.worldPos, this.outColor, that.drawContext, premultiplied);
|
|
1079
1137
|
output = !that.drawContext.oit || !that.drawContext.oit.outputFragmentColor(this, this.outColor, that.drawContext);
|
|
1138
|
+
} else {
|
|
1139
|
+
ShaderHelper.applyFog(this, this.worldPos, this.outColor, that.drawContext);
|
|
1080
1140
|
}
|
|
1081
1141
|
if (output) {
|
|
1082
|
-
ShaderHelper.applyFog(this, this.worldPos, this.outColor, that.drawContext);
|
|
1083
1142
|
this.$outputs.zFragmentOutput = ShaderHelper.encodeColorOutput(this, this.outColor);
|
|
1084
1143
|
}
|
|
1085
1144
|
} else if (that.drawContext.renderPass.type === RENDER_PASS_TYPE_DEPTH) {
|
|
@@ -1119,6 +1178,25 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
1119
1178
|
}
|
|
1120
1179
|
}
|
|
1121
1180
|
}
|
|
1181
|
+
// Not in the motion-vector-only pass, whose framebuffer carries a single
|
|
1182
|
+
// attachment: assigning to `$outputs` declares the output implicitly, so
|
|
1183
|
+
// writing here regardless would give that pass one the framebuffer has no
|
|
1184
|
+
// target for. It is also right on its own terms - the profile id is a
|
|
1185
|
+
// prepass product and the prepass draws only opaque geometry.
|
|
1186
|
+
if (that.drawContext.sssProfileId && !depthPass.motionVectorOnly) {
|
|
1187
|
+
// Every material in the prepass writes this attachment, so non-skin ones
|
|
1188
|
+
// must write the "no profile" id: the target is shared, and a stale texel
|
|
1189
|
+
// would be read as a real profile row.
|
|
1190
|
+
const profileId = that.getDepthPassProfileId(this);
|
|
1191
|
+
this.$outputs.zSSSProfileId = pb.vec4(profileId ?? pb.float(0));
|
|
1192
|
+
}
|
|
1193
|
+
} else if (that.drawContext.renderPass.type === RENDER_PASS_TYPE_VOXELIZE) {
|
|
1194
|
+
// No alpha test: the distance field ignores masking, so rays hit the whole
|
|
1195
|
+
// card and need material everywhere. The colour handed in is the albedo (see supportsVoxelization)
|
|
1196
|
+
const emissiveMaterial = that;
|
|
1197
|
+
const emissive = emissiveMaterial.calculateEmissiveColor?.(this) ?? pb.vec3(0);
|
|
1198
|
+
storeVoxelMaterial(this, this.worldPos, color ? this.outColor.rgb : pb.vec3(0.5), emissive);
|
|
1199
|
+
this.$outputs.zFragmentOutput = pb.vec4(0);
|
|
1122
1200
|
} else if (that.drawContext.renderPass.type === RENDER_PASS_TYPE_OBJECT_COLOR) {
|
|
1123
1201
|
if (color) {
|
|
1124
1202
|
this.$if(pb.getGlobalScope()[alphaClipFuncName](this.outColor.a, this.zAlphaCutoff), function() {
|
|
@@ -1126,12 +1204,7 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
1126
1204
|
});
|
|
1127
1205
|
}
|
|
1128
1206
|
this.$outputs.zFragmentOutput = scope.$inputs.zObjectColor;
|
|
1129
|
-
|
|
1130
|
-
this.$l.linearDepth = ShaderHelper.nonLinearDepthToLinearNormalized(this, this.$builtins.fragCoord.z);
|
|
1131
|
-
this.$outputs.zDistance = encodeNormalizedFloatToRGBA(this, this.linearDepth);
|
|
1132
|
-
} else {
|
|
1133
|
-
this.$outputs.zDistance = pb.vec4(this.worldPos, pb.distance(ShaderHelper.getCameraPosition(this), this.worldPos));
|
|
1134
|
-
}
|
|
1207
|
+
this.$outputs.zDistance = pb.vec4(this.worldPos, pb.distance(ShaderHelper.getCameraPosition(this), this.worldPos));
|
|
1135
1208
|
} else {
|
|
1136
1209
|
const shadowMapParams = that.drawContext.shadowMapInfo.get(that.drawContext.renderPass.light);
|
|
1137
1210
|
// Coverage-accumulating implementations read the alpha rather than test
|
|
@@ -1190,8 +1263,8 @@ let FEATURE_TRANSPARENT_MOTION_VECTOR = 0;
|
|
|
1190
1263
|
scope.$outputs.zSSSTransmission = disableSSS ? pb.vec4(0) : sssTransmission ?? pb.vec4(0);
|
|
1191
1264
|
}
|
|
1192
1265
|
if (that.drawContext.materialFlags & MaterialVaryingFlags.SKIN_SSS_STORE) {
|
|
1193
|
-
const
|
|
1194
|
-
scope.$outputs.
|
|
1266
|
+
const disablePostSSS = that.drawContext.renderPass.type !== RENDER_PASS_TYPE_LIGHT || that.isTransparentPass(that.pass, that.drawContext) && !that.alphaToCoverage || that.needSceneColor();
|
|
1267
|
+
scope.$outputs.zPostSSS = disablePostSSS ? pb.vec4(0) : postSSS ?? pb.vec4(0);
|
|
1195
1268
|
}
|
|
1196
1269
|
}
|
|
1197
1270
|
}
|