import { LinearFilter, NearestFilter, RenderTarget, Texture, Vector2 } from "three"; import { WebGPURenderer } from "three/webgpu"; //#region src/lights/SDFGenerator.d.ts /** @internal */ declare class SDFGenerator { /** Final SDF output texture. Reference is stable across resizes. */ get sdfTexture(): Texture; private _pingRT; private _pongRT; private _sdfRT; private _sdfBlurRT; private _seedMaterial; private _jfaMaterialA; private _jfaMaterialB; private _finalMaterialA; private _finalMaterialB; private _blurHMaterial; private _blurVMaterial; private _jumpSizeA; private _jumpSizeB; private _texelSize; private _worldSizeNode; private _occlusionTex; private _sdfFilter; constructor(); init(width: number, height: number): void; /** * Select the sampling filter for the SDF-output texture (and its blur * scratch). Nearest avoids the eps-threshold halo for crisp / pixel- * snapped shadows; linear is safe once the blur pass has smoothed the * field, giving softer edges for non-snapped shadows. No-op when the * filter is unchanged — safe to call every frame. Never touches the JFA * ping-pong RTs, which must stay nearest for correct seed propagation. */ setFilter(filter: typeof NearestFilter | typeof LinearFilter): void; resize(width: number, height: number): void; /** * Push the current camera frustum (world units) to the JFA / final-pass * shaders so distance math is world-isotropic on non-square viewports. * Must be called each frame before {@link generate}. */ setWorldBounds(worldSize: Vector2): void; /** * Run the full JFA pipeline: seed pass → N ping-pong passes → final * distance pass → separable blur. All passes go through the shared * `QuadMesh` with `RendererUtils` wrapping the state save/restore — * matching the three.js canonical TSL post-effect pattern (N8AONode, * BloomNode, etc.). That path is what lets three.js handle the WebGPU * Y-flip and binding refresh correctly; our previous hand-rolled * Scene/Camera/Mesh render did not. */ generate(renderer: WebGPURenderer, occlusionRT: RenderTarget): void; dispose(): void; /** * Seed pass — classifies each texel by occluder alpha (threshold 0.5 * to clamp sub-pixel / anti-aliased edges to a clean binary mask) and * writes two seed UVs packed into RGBA: * * (R, G) = occluder fragments seed their own UV, empty fragments * seed a FAR sentinel. JFA converges this to "nearest- * occluder seed UV" at every fragment. * (B, A) = empty fragments seed their own UV, occluder fragments * seed FAR. JFA converges to "nearest-empty-space seed UV" * at every fragment. * * One material, one draw, both chains propagated in parallel through * the JFA pass. */ private _ensureSeedMaterial; /** * JFA propagation material. For each fragment, tests 9 neighbor texels * at `jumpSize` UV distance and updates BOTH the outside and inside * best-seed records in parallel. One texture sample per neighbor * (identical bandwidth to the pre-signed single-chain design); two * distance comparisons and two conditional updates per neighbor (cheap * ALU relative to the sample cost). * * UV diffs are weighted by world size so the sphere-trace distance * comparison is isotropic on non-square viewports — UV-space comparison * on a rectangular RT would pick an anisotropic winner and squash the * SDF along one axis. */ private _buildJFAMaterial; /** * Final-distance material. Reads the packed converged seed UVs from * one texture and writes a signed distance: * * distOutside = |fragUV - nearestOccluderSeedUV| in world units * distInside = |fragUV - nearestEmptySeedUV| in world units * signedDist = distOutside - distInside * * Because the two terms never both exceed zero — a fragment either * sits in empty space (distOutside > 0, distInside = 0) or inside an * occluder (distOutside = 0, distInside > 0) — the subtraction yields * a clean signed output: positive outside, negative inside. * * G/B hold the outward-pointing world-space gradient (vector toward * the nearest occluder). Consumers use them as a direction hint; * magnitude is redundant with |R|. */ private _buildFinalMaterial; /** * 5-tap binomial separable blur [1,4,6,4,1]/16. Runs every frame in the * hot path: the H pass writes sdfRT → sdfBlurRT and the V pass writes * sdfBlurRT → sdfRT (see `generate()`), so the final SDF in `sdfRT` is * always the blurred field. `sdfBlurRT` doubles as a valid debug target. */ private _buildBlurMaterial; } //#endregion export { SDFGenerator }; //# sourceMappingURL=SDFGenerator.d.ts.map