@zephyr3d/scene 0.9.24 → 0.9.26
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/dist/animation/hair/gpu_hair_simulation.js +1090 -0
- package/dist/animation/hair/gpu_hair_simulation.js.map +1 -0
- package/dist/animation/joint_dynamics/controller.js +7 -5
- package/dist/animation/joint_dynamics/controller.js.map +1 -1
- package/dist/animation/joint_dynamics/joint_dynamics_system.js +81 -5
- package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
- package/dist/animation/morphtrack.js +3 -4
- package/dist/animation/morphtrack.js.map +1 -1
- package/dist/animation/skeleton.js +58 -24
- package/dist/animation/skeleton.js.map +1 -1
- package/dist/animation/spring/multi_chain_spring_system.js +577 -179
- package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
- package/dist/animation/spring/spring_collider.js +4 -3
- package/dist/animation/spring/spring_collider.js.map +1 -1
- package/dist/animation/spring/spring_node_pose_tracker.js +40 -0
- package/dist/animation/spring/spring_node_pose_tracker.js.map +1 -0
- package/dist/animation/spring/spring_particle.js +2 -0
- package/dist/animation/spring/spring_particle.js.map +1 -1
- package/dist/animation/spring/spring_system.js +11 -3
- package/dist/animation/spring/spring_system.js.map +1 -1
- package/dist/animation/spring_modifier.js +10 -0
- package/dist/animation/spring_modifier.js.map +1 -1
- package/dist/app/engine.js +53 -43
- package/dist/app/engine.js.map +1 -1
- package/dist/app/scriptingsystem.js +119 -6
- package/dist/app/scriptingsystem.js.map +1 -1
- package/dist/app/scriptregistry.js +3 -2
- package/dist/app/scriptregistry.js.map +1 -1
- package/dist/asset/assetmanager.js +284 -67
- package/dist/asset/assetmanager.js.map +1 -1
- package/dist/asset/loaders/zhair/zhair_format.js +288 -0
- package/dist/asset/loaders/zhair/zhair_format.js.map +1 -0
- package/dist/asset/loaders/zhair/zhair_loader.js +221 -0
- package/dist/asset/loaders/zhair/zhair_loader.js.map +1 -0
- package/dist/asset/model.js +178 -67
- package/dist/asset/model.js.map +1 -1
- package/dist/camera/camera.js +193 -21
- package/dist/camera/camera.js.map +1 -1
- package/dist/camera/perspectivecamera.js +3 -1
- package/dist/camera/perspectivecamera.js.map +1 -1
- package/dist/index.d.ts +4040 -1290
- package/dist/index.js +16 -6
- package/dist/index.js.map +1 -1
- package/dist/material/eye.js +932 -0
- package/dist/material/eye.js.map +1 -0
- package/dist/material/hair.js +917 -0
- package/dist/material/hair.js.map +1 -0
- package/dist/material/hairstrand.js +842 -0
- package/dist/material/hairstrand.js.map +1 -0
- package/dist/material/hairstrand_data.js +162 -0
- package/dist/material/hairstrand_data.js.map +1 -0
- package/dist/material/lambert.js +5 -2
- package/dist/material/lambert.js.map +1 -1
- package/dist/material/material.js +338 -300
- package/dist/material/material.js.map +1 -1
- package/dist/material/meshmaterial.js +120 -19
- package/dist/material/meshmaterial.js.map +1 -1
- package/dist/material/mixins/albedocolor.js +1 -1
- package/dist/material/mixins/albedocolor.js.map +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js +5 -3
- package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
- package/dist/material/mixins/lightmodel/lambert.js +5 -4
- package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +3 -3
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +5 -5
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js +3 -3
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
- package/dist/material/mixins/lit.js +73 -18
- package/dist/material/mixins/lit.js.map +1 -1
- package/dist/material/mixins/pbr/common.js +4 -4
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/mixins/texture.js +48 -11
- package/dist/material/mixins/texture.js.map +1 -1
- package/dist/material/mtoon.js +6 -5
- package/dist/material/mtoon.js.map +1 -1
- package/dist/material/pbrblueprint.js +146 -28
- package/dist/material/pbrblueprint.js.map +1 -1
- package/dist/material/pbrblueprint_instance.js +501 -0
- package/dist/material/pbrblueprint_instance.js.map +1 -0
- package/dist/material/pbrmr.js +15 -16
- package/dist/material/pbrmr.js.map +1 -1
- package/dist/material/shader/helper.js +766 -456
- package/dist/material/shader/helper.js.map +1 -1
- package/dist/material/shader/terrain_blend.js +55 -0
- package/dist/material/shader/terrain_blend.js.map +1 -0
- package/dist/material/skin.js +192 -32
- package/dist/material/skin.js.map +1 -1
- package/dist/material/spriteblueprint.js +16 -1
- package/dist/material/spriteblueprint.js.map +1 -1
- package/dist/material/subsurfaceprofile.js +86 -23
- package/dist/material/subsurfaceprofile.js.map +1 -1
- package/dist/material/water.js +3 -1
- package/dist/material/water.js.map +1 -1
- package/dist/posteffect/bloom.js +167 -7
- package/dist/posteffect/bloom.js.map +1 -1
- package/dist/posteffect/coloradjust.js +2 -1
- package/dist/posteffect/coloradjust.js.map +1 -1
- package/dist/posteffect/compositor.js.map +1 -1
- package/dist/posteffect/fxaa.js +2 -1
- package/dist/posteffect/fxaa.js.map +1 -1
- package/dist/posteffect/grayscale.js +3 -1
- package/dist/posteffect/grayscale.js.map +1 -1
- package/dist/posteffect/motionblur.js +4 -1
- package/dist/posteffect/motionblur.js.map +1 -1
- package/dist/posteffect/posteffect.js.map +1 -1
- package/dist/posteffect/skinsss.js +368 -69
- package/dist/posteffect/skinsss.js.map +1 -1
- package/dist/posteffect/ssgi.js +16 -9
- package/dist/posteffect/ssgi.js.map +1 -1
- package/dist/posteffect/ssr.js +3 -0
- package/dist/posteffect/ssr.js.map +1 -1
- package/dist/posteffect/sss.js +91 -34
- package/dist/posteffect/sss.js.map +1 -1
- package/dist/posteffect/taa.js.map +1 -1
- package/dist/posteffect/tonemap.js +44 -1
- package/dist/posteffect/tonemap.js.map +1 -1
- package/dist/render/abuffer_oit.js +45 -39
- package/dist/render/abuffer_oit.js.map +1 -1
- package/dist/render/cluster_light.js +4 -4
- package/dist/render/cluster_light.js.map +1 -1
- package/dist/render/cull_visitor.js +19 -0
- package/dist/render/cull_visitor.js.map +1 -1
- package/dist/render/depthpass.js +36 -2
- package/dist/render/depthpass.js.map +1 -1
- package/dist/render/drawable_mixin.js +26 -1
- package/dist/render/drawable_mixin.js.map +1 -1
- package/dist/render/dualdepthpeeling_oit.js +52 -51
- package/dist/render/dualdepthpeeling_oit.js.map +1 -1
- package/dist/render/envlight.js +1 -1
- package/dist/render/envlight.js.map +1 -1
- package/dist/render/fbm_wavegenerator.js +3 -0
- package/dist/render/fbm_wavegenerator.js.map +1 -1
- package/dist/render/gerstner_wavegenerator.js +3 -0
- package/dist/render/gerstner_wavegenerator.js.map +1 -1
- package/dist/render/globalbindgroup_allocator.js +3 -0
- package/dist/render/globalbindgroup_allocator.js.map +1 -1
- package/dist/render/oit.js +29 -0
- package/dist/render/oit.js.map +1 -0
- package/dist/render/render_queue.js +3 -0
- package/dist/render/render_queue.js.map +1 -1
- package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
- package/dist/render/rendergraph/executor.js +2 -0
- package/dist/render/rendergraph/executor.js.map +1 -1
- package/dist/render/rendergraph/forward_plus_builder.js +61 -1
- package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
- package/dist/render/rendergraph/rendergraph.js.map +1 -1
- package/dist/render/rendergraph/texture_affinity_cache.js +1 -1
- package/dist/render/rendergraph/texture_affinity_cache.js.map +1 -1
- package/dist/render/rendergraph/types.js.map +1 -1
- package/dist/render/shadow_mask_pass.js +73 -8
- package/dist/render/shadow_mask_pass.js.map +1 -1
- package/dist/render/sky.js +166 -126
- package/dist/render/sky.js.map +1 -1
- package/dist/render/weightedblended_oit.js +36 -35
- package/dist/render/weightedblended_oit.js.map +1 -1
- package/dist/scene/basesprite.js +8 -0
- package/dist/scene/basesprite.js.map +1 -1
- package/dist/scene/batchgroup.js +3 -0
- package/dist/scene/batchgroup.js.map +1 -1
- package/dist/scene/environment.js +4 -1
- package/dist/scene/environment.js.map +1 -1
- package/dist/scene/hair.js +963 -0
- package/dist/scene/hair.js.map +1 -0
- package/dist/scene/light.js +5 -1
- package/dist/scene/light.js.map +1 -1
- package/dist/scene/mesh.js +481 -47
- 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 +3 -0
- package/dist/scene/msdftext.js.map +1 -1
- package/dist/scene/msdftextsprite.js +3 -0
- package/dist/scene/msdftextsprite.js.map +1 -1
- package/dist/scene/particlesys.js +6 -0
- package/dist/scene/particlesys.js.map +1 -1
- package/dist/scene/scene.js +3 -0
- package/dist/scene/scene.js.map +1 -1
- package/dist/scene/scene_node.js +6 -1
- package/dist/scene/scene_node.js.map +1 -1
- package/dist/scene/terrain-cm/grass.js +273 -249
- package/dist/scene/terrain-cm/grass.js.map +1 -1
- package/dist/scene/terrain-cm/grassmaterial.js +3 -0
- package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
- package/dist/scene/terrain-cm/terrain-cm.js +6 -0
- package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
- package/dist/scene/terrain-cm/texture_cache.js +309 -0
- package/dist/scene/terrain-cm/texture_cache.js.map +1 -0
- package/dist/scene/water.js +6 -0
- package/dist/scene/water.js.map +1 -1
- package/dist/shaders/atmosphere.js.map +1 -1
- package/dist/shaders/diffusion.js +54 -0
- package/dist/shaders/diffusion.js.map +1 -0
- package/dist/shaders/shadow.js +33 -21
- package/dist/shaders/shadow.js.map +1 -1
- package/dist/shaders/temporal.js +71 -33
- package/dist/shaders/temporal.js.map +1 -1
- package/dist/shadow/dom.js +546 -0
- package/dist/shadow/dom.js.map +1 -0
- package/dist/shadow/pcf_opt.js +3 -5
- package/dist/shadow/pcf_opt.js.map +1 -1
- package/dist/shadow/pcf_pd.js +1 -1
- package/dist/shadow/pcf_pd.js.map +1 -1
- package/dist/shadow/receiver_bias.js +41 -0
- package/dist/shadow/receiver_bias.js.map +1 -0
- package/dist/shadow/shader.js +20 -60
- package/dist/shadow/shader.js.map +1 -1
- package/dist/shadow/shadow_impl.js +89 -0
- package/dist/shadow/shadow_impl.js.map +1 -1
- package/dist/shadow/shadow_region.js +50 -50
- package/dist/shadow/shadow_region.js.map +1 -1
- package/dist/shadow/shadowmapper.js +150 -37
- package/dist/shadow/shadowmapper.js.map +1 -1
- package/dist/shapes/shape.js +11 -2
- package/dist/shapes/shape.js.map +1 -1
- package/dist/shapes/sphere.js +50 -9
- package/dist/shapes/sphere.js.map +1 -1
- package/dist/utility/blueprint/common/constants.js +112 -2
- package/dist/utility/blueprint/common/constants.js.map +1 -1
- package/dist/utility/blueprint/material/func.js +142 -49
- package/dist/utility/blueprint/material/func.js.map +1 -1
- package/dist/utility/blueprint/material/ir.js +490 -25
- package/dist/utility/blueprint/material/ir.js.map +1 -1
- package/dist/utility/blueprint/material/texture.js +898 -4
- package/dist/utility/blueprint/material/texture.js.map +1 -1
- package/dist/utility/serialization/manager.js +431 -100
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +370 -3
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/batch.js +4 -0
- package/dist/utility/serialization/scene/batch.js.map +1 -1
- package/dist/utility/serialization/scene/camera.js +133 -1
- package/dist/utility/serialization/scene/camera.js.map +1 -1
- package/dist/utility/serialization/scene/common.js +26 -5
- package/dist/utility/serialization/scene/common.js.map +1 -1
- package/dist/utility/serialization/scene/hair.js +1141 -0
- package/dist/utility/serialization/scene/hair.js.map +1 -0
- package/dist/utility/serialization/scene/light.js +84 -4
- package/dist/utility/serialization/scene/light.js.map +1 -1
- package/dist/utility/serialization/scene/material.js +1867 -166
- package/dist/utility/serialization/scene/material.js.map +1 -1
- package/dist/utility/serialization/scene/mesh.js +231 -14
- package/dist/utility/serialization/scene/mesh.js.map +1 -1
- package/dist/utility/serialization/scene/node.js +141 -7
- package/dist/utility/serialization/scene/node.js.map +1 -1
- package/dist/utility/serialization/scene/particle.js +4 -0
- package/dist/utility/serialization/scene/particle.js.map +1 -1
- package/dist/utility/serialization/scene/primitive.js +18 -0
- package/dist/utility/serialization/scene/primitive.js.map +1 -1
- package/dist/utility/serialization/scene/sprite.js +4 -0
- package/dist/utility/serialization/scene/sprite.js.map +1 -1
- package/dist/utility/serialization/scene/terrain.js +92 -69
- package/dist/utility/serialization/scene/terrain.js.map +1 -1
- package/dist/utility/serialization/scene/text.js +4 -0
- package/dist/utility/serialization/scene/text.js.map +1 -1
- package/dist/utility/serialization/scene/water.js +4 -0
- package/dist/utility/serialization/scene/water.js.map +1 -1
- package/dist/utility/serialization/types.js.map +1 -1
- package/dist/utility/shprojector.js +96 -95
- package/dist/utility/shprojector.js.map +1 -1
- package/dist/values.js +105 -58
- package/dist/values.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hairstrand.js","sources":["../../src/material/hairstrand.ts"],"sourcesContent":["import type {\n BindGroup,\n GPUDataBuffer,\n PBFunctionScope,\n PBInsideFunctionScope,\n PBShaderExp\n} from '@zephyr3d/device';\nimport { HairMaterial } from './hair';\nimport { ShaderHelper } from './shader/helper';\nimport type { DrawContext } from '../render';\nimport type { Clonable, Nullable } from '@zephyr3d/base';\nimport { Vector4 } from '@zephyr3d/base';\nimport type { HairStrandData } from './hairstrand_data';\n\n/**\n * Hair material that expands strand control points into ribbons on the GPU.\n *\n * @remarks\n * Where {@link HairMaterial} shades ribbon geometry that something else built,\n * this material builds the ribbon itself. The vertex shader derives which strand,\n * which segment and which corner it is drawing from the vertex index alone, reads\n * the control points from a storage buffer, and emits a camera-facing quad. No\n * position, normal, tangent or texture coordinate attribute is read.\n *\n * Two things fall out of that, and both are the reason to do it:\n *\n * - **Memory.** A CPU-built ribbon mesh for a full 69k-strand hair set costs\n * around 266 MB of vertex data. The control points it is built from are about\n * 20 MB, and that is all this material needs resident.\n * - **Orientation.** A stored ribbon has a fixed plane, so there is a viewing\n * angle at which it degenerates to an edge, and a whole coplanar group of\n * strands can vanish at once. A quad expanded toward the camera never does.\n *\n * Lighting is inherited unchanged from {@link HairMaterial}, so the two paths\n * shade identically and can be compared against each other.\n *\n * Control points are read in the drawing node's local space and put through its\n * world matrix, so a groom follows the node it hangs off - a head bone, say -\n * and several nodes can share one set of strands at different transforms.\n *\n * Requires storage buffers in the vertex stage, which means WebGPU.\n * @public\n */\nexport class HairStrandMaterial extends HairMaterial implements Clonable<HairStrandMaterial> {\n /** @internal Enables per-strand distance decimation in the vertex shader. */\n private static readonly FEATURE_STRAND_LOD = this.defineFeature();\n /** @internal Samples a second point buffer to build motion vectors. */\n private static readonly FEATURE_STRAND_MOTION = this.defineFeature();\n /** @internal */\n private _strands: Nullable<HairStrandData>;\n /** @internal Control points as of the previously rendered frame. */\n private _prevPoints: Nullable<GPUDataBuffer>;\n /** @internal Ribbon segments generated per strand. */\n private _segmentsPerStrand: number;\n /** @internal Multiplier on the width stored in the strand data. */\n private _strandWidthScale: number;\n /** @internal Lower bound on ribbon width, in world units. */\n private _minStrandWidth: number;\n /** @internal Lower bound on ribbon width, in pixels. */\n private _minPixelWidth: number;\n /** @internal Floor on the fraction of strands distance decimation keeps. */\n private _minStrandLODRatio: number;\n /** @internal How far the shading normal bends across the ribbon, in [0, 1]. */\n private _strandRoundness: number;\n /** @internal Strength of the root-depth ambient occlusion, in [0, 1]. */\n private _rootOcclusion: number;\n /** @internal How far along a strand the root occlusion reaches, in (0, 1]. */\n private _rootOcclusionRange: number;\n /** @internal Scratch vector, so applying uniforms allocates nothing. */\n private readonly _strandScratch: Vector4;\n /** @internal Scratch vector for the LOD uniform. */\n private readonly _lodScratch: Vector4;\n /** @internal Scratch vector for the shape uniform. */\n private readonly _shapeScratch: Vector4;\n /**\n * Creates a GPU strand material.\n */\n constructor() {\n super();\n this._strands = null;\n this._segmentsPerStrand = 8;\n this._strandWidthScale = 1;\n this._minStrandWidth = 0;\n this._minPixelWidth = 1.4;\n this._minStrandLODRatio = 0.05;\n this._strandRoundness = 1;\n this._rootOcclusion = 0.5;\n this._rootOcclusionRange = 0.6;\n this._strandScratch = new Vector4();\n this._lodScratch = new Vector4();\n this._shapeScratch = new Vector4();\n this._prevPoints = null;\n this.useFeature(HairStrandMaterial.FEATURE_STRAND_LOD, false);\n this.useFeature(HairStrandMaterial.FEATURE_STRAND_MOTION, false);\n // A groom is dense enough that one velocity per pixel is a fair summary of\n // it, so a blended groom writes motion vectors rather than inheriting the\n // background's and ghosting as it swings.\n this.transparentMotionVector = true;\n this.transparentShadowCaster = true;\n // The quad is built facing the camera, so there is no back face to cull.\n this.cullMode = 'none';\n // Strand geometry carries no vertex attributes at all: the frame is derived\n // from the curve, so the inherited attribute paths must stay off.\n this.vertexNormal = false;\n this.vertexTangent = false;\n // The inherited default is 'binormal', which is right for a hair card: its\n // atlas runs strands along V, and V is the binormal. This material builds its\n // own frame and puts the curve direction in the tangent, so the anisotropic\n // lobes have to be told to look there. Left at the default they measure the\n // highlight against the ribbon's side vector instead - and the side vector is\n // perpendicular to the view by construction, so sin(T,H) sits near one over\n // the whole groom and the lobes degenerate into a flat sheen with no band in\n // it. That is the single largest difference between this reading as hair and\n // reading as wet plastic, so it is set here rather than left to the caller.\n this.strandDirection = 'tangent';\n }\n clone() {\n const other = new HairStrandMaterial();\n other.copyFrom(this);\n return other;\n }\n copyFrom(other: this) {\n super.copyFrom(other);\n this.strands = other.strands;\n this.segmentsPerStrand = other.segmentsPerStrand;\n this.strandWidthScale = other.strandWidthScale;\n this.minStrandWidth = other.minStrandWidth;\n this.minPixelWidth = other.minPixelWidth;\n this.strandLOD = other.strandLOD;\n this.minStrandLODRatio = other.minStrandLODRatio;\n this.strandRoundness = other.strandRoundness;\n this.rootOcclusion = other.rootOcclusion;\n this.rootOcclusionRange = other.rootOcclusionRange;\n }\n /** GPU-resident strand geometry. */\n get strands(): Nullable<HairStrandData> {\n return this._strands;\n }\n set strands(val: Nullable<HairStrandData>) {\n if (val !== this._strands) {\n this._strands = val;\n this.uniformChanged();\n }\n }\n /**\n * Ribbon segments generated per strand.\n *\n * @remarks\n * The primary quality/cost dial, and independent of the control point count:\n * the shader resamples the curve, so the same 30-point strand can be drawn with\n * 12 segments up close and 3 far away.\n */\n get segmentsPerStrand() {\n return this._segmentsPerStrand;\n }\n set segmentsPerStrand(val) {\n const v = val < 1 ? 1 : val | 0;\n if (v !== this._segmentsPerStrand) {\n this._segmentsPerStrand = v;\n this.uniformChanged();\n }\n }\n /** Multiplier applied to the width stored in the strand data. */\n get strandWidthScale() {\n return this._strandWidthScale;\n }\n set strandWidthScale(val) {\n if (val !== this._strandWidthScale) {\n this._strandWidthScale = val;\n this.uniformChanged();\n }\n }\n /** Lower bound on ribbon width in world units. */\n get minStrandWidth() {\n return this._minStrandWidth;\n }\n set minStrandWidth(val) {\n const v = val < 0 ? 0 : val;\n if (v !== this._minStrandWidth) {\n this._minStrandWidth = v;\n this.uniformChanged();\n }\n }\n /**\n * Lower bound on ribbon width in pixels.\n *\n * @remarks\n * A strand narrower than a pixel rasterises to a flickering dotted line,\n * because whether a given segment covers a sample point changes with subpixel\n * position. Clamping the quad to about a pixel and scaling alpha by how much it\n * was widened keeps total energy roughly constant, so the strand reads as\n * fainter rather than as broken. Set to 0 to disable.\n */\n get minPixelWidth() {\n return this._minPixelWidth;\n }\n set minPixelWidth(val) {\n const v = val < 0 ? 0 : val;\n if (v !== this._minPixelWidth) {\n this._minPixelWidth = v;\n this.uniformChanged();\n }\n }\n /**\n * Trades strand count for strand opacity with distance.\n *\n * @remarks\n * Past the point where a strand is thinner than a pixel, {@link minPixelWidth}\n * widens it and pays the widening back as alpha, so a distant groom is drawn as\n * tens of thousands of ribbons each contributing a few percent of a pixel. That\n * is correct on average and unstable in practice: any per-fragment stochastic\n * alpha - `alphaDither`, alpha-to-coverage - is sampling a five percent event\n * once per pixel per frame, and the variance reads as pixel-level crawl that a\n * temporal filter's short history cannot average away.\n *\n * This moves the randomness from the fragment to the strand. Each strand is\n * kept with a probability equal to the coverage it would have been drawn at and\n * the survivors are drawn at full coverage, which puts the same quantity of hair\n * on screen: `N` strands at alpha `a` and `N*a` strands at alpha 1 integrate to\n * the same image. The difference is that the draw is decided once per strand\n * from a fixed seed rather than once per fragment per frame, so the result is\n * stable across frames, and the culled strands cost no fragments at all.\n *\n * Off by default: it changes which strands are drawn, so it is opted into\n * rather than applied to existing grooms silently.\n */\n get strandLOD() {\n return this.featureUsed<boolean>(HairStrandMaterial.FEATURE_STRAND_LOD);\n }\n set strandLOD(val: boolean) {\n this.useFeature(HairStrandMaterial.FEATURE_STRAND_LOD, !!val);\n }\n /**\n * Control points as of the previously rendered frame, or null.\n *\n * @remarks\n * Set by {@link HairNode} while a simulation is running. Without it the\n * previous position is the *current* control point put through the previous\n * world matrix, which carries the node's motion but none of the strand's own -\n * so a groom swinging under a still head reports no motion at all, and a\n * temporal filter blends a history that has nothing to do with the pixel.\n * Costs four extra point fetches per vertex, hence a feature rather than an\n * always-on path: a static groom does not need it.\n */\n get prevPoints() {\n return this._prevPoints;\n }\n set prevPoints(buffer: Nullable<GPUDataBuffer>) {\n this._prevPoints = buffer ?? null;\n this.useFeature(HairStrandMaterial.FEATURE_STRAND_MOTION, !!this._prevPoints);\n }\n /** Whether motion vectors follow the control points. @internal */\n get strandMotion() {\n return this.featureUsed<boolean>(HairStrandMaterial.FEATURE_STRAND_MOTION);\n }\n /**\n * Floor on the fraction of strands {@link strandLOD} keeps.\n *\n * @remarks\n * Decimation follows coverage, and coverage falls without bound as the groom\n * recedes, so an unclamped ratio eventually culls every strand and the hair\n * disappears. This is the point past which thinning stops and the remaining\n * strands simply fade instead. Defaults to 0.05.\n */\n get minStrandLODRatio() {\n return this._minStrandLODRatio;\n }\n set minStrandLODRatio(val) {\n const v = val < 0 ? 0 : val > 1 ? 1 : val;\n if (v !== this._minStrandLODRatio) {\n this._minStrandLODRatio = v;\n this.uniformChanged();\n }\n }\n /**\n * How far the shading normal bends across the ribbon, in [0, 1].\n *\n * @remarks\n * The quad is a stand-in for a cylinder, and this is how much it is shaded like\n * one. At 1 the normal sweeps a full half turn about the curve tangent between\n * the two edges, as the visible surface of a fibre does; at 0 it stays the\n * quad's own normal and every fragment across the width shades identically,\n * which is the flat ribbon this material drew before.\n *\n * It matters more than its size suggests. A flat ribbon has one normal, so the\n * specular lobes either fire across the strand's whole width or not at all, and\n * a groom becomes a field of uniformly bright or uniformly dull tape. Bending\n * the normal puts a narrow highlight down the length of each strand and lets the\n * edges fall off, which is most of what separates strands from one another when\n * they are all the same colour.\n *\n * Values below 1 keep the highlight but widen it, which reads as a softer,\n * thicker fibre; artists after a stylised look sometimes want that.\n */\n get strandRoundness() {\n return this._strandRoundness;\n }\n set strandRoundness(val) {\n const v = val < 0 ? 0 : val > 1 ? 1 : val;\n if (v !== this._strandRoundness) {\n this._strandRoundness = v;\n this.uniformChanged();\n }\n }\n /**\n * Strength of the root-depth ambient occlusion, in [0, 1].\n *\n * @remarks\n * Environment irradiance is not attenuated by anything - a shadow map answers\n * for one light, not for the sky - so without this every strand of a groom\n * receives the full sky, and a dense hairstyle lights up as brightly in its\n * interior as on its surface. That reads as a flat silhouette with no volume,\n * and it is most obvious on pale hair, where there is little pigment to darken\n * the interior instead.\n *\n * Real occlusion would need to know how much hair sits between a fibre and the\n * sky. This approximates that by where along the strand the fragment is: roots\n * grow from the scalp, buried under everything above them, while tips are on\n * the outside. It is only an approximation - a tip tucked under a fringe is\n * treated as exposed - but it is free, it needs no texture coordinates, which\n * this material has none of, and it captures the dominant effect. Set to 0 to\n * disable.\n *\n * Applied to ambient light and the scatter term only. Direct light keeps its\n * own answer - the shadow map, or DOM's graded transmittance - and multiplying\n * this on top would count the same blockage twice.\n */\n get rootOcclusion() {\n return this._rootOcclusion;\n }\n set rootOcclusion(val) {\n const v = val < 0 ? 0 : val > 1 ? 1 : val;\n if (v !== this._rootOcclusion) {\n this._rootOcclusion = v;\n this.uniformChanged();\n }\n }\n /**\n * How far along a strand the root occlusion reaches, in (0, 1].\n *\n * @remarks\n * The fraction of the strand's length over which occlusion fades from full at\n * the root to none. Short for a groom whose strands leave the scalp quickly,\n * longer for one where they lie against each other most of their length.\n */\n get rootOcclusionRange() {\n return this._rootOcclusionRange;\n }\n set rootOcclusionRange(val) {\n const v = val < 0.001 ? 0.001 : val > 1 ? 1 : val;\n if (v !== this._rootOcclusionRange) {\n this._rootOcclusionRange = v;\n this.uniformChanged();\n }\n }\n /**\n * Vertex count needed to draw the current strand set.\n *\n * @remarks\n * Assign this to the primitive's `indexCount`. Drawing is non-indexed, with six\n * vertices per ribbon segment forming two triangles.\n */\n get vertexCount() {\n return this._strands ? this._strands.strandCount * this._segmentsPerStrand * 6 : 0;\n }\n /**\n * Albedo, with alpha scaled by how much the ribbon was widened to meet the\n * pixel floor.\n *\n * @remarks\n * Widening a sub-pixel strand to a pixel adds coverage that is not physically\n * there. Scaling alpha by the inverse keeps the strand's contribution roughly\n * constant, so distant hair thins out in opacity instead of breaking into a\n * flickering dotted line.\n */\n calculateAlbedoColor(scope: PBInsideFunctionScope, uv?: PBShaderExp) {\n const pb = scope.$builder;\n const albedo = super.calculateAlbedoColor(scope, uv);\n const coverage = scope.$inputs.zStrandCoverage;\n if (!coverage) {\n return albedo;\n }\n return pb.vec4(albedo.rgb, pb.mul(albedo.a, coverage));\n }\n protected vertexShaderImpl(scope: PBFunctionScope) {\n const pb = scope.$builder;\n this.declareStrandBindings(scope);\n scope.$l.strand = this.expandStrandVertex(scope);\n scope.$outputs.worldPos = scope.strand.worldPos;\n scope.$outputs.wNorm = scope.strand.normal;\n scope.$outputs.wTangent = scope.strand.tangent;\n // Completes the frame the inherited lighting reads. The ribbon's own side\n // vector is already perpendicular to the strand and to the shading normal.\n scope.$outputs.wBinormal = scope.strand.side;\n scope.$outputs.zStrandCoverage = scope.strand.coverage;\n // Where across the ribbon this vertex sits, as the sine of the angle round the\n // fibre it stands for: -1 and +1 at the edges, 0 down the middle. The fragment\n // stage rebuilds the cylinder normal from it. Carrying the sine rather than the\n // angle is what makes it safe to interpolate - it is linear in the offset from\n // the centre, which is exactly what the rasteriser interpolates - and the\n // roundness dial is already folded in, so no fragment-stage uniform is needed.\n scope.$outputs.zStrandRound = scope.strand.across;\n scope.$outputs.zStrandAO = scope.strand.occlusion;\n // Without this the inherited path reports zero motion for every pixel - it\n // emits motion vectors from resolveVertexPosition, which reads the vertex\n // attribute this material does not have. A temporal filter then reprojects\n // rotating hair onto the pixel it used to occupy, rejects the mismatched\n // history and falls back to the raw frame, which on dithered strands is\n // visible as noise that only settles once the camera stops.\n //\n // The previous position is the previous frame's control point put through\n // the previous frame's world matrix. The two halves are independent: the\n // matrix carries the node - a head bone, say - and the control point carries\n // whatever the solver did to the strand. With a static groom the previous\n // control point is the current one and only the matrix contributes; see\n // {@link HairStrandMaterial.prevPoints} for the other case.\n //\n // The camera-facing offset is reused rather than rebuilt against the previous\n // camera: its per-frame change is the ribbon half-width times the per-frame\n // camera rotation, hundredths of a pixel even while orbiting quickly, and\n // recomputing it would double the control point fetches for a sub-pixel\n // correction.\n if (ShaderHelper.getPrevUnjitteredViewProjectionMatrix(scope)) {\n scope.$l.zPrevWorldPos = pb.add(\n pb.mul(ShaderHelper.getPrevWorldMatrix(scope), pb.vec4(scope.strand.prevLocalCentre, 1)).xyz,\n scope.strand.offset\n );\n ShaderHelper.resolveMotionVector(scope, scope.strand.worldPos, scope.zPrevWorldPos);\n }\n ShaderHelper.setClipSpacePosition(\n scope,\n pb.mul(ShaderHelper.getViewProjectionMatrix(scope), pb.vec4(scope.strand.worldPos, 1))\n );\n }\n /**\n * Rebuilds the cylinder normal the flat quad stands for.\n *\n * @remarks\n * The quad's own normal points at the camera everywhere on it, so every fragment\n * across a strand's width shades the same and the strand reads as tape. A real\n * fibre presents a curved surface: at the centre of the visible side its normal\n * faces the viewer, and by the silhouette edges it has turned a quarter turn to\n * lie perpendicular to the view. With `a` the interpolated sine of that angle,\n * the normal is `side * a + faceNormal * cos`, and `cos = sqrt(1 - a * a)`.\n *\n * Built from the varyings rather than from the interpolated TBN on purpose. The\n * TBN may be flipped for back faces, and the sine carried alongside it would not\n * be, which would turn the fibre inside out; the varyings need no flip, because\n * a camera-facing quad's normal already points at the camera by construction.\n * @internal\n */\n /**\n * Ambient occlusion from how deep in the groom the fragment sits.\n *\n * @remarks\n * Stands in for the occlusion map the inherited path uses, which this material\n * cannot sample: it emits no texture coordinates. See\n * {@link HairStrandMaterial.rootOcclusion} for why an approximation is worth\n * having at all.\n *\n * Only the ambient hook is overridden. The inherited direct hook resolves to\n * one here - there is no occlusion map - which is correct: the geometric term\n * describes being buried in the groom, and for direct light that is exactly\n * what the shadow map already measures.\n * @internal\n */\n protected calculateHairOcclusion(scope: PBInsideFunctionScope): PBShaderExp {\n const pb = scope.$builder;\n // Evaluated at the vertex stage and interpolated, the same way the roundness\n // dial is: the expansion parameters live in a vertex-stage uniform block, and\n // the term is smooth along a strand, so nothing is gained by computing it per\n // fragment.\n const occlusion = scope.$inputs.zStrandAO;\n if (!occlusion) {\n return super.calculateHairOcclusion(scope);\n }\n return pb.mul(super.calculateHairOcclusion(scope), occlusion);\n }\n protected calculateShadingNormal(scope: PBInsideFunctionScope, normalInfo: PBShaderExp) {\n const pb = scope.$builder;\n const across = scope.$inputs.zStrandRound;\n const faceNormal = scope.$inputs.wNorm;\n const side = scope.$inputs.wBinormal;\n if (!across || !faceNormal || !side) {\n return normalInfo.normal;\n }\n const funcName = 'Z_strandShadingNormal';\n pb.func(funcName, [pb.float('across'), pb.vec3('faceNormal'), pb.vec3('side')], function () {\n // Interpolating between two unit vectors shortens them, so both are\n // renormalised before they are combined rather than trusting the varyings.\n this.$l.n = pb.normalize(this.faceNormal);\n this.$l.s = pb.normalize(this.side);\n this.$l.sinA = pb.clamp(this.across, -1, 1);\n this.$l.cosA = pb.sqrt(pb.max(pb.sub(1, pb.mul(this.sinA, this.sinA)), 0));\n this.$return(pb.normalize(pb.add(pb.mul(this.s, this.sinA), pb.mul(this.n, this.cosA))));\n });\n return pb.getGlobalScope()[funcName](across, faceNormal, side) as PBShaderExp;\n }\n applyUniformValues(bindGroup: BindGroup, ctx: DrawContext, pass: number) {\n super.applyUniformValues(bindGroup, ctx, pass);\n const strands = this._strands;\n if (!strands?.headerBuffer || !strands.pointBuffer) {\n return;\n }\n bindGroup.setBuffer('zStrandHeaders', strands.headerBuffer);\n bindGroup.setBuffer('zStrandPoints', strands.pointBuffer);\n if (this.strandMotion && this._prevPoints) {\n bindGroup.setBuffer('zStrandPrevPoints', this._prevPoints);\n }\n // The pixel floor, in the form the rendering camera calls for. Perspective:\n // half a pixel subtends tan(fovY/2)/renderHeight radians, so a per-distance\n // factor multiplied by view distance in the shader yields the world-space\n // half-width. Orthographic - which is what a directional light's shadow pass\n // uses - has no notion of subtended angle: a pixel is a constant world size,\n // read off the projection matrix, and the floor is a constant half-width.\n // Exactly one of the two is non-zero, and the shader adds them.\n let pixelFactor = 0;\n let pixelFloorWorld = 0;\n const camera = ctx.camera;\n if (this._minPixelWidth > 0 && camera && ctx.renderHeight > 0) {\n if (camera.isPerspective()) {\n const tanHalfFov = camera.getTanHalfFovy();\n if (tanHalfFov > 0) {\n pixelFactor = (this._minPixelWidth * tanHalfFov) / ctx.renderHeight;\n }\n } else {\n // m11 of an orthographic projection is 2 / frustumHeight, so a texel is\n // frustumHeight / renderHeight world units tall and the half-width floor\n // follows. Keeping shadow-pass strands at roughly a texel matches what\n // the view pass does per pixel, so caster and receiver agree on width.\n const m11 = camera.getProjectionMatrix()[5];\n if (Number.isFinite(m11) && m11 > 0) {\n pixelFloorWorld = this._minPixelWidth / m11 / ctx.renderHeight;\n }\n }\n }\n bindGroup.setValue(\n 'zStrandParams',\n this._strandScratch.setXYZW(\n this._segmentsPerStrand,\n this._strandWidthScale,\n this._minStrandWidth,\n pixelFactor\n )\n );\n bindGroup.setValue(\n 'zStrandShape',\n this._shapeScratch.setXYZW(\n this._strandRoundness,\n this._rootOcclusion,\n this._rootOcclusionRange,\n pixelFloorWorld\n )\n );\n if (this.strandLOD) {\n bindGroup.setValue('zStrandLOD', this._lodScratch.setXYZW(this._minStrandLODRatio, 0, 0, 0));\n }\n }\n /**\n * Declares the strand storage buffers and expansion parameters.\n *\n * @remarks\n * Group 2 is the material's own bind group, matching the inherited uniforms.\n * @internal\n */\n private declareStrandBindings(scope: PBFunctionScope) {\n const pb = scope.$builder;\n scope.zStrandHeaders = pb.uint[0]().storageBufferReadonly(2);\n scope.zStrandPoints = pb.float[0]().storageBufferReadonly(2);\n if (this.strandMotion) {\n scope.zStrandPrevPoints = pb.float[0]().storageBufferReadonly(2);\n }\n scope.zStrandParams = pb.vec4().uniform(2);\n scope.zStrandShape = pb.vec4().uniform(2);\n if (this.strandLOD) {\n scope.zStrandLOD = pb.vec4().uniform(2);\n }\n }\n /**\n * Reads one control point as position in xyz and width in w.\n * @internal\n */\n private fetchStrandPoint(scope: PBInsideFunctionScope, index: PBShaderExp, prev = false) {\n const pb = scope.$builder;\n const funcName = prev ? 'Z_strandPointPrev' : 'Z_strandPoint';\n pb.func(funcName, [pb.uint('index')], function () {\n if (prev) {\n // The snapshot carries positions only - three floats per point, against\n // the live buffer's four. Width does not change between frames and the\n // caller only reads xyz off the previous sample, so w is left at zero\n // rather than given a buffer to come from.\n this.$l.base = pb.mul(this.index, 3);\n this.$return(\n pb.vec4(\n this.zStrandPrevPoints.at(this.base),\n this.zStrandPrevPoints.at(pb.add(this.base, 1)),\n this.zStrandPrevPoints.at(pb.add(this.base, 2)),\n 0\n )\n );\n } else {\n this.$l.base = pb.mul(this.index, 4);\n this.$return(\n pb.vec4(\n this.zStrandPoints.at(this.base),\n this.zStrandPoints.at(pb.add(this.base, 1)),\n this.zStrandPoints.at(pb.add(this.base, 2)),\n this.zStrandPoints.at(pb.add(this.base, 3))\n )\n );\n }\n });\n return pb.getGlobalScope()[funcName](index) as PBShaderExp;\n }\n /**\n * Evaluates a strand at parameter `t`, returning position, width and tangent.\n *\n * @remarks\n * A Catmull-Rom spline through the control points, not the control polygon\n * itself, and both quantities come from the same curve: the sample is the\n * spline's value, the tangent its analytic derivative.\n *\n * The reason is the tangent. A polyline's derivative is constant within a span\n * and jumps at every control point, and the anisotropic lobes are a function of\n * that direction raised to a large power, so what is a slight kink in the\n * silhouette becomes a hard step in the highlight - each span of a strand shading\n * as its own uniformly bright or dark facet. Interpolating the position more\n * accurately is the lesser half of the change.\n *\n * The curve matters too once {@link segmentsPerStrand} is below the control\n * point count, which is the normal case: the default draws 8 segments from\n * strands carrying 30 points, so a polyline reading cuts the corner across three\n * points at a time and quietly straightens out every curl in the groom. A spline\n * sampled at the same rate keeps the bend.\n *\n * Costs four control point fetches against the three the polyline reading of\n * position and tangent needed between them.\n * @internal\n */\n private evaluateStrand(\n scope: PBInsideFunctionScope,\n firstPoint: PBShaderExp,\n pointCount: PBShaderExp,\n t: PBShaderExp,\n prev = false\n ) {\n const pb = scope.$builder;\n const that = this;\n const funcName = prev ? 'Z_strandEvaluatePrev' : 'Z_strandEvaluate';\n const StrandSample = pb.defineStruct([pb.vec4('sample'), pb.vec3('tangent')]);\n pb.func(funcName, [pb.uint('firstPoint'), pb.uint('pointCount'), pb.float('t')], function () {\n this.$l.last = pb.sub(this.pointCount, 1);\n this.$l.f = pb.mul(this.t, pb.float(this.last));\n this.$l.i1 = pb.min(pb.uint(pb.floor(this.f)), pb.sub(this.last, 1));\n this.$l.s = pb.clamp(pb.sub(this.f, pb.float(this.i1)), 0, 1);\n // The span is p1..p2, with p0 and p3 as the neighbours that set its\n // curvature. Both ends duplicate rather than wrap: max(i,1)-1 gives i-1\n // without underflowing at the root, and the tip clamps to the last point,\n // which is the usual way to end a Catmull-Rom without inventing points.\n this.$l.p0 = that.fetchStrandPoint(this, pb.add(this.firstPoint, pb.sub(pb.max(this.i1, 1), 1)), prev);\n this.$l.p1 = that.fetchStrandPoint(this, pb.add(this.firstPoint, this.i1), prev);\n this.$l.p2 = that.fetchStrandPoint(this, pb.add(this.firstPoint, pb.add(this.i1, 1)), prev);\n this.$l.p3 = that.fetchStrandPoint(\n this,\n pb.add(this.firstPoint, pb.min(pb.add(this.i1, 2), this.last)),\n prev\n );\n // Uniform Catmull-Rom in Hermite form: the span p1..p2 with the endpoint\n // tangents each spline segment inherits from its neighbours. Kept in this\n // form rather than as a collected cubic so the value and the derivative are\n // visibly the same polynomial, and so the endpoint conditions - value p1 and\n // slope m1 at s = 0, value p2 and slope m2 at s = 1 - can be read off.\n this.$l.m1 = pb.mul(pb.sub(this.p2, this.p0), 0.5);\n this.$l.m2 = pb.mul(pb.sub(this.p3, this.p1), 0.5);\n this.$l.d = pb.sub(this.p2, this.p1);\n this.$l.a2 = pb.sub(pb.mul(this.d, 3), pb.add(pb.mul(this.m1, 2), this.m2));\n this.$l.a3 = pb.add(pb.mul(this.d, -2), this.m1, this.m2);\n this.$l.s2 = pb.mul(this.s, this.s);\n this.$l.value = pb.add(\n this.p1,\n pb.mul(this.m1, this.s),\n pb.mul(this.a2, this.s2),\n pb.mul(this.a3, pb.mul(this.s2, this.s))\n );\n this.$l.deriv = pb.add(\n this.m1.xyz,\n pb.mul(this.a2.xyz, pb.mul(this.s, 2)),\n pb.mul(this.a3.xyz, pb.mul(this.s2, 3))\n );\n this.$l.out = StrandSample();\n // A spline can undershoot between control points, and a negative width\n // would flip the quad inside out, so the width is floored at zero.\n this.out.sample = pb.vec4(this.value.xyz, pb.max(this.value.w, 0));\n this.$l.len = pb.length(this.deriv);\n this.$if(pb.greaterThan(this.len, 0.000001), function () {\n this.out.tangent = pb.div(this.deriv, this.len);\n }).$else(function () {\n // Coincident control points leave the derivative undefined; fall back to\n // the chord across the span, and to an arbitrary axis if that is degenerate\n // too, so a duplicated point cannot produce a NaN frame.\n this.$l.chord = pb.sub(this.p2.xyz, this.p1.xyz);\n this.$l.chordLen = pb.length(this.chord);\n this.$if(pb.greaterThan(this.chordLen, 0.000001), function () {\n this.out.tangent = pb.div(this.chord, this.chordLen);\n }).$else(function () {\n this.out.tangent = pb.vec3(0, 1, 0);\n });\n });\n this.$return(this.out);\n });\n return pb.getGlobalScope()[funcName](firstPoint, pointCount, t) as PBShaderExp;\n }\n /**\n * Rotates a strand direction into world space and renormalises it.\n *\n * @remarks\n * The direction is transformed by the world matrix rather than by its inverse\n * transpose on purpose: this is a tangent, not a normal. The shading normal is\n * rebuilt from the tangent and the ribbon's side vector after the fact, so a\n * non-uniform scale reaches the lighting through the frame it actually bends.\n *\n * A degenerate scale can collapse the direction entirely, which would leave a\n * zero-length tangent and produce NaN once it is normalised, so the untransformed\n * direction stands in for that case.\n * @internal\n */\n private transformStrandDirection(\n scope: PBInsideFunctionScope,\n worldMatrix: PBShaderExp,\n direction: PBShaderExp\n ) {\n const pb = scope.$builder;\n const funcName = 'Z_strandDirectionToWorld';\n pb.func(funcName, [pb.mat4('worldMatrix'), pb.vec3('direction')], function () {\n this.$l.transformed = pb.mul(this.worldMatrix, pb.vec4(this.direction, 0)).xyz;\n this.$l.len = pb.length(this.transformed);\n this.$if(pb.greaterThan(this.len, 0.000001), function () {\n this.$return(pb.div(this.transformed, this.len));\n });\n this.$return(this.direction);\n });\n return pb.getGlobalScope()[funcName](worldMatrix, direction) as PBShaderExp;\n }\n /**\n * Derives this vertex's ribbon corner from the vertex index.\n *\n * @remarks\n * Six vertices per segment form two triangles over a quad whose corners are\n * indexed by (ring, side). Independent triangles rather than a strip means no\n * degenerate vertices are needed to cut between strands, and the duplicated\n * corners cost nothing because corners are computed rather than fetched.\n * @internal\n */\n private expandStrandVertex(scope: PBInsideFunctionScope) {\n const pb = scope.$builder;\n const funcName = 'Z_expandStrandVertex';\n const that = this;\n const StrandVertex = pb.defineStruct([\n pb.vec3('worldPos'),\n pb.vec3('normal'),\n pb.vec3('tangent'),\n pb.vec3('side'),\n pb.float('coverage'),\n pb.float('across'),\n pb.vec3('localCentre'),\n pb.vec3('prevLocalCentre'),\n pb.vec3('offset'),\n pb.float('occlusion')\n ]);\n pb.func(funcName, [], function () {\n this.$l.vid = pb.uint(this.$builtins.vertexIndex);\n this.$l.segCount = pb.max(pb.uint(this.zStrandParams.x), 1);\n this.$l.perStrand = pb.mul(this.segCount, 6);\n this.$l.strandIndex = pb.div(this.vid, this.perStrand);\n this.$l.local = pb.sub(this.vid, pb.mul(this.strandIndex, this.perStrand));\n this.$l.segIndex = pb.div(this.local, 6);\n this.$l.corner = pb.sub(this.local, pb.mul(this.segIndex, 6));\n // Quad corners as (ring offset, side): triangle one is 0,2,1 and triangle\n // two is 1,2,3, which keeps a consistent winding for both.\n this.$l.ringStep = pb.uint(0);\n this.$l.sideSel = pb.float(0);\n this.$if(pb.equal(this.corner, 0), function () {\n this.ringStep = pb.uint(0);\n this.sideSel = pb.float(0);\n })\n .$elseif(pb.equal(this.corner, 1), function () {\n this.ringStep = pb.uint(0);\n this.sideSel = pb.float(1);\n })\n .$elseif(pb.equal(this.corner, 2), function () {\n this.ringStep = pb.uint(1);\n this.sideSel = pb.float(0);\n })\n .$elseif(pb.equal(this.corner, 3), function () {\n this.ringStep = pb.uint(1);\n this.sideSel = pb.float(0);\n })\n .$elseif(pb.equal(this.corner, 4), function () {\n this.ringStep = pb.uint(0);\n this.sideSel = pb.float(1);\n })\n .$else(function () {\n this.ringStep = pb.uint(1);\n this.sideSel = pb.float(1);\n });\n this.$l.ring = pb.add(this.segIndex, this.ringStep);\n\n // Header: first point, point count, packed root UV, seed.\n this.$l.hBase = pb.mul(this.strandIndex, 4);\n this.$l.firstPoint = this.zStrandHeaders.at(this.hBase);\n this.$l.pointCount = pb.max(this.zStrandHeaders.at(pb.add(this.hBase, 1)), 2);\n\n this.$l.t = pb.div(pb.float(this.ring), pb.float(this.segCount));\n this.$l.curve = that.evaluateStrand(this, this.firstPoint, this.pointCount, this.t);\n // Control points are stored in the node's local space, so the frame is\n // built after the world transform rather than before it: the ribbon faces\n // the camera in world space, and a non-uniform scale must not be allowed\n // to shear that facing direction.\n this.$l.worldMatrix = ShaderHelper.getWorldMatrix(this);\n this.$l.localCentre = this.curve.sample.xyz;\n // Where this vertex's control point sat when the last frame was drawn. The\n // spline weights depend only on t and the span index, both of which are\n // fixed by the topology, so the second evaluation costs four fetches and\n // repeats arithmetic the compiler is free to share.\n this.$l.prevLocalCentre = this.localCentre;\n if (that.strandMotion) {\n this.prevLocalCentre = that.evaluateStrand(\n this,\n this.firstPoint,\n this.pointCount,\n this.t,\n true\n ).sample.xyz;\n }\n this.$l.centre = pb.mul(this.worldMatrix, pb.vec4(this.localCentre, 1)).xyz;\n this.$l.tangent = that.transformStrandDirection(this, this.worldMatrix, this.curve.tangent);\n // Width is a length in the same space as the control points, so it follows\n // the same transform. A single factor stands in for the three axis scales\n // because a strand is a fibre with no preferred cross-section direction -\n // and the mean is what keeps a uniformly scaled groom exactly proportional.\n this.$l.worldScale = pb.div(\n pb.add(\n pb.length(this.worldMatrix[0].xyz),\n pb.length(this.worldMatrix[1].xyz),\n pb.length(this.worldMatrix[2].xyz)\n ),\n 3\n );\n this.$l.halfWidth = pb.mul(this.curve.sample.w, 0.5, this.zStrandParams.y, this.worldScale);\n\n // Camera-facing side vector: perpendicular to the strand and to the view\n // ray, so the ribbon always presents its full width.\n this.$l.camPos = ShaderHelper.getCameraPosition(this);\n this.$l.toCam = pb.sub(this.camPos, this.centre);\n this.$l.viewDist = pb.length(this.toCam);\n this.$l.viewDir = pb.vec3(0, 0, 1);\n this.$if(pb.greaterThan(this.viewDist, 0.000001), function () {\n this.viewDir = pb.div(this.toCam, this.viewDist);\n });\n this.$l.side = pb.cross(this.tangent, this.viewDir);\n this.$l.sideLen = pb.length(this.side);\n this.$if(pb.greaterThan(this.sideLen, 0.000001), function () {\n this.side = pb.div(this.side, this.sideLen);\n }).$else(function () {\n // Strand pointing straight at the camera: any perpendicular will do.\n this.side = pb.normalize(pb.cross(this.tangent, pb.vec3(0.0, 1.0, 0.001)));\n });\n\n // Clamp to the world-space floor, then to the pixel floor, tracking how much\n // the quad was widened so the fragment stage can pay it back in alpha.\n this.$l.halfW = pb.max(this.halfWidth, pb.mul(this.zStrandParams.z, 0.5));\n this.$l.coverage = pb.float(1);\n // The pixel floor has two forms because a pixel has two meanings. Under a\n // perspective camera its world size grows with distance: zStrandParams.w\n // holds minPixelWidth * tan(fovY/2) / renderHeight and one multiply by view\n // distance gives the floor - folding the projection terms on the CPU avoids\n // needing a viewport uniform here. Under an orthographic camera - a\n // directional light's shadow pass - a pixel is the same world size\n // everywhere, so zStrandShape.w carries the floor as a constant. The CPU\n // fills exactly one of the two, so their sum is whichever applies; without\n // the ortho term, sub-texel strands leave no footprint in the shadow map at\n // all and the deep opacity map under-counts the very hair it exists to\n // shadow.\n this.$l.floorHalf = pb.add(pb.mul(this.zStrandParams.w, this.viewDist), this.zStrandShape.w);\n this.$if(pb.greaterThan(this.floorHalf, 0), function () {\n this.$if(pb.lessThan(this.halfW, this.floorHalf), function () {\n this.coverage = pb.div(this.halfW, this.floorHalf);\n this.halfW = this.floorHalf;\n });\n });\n\n if (that.strandLOD) {\n // Taken from the root control point rather than from this ring: both the\n // view distance and the tapered width vary along a strand, so a\n // ring-local threshold would fall between two rings on strands near the\n // cut-off and lop them off partway down their length.\n const points = this.zStrandPoints;\n this.$l.rootBase = pb.mul(this.firstPoint, 4);\n this.$l.rootLocal = pb.vec3(\n points.at(this.rootBase),\n points.at(pb.add(this.rootBase, 1)),\n points.at(pb.add(this.rootBase, 2))\n );\n // The threshold compares a width against a view distance, so the root has\n // to reach world space like everything else - otherwise a scaled groom\n // would decimate against distances measured in its own local units.\n this.$l.rootPos = pb.mul(this.worldMatrix, pb.vec4(this.rootLocal, 1)).xyz;\n this.$l.rootHalf = pb.mul(\n points.at(pb.add(this.rootBase, 3)),\n 0.5,\n this.zStrandParams.y,\n this.worldScale\n );\n this.$l.rootFloor = pb.add(\n pb.mul(this.zStrandParams.w, pb.distance(this.camPos, this.rootPos)),\n this.zStrandShape.w\n );\n this.$l.keep = pb.float(1);\n this.$if(pb.greaterThan(this.rootFloor, 0), function () {\n this.keep = pb.clamp(pb.div(this.rootHalf, this.rootFloor), this.zStrandLOD.x, 1);\n });\n // The per-strand seed the importer hashed into the header. Stored as\n // float bits in a uint buffer, hence the bitcast.\n this.$l.seed = pb.uintBitsToFloat(this.zStrandHeaders.at(pb.add(this.hBase, 3)));\n // Survivors absorb the coverage of the strands dropped alongside them,\n // which is what leaves the total amount of hair unchanged. At the ratio\n // floor this stops reaching 1 and the strands fade instead.\n this.coverage = pb.min(pb.div(this.coverage, this.keep), 1);\n this.$if(pb.greaterThanEqual(this.seed, this.keep), function () {\n // Collapse the strand onto a single point: every triangle it would\n // have produced becomes zero-area and is dropped before rasterisation,\n // so a culled strand costs no fragments at all.\n this.centre = this.rootPos;\n this.localCentre = this.rootLocal;\n this.prevLocalCentre = this.rootLocal;\n this.halfW = pb.float(0);\n });\n }\n\n this.$l.acrossSign = pb.sub(pb.mul(this.sideSel, 2), 1);\n this.$l.offset = pb.mul(this.side, this.halfW, this.acrossSign);\n this.$l.result = StrandVertex();\n this.result.worldPos = pb.add(this.centre, this.offset);\n // On a cylinder seen from outside, the visible surface points back along the\n // side vector toward the camera; crossing side with tangent gives that.\n this.result.normal = pb.normalize(pb.cross(this.side, this.tangent));\n this.result.tangent = this.tangent;\n this.result.side = this.side;\n this.result.coverage = this.coverage;\n this.result.across = pb.mul(this.acrossSign, this.zStrandShape.x);\n // Carried out so the caller can rebuild this vertex against the previous\n // frame's world matrix without re-running the expansion.\n this.result.localCentre = this.localCentre;\n this.result.prevLocalCentre = this.prevLocalCentre;\n this.result.offset = this.offset;\n // How deep in the groom this vertex sits, stood in for by where along the\n // strand it is: full occlusion at the root, fading to none once the strand\n // has climbed `range` of its length clear. Smoothstep rather than a linear\n // ramp so the transition leaves no visible edge across a dense groom.\n this.$l.aoDepth = pb.sub(1, pb.smoothStep(0, pb.max(this.zStrandShape.z, 0.001), this.t));\n this.result.occlusion = pb.clamp(pb.sub(1, pb.mul(this.aoDepth, this.zStrandShape.y)), 0, 1);\n this.$return(this.result);\n });\n return pb.getGlobalScope()[funcName]() as PBShaderExp;\n }\n}\n"],"names":["HairStrandMaterial","HairMaterial","FEATURE_STRAND_LOD","defineFeature","FEATURE_STRAND_MOTION","_strands","_segmentsPerStrand","_strandWidthScale","_minStrandWidth","_minPixelWidth","_minStrandLODRatio","_strandRoundness","_rootOcclusion","_rootOcclusionRange","_strandScratch","Vector4","_lodScratch","_shapeScratch","_prevPoints","useFeature","transparentMotionVector","transparentShadowCaster","cullMode","vertexNormal","vertexTangent","strandDirection","clone","other","copyFrom","strands","segmentsPerStrand","strandWidthScale","minStrandWidth","minPixelWidth","strandLOD","minStrandLODRatio","strandRoundness","rootOcclusion","rootOcclusionRange","val","uniformChanged","v","featureUsed","prevPoints","buffer","strandMotion","vertexCount","strandCount","calculateAlbedoColor","scope","uv","pb","$builder","albedo","coverage","$inputs","zStrandCoverage","vec4","rgb","mul","a","vertexShaderImpl","declareStrandBindings","$l","strand","expandStrandVertex","$outputs","worldPos","wNorm","normal","wTangent","tangent","wBinormal","side","zStrandRound","across","zStrandAO","occlusion","ShaderHelper","getPrevUnjitteredViewProjectionMatrix","zPrevWorldPos","add","getPrevWorldMatrix","prevLocalCentre","xyz","offset","resolveMotionVector","setClipSpacePosition","getViewProjectionMatrix","calculateHairOcclusion","calculateShadingNormal","normalInfo","faceNormal","funcName","func","float","vec3","n","normalize","s","sinA","clamp","cosA","sqrt","max","sub","$return","getGlobalScope","applyUniformValues","bindGroup","ctx","pass","headerBuffer","pointBuffer","setBuffer","pixelFactor","pixelFloorWorld","camera","renderHeight","isPerspective","tanHalfFov","getTanHalfFovy","m11","getProjectionMatrix","Number","isFinite","setValue","setXYZW","zStrandHeaders","uint","storageBufferReadonly","zStrandPoints","zStrandPrevPoints","zStrandParams","uniform","zStrandShape","zStrandLOD","fetchStrandPoint","index","prev","base","at","evaluateStrand","firstPoint","pointCount","t","that","StrandSample","defineStruct","last","f","i1","min","floor","p0","p1","p2","p3","m1","m2","d","a2","a3","s2","value","deriv","out","sample","w","len","length","$if","greaterThan","div","$else","chord","chordLen","worldMatrix","direction","mat4","transformed","StrandVertex","vid","$builtins","vertexIndex","segCount","x","perStrand","strandIndex","local","segIndex","corner","ringStep","sideSel","equal","$elseif","ring","hBase","curve","getWorldMatrix","localCentre","centre","transformStrandDirection","worldScale","halfWidth","y","camPos","getCameraPosition","toCam","viewDist","viewDir","cross","sideLen","halfW","z","floorHalf","lessThan","points","rootBase","rootLocal","rootPos","rootHalf","rootFloor","distance","keep","seed","uintBitsToFloat","greaterThanEqual","acrossSign","result","aoDepth","smoothStep"],"mappings":";;;;AAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6BO,MAAMA,kBAA2BC,SAAAA,YAAAA,CAAAA;AACtC,kFACA,OAAwBC,kBAAAA,GAAqB,IAAI,CAACC,aAAa,EAAG;AAClE,4EACA,OAAwBC,qBAAAA,GAAwB,IAAI,CAACD,aAAa,EAAG;qBAErE,QAA2C;yEAE3C,WAA6C;2DAE7C,kBAAmC;wEAEnC,iBAAkC;kEAElC,eAAgC;6DAEhC,cAA+B;iFAE/B,kBAAmC;oFAEnC,gBAAiC;8EAEjC,cAA+B;mFAE/B,mBAAoC;6EAEpC,cAAyC;yDAEzC,WAAsC;2DAEtC,aAAwC;AACxC;;AAEC,MACD,WAAc,EAAA;QACZ,KAAK,EAAA;QACL,IAAI,CAACE,QAAQ,GAAG,IAAA;QAChB,IAAI,CAACC,kBAAkB,GAAG,CAAA;QAC1B,IAAI,CAACC,iBAAiB,GAAG,CAAA;QACzB,IAAI,CAACC,eAAe,GAAG,CAAA;QACvB,IAAI,CAACC,cAAc,GAAG,GAAA;QACtB,IAAI,CAACC,kBAAkB,GAAG,IAAA;QAC1B,IAAI,CAACC,gBAAgB,GAAG,CAAA;QACxB,IAAI,CAACC,cAAc,GAAG,GAAA;QACtB,IAAI,CAACC,mBAAmB,GAAG,GAAA;QAC3B,IAAI,CAACC,cAAc,GAAG,IAAIC,OAAAA,EAAAA;QAC1B,IAAI,CAACC,WAAW,GAAG,IAAID,OAAAA,EAAAA;QACvB,IAAI,CAACE,aAAa,GAAG,IAAIF,OAAAA,EAAAA;QACzB,IAAI,CAACG,WAAW,GAAG,IAAA;AACnB,QAAA,IAAI,CAACC,UAAU,CAACnB,kBAAAA,CAAmBE,kBAAkB,EAAE,KAAA,CAAA;AACvD,QAAA,IAAI,CAACiB,UAAU,CAACnB,kBAAAA,CAAmBI,qBAAqB,EAAE,KAAA,CAAA;;;;QAI1D,IAAI,CAACgB,uBAAuB,GAAG,IAAA;QAC/B,IAAI,CAACC,uBAAuB,GAAG,IAAA;;QAE/B,IAAI,CAACC,QAAQ,GAAG,MAAA;;;QAGhB,IAAI,CAACC,YAAY,GAAG,KAAA;QACpB,IAAI,CAACC,aAAa,GAAG,KAAA;;;;;;;;;;QAUrB,IAAI,CAACC,eAAe,GAAG,SAAA;AACzB;IACAC,KAAQ,GAAA;AACN,QAAA,MAAMC,QAAQ,IAAI3B,kBAAAA,EAAAA;QAClB2B,KAAMC,CAAAA,QAAQ,CAAC,IAAI,CAAA;QACnB,OAAOD,KAAAA;AACT;AACAC,IAAAA,QAAAA,CAASD,KAAW,EAAE;AACpB,QAAA,KAAK,CAACC,QAASD,CAAAA,KAAAA,CAAAA;AACf,QAAA,IAAI,CAACE,OAAO,GAAGF,KAAAA,CAAME,OAAO;AAC5B,QAAA,IAAI,CAACC,iBAAiB,GAAGH,KAAAA,CAAMG,iBAAiB;AAChD,QAAA,IAAI,CAACC,gBAAgB,GAAGJ,KAAAA,CAAMI,gBAAgB;AAC9C,QAAA,IAAI,CAACC,cAAc,GAAGL,KAAAA,CAAMK,cAAc;AAC1C,QAAA,IAAI,CAACC,aAAa,GAAGN,KAAAA,CAAMM,aAAa;AACxC,QAAA,IAAI,CAACC,SAAS,GAAGP,KAAAA,CAAMO,SAAS;AAChC,QAAA,IAAI,CAACC,iBAAiB,GAAGR,KAAAA,CAAMQ,iBAAiB;AAChD,QAAA,IAAI,CAACC,eAAe,GAAGT,KAAAA,CAAMS,eAAe;AAC5C,QAAA,IAAI,CAACC,aAAa,GAAGV,KAAAA,CAAMU,aAAa;AACxC,QAAA,IAAI,CAACC,kBAAkB,GAAGX,KAAAA,CAAMW,kBAAkB;AACpD;yCAEA,IAAIT,OAAoC,GAAA;QACtC,OAAO,IAAI,CAACxB,QAAQ;AACtB;IACA,IAAIwB,OAAAA,CAAQU,GAA6B,EAAE;AACzC,QAAA,IAAIA,GAAQ,KAAA,IAAI,CAAClC,QAAQ,EAAE;YACzB,IAAI,CAACA,QAAQ,GAAGkC,GAAAA;AAChB,YAAA,IAAI,CAACC,cAAc,EAAA;AACrB;AACF;AACA;;;;;;;AAOC,MACD,IAAIV,iBAAoB,GAAA;QACtB,OAAO,IAAI,CAACxB,kBAAkB;AAChC;IACA,IAAIwB,iBAAAA,CAAkBS,GAAG,EAAE;AACzB,QAAA,MAAME,CAAIF,GAAAA,GAAAA,GAAM,CAAI,GAAA,CAAA,GAAIA,GAAM,GAAA,CAAA;AAC9B,QAAA,IAAIE,CAAM,KAAA,IAAI,CAACnC,kBAAkB,EAAE;YACjC,IAAI,CAACA,kBAAkB,GAAGmC,CAAAA;AAC1B,YAAA,IAAI,CAACD,cAAc,EAAA;AACrB;AACF;sEAEA,IAAIT,gBAAmB,GAAA;QACrB,OAAO,IAAI,CAACxB,iBAAiB;AAC/B;IACA,IAAIwB,gBAAAA,CAAiBQ,GAAG,EAAE;AACxB,QAAA,IAAIA,GAAQ,KAAA,IAAI,CAAChC,iBAAiB,EAAE;YAClC,IAAI,CAACA,iBAAiB,GAAGgC,GAAAA;AACzB,YAAA,IAAI,CAACC,cAAc,EAAA;AACrB;AACF;uDAEA,IAAIR,cAAiB,GAAA;QACnB,OAAO,IAAI,CAACxB,eAAe;AAC7B;IACA,IAAIwB,cAAAA,CAAeO,GAAG,EAAE;QACtB,MAAME,CAAAA,GAAIF,GAAM,GAAA,CAAA,GAAI,CAAIA,GAAAA,GAAAA;AACxB,QAAA,IAAIE,CAAM,KAAA,IAAI,CAACjC,eAAe,EAAE;YAC9B,IAAI,CAACA,eAAe,GAAGiC,CAAAA;AACvB,YAAA,IAAI,CAACD,cAAc,EAAA;AACrB;AACF;AACA;;;;;;;;;AASC,MACD,IAAIP,aAAgB,GAAA;QAClB,OAAO,IAAI,CAACxB,cAAc;AAC5B;IACA,IAAIwB,aAAAA,CAAcM,GAAG,EAAE;QACrB,MAAME,CAAAA,GAAIF,GAAM,GAAA,CAAA,GAAI,CAAIA,GAAAA,GAAAA;AACxB,QAAA,IAAIE,CAAM,KAAA,IAAI,CAAChC,cAAc,EAAE;YAC7B,IAAI,CAACA,cAAc,GAAGgC,CAAAA;AACtB,YAAA,IAAI,CAACD,cAAc,EAAA;AACrB;AACF;AACA;;;;;;;;;;;;;;;;;;;;;;AAsBC,MACD,IAAIN,SAAY,GAAA;AACd,QAAA,OAAO,IAAI,CAACQ,WAAW,CAAU1C,mBAAmBE,kBAAkB,CAAA;AACxE;IACA,IAAIgC,SAAAA,CAAUK,GAAY,EAAE;AAC1B,QAAA,IAAI,CAACpB,UAAU,CAACnB,mBAAmBE,kBAAkB,EAAE,CAAC,CAACqC,GAAAA,CAAAA;AAC3D;AACA;;;;;;;;;;;AAWC,MACD,IAAII,UAAa,GAAA;QACf,OAAO,IAAI,CAACzB,WAAW;AACzB;IACA,IAAIyB,UAAAA,CAAWC,MAA+B,EAAE;QAC9C,IAAI,CAAC1B,WAAW,GAAG0B,MAAU,IAAA,IAAA;QAC7B,IAAI,CAACzB,UAAU,CAACnB,kBAAmBI,CAAAA,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAACc,WAAW,CAAA;AAC9E;uEAEA,IAAI2B,YAAe,GAAA;AACjB,QAAA,OAAO,IAAI,CAACH,WAAW,CAAU1C,mBAAmBI,qBAAqB,CAAA;AAC3E;AACA;;;;;;;;AAQC,MACD,IAAI+B,iBAAoB,GAAA;QACtB,OAAO,IAAI,CAACzB,kBAAkB;AAChC;IACA,IAAIyB,iBAAAA,CAAkBI,GAAG,EAAE;AACzB,QAAA,MAAME,IAAIF,GAAM,GAAA,CAAA,GAAI,CAAIA,GAAAA,GAAAA,GAAM,IAAI,CAAIA,GAAAA,GAAAA;AACtC,QAAA,IAAIE,CAAM,KAAA,IAAI,CAAC/B,kBAAkB,EAAE;YACjC,IAAI,CAACA,kBAAkB,GAAG+B,CAAAA;AAC1B,YAAA,IAAI,CAACD,cAAc,EAAA;AACrB;AACF;AACA;;;;;;;;;;;;;;;;;;;AAmBC,MACD,IAAIJ,eAAkB,GAAA;QACpB,OAAO,IAAI,CAACzB,gBAAgB;AAC9B;IACA,IAAIyB,eAAAA,CAAgBG,GAAG,EAAE;AACvB,QAAA,MAAME,IAAIF,GAAM,GAAA,CAAA,GAAI,CAAIA,GAAAA,GAAAA,GAAM,IAAI,CAAIA,GAAAA,GAAAA;AACtC,QAAA,IAAIE,CAAM,KAAA,IAAI,CAAC9B,gBAAgB,EAAE;YAC/B,IAAI,CAACA,gBAAgB,GAAG8B,CAAAA;AACxB,YAAA,IAAI,CAACD,cAAc,EAAA;AACrB;AACF;AACA;;;;;;;;;;;;;;;;;;;;;;AAsBC,MACD,IAAIH,aAAgB,GAAA;QAClB,OAAO,IAAI,CAACzB,cAAc;AAC5B;IACA,IAAIyB,aAAAA,CAAcE,GAAG,EAAE;AACrB,QAAA,MAAME,IAAIF,GAAM,GAAA,CAAA,GAAI,CAAIA,GAAAA,GAAAA,GAAM,IAAI,CAAIA,GAAAA,GAAAA;AACtC,QAAA,IAAIE,CAAM,KAAA,IAAI,CAAC7B,cAAc,EAAE;YAC7B,IAAI,CAACA,cAAc,GAAG6B,CAAAA;AACtB,YAAA,IAAI,CAACD,cAAc,EAAA;AACrB;AACF;AACA;;;;;;;AAOC,MACD,IAAIF,kBAAqB,GAAA;QACvB,OAAO,IAAI,CAACzB,mBAAmB;AACjC;IACA,IAAIyB,kBAAAA,CAAmBC,GAAG,EAAE;AAC1B,QAAA,MAAME,IAAIF,GAAM,GAAA,KAAA,GAAQ,KAAQA,GAAAA,GAAAA,GAAM,IAAI,CAAIA,GAAAA,GAAAA;AAC9C,QAAA,IAAIE,CAAM,KAAA,IAAI,CAAC5B,mBAAmB,EAAE;YAClC,IAAI,CAACA,mBAAmB,GAAG4B,CAAAA;AAC3B,YAAA,IAAI,CAACD,cAAc,EAAA;AACrB;AACF;AACA;;;;;;AAMC,MACD,IAAIM,WAAc,GAAA;AAChB,QAAA,OAAO,IAAI,CAACzC,QAAQ,GAAG,IAAI,CAACA,QAAQ,CAAC0C,WAAW,GAAG,IAAI,CAACzC,kBAAkB,GAAG,CAAI,GAAA,CAAA;AACnF;AACA;;;;;;;;;AASC,MACD0C,oBAAqBC,CAAAA,KAA4B,EAAEC,EAAgB,EAAE;QACnE,MAAMC,EAAAA,GAAKF,MAAMG,QAAQ;AACzB,QAAA,MAAMC,MAAS,GAAA,KAAK,CAACL,oBAAAA,CAAqBC,KAAOC,EAAAA,EAAAA,CAAAA;AACjD,QAAA,MAAMI,QAAWL,GAAAA,KAAAA,CAAMM,OAAO,CAACC,eAAe;AAC9C,QAAA,IAAI,CAACF,QAAU,EAAA;YACb,OAAOD,MAAAA;AACT;QACA,OAAOF,EAAAA,CAAGM,IAAI,CAACJ,MAAOK,CAAAA,GAAG,EAAEP,EAAAA,CAAGQ,GAAG,CAACN,MAAOO,CAAAA,CAAC,EAAEN,QAAAA,CAAAA,CAAAA;AAC9C;AACUO,IAAAA,gBAAAA,CAAiBZ,KAAsB,EAAE;QACjD,MAAME,EAAAA,GAAKF,MAAMG,QAAQ;QACzB,IAAI,CAACU,qBAAqB,CAACb,KAAAA,CAAAA;AAC3BA,QAAAA,KAAAA,CAAMc,EAAE,CAACC,MAAM,GAAG,IAAI,CAACC,kBAAkB,CAAChB,KAAAA,CAAAA;AAC1CA,QAAAA,KAAAA,CAAMiB,QAAQ,CAACC,QAAQ,GAAGlB,KAAMe,CAAAA,MAAM,CAACG,QAAQ;AAC/ClB,QAAAA,KAAAA,CAAMiB,QAAQ,CAACE,KAAK,GAAGnB,KAAMe,CAAAA,MAAM,CAACK,MAAM;AAC1CpB,QAAAA,KAAAA,CAAMiB,QAAQ,CAACI,QAAQ,GAAGrB,KAAMe,CAAAA,MAAM,CAACO,OAAO;;;AAG9CtB,QAAAA,KAAAA,CAAMiB,QAAQ,CAACM,SAAS,GAAGvB,KAAMe,CAAAA,MAAM,CAACS,IAAI;AAC5CxB,QAAAA,KAAAA,CAAMiB,QAAQ,CAACV,eAAe,GAAGP,KAAMe,CAAAA,MAAM,CAACV,QAAQ;;;;;;;AAOtDL,QAAAA,KAAAA,CAAMiB,QAAQ,CAACQ,YAAY,GAAGzB,KAAMe,CAAAA,MAAM,CAACW,MAAM;AACjD1B,QAAAA,KAAAA,CAAMiB,QAAQ,CAACU,SAAS,GAAG3B,KAAMe,CAAAA,MAAM,CAACa,SAAS;;;;;;;;;;;;;;;;;;;;QAoBjD,IAAIC,YAAAA,CAAaC,qCAAqC,CAAC9B,KAAQ,CAAA,EAAA;AAC7DA,YAAAA,KAAAA,CAAMc,EAAE,CAACiB,aAAa,GAAG7B,EAAG8B,CAAAA,GAAG,CAC7B9B,EAAAA,CAAGQ,GAAG,CAACmB,YAAaI,CAAAA,kBAAkB,CAACjC,KAAAA,CAAAA,EAAQE,EAAGM,CAAAA,IAAI,CAACR,KAAAA,CAAMe,MAAM,CAACmB,eAAe,EAAE,CAAIC,CAAAA,CAAAA,CAAAA,GAAG,EAC5FnC,KAAAA,CAAMe,MAAM,CAACqB,MAAM,CAAA;YAErBP,YAAaQ,CAAAA,mBAAmB,CAACrC,KAAOA,EAAAA,KAAAA,CAAMe,MAAM,CAACG,QAAQ,EAAElB,KAAAA,CAAM+B,aAAa,CAAA;AACpF;AACAF,QAAAA,YAAAA,CAAaS,oBAAoB,CAC/BtC,KAAAA,EACAE,EAAGQ,CAAAA,GAAG,CAACmB,YAAaU,CAAAA,uBAAuB,CAACvC,KAAAA,CAAAA,EAAQE,GAAGM,IAAI,CAACR,MAAMe,MAAM,CAACG,QAAQ,EAAE,CAAA,CAAA,CAAA,CAAA;AAEvF;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAgCUsB,sBAAuBxC,CAAAA,KAA4B,EAAe;QAC1E,MAAME,EAAAA,GAAKF,MAAMG,QAAQ;;;;;AAKzB,QAAA,MAAMyB,SAAY5B,GAAAA,KAAAA,CAAMM,OAAO,CAACqB,SAAS;AACzC,QAAA,IAAI,CAACC,SAAW,EAAA;YACd,OAAO,KAAK,CAACY,sBAAuBxC,CAAAA,KAAAA,CAAAA;AACtC;AACA,QAAA,OAAOE,GAAGQ,GAAG,CAAC,KAAK,CAAC8B,uBAAuBxC,KAAQ4B,CAAAA,EAAAA,SAAAA,CAAAA;AACrD;IACUa,sBAAuBzC,CAAAA,KAA4B,EAAE0C,UAAuB,EAAE;QACtF,MAAMxC,EAAAA,GAAKF,MAAMG,QAAQ;AACzB,QAAA,MAAMuB,MAAS1B,GAAAA,KAAAA,CAAMM,OAAO,CAACmB,YAAY;AACzC,QAAA,MAAMkB,UAAa3C,GAAAA,KAAAA,CAAMM,OAAO,CAACa,KAAK;AACtC,QAAA,MAAMK,IAAOxB,GAAAA,KAAAA,CAAMM,OAAO,CAACiB,SAAS;AACpC,QAAA,IAAI,CAACG,MAAAA,IAAU,CAACiB,UAAAA,IAAc,CAACnB,IAAM,EAAA;AACnC,YAAA,OAAOkB,WAAWtB,MAAM;AAC1B;AACA,QAAA,MAAMwB,QAAW,GAAA,uBAAA;QACjB1C,EAAG2C,CAAAA,IAAI,CAACD,QAAU,EAAA;AAAC1C,YAAAA,EAAAA,CAAG4C,KAAK,CAAC,QAAA,CAAA;AAAW5C,YAAAA,EAAAA,CAAG6C,IAAI,CAAC,YAAA,CAAA;AAAe7C,YAAAA,EAAAA,CAAG6C,IAAI,CAAC,MAAA;SAAQ,EAAE,WAAA;;;YAG9E,IAAI,CAACjC,EAAE,CAACkC,CAAC,GAAG9C,GAAG+C,SAAS,CAAC,IAAI,CAACN,UAAU,CAAA;YACxC,IAAI,CAAC7B,EAAE,CAACoC,CAAC,GAAGhD,GAAG+C,SAAS,CAAC,IAAI,CAACzB,IAAI,CAAA;AAClC,YAAA,IAAI,CAACV,EAAE,CAACqC,IAAI,GAAGjD,EAAAA,CAAGkD,KAAK,CAAC,IAAI,CAAC1B,MAAM,EAAE,EAAI,EAAA,CAAA,CAAA;YACzC,IAAI,CAACZ,EAAE,CAACuC,IAAI,GAAGnD,GAAGoD,IAAI,CAACpD,EAAGqD,CAAAA,GAAG,CAACrD,EAAAA,CAAGsD,GAAG,CAAC,CAAA,EAAGtD,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACyC,IAAI,EAAE,IAAI,CAACA,IAAI,CAAI,CAAA,EAAA,CAAA,CAAA,CAAA;AACvE,YAAA,IAAI,CAACM,OAAO,CAACvD,EAAAA,CAAG+C,SAAS,CAAC/C,EAAG8B,CAAAA,GAAG,CAAC9B,EAAAA,CAAGQ,GAAG,CAAC,IAAI,CAACwC,CAAC,EAAE,IAAI,CAACC,IAAI,CAAA,EAAGjD,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACsC,CAAC,EAAE,IAAI,CAACK,IAAI,CAAA,CAAA,CAAA,CAAA;AACtF,SAAA,CAAA;AACA,QAAA,OAAOnD,GAAGwD,cAAc,EAAE,CAACd,QAAS,CAAA,CAAClB,QAAQiB,UAAYnB,EAAAA,IAAAA,CAAAA;AAC3D;AACAmC,IAAAA,kBAAAA,CAAmBC,SAAoB,EAAEC,GAAgB,EAAEC,IAAY,EAAE;QACvE,KAAK,CAACH,kBAAmBC,CAAAA,SAAAA,EAAWC,GAAKC,EAAAA,IAAAA,CAAAA;QACzC,MAAMlF,OAAAA,GAAU,IAAI,CAACxB,QAAQ;AAC7B,QAAA,IAAI,CAACwB,OAASmF,EAAAA,YAAAA,IAAgB,CAACnF,OAAAA,CAAQoF,WAAW,EAAE;AAClD,YAAA;AACF;AACAJ,QAAAA,SAAAA,CAAUK,SAAS,CAAC,gBAAkBrF,EAAAA,OAAAA,CAAQmF,YAAY,CAAA;AAC1DH,QAAAA,SAAAA,CAAUK,SAAS,CAAC,eAAiBrF,EAAAA,OAAAA,CAAQoF,WAAW,CAAA;AACxD,QAAA,IAAI,IAAI,CAACpE,YAAY,IAAI,IAAI,CAAC3B,WAAW,EAAE;AACzC2F,YAAAA,SAAAA,CAAUK,SAAS,CAAC,mBAAqB,EAAA,IAAI,CAAChG,WAAW,CAAA;AAC3D;;;;;;;;AAQA,QAAA,IAAIiG,WAAc,GAAA,CAAA;AAClB,QAAA,IAAIC,eAAkB,GAAA,CAAA;QACtB,MAAMC,MAAAA,GAASP,IAAIO,MAAM;QACzB,IAAI,IAAI,CAAC5G,cAAc,GAAG,KAAK4G,MAAUP,IAAAA,GAAAA,CAAIQ,YAAY,GAAG,CAAG,EAAA;YAC7D,IAAID,MAAAA,CAAOE,aAAa,EAAI,EAAA;gBAC1B,MAAMC,UAAAA,GAAaH,OAAOI,cAAc,EAAA;AACxC,gBAAA,IAAID,aAAa,CAAG,EAAA;AAClBL,oBAAAA,WAAAA,GAAc,IAAK,CAAC1G,cAAc,GAAG+G,UAAAA,GAAcV,IAAIQ,YAAY;AACrE;aACK,MAAA;;;;;AAKL,gBAAA,MAAMI,GAAML,GAAAA,MAAAA,CAAOM,mBAAmB,EAAE,CAAC,CAAE,CAAA;AAC3C,gBAAA,IAAIC,MAAOC,CAAAA,QAAQ,CAACH,GAAAA,CAAAA,IAAQA,MAAM,CAAG,EAAA;AACnCN,oBAAAA,eAAAA,GAAkB,IAAI,CAAC3G,cAAc,GAAGiH,GAAAA,GAAMZ,IAAIQ,YAAY;AAChE;AACF;AACF;QACAT,SAAUiB,CAAAA,QAAQ,CAChB,eACA,EAAA,IAAI,CAAChH,cAAc,CAACiH,OAAO,CACzB,IAAI,CAACzH,kBAAkB,EACvB,IAAI,CAACC,iBAAiB,EACtB,IAAI,CAACC,eAAe,EACpB2G,WAAAA,CAAAA,CAAAA;QAGJN,SAAUiB,CAAAA,QAAQ,CAChB,cACA,EAAA,IAAI,CAAC7G,aAAa,CAAC8G,OAAO,CACxB,IAAI,CAACpH,gBAAgB,EACrB,IAAI,CAACC,cAAc,EACnB,IAAI,CAACC,mBAAmB,EACxBuG,eAAAA,CAAAA,CAAAA;QAGJ,IAAI,IAAI,CAAClF,SAAS,EAAE;AAClB2E,YAAAA,SAAAA,CAAUiB,QAAQ,CAAC,YAAc,EAAA,IAAI,CAAC9G,WAAW,CAAC+G,OAAO,CAAC,IAAI,CAACrH,kBAAkB,EAAE,GAAG,CAAG,EAAA,CAAA,CAAA,CAAA;AAC3F;AACF;AACA;;;;;;MAOQoD,qBAAsBb,CAAAA,KAAsB,EAAE;QACpD,MAAME,EAAAA,GAAKF,MAAMG,QAAQ;QACzBH,KAAM+E,CAAAA,cAAc,GAAG7E,EAAG8E,CAAAA,IAAI,CAAC,CAAE,CAAA,EAAA,CAAGC,qBAAqB,CAAC,CAAA,CAAA;QAC1DjF,KAAMkF,CAAAA,aAAa,GAAGhF,EAAG4C,CAAAA,KAAK,CAAC,CAAE,CAAA,EAAA,CAAGmC,qBAAqB,CAAC,CAAA,CAAA;QAC1D,IAAI,IAAI,CAACrF,YAAY,EAAE;YACrBI,KAAMmF,CAAAA,iBAAiB,GAAGjF,EAAG4C,CAAAA,KAAK,CAAC,CAAE,CAAA,EAAA,CAAGmC,qBAAqB,CAAC,CAAA,CAAA;AAChE;AACAjF,QAAAA,KAAAA,CAAMoF,aAAa,GAAGlF,EAAAA,CAAGM,IAAI,EAAA,CAAG6E,OAAO,CAAC,CAAA,CAAA;AACxCrF,QAAAA,KAAAA,CAAMsF,YAAY,GAAGpF,EAAAA,CAAGM,IAAI,EAAA,CAAG6E,OAAO,CAAC,CAAA,CAAA;QACvC,IAAI,IAAI,CAACpG,SAAS,EAAE;AAClBe,YAAAA,KAAAA,CAAMuF,UAAU,GAAGrF,EAAAA,CAAGM,IAAI,EAAA,CAAG6E,OAAO,CAAC,CAAA,CAAA;AACvC;AACF;AACA;;;MAIQG,iBAAiBxF,KAA4B,EAAEyF,KAAkB,EAAEC,IAAAA,GAAO,KAAK,EAAE;QACvF,MAAMxF,EAAAA,GAAKF,MAAMG,QAAQ;QACzB,MAAMyC,QAAAA,GAAW8C,OAAO,mBAAsB,GAAA,eAAA;QAC9CxF,EAAG2C,CAAAA,IAAI,CAACD,QAAU,EAAA;AAAC1C,YAAAA,EAAAA,CAAG8E,IAAI,CAAC,OAAA;SAAS,EAAE,WAAA;AACpC,YAAA,IAAIU,IAAM,EAAA;;;;;gBAKR,IAAI,CAAC5E,EAAE,CAAC6E,IAAI,GAAGzF,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAAC+E,KAAK,EAAE,CAAA,CAAA;AAClC,gBAAA,IAAI,CAAChC,OAAO,CACVvD,GAAGM,IAAI,CACL,IAAI,CAAC2E,iBAAiB,CAACS,EAAE,CAAC,IAAI,CAACD,IAAI,GACnC,IAAI,CAACR,iBAAiB,CAACS,EAAE,CAAC1F,EAAG8B,CAAAA,GAAG,CAAC,IAAI,CAAC2D,IAAI,EAAE,CAAA,CAAA,CAAA,EAC5C,IAAI,CAACR,iBAAiB,CAACS,EAAE,CAAC1F,GAAG8B,GAAG,CAAC,IAAI,CAAC2D,IAAI,EAAE,CAC5C,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;aAGC,MAAA;gBACL,IAAI,CAAC7E,EAAE,CAAC6E,IAAI,GAAGzF,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAAC+E,KAAK,EAAE,CAAA,CAAA;gBAClC,IAAI,CAAChC,OAAO,CACVvD,EAAGM,CAAAA,IAAI,CACL,IAAI,CAAC0E,aAAa,CAACU,EAAE,CAAC,IAAI,CAACD,IAAI,CAAA,EAC/B,IAAI,CAACT,aAAa,CAACU,EAAE,CAAC1F,EAAG8B,CAAAA,GAAG,CAAC,IAAI,CAAC2D,IAAI,EAAE,CACxC,CAAA,CAAA,EAAA,IAAI,CAACT,aAAa,CAACU,EAAE,CAAC1F,EAAAA,CAAG8B,GAAG,CAAC,IAAI,CAAC2D,IAAI,EAAE,KACxC,IAAI,CAACT,aAAa,CAACU,EAAE,CAAC1F,EAAG8B,CAAAA,GAAG,CAAC,IAAI,CAAC2D,IAAI,EAAE,CAAA,CAAA,CAAA,CAAA,CAAA;AAG9C;AACF,SAAA,CAAA;AACA,QAAA,OAAOzF,EAAGwD,CAAAA,cAAc,EAAE,CAACd,SAAS,CAAC6C,KAAAA,CAAAA;AACvC;AACA;;;;;;;;;;;;;;;;;;;;;;;;AAwBC,MACD,cAAQI,CACN7F,KAA4B,EAC5B8F,UAAuB,EACvBC,UAAuB,EACvBC,CAAc,EACdN,IAAO,GAAA,KAAK,EACZ;QACA,MAAMxF,EAAAA,GAAKF,MAAMG,QAAQ;AACzB,QAAA,MAAM8F,OAAO,IAAI;QACjB,MAAMrD,QAAAA,GAAW8C,OAAO,sBAAyB,GAAA,kBAAA;QACjD,MAAMQ,YAAAA,GAAehG,EAAGiG,CAAAA,YAAY,CAAC;AAACjG,YAAAA,EAAAA,CAAGM,IAAI,CAAC,QAAA,CAAA;AAAWN,YAAAA,EAAAA,CAAG6C,IAAI,CAAC,SAAA;AAAW,SAAA,CAAA;QAC5E7C,EAAG2C,CAAAA,IAAI,CAACD,QAAU,EAAA;AAAC1C,YAAAA,EAAAA,CAAG8E,IAAI,CAAC,YAAA,CAAA;AAAe9E,YAAAA,EAAAA,CAAG8E,IAAI,CAAC,YAAA,CAAA;AAAe9E,YAAAA,EAAAA,CAAG4C,KAAK,CAAC,GAAA;SAAK,EAAE,WAAA;YAC/E,IAAI,CAAChC,EAAE,CAACsF,IAAI,GAAGlG,EAAGsD,CAAAA,GAAG,CAAC,IAAI,CAACuC,UAAU,EAAE,CAAA,CAAA;AACvC,YAAA,IAAI,CAACjF,EAAE,CAACuF,CAAC,GAAGnG,GAAGQ,GAAG,CAAC,IAAI,CAACsF,CAAC,EAAE9F,EAAAA,CAAG4C,KAAK,CAAC,IAAI,CAACsD,IAAI,CAAA,CAAA;YAC7C,IAAI,CAACtF,EAAE,CAACwF,EAAE,GAAGpG,GAAGqG,GAAG,CAACrG,EAAG8E,CAAAA,IAAI,CAAC9E,EAAAA,CAAGsG,KAAK,CAAC,IAAI,CAACH,CAAC,CAAInG,CAAAA,EAAAA,EAAAA,CAAGsD,GAAG,CAAC,IAAI,CAAC4C,IAAI,EAAE,CAAA,CAAA,CAAA;YACjE,IAAI,CAACtF,EAAE,CAACoC,CAAC,GAAGhD,EAAGkD,CAAAA,KAAK,CAAClD,EAAAA,CAAGsD,GAAG,CAAC,IAAI,CAAC6C,CAAC,EAAEnG,EAAG4C,CAAAA,KAAK,CAAC,IAAI,CAACwD,EAAE,CAAA,CAAA,EAAI,CAAG,EAAA,CAAA,CAAA;;;;;AAK3D,YAAA,IAAI,CAACxF,EAAE,CAAC2F,EAAE,GAAGR,IAAAA,CAAKT,gBAAgB,CAAC,IAAI,EAAEtF,EAAG8B,CAAAA,GAAG,CAAC,IAAI,CAAC8D,UAAU,EAAE5F,EAAAA,CAAGsD,GAAG,CAACtD,EAAGqD,CAAAA,GAAG,CAAC,IAAI,CAAC+C,EAAE,EAAE,CAAA,CAAA,EAAI,CAAKZ,CAAAA,CAAAA,EAAAA,IAAAA,CAAAA;YACjG,IAAI,CAAC5E,EAAE,CAAC4F,EAAE,GAAGT,IAAKT,CAAAA,gBAAgB,CAAC,IAAI,EAAEtF,GAAG8B,GAAG,CAAC,IAAI,CAAC8D,UAAU,EAAE,IAAI,CAACQ,EAAE,CAAGZ,EAAAA,IAAAA,CAAAA;YAC3E,IAAI,CAAC5E,EAAE,CAAC6F,EAAE,GAAGV,KAAKT,gBAAgB,CAAC,IAAI,EAAEtF,EAAG8B,CAAAA,GAAG,CAAC,IAAI,CAAC8D,UAAU,EAAE5F,EAAG8B,CAAAA,GAAG,CAAC,IAAI,CAACsE,EAAE,EAAE,CAAKZ,CAAAA,CAAAA,EAAAA,IAAAA,CAAAA;AACtF,YAAA,IAAI,CAAC5E,EAAE,CAAC8F,EAAE,GAAGX,IAAAA,CAAKT,gBAAgB,CAChC,IAAI,EACJtF,EAAG8B,CAAAA,GAAG,CAAC,IAAI,CAAC8D,UAAU,EAAE5F,EAAGqG,CAAAA,GAAG,CAACrG,EAAAA,CAAG8B,GAAG,CAAC,IAAI,CAACsE,EAAE,EAAE,CAAA,CAAA,EAAI,IAAI,CAACF,IAAI,CAC5DV,CAAAA,EAAAA,IAAAA,CAAAA;;;;;;AAOF,YAAA,IAAI,CAAC5E,EAAE,CAAC+F,EAAE,GAAG3G,EAAAA,CAAGQ,GAAG,CAACR,EAAAA,CAAGsD,GAAG,CAAC,IAAI,CAACmD,EAAE,EAAE,IAAI,CAACF,EAAE,CAAG,EAAA,GAAA,CAAA;AAC9C,YAAA,IAAI,CAAC3F,EAAE,CAACgG,EAAE,GAAG5G,EAAAA,CAAGQ,GAAG,CAACR,EAAAA,CAAGsD,GAAG,CAAC,IAAI,CAACoD,EAAE,EAAE,IAAI,CAACF,EAAE,CAAG,EAAA,GAAA,CAAA;AAC9C,YAAA,IAAI,CAAC5F,EAAE,CAACiG,CAAC,GAAG7G,EAAGsD,CAAAA,GAAG,CAAC,IAAI,CAACmD,EAAE,EAAE,IAAI,CAACD,EAAE,CAAA;AACnC,YAAA,IAAI,CAAC5F,EAAE,CAACkG,EAAE,GAAG9G,EAAAA,CAAGsD,GAAG,CAACtD,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACqG,CAAC,EAAE,CAAA,CAAA,EAAI7G,EAAG8B,CAAAA,GAAG,CAAC9B,EAAAA,CAAGQ,GAAG,CAAC,IAAI,CAACmG,EAAE,EAAE,CAAI,CAAA,EAAA,IAAI,CAACC,EAAE,CAAA,CAAA;YACzE,IAAI,CAAChG,EAAE,CAACmG,EAAE,GAAG/G,EAAG8B,CAAAA,GAAG,CAAC9B,EAAAA,CAAGQ,GAAG,CAAC,IAAI,CAACqG,CAAC,EAAE,EAAK,CAAA,EAAA,IAAI,CAACF,EAAE,EAAE,IAAI,CAACC,EAAE,CAAA;AACxD,YAAA,IAAI,CAAChG,EAAE,CAACoG,EAAE,GAAGhH,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACwC,CAAC,EAAE,IAAI,CAACA,CAAC,CAAA;YAClC,IAAI,CAACpC,EAAE,CAACqG,KAAK,GAAGjH,EAAG8B,CAAAA,GAAG,CACpB,IAAI,CAAC0E,EAAE,EACPxG,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACmG,EAAE,EAAE,IAAI,CAAC3D,CAAC,CAAA,EACtBhD,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACsG,EAAE,EAAE,IAAI,CAACE,EAAE,CAAA,EACvBhH,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACuG,EAAE,EAAE/G,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACwG,EAAE,EAAE,IAAI,CAAChE,CAAC,CAAA,CAAA,CAAA;YAExC,IAAI,CAACpC,EAAE,CAACsG,KAAK,GAAGlH,EAAG8B,CAAAA,GAAG,CACpB,IAAI,CAAC6E,EAAE,CAAC1E,GAAG,EACXjC,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACsG,EAAE,CAAC7E,GAAG,EAAEjC,GAAGQ,GAAG,CAAC,IAAI,CAACwC,CAAC,EAAE,CACnChD,CAAAA,CAAAA,EAAAA,EAAAA,CAAGQ,GAAG,CAAC,IAAI,CAACuG,EAAE,CAAC9E,GAAG,EAAEjC,EAAAA,CAAGQ,GAAG,CAAC,IAAI,CAACwG,EAAE,EAAE,CAAA,CAAA,CAAA,CAAA;AAEtC,YAAA,IAAI,CAACpG,EAAE,CAACuG,GAAG,GAAGnB,YAAAA,EAAAA;;;YAGd,IAAI,CAACmB,GAAG,CAACC,MAAM,GAAGpH,EAAGM,CAAAA,IAAI,CAAC,IAAI,CAAC2G,KAAK,CAAChF,GAAG,EAAEjC,GAAGqD,GAAG,CAAC,IAAI,CAAC4D,KAAK,CAACI,CAAC,EAAE,CAAA,CAAA,CAAA;YAC/D,IAAI,CAACzG,EAAE,CAAC0G,GAAG,GAAGtH,GAAGuH,MAAM,CAAC,IAAI,CAACL,KAAK,CAAA;YAClC,IAAI,CAACM,GAAG,CAACxH,EAAGyH,CAAAA,WAAW,CAAC,IAAI,CAACH,GAAG,EAAE,QAAW,CAAA,EAAA,WAAA;AAC3C,gBAAA,IAAI,CAACH,GAAG,CAAC/F,OAAO,GAAGpB,EAAG0H,CAAAA,GAAG,CAAC,IAAI,CAACR,KAAK,EAAE,IAAI,CAACI,GAAG,CAAA;AAChD,aAAA,CAAA,CAAGK,KAAK,CAAC,WAAA;;;;AAIP,gBAAA,IAAI,CAAC/G,EAAE,CAACgH,KAAK,GAAG5H,EAAAA,CAAGsD,GAAG,CAAC,IAAI,CAACmD,EAAE,CAACxE,GAAG,EAAE,IAAI,CAACuE,EAAE,CAACvE,GAAG,CAAA;gBAC/C,IAAI,CAACrB,EAAE,CAACiH,QAAQ,GAAG7H,GAAGuH,MAAM,CAAC,IAAI,CAACK,KAAK,CAAA;gBACvC,IAAI,CAACJ,GAAG,CAACxH,EAAGyH,CAAAA,WAAW,CAAC,IAAI,CAACI,QAAQ,EAAE,QAAW,CAAA,EAAA,WAAA;AAChD,oBAAA,IAAI,CAACV,GAAG,CAAC/F,OAAO,GAAGpB,EAAG0H,CAAAA,GAAG,CAAC,IAAI,CAACE,KAAK,EAAE,IAAI,CAACC,QAAQ,CAAA;AACrD,iBAAA,CAAA,CAAGF,KAAK,CAAC,WAAA;oBACP,IAAI,CAACR,GAAG,CAAC/F,OAAO,GAAGpB,EAAG6C,CAAAA,IAAI,CAAC,CAAA,EAAG,CAAG,EAAA,CAAA,CAAA;AACnC,iBAAA,CAAA;AACF,aAAA,CAAA;AACA,YAAA,IAAI,CAACU,OAAO,CAAC,IAAI,CAAC4D,GAAG,CAAA;AACvB,SAAA,CAAA;AACA,QAAA,OAAOnH,GAAGwD,cAAc,EAAE,CAACd,QAAS,CAAA,CAACkD,YAAYC,UAAYC,EAAAA,CAAAA,CAAAA;AAC/D;AACA;;;;;;;;;;;;;AAaC,MACD,wBACEhG,CAAAA,KAA4B,EAC5BgI,WAAwB,EACxBC,SAAsB,EACtB;QACA,MAAM/H,EAAAA,GAAKF,MAAMG,QAAQ;AACzB,QAAA,MAAMyC,QAAW,GAAA,0BAAA;QACjB1C,EAAG2C,CAAAA,IAAI,CAACD,QAAU,EAAA;AAAC1C,YAAAA,EAAAA,CAAGgI,IAAI,CAAC,aAAA,CAAA;AAAgBhI,YAAAA,EAAAA,CAAG6C,IAAI,CAAC,WAAA;SAAa,EAAE,WAAA;YAChE,IAAI,CAACjC,EAAE,CAACqH,WAAW,GAAGjI,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACsH,WAAW,EAAE9H,EAAAA,CAAGM,IAAI,CAAC,IAAI,CAACyH,SAAS,EAAE,IAAI9F,GAAG;YAC9E,IAAI,CAACrB,EAAE,CAAC0G,GAAG,GAAGtH,GAAGuH,MAAM,CAAC,IAAI,CAACU,WAAW,CAAA;YACxC,IAAI,CAACT,GAAG,CAACxH,EAAGyH,CAAAA,WAAW,CAAC,IAAI,CAACH,GAAG,EAAE,QAAW,CAAA,EAAA,WAAA;AAC3C,gBAAA,IAAI,CAAC/D,OAAO,CAACvD,EAAAA,CAAG0H,GAAG,CAAC,IAAI,CAACO,WAAW,EAAE,IAAI,CAACX,GAAG,CAAA,CAAA;AAChD,aAAA,CAAA;AACA,YAAA,IAAI,CAAC/D,OAAO,CAAC,IAAI,CAACwE,SAAS,CAAA;AAC7B,SAAA,CAAA;AACA,QAAA,OAAO/H,GAAGwD,cAAc,EAAE,CAACd,QAAAA,CAAS,CAACoF,WAAaC,EAAAA,SAAAA,CAAAA;AACpD;AACA;;;;;;;;;MAUQjH,kBAAmBhB,CAAAA,KAA4B,EAAE;QACvD,MAAME,EAAAA,GAAKF,MAAMG,QAAQ;AACzB,QAAA,MAAMyC,QAAW,GAAA,sBAAA;AACjB,QAAA,MAAMqD,OAAO,IAAI;QACjB,MAAMmC,YAAAA,GAAelI,EAAGiG,CAAAA,YAAY,CAAC;AACnCjG,YAAAA,EAAAA,CAAG6C,IAAI,CAAC,UAAA,CAAA;AACR7C,YAAAA,EAAAA,CAAG6C,IAAI,CAAC,QAAA,CAAA;AACR7C,YAAAA,EAAAA,CAAG6C,IAAI,CAAC,SAAA,CAAA;AACR7C,YAAAA,EAAAA,CAAG6C,IAAI,CAAC,MAAA,CAAA;AACR7C,YAAAA,EAAAA,CAAG4C,KAAK,CAAC,UAAA,CAAA;AACT5C,YAAAA,EAAAA,CAAG4C,KAAK,CAAC,QAAA,CAAA;AACT5C,YAAAA,EAAAA,CAAG6C,IAAI,CAAC,aAAA,CAAA;AACR7C,YAAAA,EAAAA,CAAG6C,IAAI,CAAC,iBAAA,CAAA;AACR7C,YAAAA,EAAAA,CAAG6C,IAAI,CAAC,QAAA,CAAA;AACR7C,YAAAA,EAAAA,CAAG4C,KAAK,CAAC,WAAA;AACV,SAAA,CAAA;AACD5C,QAAAA,EAAAA,CAAG2C,IAAI,CAACD,QAAU,EAAA,EAAE,EAAE,WAAA;AACpB,YAAA,IAAI,CAAC9B,EAAE,CAACuH,GAAG,GAAGnI,EAAAA,CAAG8E,IAAI,CAAC,IAAI,CAACsD,SAAS,CAACC,WAAW,CAAA;AAChD,YAAA,IAAI,CAACzH,EAAE,CAAC0H,QAAQ,GAAGtI,GAAGqD,GAAG,CAACrD,EAAG8E,CAAAA,IAAI,CAAC,IAAI,CAACI,aAAa,CAACqD,CAAC,CAAG,EAAA,CAAA,CAAA;YACzD,IAAI,CAAC3H,EAAE,CAAC4H,SAAS,GAAGxI,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAAC8H,QAAQ,EAAE,CAAA,CAAA;AAC1C,YAAA,IAAI,CAAC1H,EAAE,CAAC6H,WAAW,GAAGzI,EAAG0H,CAAAA,GAAG,CAAC,IAAI,CAACS,GAAG,EAAE,IAAI,CAACK,SAAS,CAAA;YACrD,IAAI,CAAC5H,EAAE,CAAC8H,KAAK,GAAG1I,EAAGsD,CAAAA,GAAG,CAAC,IAAI,CAAC6E,GAAG,EAAEnI,EAAAA,CAAGQ,GAAG,CAAC,IAAI,CAACiI,WAAW,EAAE,IAAI,CAACD,SAAS,CAAA,CAAA;YACxE,IAAI,CAAC5H,EAAE,CAAC+H,QAAQ,GAAG3I,EAAG0H,CAAAA,GAAG,CAAC,IAAI,CAACgB,KAAK,EAAE,CAAA,CAAA;AACtC,YAAA,IAAI,CAAC9H,EAAE,CAACgI,MAAM,GAAG5I,EAAAA,CAAGsD,GAAG,CAAC,IAAI,CAACoF,KAAK,EAAE1I,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACmI,QAAQ,EAAE,CAAA,CAAA,CAAA;;;AAG1D,YAAA,IAAI,CAAC/H,EAAE,CAACiI,QAAQ,GAAG7I,EAAAA,CAAG8E,IAAI,CAAC,CAAA,CAAA;AAC3B,YAAA,IAAI,CAAClE,EAAE,CAACkI,OAAO,GAAG9I,EAAAA,CAAG4C,KAAK,CAAC,CAAA,CAAA;YAC3B,IAAI,CAAC4E,GAAG,CAACxH,EAAG+I,CAAAA,KAAK,CAAC,IAAI,CAACH,MAAM,EAAE,CAAI,CAAA,EAAA,WAAA;AACjC,gBAAA,IAAI,CAACC,QAAQ,GAAG7I,EAAAA,CAAG8E,IAAI,CAAC,CAAA,CAAA;AACxB,gBAAA,IAAI,CAACgE,OAAO,GAAG9I,EAAAA,CAAG4C,KAAK,CAAC,CAAA,CAAA;aAEvBoG,CAAAA,CAAAA,OAAO,CAAChJ,EAAG+I,CAAAA,KAAK,CAAC,IAAI,CAACH,MAAM,EAAE,CAAI,CAAA,EAAA,WAAA;AACjC,gBAAA,IAAI,CAACC,QAAQ,GAAG7I,EAAAA,CAAG8E,IAAI,CAAC,CAAA,CAAA;AACxB,gBAAA,IAAI,CAACgE,OAAO,GAAG9I,EAAAA,CAAG4C,KAAK,CAAC,CAAA,CAAA;aAEzBoG,CAAAA,CAAAA,OAAO,CAAChJ,EAAG+I,CAAAA,KAAK,CAAC,IAAI,CAACH,MAAM,EAAE,CAAI,CAAA,EAAA,WAAA;AACjC,gBAAA,IAAI,CAACC,QAAQ,GAAG7I,EAAAA,CAAG8E,IAAI,CAAC,CAAA,CAAA;AACxB,gBAAA,IAAI,CAACgE,OAAO,GAAG9I,EAAAA,CAAG4C,KAAK,CAAC,CAAA,CAAA;aAEzBoG,CAAAA,CAAAA,OAAO,CAAChJ,EAAG+I,CAAAA,KAAK,CAAC,IAAI,CAACH,MAAM,EAAE,CAAI,CAAA,EAAA,WAAA;AACjC,gBAAA,IAAI,CAACC,QAAQ,GAAG7I,EAAAA,CAAG8E,IAAI,CAAC,CAAA,CAAA;AACxB,gBAAA,IAAI,CAACgE,OAAO,GAAG9I,EAAAA,CAAG4C,KAAK,CAAC,CAAA,CAAA;aAEzBoG,CAAAA,CAAAA,OAAO,CAAChJ,EAAG+I,CAAAA,KAAK,CAAC,IAAI,CAACH,MAAM,EAAE,CAAI,CAAA,EAAA,WAAA;AACjC,gBAAA,IAAI,CAACC,QAAQ,GAAG7I,EAAAA,CAAG8E,IAAI,CAAC,CAAA,CAAA;AACxB,gBAAA,IAAI,CAACgE,OAAO,GAAG9I,EAAAA,CAAG4C,KAAK,CAAC,CAAA,CAAA;AAC1B,aAAA,CAAA,CACC+E,KAAK,CAAC,WAAA;AACL,gBAAA,IAAI,CAACkB,QAAQ,GAAG7I,EAAAA,CAAG8E,IAAI,CAAC,CAAA,CAAA;AACxB,gBAAA,IAAI,CAACgE,OAAO,GAAG9I,EAAAA,CAAG4C,KAAK,CAAC,CAAA,CAAA;AAC1B,aAAA,CAAA;AACF,YAAA,IAAI,CAAChC,EAAE,CAACqI,IAAI,GAAGjJ,EAAG8B,CAAAA,GAAG,CAAC,IAAI,CAAC6G,QAAQ,EAAE,IAAI,CAACE,QAAQ,CAAA;;YAGlD,IAAI,CAACjI,EAAE,CAACsI,KAAK,GAAGlJ,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACiI,WAAW,EAAE,CAAA,CAAA;AACzC,YAAA,IAAI,CAAC7H,EAAE,CAACgF,UAAU,GAAG,IAAI,CAACf,cAAc,CAACa,EAAE,CAAC,IAAI,CAACwD,KAAK,CAAA;YACtD,IAAI,CAACtI,EAAE,CAACiF,UAAU,GAAG7F,EAAGqD,CAAAA,GAAG,CAAC,IAAI,CAACwB,cAAc,CAACa,EAAE,CAAC1F,EAAG8B,CAAAA,GAAG,CAAC,IAAI,CAACoH,KAAK,EAAE,CAAK,CAAA,CAAA,EAAA,CAAA,CAAA;YAE3E,IAAI,CAACtI,EAAE,CAACkF,CAAC,GAAG9F,EAAG0H,CAAAA,GAAG,CAAC1H,EAAG4C,CAAAA,KAAK,CAAC,IAAI,CAACqG,IAAI,CAAGjJ,EAAAA,EAAAA,CAAG4C,KAAK,CAAC,IAAI,CAAC0F,QAAQ,CAAA,CAAA;YAC9D,IAAI,CAAC1H,EAAE,CAACuI,KAAK,GAAGpD,IAAKJ,CAAAA,cAAc,CAAC,IAAI,EAAE,IAAI,CAACC,UAAU,EAAE,IAAI,CAACC,UAAU,EAAE,IAAI,CAACC,CAAC,CAAA;;;;;YAKlF,IAAI,CAAClF,EAAE,CAACkH,WAAW,GAAGnG,YAAayH,CAAAA,cAAc,CAAC,IAAI,CAAA;YACtD,IAAI,CAACxI,EAAE,CAACyI,WAAW,GAAG,IAAI,CAACF,KAAK,CAAC/B,MAAM,CAACnF,GAAG;;;;;AAK3C,YAAA,IAAI,CAACrB,EAAE,CAACoB,eAAe,GAAG,IAAI,CAACqH,WAAW;YAC1C,IAAItD,IAAAA,CAAKrG,YAAY,EAAE;gBACrB,IAAI,CAACsC,eAAe,GAAG+D,IAAAA,CAAKJ,cAAc,CACxC,IAAI,EACJ,IAAI,CAACC,UAAU,EACf,IAAI,CAACC,UAAU,EACf,IAAI,CAACC,CAAC,EACN,IAAA,CAAA,CACAsB,MAAM,CAACnF,GAAG;AACd;YACA,IAAI,CAACrB,EAAE,CAAC0I,MAAM,GAAGtJ,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACsH,WAAW,EAAE9H,EAAAA,CAAGM,IAAI,CAAC,IAAI,CAAC+I,WAAW,EAAE,IAAIpH,GAAG;AAC3E,YAAA,IAAI,CAACrB,EAAE,CAACQ,OAAO,GAAG2E,IAAAA,CAAKwD,wBAAwB,CAAC,IAAI,EAAE,IAAI,CAACzB,WAAW,EAAE,IAAI,CAACqB,KAAK,CAAC/H,OAAO,CAAA;;;;;AAK1F,YAAA,IAAI,CAACR,EAAE,CAAC4I,UAAU,GAAGxJ,EAAAA,CAAG0H,GAAG,CACzB1H,EAAAA,CAAG8B,GAAG,CACJ9B,EAAAA,CAAGuH,MAAM,CAAC,IAAI,CAACO,WAAW,CAAC,EAAE,CAAC7F,GAAG,GACjCjC,EAAGuH,CAAAA,MAAM,CAAC,IAAI,CAACO,WAAW,CAAC,CAAA,CAAE,CAAC7F,GAAG,CAAA,EACjCjC,GAAGuH,MAAM,CAAC,IAAI,CAACO,WAAW,CAAC,CAAE,CAAA,CAAC7F,GAAG,CAEnC,CAAA,EAAA,CAAA,CAAA;YAEF,IAAI,CAACrB,EAAE,CAAC6I,SAAS,GAAGzJ,GAAGQ,GAAG,CAAC,IAAI,CAAC2I,KAAK,CAAC/B,MAAM,CAACC,CAAC,EAAE,GAAA,EAAK,IAAI,CAACnC,aAAa,CAACwE,CAAC,EAAE,IAAI,CAACF,UAAU,CAAA;;;YAI1F,IAAI,CAAC5I,EAAE,CAAC+I,MAAM,GAAGhI,YAAaiI,CAAAA,iBAAiB,CAAC,IAAI,CAAA;AACpD,YAAA,IAAI,CAAChJ,EAAE,CAACiJ,KAAK,GAAG7J,EAAGsD,CAAAA,GAAG,CAAC,IAAI,CAACqG,MAAM,EAAE,IAAI,CAACL,MAAM,CAAA;YAC/C,IAAI,CAAC1I,EAAE,CAACkJ,QAAQ,GAAG9J,GAAGuH,MAAM,CAAC,IAAI,CAACsC,KAAK,CAAA;YACvC,IAAI,CAACjJ,EAAE,CAACmJ,OAAO,GAAG/J,EAAG6C,CAAAA,IAAI,CAAC,CAAA,EAAG,CAAG,EAAA,CAAA,CAAA;YAChC,IAAI,CAAC2E,GAAG,CAACxH,EAAGyH,CAAAA,WAAW,CAAC,IAAI,CAACqC,QAAQ,EAAE,QAAW,CAAA,EAAA,WAAA;AAChD,gBAAA,IAAI,CAACC,OAAO,GAAG/J,EAAAA,CAAG0H,GAAG,CAAC,IAAI,CAACmC,KAAK,EAAE,IAAI,CAACC,QAAQ,CAAA;AACjD,aAAA,CAAA;AACA,YAAA,IAAI,CAAClJ,EAAE,CAACU,IAAI,GAAGtB,EAAGgK,CAAAA,KAAK,CAAC,IAAI,CAAC5I,OAAO,EAAE,IAAI,CAAC2I,OAAO,CAAA;YAClD,IAAI,CAACnJ,EAAE,CAACqJ,OAAO,GAAGjK,GAAGuH,MAAM,CAAC,IAAI,CAACjG,IAAI,CAAA;YACrC,IAAI,CAACkG,GAAG,CAACxH,EAAGyH,CAAAA,WAAW,CAAC,IAAI,CAACwC,OAAO,EAAE,QAAW,CAAA,EAAA,WAAA;AAC/C,gBAAA,IAAI,CAAC3I,IAAI,GAAGtB,EAAAA,CAAG0H,GAAG,CAAC,IAAI,CAACpG,IAAI,EAAE,IAAI,CAAC2I,OAAO,CAAA;AAC5C,aAAA,CAAA,CAAGtC,KAAK,CAAC,WAAA;;AAEP,gBAAA,IAAI,CAACrG,IAAI,GAAGtB,EAAG+C,CAAAA,SAAS,CAAC/C,EAAGgK,CAAAA,KAAK,CAAC,IAAI,CAAC5I,OAAO,EAAEpB,GAAG6C,IAAI,CAAC,KAAK,GAAK,EAAA,KAAA,CAAA,CAAA,CAAA;AACpE,aAAA,CAAA;;;YAIA,IAAI,CAACjC,EAAE,CAACsJ,KAAK,GAAGlK,EAAGqD,CAAAA,GAAG,CAAC,IAAI,CAACoG,SAAS,EAAEzJ,EAAAA,CAAGQ,GAAG,CAAC,IAAI,CAAC0E,aAAa,CAACiF,CAAC,EAAE,GAAA,CAAA,CAAA;AACpE,YAAA,IAAI,CAACvJ,EAAE,CAACT,QAAQ,GAAGH,EAAAA,CAAG4C,KAAK,CAAC,CAAA,CAAA;;;;;;;;;;;;YAY5B,IAAI,CAAChC,EAAE,CAACwJ,SAAS,GAAGpK,GAAG8B,GAAG,CAAC9B,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAAC0E,aAAa,CAACmC,CAAC,EAAE,IAAI,CAACyC,QAAQ,CAAA,EAAG,IAAI,CAAC1E,YAAY,CAACiC,CAAC,CAAA;YAC3F,IAAI,CAACG,GAAG,CAACxH,EAAGyH,CAAAA,WAAW,CAAC,IAAI,CAAC2C,SAAS,EAAE,CAAI,CAAA,EAAA,WAAA;AAC1C,gBAAA,IAAI,CAAC5C,GAAG,CAACxH,EAAAA,CAAGqK,QAAQ,CAAC,IAAI,CAACH,KAAK,EAAE,IAAI,CAACE,SAAS,CAAG,EAAA,WAAA;AAChD,oBAAA,IAAI,CAACjK,QAAQ,GAAGH,EAAAA,CAAG0H,GAAG,CAAC,IAAI,CAACwC,KAAK,EAAE,IAAI,CAACE,SAAS,CAAA;AACjD,oBAAA,IAAI,CAACF,KAAK,GAAG,IAAI,CAACE,SAAS;AAC7B,iBAAA,CAAA;AACF,aAAA,CAAA;YAEA,IAAIrE,IAAAA,CAAKhH,SAAS,EAAE;;;;;gBAKlB,MAAMuL,MAAAA,GAAS,IAAI,CAACtF,aAAa;gBACjC,IAAI,CAACpE,EAAE,CAAC2J,QAAQ,GAAGvK,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACoF,UAAU,EAAE,CAAA,CAAA;AAC3C,gBAAA,IAAI,CAAChF,EAAE,CAAC4J,SAAS,GAAGxK,EAAG6C,CAAAA,IAAI,CACzByH,MAAAA,CAAO5E,EAAE,CAAC,IAAI,CAAC6E,QAAQ,GACvBD,MAAO5E,CAAAA,EAAE,CAAC1F,EAAAA,CAAG8B,GAAG,CAAC,IAAI,CAACyI,QAAQ,EAAE,CAChCD,CAAAA,CAAAA,EAAAA,MAAAA,CAAO5E,EAAE,CAAC1F,GAAG8B,GAAG,CAAC,IAAI,CAACyI,QAAQ,EAAE,CAAA,CAAA,CAAA,CAAA;;;;gBAKlC,IAAI,CAAC3J,EAAE,CAAC6J,OAAO,GAAGzK,EAAGQ,CAAAA,GAAG,CAAC,IAAI,CAACsH,WAAW,EAAE9H,EAAAA,CAAGM,IAAI,CAAC,IAAI,CAACkK,SAAS,EAAE,IAAIvI,GAAG;AAC1E,gBAAA,IAAI,CAACrB,EAAE,CAAC8J,QAAQ,GAAG1K,EAAAA,CAAGQ,GAAG,CACvB8J,MAAO5E,CAAAA,EAAE,CAAC1F,EAAAA,CAAG8B,GAAG,CAAC,IAAI,CAACyI,QAAQ,EAAE,CAChC,CAAA,CAAA,EAAA,GAAA,EACA,IAAI,CAACrF,aAAa,CAACwE,CAAC,EACpB,IAAI,CAACF,UAAU,CAAA;AAEjB,gBAAA,IAAI,CAAC5I,EAAE,CAAC+J,SAAS,GAAG3K,EAAG8B,CAAAA,GAAG,CACxB9B,EAAAA,CAAGQ,GAAG,CAAC,IAAI,CAAC0E,aAAa,CAACmC,CAAC,EAAErH,EAAAA,CAAG4K,QAAQ,CAAC,IAAI,CAACjB,MAAM,EAAE,IAAI,CAACc,OAAO,CAClE,CAAA,EAAA,IAAI,CAACrF,YAAY,CAACiC,CAAC,CAAA;AAErB,gBAAA,IAAI,CAACzG,EAAE,CAACiK,IAAI,GAAG7K,EAAAA,CAAG4C,KAAK,CAAC,CAAA,CAAA;gBACxB,IAAI,CAAC4E,GAAG,CAACxH,EAAGyH,CAAAA,WAAW,CAAC,IAAI,CAACkD,SAAS,EAAE,CAAI,CAAA,EAAA,WAAA;oBAC1C,IAAI,CAACE,IAAI,GAAG7K,EAAAA,CAAGkD,KAAK,CAAClD,EAAAA,CAAG0H,GAAG,CAAC,IAAI,CAACgD,QAAQ,EAAE,IAAI,CAACC,SAAS,CAAA,EAAG,IAAI,CAACtF,UAAU,CAACkD,CAAC,EAAE,CAAA,CAAA;AACjF,iBAAA,CAAA;;;gBAGA,IAAI,CAAC3H,EAAE,CAACkK,IAAI,GAAG9K,EAAG+K,CAAAA,eAAe,CAAC,IAAI,CAAClG,cAAc,CAACa,EAAE,CAAC1F,EAAG8B,CAAAA,GAAG,CAAC,IAAI,CAACoH,KAAK,EAAE,CAAA,CAAA,CAAA,CAAA;;;;AAI5E,gBAAA,IAAI,CAAC/I,QAAQ,GAAGH,EAAGqG,CAAAA,GAAG,CAACrG,EAAG0H,CAAAA,GAAG,CAAC,IAAI,CAACvH,QAAQ,EAAE,IAAI,CAAC0K,IAAI,CAAG,EAAA,CAAA,CAAA;AACzD,gBAAA,IAAI,CAACrD,GAAG,CAACxH,EAAAA,CAAGgL,gBAAgB,CAAC,IAAI,CAACF,IAAI,EAAE,IAAI,CAACD,IAAI,CAAG,EAAA,WAAA;;;;AAIlD,oBAAA,IAAI,CAACvB,MAAM,GAAG,IAAI,CAACmB,OAAO;AAC1B,oBAAA,IAAI,CAACpB,WAAW,GAAG,IAAI,CAACmB,SAAS;AACjC,oBAAA,IAAI,CAACxI,eAAe,GAAG,IAAI,CAACwI,SAAS;AACrC,oBAAA,IAAI,CAACN,KAAK,GAAGlK,EAAAA,CAAG4C,KAAK,CAAC,CAAA,CAAA;AACxB,iBAAA,CAAA;AACF;AAEA,YAAA,IAAI,CAAChC,EAAE,CAACqK,UAAU,GAAGjL,EAAGsD,CAAAA,GAAG,CAACtD,EAAAA,CAAGQ,GAAG,CAAC,IAAI,CAACsI,OAAO,EAAE,CAAI,CAAA,EAAA,CAAA,CAAA;AACrD,YAAA,IAAI,CAAClI,EAAE,CAACsB,MAAM,GAAGlC,EAAAA,CAAGQ,GAAG,CAAC,IAAI,CAACc,IAAI,EAAE,IAAI,CAAC4I,KAAK,EAAE,IAAI,CAACe,UAAU,CAAA;AAC9D,YAAA,IAAI,CAACrK,EAAE,CAACsK,MAAM,GAAGhD,YAAAA,EAAAA;AACjB,YAAA,IAAI,CAACgD,MAAM,CAAClK,QAAQ,GAAGhB,EAAG8B,CAAAA,GAAG,CAAC,IAAI,CAACwH,MAAM,EAAE,IAAI,CAACpH,MAAM,CAAA;;;AAGtD,YAAA,IAAI,CAACgJ,MAAM,CAAChK,MAAM,GAAGlB,GAAG+C,SAAS,CAAC/C,EAAGgK,CAAAA,KAAK,CAAC,IAAI,CAAC1I,IAAI,EAAE,IAAI,CAACF,OAAO,CAAA,CAAA;AAClE,YAAA,IAAI,CAAC8J,MAAM,CAAC9J,OAAO,GAAG,IAAI,CAACA,OAAO;AAClC,YAAA,IAAI,CAAC8J,MAAM,CAAC5J,IAAI,GAAG,IAAI,CAACA,IAAI;AAC5B,YAAA,IAAI,CAAC4J,MAAM,CAAC/K,QAAQ,GAAG,IAAI,CAACA,QAAQ;AACpC,YAAA,IAAI,CAAC+K,MAAM,CAAC1J,MAAM,GAAGxB,GAAGQ,GAAG,CAAC,IAAI,CAACyK,UAAU,EAAE,IAAI,CAAC7F,YAAY,CAACmD,CAAC,CAAA;;;AAGhE,YAAA,IAAI,CAAC2C,MAAM,CAAC7B,WAAW,GAAG,IAAI,CAACA,WAAW;AAC1C,YAAA,IAAI,CAAC6B,MAAM,CAAClJ,eAAe,GAAG,IAAI,CAACA,eAAe;AAClD,YAAA,IAAI,CAACkJ,MAAM,CAAChJ,MAAM,GAAG,IAAI,CAACA,MAAM;;;;;YAKhC,IAAI,CAACtB,EAAE,CAACuK,OAAO,GAAGnL,GAAGsD,GAAG,CAAC,CAAGtD,EAAAA,EAAAA,CAAGoL,UAAU,CAAC,GAAGpL,EAAGqD,CAAAA,GAAG,CAAC,IAAI,CAAC+B,YAAY,CAAC+E,CAAC,EAAE,KAAA,CAAA,EAAQ,IAAI,CAACrE,CAAC,CAAA,CAAA;YACvF,IAAI,CAACoF,MAAM,CAACxJ,SAAS,GAAG1B,GAAGkD,KAAK,CAAClD,EAAGsD,CAAAA,GAAG,CAAC,CAAA,EAAGtD,GAAGQ,GAAG,CAAC,IAAI,CAAC2K,OAAO,EAAE,IAAI,CAAC/F,YAAY,CAACsE,CAAC,CAAA,CAAA,EAAI,CAAG,EAAA,CAAA,CAAA;AAC1F,YAAA,IAAI,CAACnG,OAAO,CAAC,IAAI,CAAC2H,MAAM,CAAA;AAC1B,SAAA,CAAA;AACA,QAAA,OAAOlL,EAAGwD,CAAAA,cAAc,EAAE,CAACd,QAAS,CAAA,EAAA;AACtC;AACF;;;;"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { getDevice } from '../app/api.js';
|
|
2
|
+
import { Disposable } from '@zephyr3d/base';
|
|
3
|
+
|
|
4
|
+
/** Floats per control point in the GPU layout: position xyz plus width. */ const FLOATS_PER_POINT = 4;
|
|
5
|
+
/** Words per strand header in the GPU layout. */ const WORDS_PER_HEADER = 4;
|
|
6
|
+
/**
|
|
7
|
+
* GPU-resident strand geometry for {@link HairStrandMaterial}.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Strands live in storage buffers rather than vertex buffers, because the ribbon
|
|
11
|
+
* geometry is generated in the vertex shader from the control points rather than
|
|
12
|
+
* stored. That is what makes a full-density hair set affordable: the CPU-side
|
|
13
|
+
* ribbon for a 69k-strand cap costs 266 MB of vertex data, while the control
|
|
14
|
+
* points it was built from are around 20 MB.
|
|
15
|
+
*
|
|
16
|
+
* Two buffers:
|
|
17
|
+
* - **Headers**, one per strand: first point index, point count, packed root UV,
|
|
18
|
+
* and a seed for per-strand variation.
|
|
19
|
+
* - **Points**, one per control point: position and width.
|
|
20
|
+
*
|
|
21
|
+
* Both are read-only to the render pass. A simulation pass may write the point
|
|
22
|
+
* buffer in place, which is why positions and widths are interleaved: a solver
|
|
23
|
+
* touches position and leaves width alone, and keeping them in one buffer avoids
|
|
24
|
+
* a second binding.
|
|
25
|
+
* @public
|
|
26
|
+
*/ class HairStrandData extends Disposable {
|
|
27
|
+
/** @internal */ _headerBuffer;
|
|
28
|
+
/** @internal */ _pointBuffer;
|
|
29
|
+
/** @internal */ _strandCount;
|
|
30
|
+
/** @internal */ _pointCount;
|
|
31
|
+
/** @internal */ _maxPointsPerStrand;
|
|
32
|
+
/**
|
|
33
|
+
* Uploads strand geometry to the GPU.
|
|
34
|
+
*
|
|
35
|
+
* @param source - Strand control points and topology.
|
|
36
|
+
*/ constructor(source){
|
|
37
|
+
super();
|
|
38
|
+
const device = getDevice();
|
|
39
|
+
const scale = source.scale ?? 1;
|
|
40
|
+
const widthScale = source.widthScale ?? 1;
|
|
41
|
+
const defaultWidth = source.defaultWidth ?? 0.0001;
|
|
42
|
+
const counts = source.pointCounts;
|
|
43
|
+
const strandCount = counts.length;
|
|
44
|
+
let pointCount = 0;
|
|
45
|
+
let maxPoints = 0;
|
|
46
|
+
for(let i = 0; i < strandCount; i++){
|
|
47
|
+
const c = counts[i];
|
|
48
|
+
pointCount += c;
|
|
49
|
+
if (c > maxPoints) {
|
|
50
|
+
maxPoints = c;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (strandCount === 0 || pointCount === 0) {
|
|
54
|
+
throw new Error('HairStrandData: source contains no strands');
|
|
55
|
+
}
|
|
56
|
+
if (source.positions.length < pointCount * 3) {
|
|
57
|
+
throw new Error(`HairStrandData: positions hold ${source.positions.length / 3} points, topology needs ${pointCount}`);
|
|
58
|
+
}
|
|
59
|
+
this._strandCount = strandCount;
|
|
60
|
+
this._pointCount = pointCount;
|
|
61
|
+
this._maxPointsPerStrand = maxPoints;
|
|
62
|
+
const widths = source.widths ?? null;
|
|
63
|
+
const widthPerStrand = !!source.widthPerStrand;
|
|
64
|
+
const uv = source.uv ?? null;
|
|
65
|
+
const uvPerPoint = !!uv && uv.length >= pointCount * 2;
|
|
66
|
+
const points = new Float32Array(pointCount * FLOATS_PER_POINT);
|
|
67
|
+
// Headers are read as uint in the shader, but the packed UV is a float bit
|
|
68
|
+
// pattern, so the staging array is built as float and reinterpreted.
|
|
69
|
+
const headers = new Uint32Array(strandCount * WORDS_PER_HEADER);
|
|
70
|
+
const headerFloats = new Float32Array(headers.buffer);
|
|
71
|
+
let first = 0;
|
|
72
|
+
for(let s = 0; s < strandCount; s++){
|
|
73
|
+
const count = counts[s];
|
|
74
|
+
for(let i = 0; i < count; i++){
|
|
75
|
+
const src = (first + i) * 3;
|
|
76
|
+
const dst = (first + i) * FLOATS_PER_POINT;
|
|
77
|
+
points[dst] = source.positions[src] * scale;
|
|
78
|
+
points[dst + 1] = source.positions[src + 1] * scale;
|
|
79
|
+
points[dst + 2] = source.positions[src + 2] * scale;
|
|
80
|
+
let w = defaultWidth;
|
|
81
|
+
if (widths) {
|
|
82
|
+
w = widthPerStrand ? widths[s] : widths[first + i];
|
|
83
|
+
}
|
|
84
|
+
points[dst + 3] = w * scale * widthScale;
|
|
85
|
+
}
|
|
86
|
+
const h = s * WORDS_PER_HEADER;
|
|
87
|
+
headers[h] = first;
|
|
88
|
+
headers[h + 1] = count;
|
|
89
|
+
// Root UV, packed as two 16-bit unorm values.
|
|
90
|
+
let u = 0;
|
|
91
|
+
let v = 0;
|
|
92
|
+
if (uv) {
|
|
93
|
+
const o = uvPerPoint ? first * 2 : s * 2;
|
|
94
|
+
u = uv[o];
|
|
95
|
+
v = uv[o + 1];
|
|
96
|
+
}
|
|
97
|
+
headers[h + 2] = packUnorm2x16(u, v);
|
|
98
|
+
// A cheap decorrelated seed, so per-strand jitter does not band across the
|
|
99
|
+
// scalp. Written through the float view so the shader can read it directly.
|
|
100
|
+
headerFloats[h + 3] = hashToUnitFloat(s);
|
|
101
|
+
first += count;
|
|
102
|
+
}
|
|
103
|
+
// Unmanaged: the contents are uploaded once here, and a simulation pass may
|
|
104
|
+
// later overwrite the point buffer on the GPU, so there is no CPU-side copy
|
|
105
|
+
// worth keeping in sync.
|
|
106
|
+
this._headerBuffer = device.createBuffer(headers.byteLength, {
|
|
107
|
+
usage: 'uniform',
|
|
108
|
+
storage: true,
|
|
109
|
+
dynamic: false,
|
|
110
|
+
managed: false
|
|
111
|
+
});
|
|
112
|
+
this._headerBuffer.bufferSubData(0, headers);
|
|
113
|
+
this._pointBuffer = device.createBuffer(points.byteLength, {
|
|
114
|
+
usage: 'uniform',
|
|
115
|
+
storage: true,
|
|
116
|
+
dynamic: false,
|
|
117
|
+
managed: false
|
|
118
|
+
});
|
|
119
|
+
this._pointBuffer.bufferSubData(0, points);
|
|
120
|
+
}
|
|
121
|
+
/** Number of strands. */ get strandCount() {
|
|
122
|
+
return this._strandCount;
|
|
123
|
+
}
|
|
124
|
+
/** Total control point count across all strands. */ get pointCount() {
|
|
125
|
+
return this._pointCount;
|
|
126
|
+
}
|
|
127
|
+
/** Largest control point count of any single strand. */ get maxPointsPerStrand() {
|
|
128
|
+
return this._maxPointsPerStrand;
|
|
129
|
+
}
|
|
130
|
+
/** Per-strand header buffer. */ get headerBuffer() {
|
|
131
|
+
return this._headerBuffer;
|
|
132
|
+
}
|
|
133
|
+
/** Per-control-point buffer holding position and width. */ get pointBuffer() {
|
|
134
|
+
return this._pointBuffer;
|
|
135
|
+
}
|
|
136
|
+
/** Bytes of GPU memory held by the two buffers. */ get byteLength() {
|
|
137
|
+
return (this._headerBuffer?.byteLength ?? 0) + (this._pointBuffer?.byteLength ?? 0);
|
|
138
|
+
}
|
|
139
|
+
onDispose() {
|
|
140
|
+
this._headerBuffer?.dispose();
|
|
141
|
+
this._headerBuffer = null;
|
|
142
|
+
this._pointBuffer?.dispose();
|
|
143
|
+
this._pointBuffer = null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/** Packs two unit floats into one word as 16-bit unorms. @internal */ function packUnorm2x16(u, v) {
|
|
147
|
+
const a = Math.max(0, Math.min(1, u)) * 65535 + 0.5;
|
|
148
|
+
const b = Math.max(0, Math.min(1, v)) * 65535 + 0.5;
|
|
149
|
+
return (b & 0xffff) << 16 | a & 0xffff;
|
|
150
|
+
}
|
|
151
|
+
/** Deterministic hash of a strand index into [0, 1). @internal */ function hashToUnitFloat(index) {
|
|
152
|
+
let x = index + 1 >>> 0;
|
|
153
|
+
x = x ^ 61 ^ x >>> 16;
|
|
154
|
+
x = x + (x << 3) >>> 0;
|
|
155
|
+
x = x ^ x >>> 4;
|
|
156
|
+
x = Math.imul(x, 0x27d4eb2d) >>> 0;
|
|
157
|
+
x = x ^ x >>> 15;
|
|
158
|
+
return (x >>> 8) / 16777216;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export { HairStrandData };
|
|
162
|
+
//# sourceMappingURL=hairstrand_data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hairstrand_data.js","sources":["../../src/material/hairstrand_data.ts"],"sourcesContent":["import type { GPUDataBuffer } from '@zephyr3d/device';\r\nimport { getDevice } from '../app/api';\r\nimport { Disposable, type Nullable } from '@zephyr3d/base';\r\n\r\n/** Floats per control point in the GPU layout: position xyz plus width. */\r\nconst FLOATS_PER_POINT = 4;\r\n/** Words per strand header in the GPU layout. */\r\nconst WORDS_PER_HEADER = 4;\r\n\r\n/**\r\n * Source strands, as produced by a curve importer.\r\n *\r\n * @remarks\r\n * Control points are stored contiguously: strand `i` owns the `pointCounts[i]`\r\n * points starting at the running sum of the preceding counts, which is the same\r\n * layout Alembic uses.\r\n */\r\nexport type HairStrandSource = {\r\n /** Control point positions, 3 floats per point. */\r\n positions: Float32Array;\r\n /** Control point count per strand. */\r\n pointCounts: Int32Array | Uint32Array;\r\n /** Per-point width, or null to fall back to `defaultWidth`. */\r\n widths?: Nullable<Float32Array>;\r\n /** True when `widths` holds one value per strand rather than per point. */\r\n widthPerStrand?: boolean;\r\n /** Per-strand or per-point root UV, 2 floats each, or null. */\r\n uv?: Nullable<Float32Array>;\r\n /** Width used where the source provides none. Defaults to 0.0001. */\r\n defaultWidth?: number;\r\n /**\r\n * Uniform scale applied to control points, positions and widths alike.\r\n *\r\n * @remarks\r\n * Width is stored in the same linear unit as position, so both convert\r\n * together. The sample XGen archive is authored in centimetres and carries\r\n * widths of 0.0008 to 0.0159, which is 8 to 159 microns once scaled - the range\r\n * real hair occupies. Leaving width unscaled makes strands a hundred times too\r\n * thick, which reads as broad ribbons rather than hair.\r\n */\r\n scale?: number;\r\n /**\r\n * Extra multiplier applied to width only.\r\n *\r\n * @remarks\r\n * Separate from `scale` so thickness can be exaggerated for art direction\r\n * without disturbing the unit conversion. Defaults to 1.\r\n */\r\n widthScale?: number;\r\n};\r\n\r\n/**\r\n * GPU-resident strand geometry for {@link HairStrandMaterial}.\r\n *\r\n * @remarks\r\n * Strands live in storage buffers rather than vertex buffers, because the ribbon\r\n * geometry is generated in the vertex shader from the control points rather than\r\n * stored. That is what makes a full-density hair set affordable: the CPU-side\r\n * ribbon for a 69k-strand cap costs 266 MB of vertex data, while the control\r\n * points it was built from are around 20 MB.\r\n *\r\n * Two buffers:\r\n * - **Headers**, one per strand: first point index, point count, packed root UV,\r\n * and a seed for per-strand variation.\r\n * - **Points**, one per control point: position and width.\r\n *\r\n * Both are read-only to the render pass. A simulation pass may write the point\r\n * buffer in place, which is why positions and widths are interleaved: a solver\r\n * touches position and leaves width alone, and keeping them in one buffer avoids\r\n * a second binding.\r\n * @public\r\n */\r\nexport class HairStrandData extends Disposable {\r\n /** @internal */\r\n private _headerBuffer: Nullable<GPUDataBuffer>;\r\n /** @internal */\r\n private _pointBuffer: Nullable<GPUDataBuffer>;\r\n /** @internal */\r\n private readonly _strandCount: number;\r\n /** @internal */\r\n private readonly _pointCount: number;\r\n /** @internal */\r\n private readonly _maxPointsPerStrand: number;\r\n /**\r\n * Uploads strand geometry to the GPU.\r\n *\r\n * @param source - Strand control points and topology.\r\n */\r\n constructor(source: HairStrandSource) {\r\n super();\r\n const device = getDevice();\r\n const scale = source.scale ?? 1;\r\n const widthScale = source.widthScale ?? 1;\r\n const defaultWidth = source.defaultWidth ?? 0.0001;\r\n const counts = source.pointCounts;\r\n const strandCount = counts.length;\r\n let pointCount = 0;\r\n let maxPoints = 0;\r\n for (let i = 0; i < strandCount; i++) {\r\n const c = counts[i];\r\n pointCount += c;\r\n if (c > maxPoints) {\r\n maxPoints = c;\r\n }\r\n }\r\n if (strandCount === 0 || pointCount === 0) {\r\n throw new Error('HairStrandData: source contains no strands');\r\n }\r\n if (source.positions.length < pointCount * 3) {\r\n throw new Error(\r\n `HairStrandData: positions hold ${source.positions.length / 3} points, topology needs ${pointCount}`\r\n );\r\n }\r\n this._strandCount = strandCount;\r\n this._pointCount = pointCount;\r\n this._maxPointsPerStrand = maxPoints;\r\n\r\n const widths = source.widths ?? null;\r\n const widthPerStrand = !!source.widthPerStrand;\r\n const uv = source.uv ?? null;\r\n const uvPerPoint = !!uv && uv.length >= pointCount * 2;\r\n\r\n const points = new Float32Array(pointCount * FLOATS_PER_POINT);\r\n // Headers are read as uint in the shader, but the packed UV is a float bit\r\n // pattern, so the staging array is built as float and reinterpreted.\r\n const headers = new Uint32Array(strandCount * WORDS_PER_HEADER);\r\n const headerFloats = new Float32Array(headers.buffer);\r\n\r\n let first = 0;\r\n for (let s = 0; s < strandCount; s++) {\r\n const count = counts[s];\r\n for (let i = 0; i < count; i++) {\r\n const src = (first + i) * 3;\r\n const dst = (first + i) * FLOATS_PER_POINT;\r\n points[dst] = source.positions[src] * scale;\r\n points[dst + 1] = source.positions[src + 1] * scale;\r\n points[dst + 2] = source.positions[src + 2] * scale;\r\n let w = defaultWidth;\r\n if (widths) {\r\n w = widthPerStrand ? widths[s] : widths[first + i];\r\n }\r\n points[dst + 3] = w * scale * widthScale;\r\n }\r\n const h = s * WORDS_PER_HEADER;\r\n headers[h] = first;\r\n headers[h + 1] = count;\r\n // Root UV, packed as two 16-bit unorm values.\r\n let u = 0;\r\n let v = 0;\r\n if (uv) {\r\n const o = uvPerPoint ? first * 2 : s * 2;\r\n u = uv[o];\r\n v = uv[o + 1];\r\n }\r\n headers[h + 2] = packUnorm2x16(u, v);\r\n // A cheap decorrelated seed, so per-strand jitter does not band across the\r\n // scalp. Written through the float view so the shader can read it directly.\r\n headerFloats[h + 3] = hashToUnitFloat(s);\r\n first += count;\r\n }\r\n\r\n // Unmanaged: the contents are uploaded once here, and a simulation pass may\r\n // later overwrite the point buffer on the GPU, so there is no CPU-side copy\r\n // worth keeping in sync.\r\n this._headerBuffer = device.createBuffer(headers.byteLength, {\r\n usage: 'uniform',\r\n storage: true,\r\n dynamic: false,\r\n managed: false\r\n });\r\n this._headerBuffer.bufferSubData(0, headers);\r\n this._pointBuffer = device.createBuffer(points.byteLength, {\r\n usage: 'uniform',\r\n storage: true,\r\n dynamic: false,\r\n managed: false\r\n });\r\n this._pointBuffer.bufferSubData(0, points);\r\n }\r\n /** Number of strands. */\r\n get strandCount() {\r\n return this._strandCount;\r\n }\r\n /** Total control point count across all strands. */\r\n get pointCount() {\r\n return this._pointCount;\r\n }\r\n /** Largest control point count of any single strand. */\r\n get maxPointsPerStrand() {\r\n return this._maxPointsPerStrand;\r\n }\r\n /** Per-strand header buffer. */\r\n get headerBuffer() {\r\n return this._headerBuffer;\r\n }\r\n /** Per-control-point buffer holding position and width. */\r\n get pointBuffer() {\r\n return this._pointBuffer;\r\n }\r\n /** Bytes of GPU memory held by the two buffers. */\r\n get byteLength() {\r\n return (this._headerBuffer?.byteLength ?? 0) + (this._pointBuffer?.byteLength ?? 0);\r\n }\r\n protected onDispose() {\r\n this._headerBuffer?.dispose();\r\n this._headerBuffer = null;\r\n this._pointBuffer?.dispose();\r\n this._pointBuffer = null;\r\n }\r\n}\r\n\r\n/** Packs two unit floats into one word as 16-bit unorms. @internal */\r\nfunction packUnorm2x16(u: number, v: number) {\r\n const a = Math.max(0, Math.min(1, u)) * 65535 + 0.5;\r\n const b = Math.max(0, Math.min(1, v)) * 65535 + 0.5;\r\n return ((b & 0xffff) << 16) | (a & 0xffff);\r\n}\r\n\r\n/** Deterministic hash of a strand index into [0, 1). @internal */\r\nfunction hashToUnitFloat(index: number) {\r\n let x = (index + 1) >>> 0;\r\n x = x ^ 61 ^ (x >>> 16);\r\n x = (x + (x << 3)) >>> 0;\r\n x = x ^ (x >>> 4);\r\n x = Math.imul(x, 0x27d4eb2d) >>> 0;\r\n x = x ^ (x >>> 15);\r\n return (x >>> 8) / 16777216;\r\n}\r\n"],"names":["FLOATS_PER_POINT","WORDS_PER_HEADER","HairStrandData","Disposable","source","device","getDevice","scale","widthScale","defaultWidth","counts","pointCounts","strandCount","length","pointCount","maxPoints","i","c","Error","positions","_strandCount","_pointCount","_maxPointsPerStrand","widths","widthPerStrand","uv","uvPerPoint","points","Float32Array","headers","Uint32Array","headerFloats","buffer","first","s","count","src","dst","w","h","u","v","o","packUnorm2x16","hashToUnitFloat","_headerBuffer","createBuffer","byteLength","usage","storage","dynamic","managed","bufferSubData","_pointBuffer","maxPointsPerStrand","headerBuffer","pointBuffer","onDispose","dispose","a","Math","max","min","b","index","x","imul"],"mappings":"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"}
|
package/dist/material/lambert.js
CHANGED
|
@@ -58,7 +58,10 @@ import { RENDER_PASS_TYPE_LIGHT, MaterialVaryingFlags } from '../values.js';
|
|
|
58
58
|
}
|
|
59
59
|
if (this.drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT) {
|
|
60
60
|
scope.$l.color = pb.vec3(0);
|
|
61
|
-
|
|
61
|
+
// TBN[2] is the pre-normal-map geometric normal, needed for shadow
|
|
62
|
+
// normal offset bias.
|
|
63
|
+
scope.$l.normalInfo = this.calculateNormalAndTBN(scope, scope.$inputs.worldPos, scope.$inputs.wNorm, scope.$inputs.wTangent, scope.$inputs.wBinormal);
|
|
64
|
+
scope.$l.normal = scope.normalInfo.normal;
|
|
62
65
|
if (this.needCalculateEnvLight()) {
|
|
63
66
|
scope.color = pb.add(scope.color, this.getEnvLightIrradiance(scope, scope.normal));
|
|
64
67
|
}
|
|
@@ -68,7 +71,7 @@ import { RENDER_PASS_TYPE_LIGHT, MaterialVaryingFlags } from '../values.js';
|
|
|
68
71
|
this.$l.NoL = pb.clamp(pb.dot(this.normal, this.lightDir), 0, 1);
|
|
69
72
|
this.$l.lightContrib = pb.mul(colorIntensity.rgb, colorIntensity.a, this.NoL, this.lightAtten, 1 / Math.PI);
|
|
70
73
|
if (shadow) {
|
|
71
|
-
this.$l.shadow = pb.vec3(that.calculateShadow(this, scope.$inputs.worldPos, this.NoL));
|
|
74
|
+
this.$l.shadow = pb.vec3(that.calculateShadow(this, scope.$inputs.worldPos, scope.normalInfo.TBN[2], this.NoL));
|
|
72
75
|
this.lightContrib = pb.mul(this.lightContrib, this.shadow);
|
|
73
76
|
}
|
|
74
77
|
this.color = pb.add(this.color, this.lightContrib);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lambert.js","sources":["../../src/material/lambert.ts"],"sourcesContent":["import { mixinLight } from './mixins/lit';\r\nimport { mixinVertexColor } from './mixins/vertexcolor';\r\nimport { MeshMaterial, applyMaterialMixins } from './meshmaterial';\r\nimport type { PBFunctionScope } from '@zephyr3d/device';\r\nimport { ShaderHelper } from './shader/helper';\r\nimport { MaterialVaryingFlags, RENDER_PASS_TYPE_LIGHT } from '../values';\r\nimport type { Clonable } from '@zephyr3d/base';\r\n\r\n/**\r\n * Lambert material\r\n * @public\r\n */\r\nexport class LambertMaterial\r\n extends applyMaterialMixins(MeshMaterial, mixinLight, mixinVertexColor)\r\n implements Clonable<LambertMaterial>\r\n{\r\n private static readonly FEATURE_VERTEX_NORMAL = this.defineFeature();\r\n private static readonly FEATURE_VERTEX_TANGENT = this.defineFeature();\r\n constructor() {\r\n super();\r\n this.useFeature(LambertMaterial.FEATURE_VERTEX_NORMAL, true);\r\n }\r\n clone() {\r\n const other = new LambertMaterial();\r\n other.copyFrom(this);\r\n return other;\r\n }\r\n /** true if vertex normal attribute presents */\r\n get vertexNormal() {\r\n return this.featureUsed<boolean>(LambertMaterial.FEATURE_VERTEX_NORMAL);\r\n }\r\n set vertexNormal(val) {\r\n this.useFeature(LambertMaterial.FEATURE_VERTEX_NORMAL, !!val);\r\n }\r\n /** true if vertex normal attribute presents */\r\n get vertexTangent() {\r\n return this.featureUsed<boolean>(LambertMaterial.FEATURE_VERTEX_TANGENT);\r\n }\r\n set vertexTangent(val) {\r\n this.useFeature(LambertMaterial.FEATURE_VERTEX_TANGENT, !!val);\r\n }\r\n vertexShader(scope: PBFunctionScope) {\r\n super.vertexShader(scope);\r\n const pb = scope.$builder;\r\n scope.$l.oPos = ShaderHelper.resolveVertexPosition(scope);\r\n scope.$outputs.worldPos = pb.mul(ShaderHelper.getWorldMatrix(scope), pb.vec4(scope.oPos, 1)).xyz;\r\n ShaderHelper.setClipSpacePosition(\r\n scope,\r\n pb.mul(ShaderHelper.getViewProjectionMatrix(scope), pb.vec4(scope.$outputs.worldPos, 1))\r\n );\r\n if (this.vertexNormal) {\r\n scope.$l.oNorm = ShaderHelper.resolveVertexNormal(scope);\r\n scope.$outputs.wNorm = pb.mul(ShaderHelper.getNormalMatrix(scope), pb.vec4(scope.oNorm, 0)).xyz;\r\n if (this.vertexTangent) {\r\n scope.$l.oTangent = ShaderHelper.resolveVertexTangent(scope);\r\n scope.$outputs.wTangent = pb.mul(\r\n ShaderHelper.getNormalMatrix(scope),\r\n pb.vec4(scope.oTangent.xyz, 0)\r\n ).xyz;\r\n scope.$outputs.wBinormal = pb.mul(\r\n pb.cross(scope.$outputs.wNorm, scope.$outputs.wTangent),\r\n scope.oTangent.w\r\n );\r\n }\r\n }\r\n }\r\n fragmentShader(scope: PBFunctionScope) {\r\n super.fragmentShader(scope);\r\n const pb = scope.$builder;\r\n const that = this;\r\n if (this.needFragmentColorInput()) {\r\n scope.$l.albedo = this.calculateAlbedoColor(scope);\r\n if (this.vertexColor) {\r\n scope.albedo = pb.mul(scope.albedo, this.getVertexColor(scope));\r\n }\r\n if (this.drawContext.renderPass!.type === RENDER_PASS_TYPE_LIGHT) {\r\n scope.$l.color = pb.vec3(0);\r\n scope.$l.normal = this.calculateNormal(\r\n scope,\r\n scope.$inputs.worldPos,\r\n scope.$inputs.wNorm,\r\n scope.$inputs.wTangent,\r\n scope.$inputs.wBinormal\r\n );\r\n if (this.needCalculateEnvLight()) {\r\n scope.color = pb.add(scope.color, this.getEnvLightIrradiance(scope, scope.normal));\r\n }\r\n this.forEachLight(scope, function (type, posRange, dirCutoff, colorIntensity, extra, shadow) {\r\n this.$l.lightAtten = that.calculateLightAttenuation(\r\n this,\r\n type,\r\n scope.$inputs.worldPos,\r\n posRange,\r\n dirCutoff,\r\n extra\r\n );\r\n this.$l.lightDir = that.calculateLightDirection(\r\n this,\r\n type,\r\n scope.$inputs.worldPos,\r\n posRange,\r\n dirCutoff\r\n );\r\n this.$l.NoL = pb.clamp(pb.dot(this.normal, this.lightDir), 0, 1);\r\n this.$l.lightContrib = pb.mul(\r\n colorIntensity.rgb,\r\n colorIntensity.a,\r\n this.NoL,\r\n this.lightAtten,\r\n 1 / Math.PI\r\n );\r\n if (shadow) {\r\n this.$l.shadow = pb.vec3(that.calculateShadow(this, scope.$inputs.worldPos, this.NoL));\r\n this.lightContrib = pb.mul(this.lightContrib, this.shadow);\r\n }\r\n this.color = pb.add(this.color, this.lightContrib);\r\n });\r\n scope.$l.litColor = pb.mul(scope.albedo, pb.vec4(scope.color, 1));\r\n if (\r\n this.drawContext.materialFlags &\r\n (MaterialVaryingFlags.SCENE_STORE_ROUGHNESS | MaterialVaryingFlags.SCENE_STORE_NORMAL)\r\n ) {\r\n this.outputFragmentColor(\r\n scope,\r\n scope.$inputs.worldPos,\r\n scope.litColor,\r\n pb.vec4(0, 0, 0, 1),\r\n pb.vec4(pb.add(pb.mul(scope.normal, 0.5), pb.vec3(0.5)), 1)\r\n );\r\n } else {\r\n this.outputFragmentColor(scope, scope.$inputs.worldPos, scope.litColor);\r\n }\r\n } else {\r\n this.outputFragmentColor(scope, scope.$inputs.worldPos, scope.albedo);\r\n }\r\n } else {\r\n this.outputFragmentColor(scope, scope.$inputs.worldPos, null);\r\n }\r\n }\r\n}\r\n"],"names":["LambertMaterial","applyMaterialMixins","MeshMaterial","mixinLight","mixinVertexColor","FEATURE_VERTEX_NORMAL","defineFeature","FEATURE_VERTEX_TANGENT","useFeature","clone","other","copyFrom","vertexNormal","featureUsed","val","vertexTangent","vertexShader","scope","pb","$builder","$l","oPos","ShaderHelper","resolveVertexPosition","$outputs","worldPos","mul","getWorldMatrix","vec4","xyz","setClipSpacePosition","getViewProjectionMatrix","oNorm","resolveVertexNormal","wNorm","getNormalMatrix","oTangent","resolveVertexTangent","wTangent","wBinormal","cross","w","fragmentShader","that","needFragmentColorInput","albedo","calculateAlbedoColor","vertexColor","getVertexColor","drawContext","renderPass","type","RENDER_PASS_TYPE_LIGHT","color","vec3","normal","calculateNormal","$inputs","needCalculateEnvLight","add","getEnvLightIrradiance","forEachLight","posRange","dirCutoff","colorIntensity","extra","shadow","lightAtten","calculateLightAttenuation","lightDir","calculateLightDirection","NoL","clamp","dot","lightContrib","rgb","a","Math","PI","calculateShadow","litColor","materialFlags","MaterialVaryingFlags","SCENE_STORE_ROUGHNESS","SCENE_STORE_NORMAL","outputFragmentColor"],"mappings":";;;;;;AAQA;;;AAGC,IACM,MAAMA,eACHC,SAAAA,mBAAAA,CAAoBC,cAAcC,UAAYC,EAAAA,gBAAAA,CAAAA,CAAAA;AAGtD,IAAA,OAAwBC,qBAAwB,GAAA,IAAI,CAACC,aAAa,EAAG;AACrE,IAAA,OAAwBC,sBAAyB,GAAA,IAAI,CAACD,aAAa,EAAG;IACtE,WAAc,EAAA;QACZ,KAAK,EAAA;AACL,QAAA,IAAI,CAACE,UAAU,CAACR,eAAAA,CAAgBK,qBAAqB,EAAE,IAAA,CAAA;AACzD;IACAI,KAAQ,GAAA;AACN,QAAA,MAAMC,QAAQ,IAAIV,eAAAA,EAAAA;QAClBU,KAAMC,CAAAA,QAAQ,CAAC,IAAI,CAAA;QACnB,OAAOD,KAAAA;AACT;oDAEA,IAAIE,YAAe,GAAA;AACjB,QAAA,OAAO,IAAI,CAACC,WAAW,CAAUb,gBAAgBK,qBAAqB,CAAA;AACxE;IACA,IAAIO,YAAAA,CAAaE,GAAG,EAAE;AACpB,QAAA,IAAI,CAACN,UAAU,CAACR,gBAAgBK,qBAAqB,EAAE,CAAC,CAACS,GAAAA,CAAAA;AAC3D;oDAEA,IAAIC,aAAgB,GAAA;AAClB,QAAA,OAAO,IAAI,CAACF,WAAW,CAAUb,gBAAgBO,sBAAsB,CAAA;AACzE;IACA,IAAIQ,aAAAA,CAAcD,GAAG,EAAE;AACrB,QAAA,IAAI,CAACN,UAAU,CAACR,gBAAgBO,sBAAsB,EAAE,CAAC,CAACO,GAAAA,CAAAA;AAC5D;AACAE,IAAAA,YAAAA,CAAaC,KAAsB,EAAE;AACnC,QAAA,KAAK,CAACD,YAAaC,CAAAA,KAAAA,CAAAA;QACnB,MAAMC,EAAAA,GAAKD,MAAME,QAAQ;AACzBF,QAAAA,KAAAA,CAAMG,EAAE,CAACC,IAAI,GAAGC,YAAAA,CAAaC,qBAAqB,CAACN,KAAAA,CAAAA;AACnDA,QAAAA,KAAAA,CAAMO,QAAQ,CAACC,QAAQ,GAAGP,EAAGQ,CAAAA,GAAG,CAACJ,YAAaK,CAAAA,cAAc,CAACV,KAAAA,CAAAA,EAAQC,GAAGU,IAAI,CAACX,MAAMI,IAAI,EAAE,IAAIQ,GAAG;AAChGP,QAAAA,YAAAA,CAAaQ,oBAAoB,CAC/Bb,KAAAA,EACAC,EAAGQ,CAAAA,GAAG,CAACJ,YAAaS,CAAAA,uBAAuB,CAACd,KAAAA,CAAAA,EAAQC,GAAGU,IAAI,CAACX,MAAMO,QAAQ,CAACC,QAAQ,EAAE,CAAA,CAAA,CAAA,CAAA;QAEvF,IAAI,IAAI,CAACb,YAAY,EAAE;AACrBK,YAAAA,KAAAA,CAAMG,EAAE,CAACY,KAAK,GAAGV,YAAAA,CAAaW,mBAAmB,CAAChB,KAAAA,CAAAA;AAClDA,YAAAA,KAAAA,CAAMO,QAAQ,CAACU,KAAK,GAAGhB,EAAGQ,CAAAA,GAAG,CAACJ,YAAaa,CAAAA,eAAe,CAAClB,KAAAA,CAAAA,EAAQC,GAAGU,IAAI,CAACX,MAAMe,KAAK,EAAE,IAAIH,GAAG;YAC/F,IAAI,IAAI,CAACd,aAAa,EAAE;AACtBE,gBAAAA,KAAAA,CAAMG,EAAE,CAACgB,QAAQ,GAAGd,YAAAA,CAAae,oBAAoB,CAACpB,KAAAA,CAAAA;gBACtDA,KAAMO,CAAAA,QAAQ,CAACc,QAAQ,GAAGpB,GAAGQ,GAAG,CAC9BJ,aAAaa,eAAe,CAAClB,QAC7BC,EAAGU,CAAAA,IAAI,CAACX,KAAMmB,CAAAA,QAAQ,CAACP,GAAG,EAAE,IAC5BA,GAAG;gBACLZ,KAAMO,CAAAA,QAAQ,CAACe,SAAS,GAAGrB,GAAGQ,GAAG,CAC/BR,EAAGsB,CAAAA,KAAK,CAACvB,KAAAA,CAAMO,QAAQ,CAACU,KAAK,EAAEjB,KAAAA,CAAMO,QAAQ,CAACc,QAAQ,CACtDrB,EAAAA,KAAAA,CAAMmB,QAAQ,CAACK,CAAC,CAAA;AAEpB;AACF;AACF;AACAC,IAAAA,cAAAA,CAAezB,KAAsB,EAAE;AACrC,QAAA,KAAK,CAACyB,cAAezB,CAAAA,KAAAA,CAAAA;QACrB,MAAMC,EAAAA,GAAKD,MAAME,QAAQ;AACzB,QAAA,MAAMwB,OAAO,IAAI;QACjB,IAAI,IAAI,CAACC,sBAAsB,EAAI,EAAA;AACjC3B,YAAAA,KAAAA,CAAMG,EAAE,CAACyB,MAAM,GAAG,IAAI,CAACC,oBAAoB,CAAC7B,KAAAA,CAAAA;YAC5C,IAAI,IAAI,CAAC8B,WAAW,EAAE;gBACpB9B,KAAM4B,CAAAA,MAAM,GAAG3B,EAAAA,CAAGQ,GAAG,CAACT,KAAM4B,CAAAA,MAAM,EAAE,IAAI,CAACG,cAAc,CAAC/B,KAAAA,CAAAA,CAAAA;AAC1D;YACA,IAAI,IAAI,CAACgC,WAAW,CAACC,UAAU,CAAEC,IAAI,KAAKC,sBAAwB,EAAA;AAChEnC,gBAAAA,KAAAA,CAAMG,EAAE,CAACiC,KAAK,GAAGnC,EAAAA,CAAGoC,IAAI,CAAC,CAAA,CAAA;gBACzBrC,KAAMG,CAAAA,EAAE,CAACmC,MAAM,GAAG,IAAI,CAACC,eAAe,CACpCvC,KAAAA,EACAA,KAAMwC,CAAAA,OAAO,CAAChC,QAAQ,EACtBR,KAAAA,CAAMwC,OAAO,CAACvB,KAAK,EACnBjB,KAAMwC,CAAAA,OAAO,CAACnB,QAAQ,EACtBrB,KAAAA,CAAMwC,OAAO,CAAClB,SAAS,CAAA;gBAEzB,IAAI,IAAI,CAACmB,qBAAqB,EAAI,EAAA;AAChCzC,oBAAAA,KAAAA,CAAMoC,KAAK,GAAGnC,EAAGyC,CAAAA,GAAG,CAAC1C,KAAMoC,CAAAA,KAAK,EAAE,IAAI,CAACO,qBAAqB,CAAC3C,KAAAA,EAAOA,MAAMsC,MAAM,CAAA,CAAA;AAClF;AACA,gBAAA,IAAI,CAACM,YAAY,CAAC5C,KAAAA,EAAO,SAAUkC,IAAI,EAAEW,QAAQ,EAAEC,SAAS,EAAEC,cAAc,EAAEC,KAAK,EAAEC,MAAM,EAAA;AACzF,oBAAA,IAAI,CAAC9C,EAAE,CAAC+C,UAAU,GAAGxB,KAAKyB,yBAAyB,CACjD,IAAI,EACJjB,MACAlC,KAAMwC,CAAAA,OAAO,CAAChC,QAAQ,EACtBqC,UACAC,SACAE,EAAAA,KAAAA,CAAAA;AAEF,oBAAA,IAAI,CAAC7C,EAAE,CAACiD,QAAQ,GAAG1B,KAAK2B,uBAAuB,CAC7C,IAAI,EACJnB,MACAlC,KAAMwC,CAAAA,OAAO,CAAChC,QAAQ,EACtBqC,QACAC,EAAAA,SAAAA,CAAAA;AAEF,oBAAA,IAAI,CAAC3C,EAAE,CAACmD,GAAG,GAAGrD,EAAAA,CAAGsD,KAAK,CAACtD,EAAAA,CAAGuD,GAAG,CAAC,IAAI,CAAClB,MAAM,EAAE,IAAI,CAACc,QAAQ,GAAG,CAAG,EAAA,CAAA,CAAA;oBAC9D,IAAI,CAACjD,EAAE,CAACsD,YAAY,GAAGxD,GAAGQ,GAAG,CAC3BsC,cAAeW,CAAAA,GAAG,EAClBX,cAAAA,CAAeY,CAAC,EAChB,IAAI,CAACL,GAAG,EACR,IAAI,CAACJ,UAAU,EACf,CAAIU,GAAAA,IAAAA,CAAKC,EAAE,CAAA;AAEb,oBAAA,IAAIZ,MAAQ,EAAA;wBACV,IAAI,CAAC9C,EAAE,CAAC8C,MAAM,GAAGhD,EAAGoC,CAAAA,IAAI,CAACX,IAAKoC,CAAAA,eAAe,CAAC,IAAI,EAAE9D,MAAMwC,OAAO,CAAChC,QAAQ,EAAE,IAAI,CAAC8C,GAAG,CAAA,CAAA;AACpF,wBAAA,IAAI,CAACG,YAAY,GAAGxD,EAAAA,CAAGQ,GAAG,CAAC,IAAI,CAACgD,YAAY,EAAE,IAAI,CAACR,MAAM,CAAA;AAC3D;AACA,oBAAA,IAAI,CAACb,KAAK,GAAGnC,EAAAA,CAAGyC,GAAG,CAAC,IAAI,CAACN,KAAK,EAAE,IAAI,CAACqB,YAAY,CAAA;AACnD,iBAAA,CAAA;AACAzD,gBAAAA,KAAAA,CAAMG,EAAE,CAAC4D,QAAQ,GAAG9D,GAAGQ,GAAG,CAACT,KAAM4B,CAAAA,MAAM,EAAE3B,EAAGU,CAAAA,IAAI,CAACX,KAAAA,CAAMoC,KAAK,EAAE,CAAA,CAAA,CAAA;AAC9D,gBAAA,IACE,IAAI,CAACJ,WAAW,CAACgC,aAAa,IAC7BC,oBAAAA,CAAqBC,qBAAqB,GAAGD,oBAAqBE,CAAAA,kBAAkB,CACrF,EAAA;AACA,oBAAA,IAAI,CAACC,mBAAmB,CACtBpE,KAAAA,EACAA,MAAMwC,OAAO,CAAChC,QAAQ,EACtBR,MAAM+D,QAAQ,EACd9D,EAAGU,CAAAA,IAAI,CAAC,CAAG,EAAA,CAAA,EAAG,CAAG,EAAA,CAAA,CAAA,EACjBV,GAAGU,IAAI,CAACV,EAAGyC,CAAAA,GAAG,CAACzC,EAAGQ,CAAAA,GAAG,CAACT,KAAAA,CAAMsC,MAAM,EAAE,GAAA,CAAA,EAAMrC,EAAGoC,CAAAA,IAAI,CAAC,GAAO,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;iBAEtD,MAAA;oBACL,IAAI,CAAC+B,mBAAmB,CAACpE,KAAOA,EAAAA,KAAAA,CAAMwC,OAAO,CAAChC,QAAQ,EAAER,KAAAA,CAAM+D,QAAQ,CAAA;AACxE;aACK,MAAA;gBACL,IAAI,CAACK,mBAAmB,CAACpE,KAAOA,EAAAA,KAAAA,CAAMwC,OAAO,CAAChC,QAAQ,EAAER,KAAAA,CAAM4B,MAAM,CAAA;AACtE;SACK,MAAA;YACL,IAAI,CAACwC,mBAAmB,CAACpE,KAAAA,EAAOA,MAAMwC,OAAO,CAAChC,QAAQ,EAAE,IAAA,CAAA;AAC1D;AACF;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"lambert.js","sources":["../../src/material/lambert.ts"],"sourcesContent":["import { mixinLight } from './mixins/lit';\r\nimport { mixinVertexColor } from './mixins/vertexcolor';\r\nimport { MeshMaterial, applyMaterialMixins } from './meshmaterial';\r\nimport type { PBFunctionScope } from '@zephyr3d/device';\r\nimport { ShaderHelper } from './shader/helper';\r\nimport { MaterialVaryingFlags, RENDER_PASS_TYPE_LIGHT } from '../values';\r\nimport type { Clonable } from '@zephyr3d/base';\r\n\r\n/**\r\n * Lambert material\r\n * @public\r\n */\r\nexport class LambertMaterial\r\n extends applyMaterialMixins(MeshMaterial, mixinLight, mixinVertexColor)\r\n implements Clonable<LambertMaterial>\r\n{\r\n private static readonly FEATURE_VERTEX_NORMAL = this.defineFeature();\r\n private static readonly FEATURE_VERTEX_TANGENT = this.defineFeature();\r\n constructor() {\r\n super();\r\n this.useFeature(LambertMaterial.FEATURE_VERTEX_NORMAL, true);\r\n }\r\n clone() {\r\n const other = new LambertMaterial();\r\n other.copyFrom(this);\r\n return other;\r\n }\r\n /** true if vertex normal attribute presents */\r\n get vertexNormal() {\r\n return this.featureUsed<boolean>(LambertMaterial.FEATURE_VERTEX_NORMAL);\r\n }\r\n set vertexNormal(val) {\r\n this.useFeature(LambertMaterial.FEATURE_VERTEX_NORMAL, !!val);\r\n }\r\n /** true if vertex normal attribute presents */\r\n get vertexTangent() {\r\n return this.featureUsed<boolean>(LambertMaterial.FEATURE_VERTEX_TANGENT);\r\n }\r\n set vertexTangent(val) {\r\n this.useFeature(LambertMaterial.FEATURE_VERTEX_TANGENT, !!val);\r\n }\r\n vertexShader(scope: PBFunctionScope) {\r\n super.vertexShader(scope);\r\n const pb = scope.$builder;\r\n scope.$l.oPos = ShaderHelper.resolveVertexPosition(scope);\r\n scope.$outputs.worldPos = pb.mul(ShaderHelper.getWorldMatrix(scope), pb.vec4(scope.oPos, 1)).xyz;\r\n ShaderHelper.setClipSpacePosition(\r\n scope,\r\n pb.mul(ShaderHelper.getViewProjectionMatrix(scope), pb.vec4(scope.$outputs.worldPos, 1))\r\n );\r\n if (this.vertexNormal) {\r\n scope.$l.oNorm = ShaderHelper.resolveVertexNormal(scope);\r\n scope.$outputs.wNorm = pb.mul(ShaderHelper.getNormalMatrix(scope), pb.vec4(scope.oNorm, 0)).xyz;\r\n if (this.vertexTangent) {\r\n scope.$l.oTangent = ShaderHelper.resolveVertexTangent(scope);\r\n scope.$outputs.wTangent = pb.mul(\r\n ShaderHelper.getNormalMatrix(scope),\r\n pb.vec4(scope.oTangent.xyz, 0)\r\n ).xyz;\r\n scope.$outputs.wBinormal = pb.mul(\r\n pb.cross(scope.$outputs.wNorm, scope.$outputs.wTangent),\r\n scope.oTangent.w\r\n );\r\n }\r\n }\r\n }\r\n fragmentShader(scope: PBFunctionScope) {\r\n super.fragmentShader(scope);\r\n const pb = scope.$builder;\r\n const that = this;\r\n if (this.needFragmentColorInput()) {\r\n scope.$l.albedo = this.calculateAlbedoColor(scope);\r\n if (this.vertexColor) {\r\n scope.albedo = pb.mul(scope.albedo, this.getVertexColor(scope));\r\n }\r\n if (this.drawContext.renderPass!.type === RENDER_PASS_TYPE_LIGHT) {\r\n scope.$l.color = pb.vec3(0);\r\n // TBN[2] is the pre-normal-map geometric normal, needed for shadow\r\n // normal offset bias.\r\n scope.$l.normalInfo = this.calculateNormalAndTBN(\r\n scope,\r\n scope.$inputs.worldPos,\r\n scope.$inputs.wNorm,\r\n scope.$inputs.wTangent,\r\n scope.$inputs.wBinormal\r\n );\r\n scope.$l.normal = scope.normalInfo.normal;\r\n if (this.needCalculateEnvLight()) {\r\n scope.color = pb.add(scope.color, this.getEnvLightIrradiance(scope, scope.normal));\r\n }\r\n this.forEachLight(scope, function (type, posRange, dirCutoff, colorIntensity, extra, shadow) {\r\n this.$l.lightAtten = that.calculateLightAttenuation(\r\n this,\r\n type,\r\n scope.$inputs.worldPos,\r\n posRange,\r\n dirCutoff,\r\n extra\r\n );\r\n this.$l.lightDir = that.calculateLightDirection(\r\n this,\r\n type,\r\n scope.$inputs.worldPos,\r\n posRange,\r\n dirCutoff\r\n );\r\n this.$l.NoL = pb.clamp(pb.dot(this.normal, this.lightDir), 0, 1);\r\n this.$l.lightContrib = pb.mul(\r\n colorIntensity.rgb,\r\n colorIntensity.a,\r\n this.NoL,\r\n this.lightAtten,\r\n 1 / Math.PI\r\n );\r\n if (shadow) {\r\n this.$l.shadow = pb.vec3(\r\n that.calculateShadow(this, scope.$inputs.worldPos, scope.normalInfo.TBN[2], this.NoL)\r\n );\r\n this.lightContrib = pb.mul(this.lightContrib, this.shadow);\r\n }\r\n this.color = pb.add(this.color, this.lightContrib);\r\n });\r\n scope.$l.litColor = pb.mul(scope.albedo, pb.vec4(scope.color, 1));\r\n if (\r\n this.drawContext.materialFlags &\r\n (MaterialVaryingFlags.SCENE_STORE_ROUGHNESS | MaterialVaryingFlags.SCENE_STORE_NORMAL)\r\n ) {\r\n this.outputFragmentColor(\r\n scope,\r\n scope.$inputs.worldPos,\r\n scope.litColor,\r\n pb.vec4(0, 0, 0, 1),\r\n pb.vec4(pb.add(pb.mul(scope.normal, 0.5), pb.vec3(0.5)), 1)\r\n );\r\n } else {\r\n this.outputFragmentColor(scope, scope.$inputs.worldPos, scope.litColor);\r\n }\r\n } else {\r\n this.outputFragmentColor(scope, scope.$inputs.worldPos, scope.albedo);\r\n }\r\n } else {\r\n this.outputFragmentColor(scope, scope.$inputs.worldPos, null);\r\n }\r\n }\r\n}\r\n"],"names":["LambertMaterial","applyMaterialMixins","MeshMaterial","mixinLight","mixinVertexColor","FEATURE_VERTEX_NORMAL","defineFeature","FEATURE_VERTEX_TANGENT","useFeature","clone","other","copyFrom","vertexNormal","featureUsed","val","vertexTangent","vertexShader","scope","pb","$builder","$l","oPos","ShaderHelper","resolveVertexPosition","$outputs","worldPos","mul","getWorldMatrix","vec4","xyz","setClipSpacePosition","getViewProjectionMatrix","oNorm","resolveVertexNormal","wNorm","getNormalMatrix","oTangent","resolveVertexTangent","wTangent","wBinormal","cross","w","fragmentShader","that","needFragmentColorInput","albedo","calculateAlbedoColor","vertexColor","getVertexColor","drawContext","renderPass","type","RENDER_PASS_TYPE_LIGHT","color","vec3","normalInfo","calculateNormalAndTBN","$inputs","normal","needCalculateEnvLight","add","getEnvLightIrradiance","forEachLight","posRange","dirCutoff","colorIntensity","extra","shadow","lightAtten","calculateLightAttenuation","lightDir","calculateLightDirection","NoL","clamp","dot","lightContrib","rgb","a","Math","PI","calculateShadow","TBN","litColor","materialFlags","MaterialVaryingFlags","SCENE_STORE_ROUGHNESS","SCENE_STORE_NORMAL","outputFragmentColor"],"mappings":"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"}
|